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