lemon/dimacs.h
author Alpar Juttner <alpar@cs.elte.hu>
Fri, 28 Nov 2008 06:38:20 +0000
changeset 402 24a2c6ee6cb0
parent 401 9d1faab5e0f1
child 403 0a3ec097a76c
permissions -rw-r--r--
Refactoring of DIMACS tools
alpar@400
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
alpar@400
     2
 *
alpar@400
     3
 * This file is a part of LEMON, a generic C++ optimization library.
alpar@400
     4
 *
alpar@400
     5
 * Copyright (C) 2003-2008
alpar@400
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
alpar@400
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
alpar@400
     8
 *
alpar@400
     9
 * Permission to use, modify and distribute this software is granted
alpar@400
    10
 * provided that this copyright notice appears in all copies. For
alpar@400
    11
 * precise terms see the accompanying LICENSE file.
alpar@400
    12
 *
alpar@400
    13
 * This software is provided "AS IS" with no warranty of any kind,
alpar@400
    14
 * express or implied, and with no claim as to its suitability for any
alpar@400
    15
 * purpose.
alpar@400
    16
 *
alpar@400
    17
 */
alpar@400
    18
alpar@400
    19
#ifndef LEMON_DIMACS_H
alpar@400
    20
#define LEMON_DIMACS_H
alpar@400
    21
alpar@400
    22
#include <iostream>
alpar@400
    23
#include <string>
alpar@400
    24
#include <vector>
alpar@400
    25
#include <lemon/maps.h>
alpar@402
    26
#include <lemon/error.h>
alpar@400
    27
alpar@400
    28
/// \ingroup dimacs_group
alpar@400
    29
/// \file
alpar@400
    30
/// \brief DIMACS file format reader.
alpar@400
    31
alpar@400
    32
namespace lemon {
alpar@400
    33
alpar@400
    34
  ///@defgroup dimacs_group DIMACS format
alpar@400
    35
  ///\brief Read and write files in DIMACS format
alpar@400
    36
  ///
alpar@400
    37
  ///Tools to read a digraph from or write it to a file in DIMACS format
alpar@400
    38
  ///data
alpar@400
    39
  ///\ingroup io_group
alpar@400
    40
alpar@400
    41
  /// \addtogroup dimacs_group
alpar@400
    42
  /// @{
alpar@400
    43
alpar@402
    44
alpar@402
    45
  /// DIMACS file type descriptor.
alpar@402
    46
  struct DimacsDescriptor
alpar@402
    47
  {
alpar@402
    48
    ///File type enum
alpar@402
    49
    enum Type
alpar@402
    50
      {
alpar@402
    51
        NONE, MIN, MAX, SP, MAT
alpar@402
    52
      };
alpar@402
    53
    ///The file type
alpar@402
    54
    Type type;
alpar@402
    55
    ///The number of nodes on the graph
alpar@402
    56
    int nodeNum;
alpar@402
    57
    ///The number of edges on the graph
alpar@402
    58
    int edgeNum;
alpar@402
    59
    int lineShift;
alpar@402
    60
    /// Constructor. Sets the type to NONE.
alpar@402
    61
    DimacsDescriptor() : type(NONE) {}
alpar@402
    62
  };
alpar@402
    63
alpar@402
    64
  ///Discover the type of a DIMACS file
alpar@402
    65
alpar@402
    66
  ///It starts seeking the begining of the file for the problem type
alpar@402
    67
  ///and size info. The found date is returned in a special struct
alpar@402
    68
  ///that can be evaluated and passed to the appropriate reader
alpar@402
    69
  ///function.
alpar@402
    70
  DimacsDescriptor dimacsType(std::istream& is)
alpar@402
    71
  {
alpar@402
    72
    DimacsDescriptor r;
alpar@402
    73
    std::string problem,str;
alpar@402
    74
    char c;
alpar@402
    75
    r.lineShift=0;
alpar@402
    76
    while (is >> c)
alpar@402
    77
      switch(c)
alpar@402
    78
        {
alpar@402
    79
        case 'p':
alpar@402
    80
          if(is >> problem >> r.nodeNum >> r.edgeNum)
alpar@402
    81
            {
alpar@402
    82
              getline(is, str);
alpar@402
    83
              r.lineShift++;
alpar@402
    84
              if(problem=="min") r.type=DimacsDescriptor::MIN;
alpar@402
    85
              else if(problem=="max") r.type=DimacsDescriptor::MAX;
alpar@402
    86
              else if(problem=="sp") r.type=DimacsDescriptor::SP;
alpar@402
    87
              else if(problem=="mat") r.type=DimacsDescriptor::MAT;
alpar@402
    88
              else throw FormatError("Unknown problem type");
alpar@402
    89
              return r;
alpar@402
    90
            }
alpar@402
    91
          else
alpar@402
    92
            {
alpar@402
    93
              throw FormatError("Missing or wrong problem type declaration.");
alpar@402
    94
            }
alpar@402
    95
          break;
alpar@402
    96
        case 'c':
alpar@402
    97
          getline(is, str);
alpar@402
    98
          r.lineShift++;
alpar@402
    99
          break;
alpar@402
   100
        default:
alpar@402
   101
          throw FormatError("Unknown DIMACS declaration.");
alpar@402
   102
        }
alpar@402
   103
    throw FormatError("Missing problem type declaration.");
alpar@402
   104
  }
alpar@402
   105
alpar@402
   106
alpar@402
   107
alpar@400
   108
  /// DIMACS min cost flow reader function.
alpar@400
   109
  ///
alpar@400
   110
  /// This function reads a min cost flow instance from DIMACS format,
alpar@400
   111
  /// i.e. from DIMACS files having a line starting with
alpar@400
   112
  /// \code
alpar@400
   113
  ///   p min
alpar@400
   114
  /// \endcode
alpar@402
   115
  /// At the beginning, \c g is cleared by \c g.clear(). The supply
alpar@400
   116
  /// amount of the nodes are written to \c supply (signed). The
alpar@400
   117
  /// lower bounds, capacities and costs of the arcs are written to
alpar@400
   118
  /// \c lower, \c capacity and \c cost.
alpar@402
   119
  ///
alpar@402
   120
  /// If the file type was previously evaluated by dimacsType(), then
alpar@402
   121
  /// the descriptor struct should be given by the \c dest parameter.
alpar@400
   122
  template <typename Digraph, typename LowerMap,
alpar@402
   123
            typename CapacityMap, typename CostMap,
alpar@402
   124
            typename SupplyMap>
alpar@402
   125
  void readDimacsMin(std::istream& is,
alpar@402
   126
                     Digraph &g,
alpar@402
   127
                     LowerMap& lower,
alpar@402
   128
                     CapacityMap& capacity,
alpar@402
   129
                     CostMap& cost,
alpar@402
   130
                     SupplyMap& supply,
alpar@402
   131
                     DimacsDescriptor desc=DimacsDescriptor())
alpar@400
   132
  {
alpar@400
   133
    g.clear();
alpar@400
   134
    std::vector<typename Digraph::Node> nodes;
alpar@400
   135
    typename Digraph::Arc e;
alpar@400
   136
    std::string problem, str;
alpar@400
   137
    char c;
alpar@400
   138
    int i, j;
alpar@402
   139
    if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
alpar@402
   140
    if(desc.type!=DimacsDescriptor::MIN)
alpar@402
   141
      throw FormatError("Problem type mismatch");
alpar@402
   142
alpar@402
   143
    nodes.resize(desc.nodeNum + 1);
alpar@402
   144
    for (int k = 1; k <= desc.nodeNum; ++k) {
alpar@402
   145
      nodes[k] = g.addNode();
alpar@402
   146
      supply.set(nodes[k], 0);
alpar@402
   147
    }
alpar@402
   148
alpar@400
   149
    typename SupplyMap::Value sup;
alpar@400
   150
    typename CapacityMap::Value low;
alpar@400
   151
    typename CapacityMap::Value cap;
alpar@400
   152
    typename CostMap::Value co;
alpar@400
   153
    while (is >> c) {
alpar@400
   154
      switch (c) {
alpar@400
   155
      case 'c': // comment line
alpar@400
   156
        getline(is, str);
alpar@400
   157
        break;
alpar@400
   158
      case 'n': // node definition line
alpar@400
   159
        is >> i >> sup;
alpar@400
   160
        getline(is, str);
alpar@400
   161
        supply.set(nodes[i], sup);
alpar@400
   162
        break;
alpar@400
   163
      case 'a': // arc (arc) definition line
alpar@400
   164
        is >> i >> j >> low >> cap >> co;
alpar@400
   165
        getline(is, str);
alpar@400
   166
        e = g.addArc(nodes[i], nodes[j]);
alpar@400
   167
        lower.set(e, low);
alpar@400
   168
        if (cap >= 0)
alpar@400
   169
          capacity.set(e, cap);
alpar@400
   170
        else
alpar@400
   171
          capacity.set(e, -1);
alpar@400
   172
        cost.set(e, co);
alpar@400
   173
        break;
alpar@400
   174
      }
alpar@400
   175
    }
alpar@400
   176
  }
alpar@400
   177
alpar@400
   178
  template<typename Digraph, typename CapacityMap>
alpar@402
   179
  void _readDimacs(std::istream& is,
alpar@402
   180
                   Digraph &g,
alpar@402
   181
                   CapacityMap& capacity,
alpar@402
   182
                   typename Digraph::Node &s,
alpar@402
   183
                   typename Digraph::Node &t,
alpar@402
   184
                   DimacsDescriptor desc=DimacsDescriptor()) {
alpar@400
   185
    g.clear();
alpar@402
   186
    s=t=INVALID;
alpar@400
   187
    std::vector<typename Digraph::Node> nodes;
alpar@400
   188
    typename Digraph::Arc e;
alpar@400
   189
    char c, d;
alpar@400
   190
    int i, j;
alpar@400
   191
    typename CapacityMap::Value _cap;
alpar@400
   192
    std::string str;
alpar@402
   193
    nodes.resize(desc.nodeNum + 1);
alpar@402
   194
    for (int k = 1; k <= desc.nodeNum; ++k) {
alpar@402
   195
      nodes[k] = g.addNode();
alpar@402
   196
    }
alpar@402
   197
alpar@400
   198
    while (is >> c) {
alpar@400
   199
      switch (c) {
alpar@400
   200
      case 'c': // comment line
alpar@400
   201
        getline(is, str);
alpar@400
   202
        break;
alpar@400
   203
      case 'n': // node definition line
alpar@402
   204
        if (desc.type==DimacsDescriptor::SP) { // shortest path problem
alpar@400
   205
          is >> i;
alpar@400
   206
          getline(is, str);
alpar@400
   207
          s = nodes[i];
alpar@400
   208
        }
alpar@402
   209
        if (desc.type==DimacsDescriptor::MAX) { // max flow problem
alpar@400
   210
          is >> i >> d;
alpar@400
   211
          getline(is, str);
alpar@400
   212
          if (d == 's') s = nodes[i];
alpar@400
   213
          if (d == 't') t = nodes[i];
alpar@400
   214
        }
alpar@400
   215
        break;
alpar@400
   216
      case 'a': // arc (arc) definition line
alpar@402
   217
        if (desc.type==DimacsDescriptor::SP ||
alpar@402
   218
            desc.type==DimacsDescriptor::MAX) {
alpar@400
   219
          is >> i >> j >> _cap;
alpar@400
   220
          getline(is, str);
alpar@400
   221
          e = g.addArc(nodes[i], nodes[j]);
alpar@400
   222
          capacity.set(e, _cap);
alpar@400
   223
        } else {
alpar@400
   224
          is >> i >> j;
alpar@400
   225
          getline(is, str);
alpar@400
   226
          g.addArc(nodes[i], nodes[j]);
alpar@400
   227
        }
alpar@400
   228
        break;
alpar@400
   229
      }
alpar@400
   230
    }
alpar@400
   231
  }
alpar@400
   232
alpar@402
   233
  /// DIMACS max flow reader function.
alpar@402
   234
  ///
alpar@402
   235
  /// This function reads a max flow instance from DIMACS format,
alpar@402
   236
  /// i.e. from DIMACS files having a line starting with
alpar@402
   237
  /// \code
alpar@402
   238
  ///   p max
alpar@402
   239
  /// \endcode
alpar@402
   240
  /// At the beginning, \c g is cleared by \c g.clear(). The arc
alpar@402
   241
  /// capacities are written to \c capacity and \c s and \c t are
alpar@402
   242
  /// set to the source and the target nodes.
alpar@402
   243
  ///
alpar@402
   244
  /// If the file type was previously evaluated by dimacsType(), then
alpar@402
   245
  /// the descriptor struct should be given by the \c dest parameter.
alpar@402
   246
  template<typename Digraph, typename CapacityMap>
alpar@402
   247
  void readDimacsMax(std::istream& is,
alpar@402
   248
                     Digraph &g,
alpar@402
   249
                     CapacityMap& capacity,
alpar@402
   250
                     typename Digraph::Node &s,
alpar@402
   251
                     typename Digraph::Node &t,
alpar@402
   252
                     DimacsDescriptor desc=DimacsDescriptor()) {
alpar@402
   253
    if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
alpar@402
   254
    if(desc.type!=DimacsDescriptor::MAX)
alpar@402
   255
      throw FormatError("Problem type mismatch");
alpar@402
   256
    _readDimacs(is,g,capacity,s,t,desc);
alpar@402
   257
  }
alpar@402
   258
alpar@400
   259
  /// DIMACS shortest path reader function.
alpar@400
   260
  ///
alpar@400
   261
  /// This function reads a shortest path instance from DIMACS format,
alpar@400
   262
  /// i.e. from DIMACS files having a line starting with
alpar@400
   263
  /// \code
alpar@400
   264
  ///   p sp
alpar@400
   265
  /// \endcode
alpar@402
   266
  /// At the beginning, \c g is cleared by \c g.clear(). The arc
alpar@402
   267
  /// lengths are written to \c lenght and \c s is set to the
alpar@400
   268
  /// source node.
alpar@402
   269
  ///
alpar@402
   270
  /// If the file type was previously evaluated by dimacsType(), then
alpar@402
   271
  /// the descriptor struct should be given by the \c dest parameter.
alpar@402
   272
  template<typename Digraph, typename LengthMap>
alpar@402
   273
  void readDimacsSp(std::istream& is,
alpar@402
   274
                    Digraph &g,
alpar@402
   275
                    LengthMap& length,
alpar@402
   276
                    typename Digraph::Node &s,
alpar@402
   277
                    DimacsDescriptor desc=DimacsDescriptor()) {
alpar@401
   278
    typename Digraph::Node t;
alpar@402
   279
    if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
alpar@402
   280
    if(desc.type!=DimacsDescriptor::SP)
alpar@402
   281
      throw FormatError("Problem type mismatch");
alpar@402
   282
    _readDimacs(is, g, length, s, t,desc);
alpar@400
   283
  }
alpar@400
   284
alpar@400
   285
  /// DIMACS capacitated digraph reader function.
alpar@400
   286
  ///
alpar@400
   287
  /// This function reads an arc capacitated digraph instance from
alpar@402
   288
  /// DIMACS 'mat' or 'sp' format.
alpar@402
   289
  /// At the beginning, \c g is cleared by \c g.clear()
alpar@402
   290
  /// and the arc capacities/lengths are written to \c capacity.
alpar@402
   291
  ///
alpar@402
   292
  /// If the file type was previously evaluated by dimacsType(), then
alpar@402
   293
  /// the descriptor struct should be given by the \c dest parameter.
alpar@400
   294
  template<typename Digraph, typename CapacityMap>
alpar@402
   295
  void readDimacsCap(std::istream& is,
alpar@402
   296
                     Digraph &g,
alpar@402
   297
                     CapacityMap& capacity,
alpar@402
   298
                     DimacsDescriptor desc=DimacsDescriptor()) {
alpar@401
   299
    typename Digraph::Node u,v;
alpar@402
   300
    if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
alpar@402
   301
    if(desc.type!=DimacsDescriptor::MAX || desc.type!=DimacsDescriptor::SP)
alpar@402
   302
      throw FormatError("Problem type mismatch");
alpar@402
   303
    _readDimacs(is, g, capacity, u, v, desc);
alpar@400
   304
  }
alpar@400
   305
alpar@400
   306
  /// DIMACS plain digraph reader function.
alpar@400
   307
  ///
alpar@400
   308
  /// This function reads a digraph without any designated nodes and
alpar@400
   309
  /// maps from DIMACS format, i.e. from DIMACS files having a line
alpar@400
   310
  /// starting with
alpar@400
   311
  /// \code
alpar@400
   312
  ///   p mat
alpar@400
   313
  /// \endcode
alpar@402
   314
  /// At the beginning, \c g is cleared by \c g.clear().
alpar@402
   315
  ///
alpar@402
   316
  /// If the file type was previously evaluated by dimacsType(), then
alpar@402
   317
  /// the descriptor struct should be given by the \c dest parameter.
alpar@400
   318
  template<typename Digraph>
alpar@402
   319
  void readDimacsMat(std::istream& is, Digraph &g,
alpar@402
   320
                     DimacsDescriptor desc=DimacsDescriptor()) {
alpar@401
   321
    typename Digraph::Node u,v;
alpar@400
   322
    NullMap<typename Digraph::Arc, int> n;
alpar@402
   323
    if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
alpar@402
   324
    if(desc.type!=DimacsDescriptor::MAT)
alpar@402
   325
      throw FormatError("Problem type mismatch");
alpar@402
   326
    _readDimacs(is, g, n, u, v, desc);
alpar@400
   327
  }
alpar@400
   328
alpar@400
   329
  /// DIMACS plain digraph writer function.
alpar@400
   330
  ///
alpar@400
   331
  /// This function writes a digraph without any designated nodes and
alpar@400
   332
  /// maps into DIMACS format, i.e. into DIMACS file having a line
alpar@400
   333
  /// starting with
alpar@400
   334
  /// \code
alpar@400
   335
  ///   p mat
alpar@400
   336
  /// \endcode
alpar@402
   337
  /// If \c comment is not empty, then it will be printed in the first line
alpar@402
   338
  /// prefixed by 'c'.
alpar@400
   339
  template<typename Digraph>
alpar@402
   340
  void writeDimacsMat(std::ostream& os, const Digraph &g,
alpar@402
   341
                      std::string comment="") {
alpar@400
   342
    typedef typename Digraph::NodeIt NodeIt;
alpar@400
   343
    typedef typename Digraph::ArcIt ArcIt;
alpar@400
   344
alpar@402
   345
    if(!comment.empty()) 
alpar@402
   346
      os << "c " << comment << std::endl;
alpar@400
   347
    os << "p mat " << g.nodeNum() << " " << g.arcNum() << std::endl;
alpar@400
   348
alpar@400
   349
    typename Digraph::template NodeMap<int> nodes(g);
alpar@400
   350
    int i = 1;
alpar@400
   351
    for(NodeIt v(g); v != INVALID; ++v) {
alpar@400
   352
      nodes.set(v, i);
alpar@400
   353
      ++i;
alpar@400
   354
    }
alpar@400
   355
    for(ArcIt e(g); e != INVALID; ++e) {
alpar@400
   356
      os << "a " << nodes[g.source(e)] << " " << nodes[g.target(e)]
alpar@400
   357
         << std::endl;
alpar@400
   358
    }
alpar@400
   359
  }
alpar@400
   360
alpar@400
   361
  /// @}
alpar@400
   362
alpar@400
   363
} //namespace lemon
alpar@400
   364
alpar@400
   365
#endif //LEMON_DIMACS_H