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