lemon/lp_utils.h
author hegyi
Tue, 08 Apr 2008 11:39:40 +0000
changeset 2602 1c7790d9e025
parent 2553 bfced05fa852
permissions -rw-r--r--
Rel.07 NEWS - 3. round
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
 *
alpar@2553
     5
 * Copyright (C) 2003-2008
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@2368
    27
#include <map>
deba@2368
    28
#include <set>
deba@2368
    29
deba@2368
    30
deba@2316
    31
namespace lemon {
deba@2316
    32
deba@2370
    33
  /// \ingroup lp_utils
deba@2368
    34
  ///
deba@2368
    35
  /// \brief The map for the result of the lp variables.
deba@2368
    36
  ///
deba@2368
    37
  /// The map for the result of the lp variables.
deba@2368
    38
  class LpResultMap {
deba@2368
    39
  public:
deba@2368
    40
    typedef LpSolverBase::Col Key;
deba@2368
    41
    typedef LpSolverBase::Value Value;
deba@2368
    42
deba@2368
    43
    /// \brief Constructor
deba@2368
    44
    ///
deba@2368
    45
    /// Constructor
deba@2368
    46
    LpResultMap(const LpSolverBase& _lp) : lp(_lp) {}
deba@2368
    47
    LpSolverBase::Value operator[](const LpSolverBase::Col col) const {
deba@2368
    48
      return lp.primal(col);
deba@2368
    49
    }
deba@2368
    50
  private:
deba@2368
    51
    const LpSolverBase& lp;
deba@2368
    52
  };
deba@2368
    53
deba@2370
    54
  /// \ingroup lp_utils
deba@2370
    55
  ///
deba@2370
    56
  /// \brief Returns an \ref LpResultMap class
deba@2370
    57
  ///
deba@2370
    58
  /// This function just returns an \ref LpResultMap class.
deba@2370
    59
  /// \relates LpResultMap
ladanyi@2578
    60
  LpResultMap lpResultMap(const LpSolverBase& lp);
deba@2370
    61
deba@2370
    62
  /// \ingroup lp_utils
deba@2368
    63
  ///
deba@2368
    64
  /// \brief The map for the name of the lp variables.
deba@2368
    65
  ///
deba@2368
    66
  /// The map for the name of the lp variables.
deba@2368
    67
  class LpColNameMap {
deba@2368
    68
  public:
deba@2368
    69
    typedef LpSolverBase::Col Key;
deba@2368
    70
    typedef std::string Value;
deba@2368
    71
deba@2368
    72
    /// \brief Constructor
deba@2368
    73
    ///
deba@2368
    74
    /// Constructor
deba@2368
    75
    LpColNameMap(const LpSolverBase& _lp) : lp(_lp) {}
deba@2368
    76
    std::string operator[](const LpSolverBase::Col col) const {
deba@2368
    77
      return lp.colName(col);
deba@2368
    78
    }
deba@2368
    79
  private:
deba@2368
    80
    const LpSolverBase& lp;
deba@2368
    81
  };
deba@2368
    82
deba@2370
    83
  /// \ingroup lp_utils
deba@2368
    84
  ///
deba@2368
    85
  /// \brief Writeable map for the name of the lp variables.
deba@2368
    86
  ///
deba@2368
    87
  /// Writeable map for the name of the lp variables.
deba@2368
    88
  class LpColNameWriteMap {
deba@2368
    89
  public:
deba@2368
    90
    typedef LpSolverBase::Col Key;
deba@2368
    91
    typedef std::string Value;
deba@2368
    92
deba@2368
    93
    /// \brief Constructor
deba@2368
    94
    ///
deba@2368
    95
    /// Constructor
deba@2368
    96
    LpColNameWriteMap(LpSolverBase& _lp) : lp(_lp) {}
deba@2368
    97
    std::string operator[](const LpSolverBase::Col col) const {
deba@2368
    98
      return lp.colName(col);
deba@2368
    99
    }
deba@2368
   100
    void set(const LpSolverBase::Col col, const std::string& name) {
deba@2368
   101
      lp.colName(col, name);
deba@2368
   102
    }
deba@2368
   103
  private:
deba@2368
   104
    LpSolverBase& lp;
deba@2368
   105
  };
deba@2368
   106
deba@2370
   107
  /// \ingroup lp_utils
deba@2368
   108
  ///
deba@2368
   109
  /// \brief Returns an \ref LpColNameMap class
deba@2368
   110
  ///
deba@2368
   111
  /// This function just returns an \ref LpColNameMap class.
deba@2368
   112
  /// \relates LpColNameMap
ladanyi@2578
   113
  LpColNameMap lpColNameMap(const LpSolverBase& lp);
deba@2368
   114
ladanyi@2578
   115
  LpColNameWriteMap lpColNameMap(LpSolverBase& lp);
deba@2368
   116
deba@2370
   117
  /// \ingroup lp_utils
deba@2368
   118
  ///
deba@2368
   119
  /// \brief Lp variable item reader for Lemon IO
deba@2368
   120
  ///
deba@2368
   121
  /// This class is an Lp variable item reader for Lemon IO. It makes
deba@2368
   122
  /// possible to store lp variables in lemon file. The usage of this
deba@2368
   123
  /// class is very simple:
deba@2368
   124
  ///
deba@2368
   125
  ///\code
deba@2368
   126
  /// Graph graph;
deba@2368
   127
  /// Lp lp;
deba@2368
   128
  /// Graph::EdgeMap<Lp::Col> var(graph); 
deba@2368
   129
  ///
deba@2368
   130
  /// GraphReader<Graph> reader(cin, graph);
deba@2368
   131
  /// reader.readEdgeMap("lpvar", var, LpColReader(lp));
deba@2368
   132
  /// reader.run();
deba@2368
   133
  ///\endcode
deba@2368
   134
  ///
deba@2368
   135
  /// If there is already a variable with the same name in the lp then
deba@2368
   136
  /// it will be used for the return value. If there is no such variable
deba@2368
   137
  /// then it will be constructed. The file could contain \c '-' as value
deba@2368
   138
  /// which means that no lp variable associated to the current item and
deba@2368
   139
  /// in this case INVALID will be returned.
deba@2368
   140
  class LpColReader {
deba@2368
   141
  public:
deba@2368
   142
deba@2368
   143
    /// \brief The value type of reader.
deba@2368
   144
    ///
deba@2368
   145
    /// The value type of reader.
deba@2368
   146
    typedef LpSolverBase::Col Value;
deba@2368
   147
deba@2368
   148
    /// \brief Constructor for the reader.
deba@2368
   149
    ///
deba@2368
   150
    /// Constructor for the reader.
deba@2368
   151
    LpColReader(LpSolverBase& _lp) : lp(_lp) {}
deba@2368
   152
deba@2368
   153
    /// \brief Reads an lp variable from the given stream.
deba@2368
   154
    ///
deba@2368
   155
    /// Reads an lp variable string from the given stream.
deba@2368
   156
    void read(std::istream& is, LpSolverBase::Col& col) const {
deba@2368
   157
      char x;
deba@2368
   158
      is >> std::ws;
deba@2368
   159
      if (!is.get(x))
deba@2368
   160
        throw DataFormatError("Wrong Lp Column format!");
deba@2368
   161
      if (varFirstChar(x)) {
deba@2368
   162
        std::string var;
deba@2368
   163
        var += x;
deba@2368
   164
        
deba@2368
   165
        while (is.get(x) && varChar(x)) {
deba@2368
   166
          var += x;
deba@2368
   167
        }
deba@2368
   168
        if (!is) {
deba@2368
   169
          is.clear();
deba@2368
   170
        } else {
deba@2368
   171
          is.putback(x);
deba@2368
   172
        }
deba@2368
   173
        col = lp.colByName(var);
deba@2368
   174
        if (col == INVALID) {
deba@2368
   175
          col = lp.addCol();
deba@2368
   176
          lp.colName(col, var);
deba@2368
   177
        }
deba@2368
   178
      } else if (x == '-') {
deba@2368
   179
        col = INVALID;
deba@2368
   180
        is >> std::ws;
deba@2368
   181
      } else {
deba@2368
   182
        std::cerr << x << std::endl;
deba@2368
   183
        throw DataFormatError("Wrong Lp Column format");
deba@2368
   184
      }
deba@2368
   185
    }
deba@2368
   186
deba@2368
   187
  private:
deba@2368
   188
deba@2368
   189
    static bool varFirstChar(char c) {
deba@2368
   190
      return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
deba@2368
   191
    }
deba@2368
   192
deba@2368
   193
    static bool varChar(char c) {
deba@2368
   194
      return (c >= '0' && c <= '9') || 
deba@2368
   195
        (c >= 'a' && c <= 'z') || 
deba@2368
   196
        (c >= 'A' && c <= 'Z') ||
deba@2368
   197
        c == '[' || c == ']';
deba@2368
   198
    }
deba@2368
   199
    
deba@2368
   200
    LpSolverBase& lp;
deba@2368
   201
deba@2368
   202
  };
deba@2368
   203
deba@2370
   204
  /// \ingroup lp_utils
deba@2368
   205
  ///
deba@2368
   206
  /// \brief Lp variable item writer for Lemon IO
deba@2368
   207
  ///
deba@2368
   208
  /// This class is an Lp variable item writer for Lemon IO. It makes
deba@2368
   209
  /// possible to store lp variables in lemon file. The usage of this
deba@2368
   210
  /// class is very simple:
deba@2368
   211
  ///
deba@2368
   212
  ///\code
deba@2368
   213
  /// Graph graph;
deba@2368
   214
  /// Lp lp;
deba@2368
   215
  /// Graph::EdgeMap<Lp::Col> var(graph); 
deba@2368
   216
  ///
deba@2368
   217
  /// GraphWriter<Graph> writer(cin, graph);
deba@2368
   218
  /// writer.writeEdgeMap("lpvar", var, LpColWriter(lp));
deba@2368
   219
  /// writer.run();
deba@2368
   220
  ///\endcode
deba@2368
   221
  ///
deba@2368
   222
  /// If there is no name associated to the current item then the name
deba@2368
   223
  /// will automatically constructed. If the value is INVALID then it
deba@2368
   224
  /// will write an \c '-' value to the file.
deba@2368
   225
  class LpColWriter {
deba@2368
   226
  public:
deba@2368
   227
deba@2368
   228
    /// \brief The value type of writer.
deba@2368
   229
    ///
deba@2368
   230
    /// The value type of writer.
deba@2368
   231
    typedef LpSolverBase::Col Value;
deba@2368
   232
deba@2368
   233
    /// \brief Constructor for the writer.
deba@2368
   234
    ///
deba@2368
   235
    /// Constructor for the writer.
deba@2368
   236
    LpColWriter(const LpSolverBase& _lp) : lp(_lp), num(0) {}
deba@2368
   237
deba@2368
   238
    /// \brief Writes an lp variable to the given stream.
deba@2368
   239
    ///
deba@2368
   240
    /// Writes an lp variable to the given stream.
deba@2368
   241
    void write(std::ostream& os, const LpSolverBase::Col& col) const {
deba@2368
   242
      if (col != INVALID) {
deba@2368
   243
        std::string name = lp.colName(col);
deba@2368
   244
        if (name.empty()) {
deba@2368
   245
          std::ostringstream ls;
deba@2368
   246
          ls << "x" << num;
deba@2368
   247
          ++num;
deba@2368
   248
          while (lp.colByName(ls.str()) != INVALID) {
deba@2368
   249
            ls.str(std::string());
deba@2368
   250
            ls << "x" << num;
deba@2368
   251
            ++num;
deba@2368
   252
          }
deba@2368
   253
          const_cast<LpSolverBase&>(lp).colName(col, ls.str());
deba@2368
   254
          os << ls.str();
deba@2368
   255
        } else {
deba@2368
   256
          os << name;
deba@2368
   257
        }
deba@2368
   258
      } else {
deba@2368
   259
        os << "-";
deba@2368
   260
      }
deba@2368
   261
    }
deba@2368
   262
deba@2368
   263
  private:
deba@2368
   264
deba@2368
   265
    const LpSolverBase& lp;
deba@2368
   266
    mutable int num;
deba@2368
   267
deba@2368
   268
  };
deba@2368
   269
deba@2370
   270
  /// \ingroup lp_utils
deba@2368
   271
  ///
deba@2368
   272
  /// \brief Lp section reader for lemon IO
deba@2368
   273
  ///
deba@2368
   274
  /// This section reader provides an easy way to read an Lp problem
deba@2368
   275
  /// from a file. The lemon lp section format contains three parts.
deba@2368
   276
  ///
deba@2368
   277
  ///\code
deba@2368
   278
  /// @lp
deba@2368
   279
  /// constraints
deba@2368
   280
  ///   7 == x1 - 1 * x2
deba@2368
   281
  ///   2 * x1 + x3 / 2 <= 7
deba@2368
   282
  ///   x2 + -3 * x3 >= 8
deba@2368
   283
  ///   3 <= x2 - 2 * x1 <= 8
deba@2368
   284
  /// bounds
deba@2368
   285
  ///   x1 >= 3
deba@2368
   286
  ///   2 <= x2 <= 5
deba@2368
   287
  ///   0 <= x3 <= 8
deba@2368
   288
  /// objective
deba@2368
   289
  ///   min x1 + 2 * x2 - x3
deba@2368
   290
  ///\endcode
deba@2368
   291
  ///
deba@2368
   292
  /// The first part gives the constraints to the lp. The constraints
deba@2368
   293
  /// could be equality, lower bound, upper bound or range for an
deba@2368
   294
  /// expression or equality, less or more for two expressions.
deba@2368
   295
  ///
deba@2368
   296
  /// The second part gives the bounds for the variables. The bounds
deba@2368
   297
  /// could be the same as for the single expression so equality,
deba@2368
   298
  /// lower bound, upper bound or range.
deba@2368
   299
  ///
deba@2368
   300
  /// The third part is the objective function, it should start with
deba@2368
   301
  /// \c min or \c max and then a valid linear expression.
deba@2368
   302
  ///
deba@2368
   303
  /// The reader constructs automatically the variable for a name if
deba@2368
   304
  /// there is not already a variable with the same name.
deba@2368
   305
  ///
deba@2368
   306
  /// The basic way to read an LP problem is made by the next code:
deba@2368
   307
  ///\code
deba@2368
   308
  /// Lp lp;
deba@2368
   309
  ///
deba@2368
   310
  /// LemonReader reader(filename_or_istream);
deba@2368
   311
  /// LpReader lpreader(reader, lp);
deba@2368
   312
  /// 
deba@2368
   313
  /// reader.run();
deba@2368
   314
  ///\endcode
deba@2368
   315
  ///
deba@2368
   316
  /// Of course instead of \c LemonReader you can give a \c
deba@2368
   317
  /// GraphReader to the LpReader constructor. Also useful that you
deba@2368
   318
  /// can mix lp problems and graphs in the same file.
deba@2316
   319
  class LpReader : public LemonReader::SectionReader {
deba@2316
   320
    typedef LemonReader::SectionReader Parent;
deba@2316
   321
  public:
deba@2316
   322
deba@2316
   323
deba@2316
   324
    /// \brief Constructor.
deba@2316
   325
    ///
deba@2368
   326
    /// Constructor for LpReader. It creates the LpReader and attachs
deba@2316
   327
    /// it into the given LemonReader. The lp reader will add
deba@2316
   328
    /// variables, constraints and objective function to the
deba@2316
   329
    /// given lp solver.
deba@2316
   330
    LpReader(LemonReader& _reader, LpSolverBase& _lp, 
deba@2316
   331
             const std::string& _name = std::string())
deba@2316
   332
      : Parent(_reader), lp(_lp), name(_name) {} 
deba@2316
   333
deba@2316
   334
deba@2316
   335
    /// \brief Destructor.
deba@2316
   336
    ///
deba@2368
   337
    /// Destructor for LpReader.
deba@2316
   338
    virtual ~LpReader() {}
deba@2316
   339
deba@2316
   340
  private:
deba@2316
   341
    LpReader(const LpReader&);
deba@2316
   342
    void operator=(const LpReader&);
deba@2316
   343
  
deba@2316
   344
  protected:
deba@2316
   345
deba@2316
   346
    /// \brief Gives back true when the SectionReader can process 
deba@2316
   347
    /// the section with the given header line.
deba@2316
   348
    ///
deba@2316
   349
    /// It gives back true when the header line starts with \c \@lp,
deba@2316
   350
    /// and the header line's name and the nodeset's name are the same.
deba@2316
   351
    virtual bool header(const std::string& line) {
deba@2316
   352
      std::istringstream ls(line);
deba@2316
   353
      std::string command;
deba@2316
   354
      std::string id;
deba@2316
   355
      ls >> command >> id;
deba@2316
   356
      return command == "@lp" && name == id;
deba@2316
   357
    }
deba@2316
   358
deba@2316
   359
  private:
deba@2316
   360
deba@2368
   361
    enum Part {
deba@2364
   362
      CONSTRAINTS, BOUNDS, OBJECTIVE
deba@2364
   363
    };
deba@2364
   364
deba@2316
   365
    enum Relation {
deba@2316
   366
      LE, EQ, GE
deba@2316
   367
    };
deba@2316
   368
deba@2364
   369
    std::istream& readConstraint(std::istream& is) {
deba@2364
   370
      LpSolverBase::Constr c;
deba@2316
   371
      char x;
deba@2316
   372
      LpSolverBase::Expr e1, e2;
deba@2316
   373
      Relation op1;
deba@2316
   374
      is >> std::ws;
deba@2316
   375
      readExpression(is, e1);
deba@2316
   376
      is >> std::ws;
deba@2316
   377
      readRelation(is, op1);
deba@2316
   378
      is >> std::ws;
deba@2316
   379
      readExpression(is, e2);
deba@2364
   380
      is >> std::ws;
deba@2316
   381
      if (!is.get(x)) {
deba@2316
   382
        if (op1 == LE) {
deba@2364
   383
          if (e1.size() == 0) {
deba@2364
   384
            c = e2 >= e1;
deba@2364
   385
          } else {
deba@2364
   386
            c = e1 <= e2;
deba@2364
   387
          }
deba@2316
   388
          c = e1 <= e2;
deba@2316
   389
        } else if (op1 == GE) {
deba@2364
   390
          if (e1.size() == 0) {
deba@2364
   391
            c = e2 <= e1;
deba@2364
   392
          } else {
deba@2364
   393
            c = e1 >= e2;
deba@2364
   394
          }
deba@2316
   395
        } else {
deba@2364
   396
          if (e1.size() == 0) {
deba@2364
   397
            c = e2 == e1;
deba@2364
   398
          } else {
deba@2364
   399
            c = e1 == e2;
deba@2364
   400
          }
deba@2316
   401
        }
deba@2316
   402
      } else {
deba@2316
   403
        is.putback(x);
deba@2316
   404
        LpSolverBase::Expr e3;
deba@2316
   405
        Relation op2;
deba@2316
   406
        readRelation(is, op2);
deba@2316
   407
        is >> std::ws;
deba@2316
   408
        readExpression(is, e3);
deba@2316
   409
        if (!e1.empty() || !e3.empty()) {
deba@2316
   410
          throw DataFormatError("Wrong range format");
deba@2316
   411
        }
deba@2316
   412
        if (op2 != op1 || op1 == EQ) {
deba@2316
   413
          throw DataFormatError("Wrong range format");
deba@2316
   414
        }
deba@2316
   415
        if (op1 == LE) {
deba@2316
   416
          c = e1.constComp() <= e2 <= e3.constComp();
deba@2316
   417
        } else {
deba@2316
   418
          c = e1.constComp() >= e2 >= e3.constComp();
deba@2316
   419
        }
deba@2364
   420
        is >> std::ws;
deba@2364
   421
        if (is.get(x)) {
deba@2364
   422
          throw DataFormatError("Wrong variable bounds format");
deba@2364
   423
        }
deba@2316
   424
      }
deba@2364
   425
      lp.addRow(c);
deba@2364
   426
      return is;
deba@2364
   427
    }
deba@2364
   428
deba@2364
   429
    std::istream& readObjective(std::istream& is) {
deba@2364
   430
      is >> std::ws;
deba@2364
   431
      std::string sense;
deba@2364
   432
      is >> sense;
deba@2364
   433
      if (sense != "min" && sense != "max") {
deba@2364
   434
        throw DataFormatError("Wrong objective function format");
deba@2364
   435
      }
deba@2364
   436
      LpSolverBase::Expr expr;
deba@2364
   437
      is >> std::ws;
deba@2364
   438
      readExpression(is, expr);
deba@2369
   439
      lp.obj(expr);
deba@2364
   440
      if (sense == "min") {
deba@2364
   441
        lp.min();
deba@2364
   442
      } else {
deba@2364
   443
        lp.max();
deba@2364
   444
      }
deba@2364
   445
      return is;
deba@2364
   446
    }
deba@2364
   447
deba@2364
   448
    std::istream& readBounds(std::istream& is) {
deba@2364
   449
      LpSolverBase::Col c;
deba@2364
   450
      char x;
deba@2364
   451
      is >> std::ws;
deba@2364
   452
      if (!is.get(x)) {
deba@2364
   453
        throw DataFormatError("Wrong variable bounds format");
deba@2364
   454
      }
deba@2364
   455
      if (varFirstChar(x)) {
deba@2364
   456
        is.putback(x);
deba@2364
   457
        readCol(is, c);
deba@2364
   458
        is >> std::ws;
deba@2364
   459
        Relation op1;
deba@2364
   460
        readRelation(is, op1);
deba@2364
   461
        double v;
deba@2364
   462
        readNum(is, v);
deba@2364
   463
        if (op1 == EQ) {
deba@2364
   464
          lp.colLowerBound(c, v);
deba@2364
   465
          lp.colUpperBound(c, v);
deba@2364
   466
        } else if (op1 == LE) {
deba@2364
   467
          lp.colUpperBound(c, v);
deba@2364
   468
        } else {
deba@2364
   469
          lp.colLowerBound(c, v);
deba@2364
   470
        }
deba@2364
   471
        is >> std::ws;
deba@2364
   472
        if (is.get(x)) {
deba@2364
   473
          throw DataFormatError("Wrong variable bounds format");
deba@2364
   474
        }
deba@2364
   475
      } else {
deba@2364
   476
        is.putback(x);
deba@2364
   477
        double v;
deba@2364
   478
        readNum(is, v);
deba@2364
   479
        is >> std::ws;
deba@2364
   480
        Relation op1;
deba@2364
   481
        readRelation(is, op1);
deba@2364
   482
        is >> std::ws;
deba@2364
   483
        readCol(is, c);
deba@2364
   484
        is >> std::ws;
deba@2364
   485
        if (is.get(x)) {
deba@2364
   486
          is.putback(x);
deba@2364
   487
          is >> std::ws;
deba@2364
   488
          Relation op2;
deba@2364
   489
          readRelation(is, op2);
deba@2364
   490
          double w;
deba@2364
   491
          is >> std::ws;
deba@2364
   492
          readNum(is, w);
deba@2364
   493
          if (op2 != op1 || op1 == EQ) {
deba@2364
   494
            throw DataFormatError("Wrong range format");
deba@2364
   495
          }
deba@2364
   496
          if (op1 == LE) {
deba@2364
   497
            lp.colLowerBound(c, v);
deba@2364
   498
            lp.colUpperBound(c, w);
deba@2364
   499
          } else {
deba@2364
   500
            lp.colLowerBound(c, w);
deba@2364
   501
            lp.colUpperBound(c, v);
deba@2364
   502
          }
deba@2368
   503
          is >> std::ws;
deba@2364
   504
          if (is.get(x)) {
deba@2364
   505
            throw DataFormatError("Wrong variable bounds format");
deba@2364
   506
          }
deba@2364
   507
        } else {
deba@2364
   508
          if (op1 == EQ) {
deba@2364
   509
            lp.colLowerBound(c, v);
deba@2364
   510
            lp.colUpperBound(c, v);
deba@2364
   511
          } else if (op1 == LE) {
deba@2364
   512
            lp.colLowerBound(c, v);
deba@2364
   513
          } else {
deba@2364
   514
            lp.colUpperBound(c, v);
deba@2364
   515
          }
deba@2364
   516
        }
deba@2364
   517
      }
deba@2364
   518
      return is;
deba@2316
   519
    }
deba@2316
   520
deba@2316
   521
    std::istream& readExpression(std::istream& is, LpSolverBase::Expr& e) {
deba@2316
   522
      LpSolverBase::Col c;
deba@2316
   523
      double d;
deba@2316
   524
      char x;
deba@2316
   525
      readElement(is, c, d);
deba@2316
   526
      if (c != INVALID) {
deba@2316
   527
        e += d * c;
deba@2316
   528
      } else {
deba@2316
   529
        e += d;
deba@2316
   530
      }
deba@2316
   531
      is >> std::ws;
deba@2316
   532
      while (is.get(x) && (x == '+' || x == '-')) {
deba@2316
   533
        is >> std::ws;
deba@2316
   534
        readElement(is, c, d);
deba@2316
   535
        if (c != INVALID) {
deba@2316
   536
          e += (x == '+' ? d : -d) * c;
deba@2316
   537
        } else {
deba@2316
   538
          e += (x == '+' ? d : -d);
deba@2316
   539
        }
deba@2316
   540
        is >> std::ws;
deba@2316
   541
      }
deba@2316
   542
      if (!is) {
deba@2316
   543
        is.clear();
deba@2316
   544
      } else {
deba@2316
   545
        is.putback(x);
deba@2316
   546
      }
deba@2316
   547
      return is;
deba@2316
   548
    }
deba@2316
   549
deba@2316
   550
    std::istream& readElement(std::istream& is, 
deba@2316
   551
                              LpSolverBase::Col& c, double& d) { 
deba@2316
   552
      d = 1.0;
deba@2316
   553
      c = INVALID;
deba@2316
   554
      char x, y;
deba@2316
   555
      if (!is.get(x)) throw DataFormatError("Cannot find lp element");
deba@2316
   556
      if (x == '+' || x == '-') {
deba@2316
   557
        is >> std::ws;
deba@2316
   558
        d *= x == '-' ? -1 : 1;
deba@2316
   559
        while (is.get(x) && (x == '+' || x == '-')) {
deba@2316
   560
          d *= x == '-' ? -1 : 1;
deba@2316
   561
          is >> std::ws;
deba@2316
   562
        }
deba@2316
   563
        if (!is) throw DataFormatError("Cannot find lp element");
deba@2316
   564
      }
deba@2316
   565
      if (numFirstChar(x)) {
deba@2316
   566
        is.putback(x);
deba@2316
   567
        double e;
deba@2316
   568
        readNum(is, e);
deba@2316
   569
        d *= e;
deba@2316
   570
      } else if (varFirstChar(x)) {
deba@2316
   571
        is.putback(x);
deba@2316
   572
        LpSolverBase::Col f;
deba@2316
   573
        readCol(is, f);
deba@2316
   574
        c = f;
deba@2316
   575
      } else {
deba@2316
   576
        throw DataFormatError("Invalid expression format");          
deba@2316
   577
      }
deba@2316
   578
      is >> std::ws;
deba@2316
   579
      while (is.get(y) && (y == '*' || y == '/')) {
deba@2316
   580
        is >> std::ws;
deba@2316
   581
        if (!is.get(x)) throw DataFormatError("Cannot find lp element");
deba@2316
   582
        if (x == '+' || x == '-') {
deba@2316
   583
          is >> std::ws;
deba@2316
   584
          d *= x == '-' ? -1 : 1;
deba@2316
   585
          while (is.get(x) && (x == '+' || x == '-')) {
deba@2316
   586
            d *= x == '-' ? -1 : 1;
deba@2316
   587
            is >> std::ws;
deba@2316
   588
          }
deba@2316
   589
          if (!is) throw DataFormatError("Cannot find lp element");
deba@2316
   590
        }
deba@2316
   591
        if (numFirstChar(x)) {
deba@2316
   592
          is.putback(x);
deba@2316
   593
          double e;
deba@2316
   594
          readNum(is, e);
deba@2316
   595
          if (y == '*') {
deba@2316
   596
            d *= e;
deba@2316
   597
          } else {
deba@2316
   598
            d /= e;
deba@2316
   599
          }
deba@2316
   600
        } else if (varFirstChar(x)) {
deba@2316
   601
          is.putback(x);
deba@2316
   602
          LpSolverBase::Col f;
deba@2316
   603
          readCol(is, f);
deba@2316
   604
          if (y == '*') {
deba@2316
   605
            if (c == INVALID) {
deba@2316
   606
              c = f;
deba@2316
   607
            } else {
deba@2316
   608
              throw DataFormatError("Quadratic element in expression");
deba@2316
   609
            }
deba@2316
   610
          } else {
deba@2316
   611
            throw DataFormatError("Division by variable");
deba@2316
   612
          }
deba@2316
   613
        } else {
deba@2316
   614
          throw DataFormatError("Invalid expression format");          
deba@2316
   615
        }
deba@2316
   616
        is >> std::ws;
deba@2316
   617
      }
deba@2316
   618
      if (!is) {
deba@2316
   619
        is.clear();
deba@2316
   620
      } else {
deba@2316
   621
        is.putback(y);
deba@2316
   622
      }
deba@2316
   623
      return is;
deba@2316
   624
    }
deba@2316
   625
deba@2316
   626
    std::istream& readCol(std::istream& is, LpSolverBase::Col& c) {
deba@2316
   627
      char x;
deba@2316
   628
      std::string var;
deba@2316
   629
      while (is.get(x) && varChar(x)) {
deba@2316
   630
        var += x;
deba@2316
   631
      }
deba@2316
   632
      if (!is) {
deba@2316
   633
        is.clear();
deba@2316
   634
      } else {
deba@2316
   635
        is.putback(x);
deba@2316
   636
      }
deba@2368
   637
      c = lp.colByName(var);
deba@2368
   638
      if (c == INVALID) {
deba@2316
   639
        c = lp.addCol();
deba@2316
   640
        lp.colName(c, var);
deba@2316
   641
      }
deba@2316
   642
      return is;
deba@2316
   643
    }
deba@2316
   644
deba@2316
   645
    std::istream& readNum(std::istream& is, double& d) {
deba@2316
   646
      is >> d;
deba@2316
   647
      if (!is) throw DataFormatError("Wrong number format");
deba@2316
   648
      return is;
deba@2316
   649
    }
deba@2316
   650
deba@2316
   651
    std::istream& readRelation(std::istream& is, Relation& op) {
deba@2316
   652
      char x, y;
deba@2316
   653
      if (!is.get(x) || !(x == '<' || x == '=' || x == '>')) {
deba@2316
   654
        throw DataFormatError("Wrong relation operator");
deba@2316
   655
      }
deba@2316
   656
      if (!is.get(y) || y != '=') {
deba@2316
   657
        throw DataFormatError("Wrong relation operator");
deba@2316
   658
      }
deba@2316
   659
      switch (x) {
deba@2316
   660
      case '<': op = LE; 
deba@2316
   661
        break;
deba@2316
   662
      case '=': op = EQ; 
deba@2316
   663
        break;
deba@2316
   664
      case '>': op = GE; 
deba@2316
   665
        break;
deba@2316
   666
      }
deba@2316
   667
      return is;
deba@2316
   668
    }
deba@2316
   669
deba@2316
   670
    static bool relationFirstChar(char c) {
deba@2316
   671
      return c == '<' || c == '=' || c == '>';
deba@2316
   672
    }
deba@2316
   673
deba@2316
   674
    static bool varFirstChar(char c) {
deba@2316
   675
      return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
deba@2316
   676
    }
deba@2316
   677
deba@2316
   678
    static bool numFirstChar(char c) {
deba@2316
   679
      return (c >= '0' && c <= '9') || c == '.';
deba@2316
   680
    }
deba@2368
   681
    
deba@2316
   682
    static bool varChar(char c) {
deba@2316
   683
      return (c >= '0' && c <= '9') || 
deba@2364
   684
        (c >= 'a' && c <= 'z') || 
deba@2364
   685
        (c >= 'A' && c <= 'Z') ||
deba@2364
   686
        c == '[' || c == ']';
deba@2316
   687
    }
deba@2316
   688
    
deba@2316
   689
  protected:
deba@2316
   690
deba@2316
   691
    /// \brief Reader function of the section.
deba@2316
   692
    ///
deba@2316
   693
    /// It reads the content of the section.
deba@2316
   694
    virtual void read(std::istream& is) {
deba@2316
   695
      std::string line;
deba@2368
   696
      Part part = CONSTRAINTS;
deba@2316
   697
      while (getline(is, line)) {
deba@2316
   698
        std::istringstream ls(line);
deba@2364
   699
        std::string type;
deba@2364
   700
        ls >> type;
deba@2364
   701
        if (type == "constraints") {
deba@2368
   702
          part = CONSTRAINTS;
deba@2368
   703
          ls >> std::ws;
deba@2368
   704
          char x;
deba@2368
   705
          if (ls.get(x))
deba@2368
   706
            throw DataFormatError("Wrong Lp format");
deba@2364
   707
        } else if (type == "bounds") {
deba@2368
   708
          part = BOUNDS;
deba@2368
   709
          ls >> std::ws;
deba@2368
   710
          char x;
deba@2368
   711
          if (ls.get(x))
deba@2368
   712
            throw DataFormatError("Wrong Lp format");
deba@2364
   713
        } else if (type == "objective") {
deba@2368
   714
          part = OBJECTIVE;
deba@2368
   715
          ls >> std::ws;
deba@2368
   716
          char x;
deba@2368
   717
          if (ls.get(x))
deba@2368
   718
            throw DataFormatError("Wrong Lp format");
deba@2316
   719
        } else {
deba@2316
   720
          ls.str(line);
deba@2368
   721
          switch (part) {
deba@2364
   722
          case CONSTRAINTS:
deba@2364
   723
            readConstraint(ls);
deba@2364
   724
            break;
deba@2364
   725
          case BOUNDS:
deba@2364
   726
            readBounds(ls);
deba@2364
   727
            break;
deba@2364
   728
          case OBJECTIVE:
deba@2364
   729
            readObjective(ls);
deba@2364
   730
            break;
deba@2364
   731
          }
deba@2368
   732
        }
deba@2316
   733
      }
deba@2316
   734
    }
deba@2316
   735
      
deba@2316
   736
    virtual void missing() {
deba@2316
   737
      ErrorMessage msg;
deba@2316
   738
      msg << "Lp section not found in file: @lp " << name;
deba@2316
   739
      throw IoParameterError(msg.message());
deba@2316
   740
    }
deba@2316
   741
deba@2316
   742
  private:
deba@2316
   743
deba@2316
   744
      
deba@2316
   745
    LpSolverBase& lp;
deba@2316
   746
    std::string name;
deba@2316
   747
  };
deba@2316
   748
deba@2363
   749
deba@2370
   750
  /// \ingroup lp_utils
deba@2368
   751
  ///
deba@2368
   752
  /// \brief Lp section writer for lemon IO
deba@2368
   753
  ///
deba@2368
   754
  /// This section reader provides an easy way to write an Lp problem
deba@2368
   755
  /// to a file. The lemon lp section format contains three parts.
deba@2368
   756
  ///
deba@2368
   757
  ///\code
deba@2368
   758
  /// @lp
deba@2368
   759
  /// constraints
deba@2368
   760
  ///   7 == x1 - 1 * x2
deba@2368
   761
  ///   2 * x1 + x3 / 2 <= 7
deba@2368
   762
  ///   x2 + -3 * x3 >= 8
deba@2368
   763
  ///   3 <= x2 - 2 * x1 <= 8
deba@2368
   764
  /// bounds
deba@2368
   765
  ///   x1 >= 3
deba@2368
   766
  ///   2 <= x2 <= 5
deba@2368
   767
  ///   0 <= x3 <= 8
deba@2368
   768
  /// objective
deba@2368
   769
  ///   min x1 + 2 * x2 - x3
deba@2368
   770
  ///\endcode
deba@2368
   771
  ///
deba@2368
   772
  /// The first part gives the constraints to the lp. The constraints
deba@2368
   773
  /// could be equality, lower bound, upper bound or range for an
deba@2368
   774
  /// expression or equality, less or more for two expressions.
deba@2368
   775
  ///
deba@2368
   776
  /// The second part gives the bounds for the variables. The bounds
deba@2368
   777
  /// could be the same as for the single expression so equality,
deba@2368
   778
  /// lower bound, upper bound or range.
deba@2368
   779
  ///
deba@2368
   780
  /// The third part is the objective function, it should start with
deba@2368
   781
  /// \c min or \c max and then a valid linear expression.
deba@2368
   782
  ///
deba@2368
   783
  /// If an LP variable does not have name in the writer, then it will
deba@2368
   784
  /// automatically created in the writer. This make a slight change
deba@2368
   785
  /// in the \c const variable.
deba@2368
   786
  ///
deba@2368
   787
  /// The basic way to write an LP problem is made by the next code:
deba@2368
   788
  ///\code
deba@2368
   789
  /// Lp lp;
deba@2368
   790
  ///
deba@2368
   791
  /// LemonWriter writer(filename_or_ostream);
deba@2368
   792
  /// LpWriter lpwriter(writer, lp);
deba@2368
   793
  /// 
deba@2368
   794
  /// writer.run();
deba@2368
   795
  ///\endcode
deba@2368
   796
  ///
deba@2368
   797
  /// Of course instead of \c LemonWriter you can give a \c
deba@2368
   798
  /// GraphWriter to the LpWriter constructor. Also useful that you
deba@2368
   799
  /// can mix lp problems and graphs in the same file.
deba@2364
   800
  class LpWriter : public LemonWriter::SectionWriter {
deba@2364
   801
    typedef LemonWriter::SectionWriter Parent;
deba@2364
   802
  public:
deba@2363
   803
deba@2363
   804
deba@2364
   805
    /// \brief Constructor.
deba@2364
   806
    ///
deba@2364
   807
    /// Constructor for LpWriter. It creates the LpWriter and attach
deba@2368
   808
    /// it into the given LemonWriter.
deba@2368
   809
    LpWriter(LemonWriter& _writer, const LpSolverBase& _lp, 
deba@2364
   810
             const std::string& _name = std::string())
deba@2364
   811
      : Parent(_writer), lp(_lp), name(_name) {} 
deba@2363
   812
deba@2363
   813
deba@2364
   814
    /// \brief Destructor.
deba@2364
   815
    ///
deba@2368
   816
    /// Destructor for LpWriter.
deba@2364
   817
    virtual ~LpWriter() {}
deba@2363
   818
deba@2364
   819
  private:
deba@2364
   820
    LpWriter(const LpWriter&);
deba@2364
   821
    void operator=(const LpWriter&);
deba@2363
   822
  
deba@2364
   823
  protected:
deba@2363
   824
deba@2364
   825
    /// \brief Gives back true when the SectionWriter can process 
deba@2364
   826
    /// the section with the given header line.
deba@2364
   827
    ///
deba@2364
   828
    /// It gives back the header line of the \c \@lp section.
deba@2364
   829
    virtual std::string header() {
deba@2364
   830
      std::ostringstream ls;
deba@2364
   831
      ls << "@lp " << name;
deba@2364
   832
      return ls.str();
deba@2364
   833
    }
deba@2363
   834
deba@2364
   835
  private:
deba@2363
   836
deba@2364
   837
    void createCols() {
deba@2368
   838
      int num = 0;
deba@2364
   839
deba@2364
   840
      for (LpSolverBase::ColIt it(lp); it != INVALID; ++it) {
deba@2364
   841
        std::string name = lp.colName(it);
deba@2368
   842
        if (name.empty()) {
deba@2364
   843
          std::ostringstream ls;
deba@2368
   844
          ls << "x" << num;
deba@2364
   845
          ++num;
deba@2368
   846
          while (lp.colByName(ls.str()) != INVALID) {
deba@2368
   847
            ls.str(std::string());
deba@2368
   848
            ls << "x" << num;
deba@2368
   849
            ++num;
deba@2368
   850
          }
deba@2368
   851
          const_cast<LpSolverBase&>(lp).colName(it, ls.str());
deba@2364
   852
        }
deba@2364
   853
      }
deba@2364
   854
    }
deba@2364
   855
    
deba@2364
   856
    void writeExpression(std::ostream& os, const LpSolverBase::Expr& e) {
deba@2364
   857
      bool first = true;
deba@2364
   858
      for (LpSolverBase::Expr::const_iterator jt = e.begin(); 
deba@2364
   859
           jt != e.end(); ++jt) {
deba@2364
   860
        if (jt->second < 0.0) {
deba@2364
   861
          os << "- ";
deba@2364
   862
          if (jt->second != -1.0) {
deba@2364
   863
            os << -jt->second << " * ";
deba@2364
   864
          }
deba@2364
   865
        } else if (jt->second > 0.0) {
deba@2364
   866
          if (!first) {
deba@2364
   867
            os << "+ ";
deba@2364
   868
          }
deba@2364
   869
          if (jt->second != 1.0) {
deba@2364
   870
            os << jt->second << " * ";
deba@2364
   871
          }          
deba@2364
   872
        }
deba@2364
   873
        first = false;
deba@2368
   874
        os << lp.colName(jt->first) << " ";
deba@2364
   875
      }
deba@2364
   876
      if (e.constComp() < 0.0) {
deba@2364
   877
        os << "- " << -e.constComp() << " ";
deba@2364
   878
      } else if (e.constComp() > 0.0) {
deba@2364
   879
        if (!first) {
deba@2364
   880
          os << "+ ";
deba@2364
   881
        }
deba@2364
   882
        os << e.constComp() << " ";
deba@2421
   883
      }
deba@2421
   884
      if (e.begin() == e.end() && e.constComp() == 0.0) {
deba@2421
   885
        os << "0 ";
deba@2421
   886
      }
deba@2364
   887
    }
deba@2364
   888
deba@2364
   889
  protected:
deba@2364
   890
deba@2364
   891
    /// \brief Writer function of the section.
deba@2364
   892
    ///
deba@2364
   893
    /// It writes the content of the section.
deba@2364
   894
    virtual void write(std::ostream& os) {
deba@2364
   895
      createCols();
deba@2364
   896
deba@2364
   897
      os << "constraints" << std::endl;
deba@2363
   898
      
deba@2364
   899
      for (LpSolverBase::RowIt it(lp); it != INVALID; ++it) {
deba@2364
   900
        double lower, upper;
deba@2364
   901
        lp.getRowBounds(it, lower, upper);
deba@2364
   902
        if (lower == -LpSolverBase::INF && upper == LpSolverBase::INF) 
deba@2364
   903
          continue;
deba@2364
   904
        os << "   ";
deba@2364
   905
        
deba@2364
   906
        if (lower != upper) {
deba@2364
   907
          if (lower != -LpSolverBase::INF) {
deba@2364
   908
            os << lower << " <= ";
deba@2364
   909
          }
deba@2364
   910
          
deba@2364
   911
          writeExpression(os, lp.row(it));
deba@2364
   912
          
deba@2364
   913
          if (upper != LpSolverBase::INF) {
deba@2364
   914
            os << "<= " << upper << " ";
deba@2364
   915
          }
deba@2364
   916
        } else {
deba@2363
   917
deba@2364
   918
          writeExpression(os, lp.row(it));
deba@2364
   919
          os << "== " << upper << " ";
deba@2364
   920
          
deba@2364
   921
        }
deba@2363
   922
deba@2364
   923
        os << std::endl;
deba@2364
   924
      }
deba@2363
   925
deba@2364
   926
      os << "bounds" << std::endl;
deba@2364
   927
      
deba@2364
   928
      for (LpSolverBase::ColIt it(lp); it != INVALID; ++it) {
deba@2364
   929
        double lower = lp.colLowerBound(it);
deba@2364
   930
        double upper = lp.colUpperBound(it);
deba@2364
   931
        if (lower == -LpSolverBase::INF && upper == LpSolverBase::INF) 
deba@2364
   932
          continue;
deba@2364
   933
        os << "   ";
deba@2363
   934
deba@2364
   935
        if (lower != upper) {
deba@2364
   936
          if (lower != -LpSolverBase::INF) {
deba@2364
   937
            os << lower << " <= ";
deba@2364
   938
          }
deba@2364
   939
          
deba@2368
   940
          os << lp.colName(it) << " ";
deba@2364
   941
          
deba@2364
   942
          if (upper != LpSolverBase::INF) {
deba@2364
   943
            os << "<= " << upper << " ";
deba@2364
   944
          }
deba@2364
   945
        } else {
deba@2368
   946
          os << lp.colName(it) << " == " << upper << " ";
deba@2364
   947
        }
deba@2364
   948
        os << std::endl;
deba@2364
   949
      }
deba@2363
   950
deba@2364
   951
      os << "objective" << std::endl;
deba@2364
   952
      os << "   ";
deba@2369
   953
      if (lp.isMin()) {
deba@2364
   954
        os << "min ";
deba@2364
   955
      } else {
deba@2364
   956
        os << "max ";
deba@2364
   957
      }
deba@2364
   958
      writeExpression(os, lp.obj());
deba@2364
   959
      os << std::endl;
deba@2364
   960
    }
deba@2364
   961
      
deba@2363
   962
deba@2364
   963
  private:
deba@2363
   964
deba@2368
   965
    const LpSolverBase& lp;
deba@2364
   966
    std::string name;
deba@2364
   967
  };
deba@2363
   968
deba@2316
   969
}
deba@2316
   970
deba@2316
   971
#endif