lemon/lp_utils.h
author deba
Thu, 15 Feb 2007 19:15:14 +0000
changeset 2364 3a5e67bd42d2
parent 2363 2aabce558574
child 2368 6b2e8b734ae7
permissions -rw-r--r--
Lp row and col getter function
lp section reader and writer for lemon IO
deba@2316
     1
/* -*- C++ -*-
deba@2316
     2
 *
deba@2316
     3
 * This file is a part of LEMON, a generic C++ optimization library
deba@2316
     4
 *
deba@2316
     5
 * Copyright (C) 2003-2006
deba@2316
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
deba@2316
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
deba@2316
     8
 *
deba@2316
     9
 * Permission to use, modify and distribute this software is granted
deba@2316
    10
 * provided that this copyright notice appears in all copies. For
deba@2316
    11
 * precise terms see the accompanying LICENSE file.
deba@2316
    12
 *
deba@2316
    13
 * This software is provided "AS IS" with no warranty of any kind,
deba@2316
    14
 * express or implied, and with no claim as to its suitability for any
deba@2316
    15
 * purpose.
deba@2316
    16
 *
deba@2316
    17
 */
deba@2316
    18
deba@2316
    19
#ifndef LEMON_LP_UTILS_H
deba@2316
    20
#define LEMON_LP_UTILS_H
deba@2316
    21
deba@2316
    22
#include <lemon/lp_base.h>
deba@2316
    23
deba@2316
    24
#include <lemon/lemon_reader.h>
deba@2363
    25
#include <lemon/lemon_writer.h>
deba@2316
    26
deba@2316
    27
namespace lemon {
deba@2316
    28
deba@2316
    29
  class LpReader : public LemonReader::SectionReader {
deba@2316
    30
    typedef LemonReader::SectionReader Parent;
deba@2316
    31
  public:
deba@2316
    32
deba@2316
    33
deba@2316
    34
    /// \brief Constructor.
deba@2316
    35
    ///
deba@2316
    36
    /// Constructor for LpReader. It creates the LpReader and attach
deba@2316
    37
    /// it into the given LemonReader. The lp reader will add
deba@2316
    38
    /// variables, constraints and objective function to the
deba@2316
    39
    /// given lp solver.
deba@2316
    40
    LpReader(LemonReader& _reader, LpSolverBase& _lp, 
deba@2316
    41
             const std::string& _name = std::string())
deba@2316
    42
      : Parent(_reader), lp(_lp), name(_name) {} 
deba@2316
    43
deba@2316
    44
deba@2316
    45
    /// \brief Destructor.
deba@2316
    46
    ///
deba@2316
    47
    /// Destructor for NodeSetReader.
deba@2316
    48
    virtual ~LpReader() {}
deba@2316
    49
deba@2316
    50
  private:
deba@2316
    51
    LpReader(const LpReader&);
deba@2316
    52
    void operator=(const LpReader&);
deba@2316
    53
  
deba@2316
    54
  protected:
deba@2316
    55
deba@2316
    56
    /// \brief Gives back true when the SectionReader can process 
deba@2316
    57
    /// the section with the given header line.
deba@2316
    58
    ///
deba@2316
    59
    /// It gives back true when the header line starts with \c \@lp,
deba@2316
    60
    /// and the header line's name and the nodeset's name are the same.
deba@2316
    61
    virtual bool header(const std::string& line) {
deba@2316
    62
      std::istringstream ls(line);
deba@2316
    63
      std::string command;
deba@2316
    64
      std::string id;
deba@2316
    65
      ls >> command >> id;
deba@2316
    66
      return command == "@lp" && name == id;
deba@2316
    67
    }
deba@2316
    68
deba@2316
    69
  private:
deba@2316
    70
deba@2364
    71
    enum SubSection {
deba@2364
    72
      CONSTRAINTS, BOUNDS, OBJECTIVE
deba@2364
    73
    };
deba@2364
    74
deba@2316
    75
    enum Relation {
deba@2316
    76
      LE, EQ, GE
deba@2316
    77
    };
deba@2316
    78
deba@2364
    79
    std::istream& readConstraint(std::istream& is) {
deba@2364
    80
      LpSolverBase::Constr c;
deba@2316
    81
      char x;
deba@2316
    82
      LpSolverBase::Expr e1, e2;
deba@2316
    83
      Relation op1;
deba@2316
    84
      is >> std::ws;
deba@2316
    85
      readExpression(is, e1);
deba@2316
    86
      is >> std::ws;
deba@2316
    87
      readRelation(is, op1);
deba@2316
    88
      is >> std::ws;
deba@2316
    89
      readExpression(is, e2);
deba@2364
    90
      is >> std::ws;
deba@2316
    91
      if (!is.get(x)) {
deba@2316
    92
        if (op1 == LE) {
deba@2364
    93
          if (e1.size() == 0) {
deba@2364
    94
            c = e2 >= e1;
deba@2364
    95
          } else {
deba@2364
    96
            c = e1 <= e2;
deba@2364
    97
          }
deba@2316
    98
          c = e1 <= e2;
deba@2316
    99
        } else if (op1 == GE) {
deba@2364
   100
          if (e1.size() == 0) {
deba@2364
   101
            c = e2 <= e1;
deba@2364
   102
          } else {
deba@2364
   103
            c = e1 >= e2;
deba@2364
   104
          }
deba@2316
   105
        } else {
deba@2364
   106
          if (e1.size() == 0) {
deba@2364
   107
            c = e2 == e1;
deba@2364
   108
          } else {
deba@2364
   109
            c = e1 == e2;
deba@2364
   110
          }
deba@2316
   111
        }
deba@2316
   112
      } else {
deba@2316
   113
        is.putback(x);
deba@2316
   114
        LpSolverBase::Expr e3;
deba@2316
   115
        Relation op2;
deba@2316
   116
        readRelation(is, op2);
deba@2316
   117
        is >> std::ws;
deba@2316
   118
        readExpression(is, e3);
deba@2316
   119
        if (!e1.empty() || !e3.empty()) {
deba@2316
   120
          throw DataFormatError("Wrong range format");
deba@2316
   121
        }
deba@2316
   122
        if (op2 != op1 || op1 == EQ) {
deba@2316
   123
          throw DataFormatError("Wrong range format");
deba@2316
   124
        }
deba@2316
   125
        if (op1 == LE) {
deba@2316
   126
          c = e1.constComp() <= e2 <= e3.constComp();
deba@2316
   127
        } else {
deba@2316
   128
          c = e1.constComp() >= e2 >= e3.constComp();
deba@2316
   129
        }
deba@2364
   130
        is >> std::ws;
deba@2364
   131
        if (is.get(x)) {
deba@2364
   132
          throw DataFormatError("Wrong variable bounds format");
deba@2364
   133
        }
deba@2316
   134
      }
deba@2364
   135
      lp.addRow(c);
deba@2364
   136
      return is;
deba@2364
   137
    }
deba@2364
   138
deba@2364
   139
    std::istream& readObjective(std::istream& is) {
deba@2364
   140
      is >> std::ws;
deba@2364
   141
      std::string sense;
deba@2364
   142
      is >> sense;
deba@2364
   143
      if (sense != "min" && sense != "max") {
deba@2364
   144
        throw DataFormatError("Wrong objective function format");
deba@2364
   145
      }
deba@2364
   146
      LpSolverBase::Expr expr;
deba@2364
   147
      is >> std::ws;
deba@2364
   148
      readExpression(is, expr);
deba@2364
   149
      lp.setObj(expr);
deba@2364
   150
      if (sense == "min") {
deba@2364
   151
        lp.min();
deba@2364
   152
      } else {
deba@2364
   153
        lp.max();
deba@2364
   154
      }
deba@2364
   155
      return is;
deba@2364
   156
    }
deba@2364
   157
deba@2364
   158
    std::istream& readBounds(std::istream& is) {
deba@2364
   159
      LpSolverBase::Col c;
deba@2364
   160
      char x;
deba@2364
   161
      is >> std::ws;
deba@2364
   162
      if (!is.get(x)) {
deba@2364
   163
        throw DataFormatError("Wrong variable bounds format");
deba@2364
   164
      }
deba@2364
   165
      if (varFirstChar(x)) {
deba@2364
   166
        is.putback(x);
deba@2364
   167
        readCol(is, c);
deba@2364
   168
        is >> std::ws;
deba@2364
   169
        Relation op1;
deba@2364
   170
        readRelation(is, op1);
deba@2364
   171
        double v;
deba@2364
   172
        readNum(is, v);
deba@2364
   173
        if (op1 == EQ) {
deba@2364
   174
          lp.colLowerBound(c, v);
deba@2364
   175
          lp.colUpperBound(c, v);
deba@2364
   176
        } else if (op1 == LE) {
deba@2364
   177
          lp.colUpperBound(c, v);
deba@2364
   178
        } else {
deba@2364
   179
          lp.colLowerBound(c, v);
deba@2364
   180
        }
deba@2364
   181
        is >> std::ws;
deba@2364
   182
        if (is.get(x)) {
deba@2364
   183
          throw DataFormatError("Wrong variable bounds format");
deba@2364
   184
        }
deba@2364
   185
      } else {
deba@2364
   186
        is.putback(x);
deba@2364
   187
        double v;
deba@2364
   188
        readNum(is, v);
deba@2364
   189
        is >> std::ws;
deba@2364
   190
        Relation op1;
deba@2364
   191
        readRelation(is, op1);
deba@2364
   192
        is >> std::ws;
deba@2364
   193
        readCol(is, c);
deba@2364
   194
        is >> std::ws;
deba@2364
   195
        if (is.get(x)) {
deba@2364
   196
          is.putback(x);
deba@2364
   197
          is >> std::ws;
deba@2364
   198
          Relation op2;
deba@2364
   199
          readRelation(is, op2);
deba@2364
   200
          double w;
deba@2364
   201
          is >> std::ws;
deba@2364
   202
          readNum(is, w);
deba@2364
   203
          if (op2 != op1 || op1 == EQ) {
deba@2364
   204
            throw DataFormatError("Wrong range format");
deba@2364
   205
          }
deba@2364
   206
          if (op1 == LE) {
deba@2364
   207
            lp.colLowerBound(c, v);
deba@2364
   208
            lp.colUpperBound(c, w);
deba@2364
   209
          } else {
deba@2364
   210
            lp.colLowerBound(c, w);
deba@2364
   211
            lp.colUpperBound(c, v);
deba@2364
   212
          }
deba@2364
   213
          if (is.get(x)) {
deba@2364
   214
            throw DataFormatError("Wrong variable bounds format");
deba@2364
   215
          }
deba@2364
   216
        } else {
deba@2364
   217
          if (op1 == EQ) {
deba@2364
   218
            lp.colLowerBound(c, v);
deba@2364
   219
            lp.colUpperBound(c, v);
deba@2364
   220
          } else if (op1 == LE) {
deba@2364
   221
            lp.colLowerBound(c, v);
deba@2364
   222
          } else {
deba@2364
   223
            lp.colUpperBound(c, v);
deba@2364
   224
          }
deba@2364
   225
        }
deba@2364
   226
      }
deba@2364
   227
      return is;
deba@2316
   228
    }
deba@2316
   229
deba@2316
   230
    std::istream& readExpression(std::istream& is, LpSolverBase::Expr& e) {
deba@2316
   231
      LpSolverBase::Col c;
deba@2316
   232
      double d;
deba@2316
   233
      char x;
deba@2316
   234
      readElement(is, c, d);
deba@2316
   235
      if (c != INVALID) {
deba@2316
   236
        e += d * c;
deba@2316
   237
      } else {
deba@2316
   238
        e += d;
deba@2316
   239
      }
deba@2316
   240
      is >> std::ws;
deba@2316
   241
      while (is.get(x) && (x == '+' || x == '-')) {
deba@2316
   242
        is >> std::ws;
deba@2316
   243
        readElement(is, c, d);
deba@2316
   244
        if (c != INVALID) {
deba@2316
   245
          e += (x == '+' ? d : -d) * c;
deba@2316
   246
        } else {
deba@2316
   247
          e += (x == '+' ? d : -d);
deba@2316
   248
        }
deba@2316
   249
        is >> std::ws;
deba@2316
   250
      }
deba@2316
   251
      if (!is) {
deba@2316
   252
        is.clear();
deba@2316
   253
      } else {
deba@2316
   254
        is.putback(x);
deba@2316
   255
      }
deba@2316
   256
      return is;
deba@2316
   257
    }
deba@2316
   258
deba@2316
   259
    std::istream& readElement(std::istream& is, 
deba@2316
   260
                              LpSolverBase::Col& c, double& d) { 
deba@2316
   261
      d = 1.0;
deba@2316
   262
      c = INVALID;
deba@2316
   263
      char x, y;
deba@2316
   264
      if (!is.get(x)) throw DataFormatError("Cannot find lp element");
deba@2316
   265
      if (x == '+' || x == '-') {
deba@2316
   266
        is >> std::ws;
deba@2316
   267
        d *= x == '-' ? -1 : 1;
deba@2316
   268
        while (is.get(x) && (x == '+' || x == '-')) {
deba@2316
   269
          d *= x == '-' ? -1 : 1;
deba@2316
   270
          is >> std::ws;
deba@2316
   271
        }
deba@2316
   272
        if (!is) throw DataFormatError("Cannot find lp element");
deba@2316
   273
      }
deba@2316
   274
      if (numFirstChar(x)) {
deba@2316
   275
        is.putback(x);
deba@2316
   276
        double e;
deba@2316
   277
        readNum(is, e);
deba@2316
   278
        d *= e;
deba@2316
   279
      } else if (varFirstChar(x)) {
deba@2316
   280
        is.putback(x);
deba@2316
   281
        LpSolverBase::Col f;
deba@2316
   282
        readCol(is, f);
deba@2316
   283
        c = f;
deba@2316
   284
      } else {
deba@2316
   285
        throw DataFormatError("Invalid expression format");          
deba@2316
   286
      }
deba@2316
   287
      is >> std::ws;
deba@2316
   288
      while (is.get(y) && (y == '*' || y == '/')) {
deba@2316
   289
        is >> std::ws;
deba@2316
   290
        if (!is.get(x)) throw DataFormatError("Cannot find lp element");
deba@2316
   291
        if (x == '+' || x == '-') {
deba@2316
   292
          is >> std::ws;
deba@2316
   293
          d *= x == '-' ? -1 : 1;
deba@2316
   294
          while (is.get(x) && (x == '+' || x == '-')) {
deba@2316
   295
            d *= x == '-' ? -1 : 1;
deba@2316
   296
            is >> std::ws;
deba@2316
   297
          }
deba@2316
   298
          if (!is) throw DataFormatError("Cannot find lp element");
deba@2316
   299
        }
deba@2316
   300
        if (numFirstChar(x)) {
deba@2316
   301
          is.putback(x);
deba@2316
   302
          double e;
deba@2316
   303
          readNum(is, e);
deba@2316
   304
          if (y == '*') {
deba@2316
   305
            d *= e;
deba@2316
   306
          } else {
deba@2316
   307
            d /= e;
deba@2316
   308
          }
deba@2316
   309
        } else if (varFirstChar(x)) {
deba@2316
   310
          is.putback(x);
deba@2316
   311
          LpSolverBase::Col f;
deba@2316
   312
          readCol(is, f);
deba@2316
   313
          if (y == '*') {
deba@2316
   314
            if (c == INVALID) {
deba@2316
   315
              c = f;
deba@2316
   316
            } else {
deba@2316
   317
              throw DataFormatError("Quadratic element in expression");
deba@2316
   318
            }
deba@2316
   319
          } else {
deba@2316
   320
            throw DataFormatError("Division by variable");
deba@2316
   321
          }
deba@2316
   322
        } else {
deba@2316
   323
          throw DataFormatError("Invalid expression format");          
deba@2316
   324
        }
deba@2316
   325
        is >> std::ws;
deba@2316
   326
      }
deba@2316
   327
      if (!is) {
deba@2316
   328
        is.clear();
deba@2316
   329
      } else {
deba@2316
   330
        is.putback(y);
deba@2316
   331
      }
deba@2316
   332
      return is;
deba@2316
   333
    }
deba@2316
   334
deba@2316
   335
    std::istream& readCol(std::istream& is, LpSolverBase::Col& c) {
deba@2316
   336
      char x;
deba@2316
   337
      std::string var;
deba@2316
   338
      while (is.get(x) && varChar(x)) {
deba@2316
   339
        var += x;
deba@2316
   340
      }
deba@2316
   341
      if (!is) {
deba@2316
   342
        is.clear();
deba@2316
   343
      } else {
deba@2316
   344
        is.putback(x);
deba@2316
   345
      }
deba@2316
   346
      ColMap::const_iterator it = cols.find(var);
deba@2316
   347
      if (cols.find(var) != cols.end()) {
deba@2316
   348
        c = it->second;
deba@2316
   349
      } else {
deba@2316
   350
        c = lp.addCol();
deba@2316
   351
        cols.insert(std::make_pair(var, c));
deba@2316
   352
        lp.colName(c, var);
deba@2316
   353
      }
deba@2316
   354
      return is;
deba@2316
   355
    }
deba@2316
   356
deba@2316
   357
    std::istream& readNum(std::istream& is, double& d) {
deba@2316
   358
      is >> d;
deba@2316
   359
      if (!is) throw DataFormatError("Wrong number format");
deba@2316
   360
      return is;
deba@2316
   361
    }
deba@2316
   362
deba@2316
   363
    std::istream& readRelation(std::istream& is, Relation& op) {
deba@2316
   364
      char x, y;
deba@2316
   365
      if (!is.get(x) || !(x == '<' || x == '=' || x == '>')) {
deba@2316
   366
        throw DataFormatError("Wrong relation operator");
deba@2316
   367
      }
deba@2316
   368
      if (!is.get(y) || y != '=') {
deba@2316
   369
        throw DataFormatError("Wrong relation operator");
deba@2316
   370
      }
deba@2316
   371
      switch (x) {
deba@2316
   372
      case '<': op = LE; 
deba@2316
   373
        break;
deba@2316
   374
      case '=': op = EQ; 
deba@2316
   375
        break;
deba@2316
   376
      case '>': op = GE; 
deba@2316
   377
        break;
deba@2316
   378
      }
deba@2316
   379
      return is;
deba@2316
   380
    }
deba@2316
   381
deba@2316
   382
    static bool relationFirstChar(char c) {
deba@2316
   383
      return c == '<' || c == '=' || c == '>';
deba@2316
   384
    }
deba@2316
   385
deba@2316
   386
    static bool varFirstChar(char c) {
deba@2316
   387
      return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
deba@2316
   388
    }
deba@2316
   389
deba@2316
   390
    static bool numFirstChar(char c) {
deba@2316
   391
      return (c >= '0' && c <= '9') || c == '.';
deba@2316
   392
    }
deba@2316
   393
deba@2316
   394
    static bool varChar(char c) {
deba@2316
   395
      return (c >= '0' && c <= '9') || 
deba@2364
   396
        (c >= 'a' && c <= 'z') || 
deba@2364
   397
        (c >= 'A' && c <= 'Z') ||
deba@2364
   398
        c == '[' || c == ']';
deba@2316
   399
    }
deba@2316
   400
    
deba@2316
   401
  protected:
deba@2316
   402
deba@2316
   403
    /// \brief Reader function of the section.
deba@2316
   404
    ///
deba@2316
   405
    /// It reads the content of the section.
deba@2316
   406
    virtual void read(std::istream& is) {
deba@2316
   407
      std::string line;
deba@2364
   408
      SubSection sub = CONSTRAINTS;
deba@2316
   409
      while (getline(is, line)) {
deba@2316
   410
        std::istringstream ls(line);
deba@2364
   411
        std::string type;
deba@2364
   412
        ls >> type;
deba@2364
   413
        if (type == "constraints") {
deba@2364
   414
          sub = CONSTRAINTS;
deba@2364
   415
        } else if (type == "bounds") {
deba@2364
   416
          sub = BOUNDS;
deba@2364
   417
        } else if (type == "objective") {
deba@2364
   418
          sub = OBJECTIVE;
deba@2316
   419
        } else {
deba@2316
   420
          ls.str(line);
deba@2364
   421
          switch (sub) {
deba@2364
   422
          case CONSTRAINTS:
deba@2364
   423
            readConstraint(ls);
deba@2364
   424
            break;
deba@2364
   425
          case BOUNDS:
deba@2364
   426
            readBounds(ls);
deba@2364
   427
            break;
deba@2364
   428
          case OBJECTIVE:
deba@2364
   429
            readObjective(ls);
deba@2364
   430
            break;
deba@2364
   431
          }
deba@2316
   432
        }        
deba@2316
   433
      }
deba@2316
   434
    }
deba@2316
   435
      
deba@2316
   436
    virtual void missing() {
deba@2316
   437
      ErrorMessage msg;
deba@2316
   438
      msg << "Lp section not found in file: @lp " << name;
deba@2316
   439
      throw IoParameterError(msg.message());
deba@2316
   440
    }
deba@2316
   441
deba@2316
   442
  private:
deba@2316
   443
deba@2316
   444
    typedef std::map<std::string, LpSolverBase::Col> ColMap;
deba@2316
   445
      
deba@2316
   446
    LpSolverBase& lp;
deba@2316
   447
    std::string name;
deba@2316
   448
    ColMap cols;
deba@2316
   449
  };
deba@2316
   450
deba@2363
   451
deba@2364
   452
  class LpWriter : public LemonWriter::SectionWriter {
deba@2364
   453
    typedef LemonWriter::SectionWriter Parent;
deba@2364
   454
  public:
deba@2363
   455
deba@2363
   456
deba@2364
   457
    /// \brief Constructor.
deba@2364
   458
    ///
deba@2364
   459
    /// Constructor for LpWriter. It creates the LpWriter and attach
deba@2364
   460
    /// it into the given LemonWriter. The lp writer will add
deba@2364
   461
    /// variables, constraints and objective function to the
deba@2364
   462
    /// given lp solver.
deba@2364
   463
    LpWriter(LemonWriter& _writer, LpSolverBase& _lp, 
deba@2364
   464
             const std::string& _name = std::string())
deba@2364
   465
      : Parent(_writer), lp(_lp), name(_name) {} 
deba@2363
   466
deba@2363
   467
deba@2364
   468
    /// \brief Destructor.
deba@2364
   469
    ///
deba@2364
   470
    /// Destructor for NodeSetWriter.
deba@2364
   471
    virtual ~LpWriter() {}
deba@2363
   472
deba@2364
   473
  private:
deba@2364
   474
    LpWriter(const LpWriter&);
deba@2364
   475
    void operator=(const LpWriter&);
deba@2363
   476
  
deba@2364
   477
  protected:
deba@2363
   478
deba@2364
   479
    /// \brief Gives back true when the SectionWriter can process 
deba@2364
   480
    /// the section with the given header line.
deba@2364
   481
    ///
deba@2364
   482
    /// It gives back the header line of the \c \@lp section.
deba@2364
   483
    virtual std::string header() {
deba@2364
   484
      std::ostringstream ls;
deba@2364
   485
      ls << "@lp " << name;
deba@2364
   486
      return ls.str();
deba@2364
   487
    }
deba@2363
   488
deba@2364
   489
  private:
deba@2363
   490
deba@2364
   491
    void createCols() {
deba@2364
   492
      int num = 1;
deba@2363
   493
deba@2364
   494
      std::map<std::string, LpSolverBase::Col> inverse;
deba@2364
   495
deba@2364
   496
      for (LpSolverBase::ColIt it(lp); it != INVALID; ++it) {
deba@2364
   497
        std::string name = lp.colName(it);
deba@2364
   498
        if (!name.empty() && inverse.find(name) == inverse.end()) {
deba@2364
   499
          cols.insert(std::make_pair(it, name));
deba@2364
   500
          inverse.insert(std::make_pair(name, it));
deba@2364
   501
        } else {
deba@2364
   502
          std::ostringstream ls;
deba@2364
   503
          ls << "var" << num;
deba@2364
   504
          ++num;
deba@2364
   505
          cols.insert(std::make_pair(it, ls.str()));
deba@2364
   506
          inverse.insert(std::make_pair(ls.str(), it));
deba@2364
   507
        }
deba@2364
   508
      }
deba@2364
   509
    }
deba@2364
   510
    
deba@2364
   511
    void writeExpression(std::ostream& os, const LpSolverBase::Expr& e) {
deba@2364
   512
      bool first = true;
deba@2364
   513
      for (LpSolverBase::Expr::const_iterator jt = e.begin(); 
deba@2364
   514
           jt != e.end(); ++jt) {
deba@2364
   515
        if (jt->second < 0.0) {
deba@2364
   516
          os << "- ";
deba@2364
   517
          if (jt->second != -1.0) {
deba@2364
   518
            os << -jt->second << " * ";
deba@2364
   519
          }
deba@2364
   520
        } else if (jt->second > 0.0) {
deba@2364
   521
          if (!first) {
deba@2364
   522
            os << "+ ";
deba@2364
   523
          }
deba@2364
   524
          if (jt->second != 1.0) {
deba@2364
   525
            os << jt->second << " * ";
deba@2364
   526
          }          
deba@2364
   527
        }
deba@2364
   528
        first = false;
deba@2364
   529
        os << cols[jt->first] << " ";
deba@2364
   530
      }
deba@2364
   531
      if (e.constComp() < 0.0) {
deba@2364
   532
        os << "- " << -e.constComp() << " ";
deba@2364
   533
      } else if (e.constComp() > 0.0) {
deba@2364
   534
        if (!first) {
deba@2364
   535
          os << "+ ";
deba@2364
   536
        }
deba@2364
   537
        os << e.constComp() << " ";
deba@2364
   538
      } 
deba@2364
   539
    }
deba@2364
   540
deba@2364
   541
  protected:
deba@2364
   542
deba@2364
   543
    /// \brief Writer function of the section.
deba@2364
   544
    ///
deba@2364
   545
    /// It writes the content of the section.
deba@2364
   546
    virtual void write(std::ostream& os) {
deba@2364
   547
      createCols();
deba@2364
   548
deba@2364
   549
      os << "constraints" << std::endl;
deba@2363
   550
      
deba@2364
   551
      for (LpSolverBase::RowIt it(lp); it != INVALID; ++it) {
deba@2364
   552
        double lower, upper;
deba@2364
   553
        lp.getRowBounds(it, lower, upper);
deba@2364
   554
        if (lower == -LpSolverBase::INF && upper == LpSolverBase::INF) 
deba@2364
   555
          continue;
deba@2364
   556
        os << "   ";
deba@2364
   557
        
deba@2364
   558
        if (lower != upper) {
deba@2364
   559
          if (lower != -LpSolverBase::INF) {
deba@2364
   560
            os << lower << " <= ";
deba@2364
   561
          }
deba@2364
   562
          
deba@2364
   563
          writeExpression(os, lp.row(it));
deba@2364
   564
          
deba@2364
   565
          if (upper != LpSolverBase::INF) {
deba@2364
   566
            os << "<= " << upper << " ";
deba@2364
   567
          }
deba@2364
   568
        } else {
deba@2363
   569
deba@2364
   570
          writeExpression(os, lp.row(it));
deba@2364
   571
          os << "== " << upper << " ";
deba@2364
   572
          
deba@2364
   573
        }
deba@2363
   574
deba@2364
   575
        os << std::endl;
deba@2364
   576
      }
deba@2363
   577
deba@2364
   578
      os << "bounds" << std::endl;
deba@2364
   579
      
deba@2364
   580
      for (LpSolverBase::ColIt it(lp); it != INVALID; ++it) {
deba@2364
   581
        double lower = lp.colLowerBound(it);
deba@2364
   582
        double upper = lp.colUpperBound(it);
deba@2364
   583
        if (lower == -LpSolverBase::INF && upper == LpSolverBase::INF) 
deba@2364
   584
          continue;
deba@2364
   585
        os << "   ";
deba@2363
   586
deba@2364
   587
        if (lower != upper) {
deba@2364
   588
          if (lower != -LpSolverBase::INF) {
deba@2364
   589
            os << lower << " <= ";
deba@2364
   590
          }
deba@2364
   591
          
deba@2364
   592
          os << cols[it] << " ";
deba@2364
   593
          
deba@2364
   594
          if (upper != LpSolverBase::INF) {
deba@2364
   595
            os << "<= " << upper << " ";
deba@2364
   596
          }
deba@2364
   597
        } else {
deba@2364
   598
          os << cols[it] << " == " << upper << " ";
deba@2364
   599
        }
deba@2364
   600
        os << std::endl;
deba@2364
   601
      }
deba@2363
   602
deba@2364
   603
      os << "objective" << std::endl;
deba@2364
   604
      os << "   ";
deba@2364
   605
      if (lp.is_min()) {
deba@2364
   606
        os << "min ";
deba@2364
   607
      } else {
deba@2364
   608
        os << "max ";
deba@2364
   609
      }
deba@2364
   610
      writeExpression(os, lp.obj());
deba@2364
   611
      os << std::endl;
deba@2364
   612
    }
deba@2364
   613
      
deba@2363
   614
deba@2364
   615
  private:
deba@2363
   616
deba@2364
   617
    typedef std::map<LpSolverBase::Col, std::string> ColMap;
deba@2363
   618
      
deba@2364
   619
    LpSolverBase& lp;
deba@2364
   620
    std::string name;
deba@2364
   621
    ColMap cols;
deba@2364
   622
  };
deba@2363
   623
deba@2316
   624
}
deba@2316
   625
deba@2316
   626
#endif