lemon/dimacs.h
author Alpar Juttner <alpar@cs.elte.hu>
Fri, 23 Mar 2018 16:09:06 +0100
branch1.3
changeset 1390 f0f15d07bf51
parent 1270 dceba191c00d
parent 1373 332627dd249e
permissions -rw-r--r--
Merge bugfix #609 to branch 1.3
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@1270
     5
 * Copyright (C) 2003-2013
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@608
    25
#include <limits>
alpar@400
    26
#include <lemon/maps.h>
alpar@402
    27
#include <lemon/error.h>
kpeter@1373
    28
alpar@400
    29
/// \ingroup dimacs_group
alpar@400
    30
/// \file
alpar@400
    31
/// \brief DIMACS file format reader.
alpar@400
    32
alpar@400
    33
namespace lemon {
alpar@400
    34
alpar@400
    35
  /// \addtogroup dimacs_group
alpar@400
    36
  /// @{
alpar@400
    37
alpar@402
    38
  /// DIMACS file type descriptor.
alpar@402
    39
  struct DimacsDescriptor
alpar@402
    40
  {
kpeter@631
    41
    ///\brief DIMACS file type enum
kpeter@631
    42
    ///
kpeter@631
    43
    ///DIMACS file type enum.
kpeter@631
    44
    enum Type {
kpeter@631
    45
      NONE,  ///< Undefined type.
kpeter@631
    46
      MIN,   ///< DIMACS file type for minimum cost flow problems.
kpeter@631
    47
      MAX,   ///< DIMACS file type for maximum flow problems.
kpeter@631
    48
      SP,    ///< DIMACS file type for shostest path problems.
kpeter@631
    49
      MAT    ///< DIMACS file type for plain graphs and matching problems.
kpeter@631
    50
    };
alpar@402
    51
    ///The file type
alpar@402
    52
    Type type;
kpeter@403
    53
    ///The number of nodes in the graph
alpar@402
    54
    int nodeNum;
kpeter@403
    55
    ///The number of edges in the graph
alpar@402
    56
    int edgeNum;
alpar@402
    57
    int lineShift;
kpeter@631
    58
    ///Constructor. It sets the type to \c NONE.
alpar@402
    59
    DimacsDescriptor() : type(NONE) {}
alpar@402
    60
  };
alpar@402
    61
alpar@402
    62
  ///Discover the type of a DIMACS file
alpar@402
    63
kpeter@631
    64
  ///This function starts seeking the beginning of the given file for the
alpar@956
    65
  ///problem type and size info.
kpeter@631
    66
  ///The found data is returned in a special struct that can be evaluated
kpeter@631
    67
  ///and passed to the appropriate reader function.
alpar@402
    68
  DimacsDescriptor dimacsType(std::istream& is)
alpar@402
    69
  {
alpar@402
    70
    DimacsDescriptor r;
alpar@402
    71
    std::string problem,str;
alpar@402
    72
    char c;
alpar@402
    73
    r.lineShift=0;
alpar@402
    74
    while (is >> c)
alpar@402
    75
      switch(c)
alpar@402
    76
        {
alpar@402
    77
        case 'p':
alpar@402
    78
          if(is >> problem >> r.nodeNum >> r.edgeNum)
alpar@402
    79
            {
alpar@402
    80
              getline(is, str);
alpar@402
    81
              r.lineShift++;
alpar@402
    82
              if(problem=="min") r.type=DimacsDescriptor::MIN;
alpar@402
    83
              else if(problem=="max") r.type=DimacsDescriptor::MAX;
alpar@402
    84
              else if(problem=="sp") r.type=DimacsDescriptor::SP;
alpar@402
    85
              else if(problem=="mat") r.type=DimacsDescriptor::MAT;
alpar@402
    86
              else throw FormatError("Unknown problem type");
alpar@402
    87
              return r;
alpar@402
    88
            }
alpar@402
    89
          else
alpar@402
    90
            {
alpar@402
    91
              throw FormatError("Missing or wrong problem type declaration.");
alpar@402
    92
            }
alpar@402
    93
          break;
alpar@402
    94
        case 'c':
alpar@402
    95
          getline(is, str);
alpar@402
    96
          r.lineShift++;
alpar@402
    97
          break;
alpar@402
    98
        default:
alpar@402
    99
          throw FormatError("Unknown DIMACS declaration.");
alpar@402
   100
        }
alpar@402
   101
    throw FormatError("Missing problem type declaration.");
alpar@402
   102
  }
alpar@402
   103
alpar@402
   104
kpeter@631
   105
  /// \brief DIMACS minimum cost flow reader function.
alpar@400
   106
  ///
kpeter@403
   107
  /// This function reads a minimum cost flow instance from DIMACS format,
kpeter@403
   108
  /// i.e. from a DIMACS file having a line starting with
alpar@400
   109
  /// \code
alpar@400
   110
  ///   p min
alpar@400
   111
  /// \endcode
alpar@402
   112
  /// At the beginning, \c g is cleared by \c g.clear(). The supply
alpar@608
   113
  /// amount of the nodes are written to the \c supply node map
alpar@608
   114
  /// (they are signed values). The lower bounds, capacities and costs
alpar@608
   115
  /// of the arcs are written to the \c lower, \c capacity and \c cost
alpar@608
   116
  /// arc maps.
alpar@608
   117
  ///
alpar@608
   118
  /// If the capacity of an arc is less than the lower bound, it will
alpar@608
   119
  /// be set to "infinite" instead. The actual value of "infinite" is
alpar@608
   120
  /// contolled by the \c infty parameter. If it is 0 (the default value),
alpar@608
   121
  /// \c std::numeric_limits<Capacity>::infinity() will be used if available,
alpar@608
   122
  /// \c std::numeric_limits<Capacity>::max() otherwise. If \c infty is set to
alpar@608
   123
  /// a non-zero value, that value will be used as "infinite".
alpar@402
   124
  ///
alpar@402
   125
  /// If the file type was previously evaluated by dimacsType(), then
kpeter@1373
   126
  /// the descriptor struct should be given by the \c desc parameter.
alpar@400
   127
  template <typename Digraph, typename LowerMap,
alpar@402
   128
            typename CapacityMap, typename CostMap,
alpar@402
   129
            typename SupplyMap>
alpar@402
   130
  void readDimacsMin(std::istream& is,
alpar@402
   131
                     Digraph &g,
alpar@402
   132
                     LowerMap& lower,
alpar@402
   133
                     CapacityMap& capacity,
alpar@402
   134
                     CostMap& cost,
alpar@402
   135
                     SupplyMap& supply,
alpar@608
   136
                     typename CapacityMap::Value infty = 0,
alpar@402
   137
                     DimacsDescriptor desc=DimacsDescriptor())
alpar@400
   138
  {
alpar@400
   139
    g.clear();
alpar@400
   140
    std::vector<typename Digraph::Node> nodes;
alpar@400
   141
    typename Digraph::Arc e;
alpar@400
   142
    std::string problem, str;
alpar@400
   143
    char c;
alpar@400
   144
    int i, j;
alpar@402
   145
    if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
alpar@402
   146
    if(desc.type!=DimacsDescriptor::MIN)
alpar@402
   147
      throw FormatError("Problem type mismatch");
alpar@402
   148
alpar@402
   149
    nodes.resize(desc.nodeNum + 1);
alpar@402
   150
    for (int k = 1; k <= desc.nodeNum; ++k) {
alpar@402
   151
      nodes[k] = g.addNode();
alpar@402
   152
      supply.set(nodes[k], 0);
alpar@402
   153
    }
alpar@402
   154
alpar@400
   155
    typename SupplyMap::Value sup;
alpar@400
   156
    typename CapacityMap::Value low;
alpar@400
   157
    typename CapacityMap::Value cap;
alpar@400
   158
    typename CostMap::Value co;
alpar@608
   159
    typedef typename CapacityMap::Value Capacity;
alpar@608
   160
    if(infty==0)
alpar@608
   161
      infty = std::numeric_limits<Capacity>::has_infinity ?
alpar@608
   162
        std::numeric_limits<Capacity>::infinity() :
alpar@608
   163
        std::numeric_limits<Capacity>::max();
alpar@608
   164
alpar@400
   165
    while (is >> c) {
alpar@400
   166
      switch (c) {
alpar@400
   167
      case 'c': // comment line
alpar@400
   168
        getline(is, str);
alpar@400
   169
        break;
alpar@400
   170
      case 'n': // node definition line
alpar@400
   171
        is >> i >> sup;
alpar@400
   172
        getline(is, str);
alpar@400
   173
        supply.set(nodes[i], sup);
alpar@400
   174
        break;
alpar@608
   175
      case 'a': // arc definition line
alpar@400
   176
        is >> i >> j >> low >> cap >> co;
alpar@400
   177
        getline(is, str);
alpar@400
   178
        e = g.addArc(nodes[i], nodes[j]);
alpar@400
   179
        lower.set(e, low);
alpar@608
   180
        if (cap >= low)
alpar@400
   181
          capacity.set(e, cap);
alpar@400
   182
        else
alpar@608
   183
          capacity.set(e, infty);
alpar@400
   184
        cost.set(e, co);
alpar@400
   185
        break;
alpar@400
   186
      }
alpar@400
   187
    }
alpar@400
   188
  }
alpar@400
   189
alpar@400
   190
  template<typename Digraph, typename CapacityMap>
alpar@402
   191
  void _readDimacs(std::istream& is,
alpar@402
   192
                   Digraph &g,
alpar@402
   193
                   CapacityMap& capacity,
alpar@402
   194
                   typename Digraph::Node &s,
alpar@402
   195
                   typename Digraph::Node &t,
alpar@608
   196
                   typename CapacityMap::Value infty = 0,
alpar@402
   197
                   DimacsDescriptor desc=DimacsDescriptor()) {
alpar@400
   198
    g.clear();
alpar@402
   199
    s=t=INVALID;
alpar@400
   200
    std::vector<typename Digraph::Node> nodes;
alpar@400
   201
    typename Digraph::Arc e;
alpar@400
   202
    char c, d;
alpar@400
   203
    int i, j;
alpar@400
   204
    typename CapacityMap::Value _cap;
alpar@400
   205
    std::string str;
alpar@402
   206
    nodes.resize(desc.nodeNum + 1);
alpar@402
   207
    for (int k = 1; k <= desc.nodeNum; ++k) {
alpar@402
   208
      nodes[k] = g.addNode();
alpar@402
   209
    }
alpar@608
   210
    typedef typename CapacityMap::Value Capacity;
alpar@402
   211
alpar@608
   212
    if(infty==0)
alpar@608
   213
      infty = std::numeric_limits<Capacity>::has_infinity ?
alpar@608
   214
        std::numeric_limits<Capacity>::infinity() :
alpar@608
   215
        std::numeric_limits<Capacity>::max();
alpar@956
   216
alpar@400
   217
    while (is >> c) {
alpar@400
   218
      switch (c) {
alpar@400
   219
      case 'c': // comment line
alpar@400
   220
        getline(is, str);
alpar@400
   221
        break;
alpar@400
   222
      case 'n': // node definition line
alpar@402
   223
        if (desc.type==DimacsDescriptor::SP) { // shortest path problem
alpar@400
   224
          is >> i;
alpar@400
   225
          getline(is, str);
alpar@400
   226
          s = nodes[i];
alpar@400
   227
        }
alpar@402
   228
        if (desc.type==DimacsDescriptor::MAX) { // max flow problem
alpar@400
   229
          is >> i >> d;
alpar@400
   230
          getline(is, str);
alpar@400
   231
          if (d == 's') s = nodes[i];
alpar@400
   232
          if (d == 't') t = nodes[i];
alpar@400
   233
        }
alpar@400
   234
        break;
alpar@608
   235
      case 'a': // arc definition line
alpar@608
   236
        if (desc.type==DimacsDescriptor::SP) {
alpar@400
   237
          is >> i >> j >> _cap;
alpar@400
   238
          getline(is, str);
alpar@400
   239
          e = g.addArc(nodes[i], nodes[j]);
alpar@400
   240
          capacity.set(e, _cap);
alpar@956
   241
        }
alpar@608
   242
        else if (desc.type==DimacsDescriptor::MAX) {
alpar@608
   243
          is >> i >> j >> _cap;
alpar@608
   244
          getline(is, str);
alpar@608
   245
          e = g.addArc(nodes[i], nodes[j]);
alpar@608
   246
          if (_cap >= 0)
alpar@608
   247
            capacity.set(e, _cap);
alpar@608
   248
          else
alpar@608
   249
            capacity.set(e, infty);
alpar@608
   250
        }
alpar@608
   251
        else {
alpar@400
   252
          is >> i >> j;
alpar@400
   253
          getline(is, str);
alpar@400
   254
          g.addArc(nodes[i], nodes[j]);
alpar@400
   255
        }
alpar@400
   256
        break;
alpar@400
   257
      }
alpar@400
   258
    }
alpar@400
   259
  }
alpar@400
   260
kpeter@631
   261
  /// \brief DIMACS maximum flow reader function.
alpar@402
   262
  ///
kpeter@403
   263
  /// This function reads a maximum flow instance from DIMACS format,
kpeter@403
   264
  /// i.e. from a DIMACS file having a line starting with
alpar@402
   265
  /// \code
alpar@402
   266
  ///   p max
alpar@402
   267
  /// \endcode
alpar@402
   268
  /// At the beginning, \c g is cleared by \c g.clear(). The arc
alpar@608
   269
  /// capacities are written to the \c capacity arc map and \c s and
alpar@608
   270
  /// \c t are set to the source and the target nodes.
alpar@608
   271
  ///
alpar@608
   272
  /// If the capacity of an arc is negative, it will
alpar@608
   273
  /// be set to "infinite" instead. The actual value of "infinite" is
alpar@608
   274
  /// contolled by the \c infty parameter. If it is 0 (the default value),
alpar@608
   275
  /// \c std::numeric_limits<Capacity>::infinity() will be used if available,
alpar@608
   276
  /// \c std::numeric_limits<Capacity>::max() otherwise. If \c infty is set to
alpar@608
   277
  /// a non-zero value, that value will be used as "infinite".
alpar@402
   278
  ///
alpar@402
   279
  /// If the file type was previously evaluated by dimacsType(), then
kpeter@1373
   280
  /// the descriptor struct should be given by the \c desc parameter.
alpar@402
   281
  template<typename Digraph, typename CapacityMap>
alpar@402
   282
  void readDimacsMax(std::istream& is,
alpar@402
   283
                     Digraph &g,
alpar@402
   284
                     CapacityMap& capacity,
alpar@402
   285
                     typename Digraph::Node &s,
alpar@402
   286
                     typename Digraph::Node &t,
alpar@608
   287
                     typename CapacityMap::Value infty = 0,
alpar@402
   288
                     DimacsDescriptor desc=DimacsDescriptor()) {
alpar@402
   289
    if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
alpar@402
   290
    if(desc.type!=DimacsDescriptor::MAX)
alpar@402
   291
      throw FormatError("Problem type mismatch");
alpar@608
   292
    _readDimacs(is,g,capacity,s,t,infty,desc);
alpar@402
   293
  }
alpar@402
   294
kpeter@631
   295
  /// \brief DIMACS shortest path reader function.
alpar@400
   296
  ///
alpar@400
   297
  /// This function reads a shortest path instance from DIMACS format,
kpeter@403
   298
  /// i.e. from a DIMACS file having a line starting with
alpar@400
   299
  /// \code
alpar@400
   300
  ///   p sp
alpar@400
   301
  /// \endcode
alpar@402
   302
  /// At the beginning, \c g is cleared by \c g.clear(). The arc
alpar@608
   303
  /// lengths are written to the \c length arc map and \c s is set to the
alpar@400
   304
  /// source node.
alpar@402
   305
  ///
alpar@402
   306
  /// If the file type was previously evaluated by dimacsType(), then
kpeter@1373
   307
  /// the descriptor struct should be given by the \c desc parameter.
alpar@402
   308
  template<typename Digraph, typename LengthMap>
alpar@402
   309
  void readDimacsSp(std::istream& is,
alpar@402
   310
                    Digraph &g,
alpar@402
   311
                    LengthMap& length,
alpar@402
   312
                    typename Digraph::Node &s,
alpar@402
   313
                    DimacsDescriptor desc=DimacsDescriptor()) {
alpar@401
   314
    typename Digraph::Node t;
alpar@402
   315
    if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
alpar@402
   316
    if(desc.type!=DimacsDescriptor::SP)
alpar@402
   317
      throw FormatError("Problem type mismatch");
alpar@608
   318
    _readDimacs(is, g, length, s, t, 0, desc);
alpar@400
   319
  }
alpar@400
   320
kpeter@631
   321
  /// \brief DIMACS capacitated digraph reader function.
alpar@400
   322
  ///
alpar@400
   323
  /// This function reads an arc capacitated digraph instance from
alpar@608
   324
  /// DIMACS 'max' or 'sp' format.
alpar@402
   325
  /// At the beginning, \c g is cleared by \c g.clear()
alpar@608
   326
  /// and the arc capacities/lengths are written to the \c capacity
alpar@608
   327
  /// arc map.
alpar@608
   328
  ///
alpar@608
   329
  /// In case of the 'max' format, if the capacity of an arc is negative,
alpar@608
   330
  /// it will
alpar@608
   331
  /// be set to "infinite" instead. The actual value of "infinite" is
alpar@608
   332
  /// contolled by the \c infty parameter. If it is 0 (the default value),
alpar@608
   333
  /// \c std::numeric_limits<Capacity>::infinity() will be used if available,
alpar@608
   334
  /// \c std::numeric_limits<Capacity>::max() otherwise. If \c infty is set to
alpar@608
   335
  /// a non-zero value, that value will be used as "infinite".
alpar@402
   336
  ///
alpar@402
   337
  /// If the file type was previously evaluated by dimacsType(), then
kpeter@1373
   338
  /// the descriptor struct should be given by the \c desc parameter.
alpar@400
   339
  template<typename Digraph, typename CapacityMap>
alpar@402
   340
  void readDimacsCap(std::istream& is,
alpar@402
   341
                     Digraph &g,
alpar@402
   342
                     CapacityMap& capacity,
alpar@608
   343
                     typename CapacityMap::Value infty = 0,
alpar@402
   344
                     DimacsDescriptor desc=DimacsDescriptor()) {
alpar@401
   345
    typename Digraph::Node u,v;
alpar@402
   346
    if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
kpeter@1372
   347
    if(desc.type!=DimacsDescriptor::MAX && desc.type!=DimacsDescriptor::SP)
alpar@402
   348
      throw FormatError("Problem type mismatch");
alpar@608
   349
    _readDimacs(is, g, capacity, u, v, infty, desc);
alpar@400
   350
  }
alpar@400
   351
alpar@572
   352
  template<typename Graph>
alpar@572
   353
  typename enable_if<lemon::UndirectedTagIndicator<Graph>,void>::type
alpar@572
   354
  _addArcEdge(Graph &g, typename Graph::Node s, typename Graph::Node t,
alpar@572
   355
              dummy<0> = 0)
alpar@572
   356
  {
alpar@572
   357
    g.addEdge(s,t);
alpar@572
   358
  }
alpar@572
   359
  template<typename Graph>
alpar@572
   360
  typename disable_if<lemon::UndirectedTagIndicator<Graph>,void>::type
alpar@572
   361
  _addArcEdge(Graph &g, typename Graph::Node s, typename Graph::Node t,
alpar@572
   362
              dummy<1> = 1)
alpar@572
   363
  {
alpar@572
   364
    g.addArc(s,t);
alpar@572
   365
  }
alpar@956
   366
kpeter@631
   367
  /// \brief DIMACS plain (di)graph reader function.
alpar@400
   368
  ///
kpeter@631
   369
  /// This function reads a plain (di)graph without any designated nodes
alpar@956
   370
  /// and maps (e.g. a matching instance) from DIMACS format, i.e. from
kpeter@631
   371
  /// DIMACS files having a line starting with
alpar@400
   372
  /// \code
alpar@400
   373
  ///   p mat
alpar@400
   374
  /// \endcode
alpar@402
   375
  /// At the beginning, \c g is cleared by \c g.clear().
alpar@402
   376
  ///
alpar@402
   377
  /// If the file type was previously evaluated by dimacsType(), then
kpeter@1373
   378
  /// the descriptor struct should be given by the \c desc parameter.
alpar@572
   379
  template<typename Graph>
alpar@572
   380
  void readDimacsMat(std::istream& is, Graph &g,
alpar@572
   381
                     DimacsDescriptor desc=DimacsDescriptor())
alpar@572
   382
  {
alpar@402
   383
    if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
alpar@402
   384
    if(desc.type!=DimacsDescriptor::MAT)
alpar@402
   385
      throw FormatError("Problem type mismatch");
alpar@572
   386
alpar@572
   387
    g.clear();
alpar@572
   388
    std::vector<typename Graph::Node> nodes;
alpar@572
   389
    char c;
alpar@572
   390
    int i, j;
alpar@572
   391
    std::string str;
alpar@572
   392
    nodes.resize(desc.nodeNum + 1);
alpar@572
   393
    for (int k = 1; k <= desc.nodeNum; ++k) {
alpar@572
   394
      nodes[k] = g.addNode();
alpar@572
   395
    }
alpar@956
   396
alpar@572
   397
    while (is >> c) {
alpar@572
   398
      switch (c) {
alpar@572
   399
      case 'c': // comment line
alpar@572
   400
        getline(is, str);
alpar@572
   401
        break;
alpar@572
   402
      case 'n': // node definition line
alpar@572
   403
        break;
alpar@608
   404
      case 'a': // arc definition line
alpar@572
   405
        is >> i >> j;
alpar@572
   406
        getline(is, str);
alpar@572
   407
        _addArcEdge(g,nodes[i], nodes[j]);
alpar@572
   408
        break;
alpar@572
   409
      }
alpar@572
   410
    }
alpar@400
   411
  }
alpar@400
   412
alpar@400
   413
  /// DIMACS plain digraph writer function.
alpar@400
   414
  ///
alpar@400
   415
  /// This function writes a digraph without any designated nodes and
alpar@400
   416
  /// maps into DIMACS format, i.e. into DIMACS file having a line
alpar@400
   417
  /// starting with
alpar@400
   418
  /// \code
alpar@400
   419
  ///   p mat
alpar@400
   420
  /// \endcode
alpar@402
   421
  /// If \c comment is not empty, then it will be printed in the first line
alpar@402
   422
  /// prefixed by 'c'.
alpar@400
   423
  template<typename Digraph>
alpar@402
   424
  void writeDimacsMat(std::ostream& os, const Digraph &g,
alpar@402
   425
                      std::string comment="") {
alpar@400
   426
    typedef typename Digraph::NodeIt NodeIt;
alpar@400
   427
    typedef typename Digraph::ArcIt ArcIt;
alpar@400
   428
alpar@463
   429
    if(!comment.empty())
alpar@402
   430
      os << "c " << comment << std::endl;
alpar@400
   431
    os << "p mat " << g.nodeNum() << " " << g.arcNum() << std::endl;
alpar@400
   432
alpar@400
   433
    typename Digraph::template NodeMap<int> nodes(g);
alpar@400
   434
    int i = 1;
alpar@400
   435
    for(NodeIt v(g); v != INVALID; ++v) {
alpar@400
   436
      nodes.set(v, i);
alpar@400
   437
      ++i;
alpar@400
   438
    }
alpar@400
   439
    for(ArcIt e(g); e != INVALID; ++e) {
alpar@400
   440
      os << "a " << nodes[g.source(e)] << " " << nodes[g.target(e)]
alpar@400
   441
         << std::endl;
alpar@400
   442
    }
alpar@400
   443
  }
alpar@400
   444
alpar@400
   445
  /// @}
alpar@400
   446
alpar@400
   447
} //namespace lemon
alpar@400
   448
alpar@400
   449
#endif //LEMON_DIMACS_H