alpar@400: /* -*- mode: C++; indent-tabs-mode: nil; -*- alpar@400: * alpar@400: * This file is a part of LEMON, a generic C++ optimization library. alpar@400: * alpar@463: * Copyright (C) 2003-2009 alpar@400: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport alpar@400: * (Egervary Research Group on Combinatorial Optimization, EGRES). alpar@400: * alpar@400: * Permission to use, modify and distribute this software is granted alpar@400: * provided that this copyright notice appears in all copies. For alpar@400: * precise terms see the accompanying LICENSE file. alpar@400: * alpar@400: * This software is provided "AS IS" with no warranty of any kind, alpar@400: * express or implied, and with no claim as to its suitability for any alpar@400: * purpose. alpar@400: * alpar@400: */ alpar@400: alpar@400: #ifndef LEMON_DIMACS_H alpar@400: #define LEMON_DIMACS_H alpar@400: alpar@400: #include alpar@400: #include alpar@400: #include alpar@400: #include alpar@402: #include alpar@400: alpar@400: /// \ingroup dimacs_group alpar@400: /// \file alpar@400: /// \brief DIMACS file format reader. alpar@400: alpar@400: namespace lemon { alpar@400: alpar@400: /// \addtogroup dimacs_group alpar@400: /// @{ alpar@400: alpar@402: /// DIMACS file type descriptor. alpar@402: struct DimacsDescriptor alpar@402: { alpar@402: ///File type enum alpar@402: enum Type alpar@402: { alpar@402: NONE, MIN, MAX, SP, MAT alpar@402: }; alpar@402: ///The file type alpar@402: Type type; kpeter@403: ///The number of nodes in the graph alpar@402: int nodeNum; kpeter@403: ///The number of edges in the graph alpar@402: int edgeNum; alpar@402: int lineShift; alpar@402: /// Constructor. Sets the type to NONE. alpar@402: DimacsDescriptor() : type(NONE) {} alpar@402: }; alpar@402: alpar@402: ///Discover the type of a DIMACS file alpar@402: alpar@402: ///It starts seeking the begining of the file for the problem type kpeter@403: ///and size info. The found data is returned in a special struct alpar@402: ///that can be evaluated and passed to the appropriate reader alpar@402: ///function. alpar@402: DimacsDescriptor dimacsType(std::istream& is) alpar@402: { alpar@402: DimacsDescriptor r; alpar@402: std::string problem,str; alpar@402: char c; alpar@402: r.lineShift=0; alpar@402: while (is >> c) alpar@402: switch(c) alpar@402: { alpar@402: case 'p': alpar@402: if(is >> problem >> r.nodeNum >> r.edgeNum) alpar@402: { alpar@402: getline(is, str); alpar@402: r.lineShift++; alpar@402: if(problem=="min") r.type=DimacsDescriptor::MIN; alpar@402: else if(problem=="max") r.type=DimacsDescriptor::MAX; alpar@402: else if(problem=="sp") r.type=DimacsDescriptor::SP; alpar@402: else if(problem=="mat") r.type=DimacsDescriptor::MAT; alpar@402: else throw FormatError("Unknown problem type"); alpar@402: return r; alpar@402: } alpar@402: else alpar@402: { alpar@402: throw FormatError("Missing or wrong problem type declaration."); alpar@402: } alpar@402: break; alpar@402: case 'c': alpar@402: getline(is, str); alpar@402: r.lineShift++; alpar@402: break; alpar@402: default: alpar@402: throw FormatError("Unknown DIMACS declaration."); alpar@402: } alpar@402: throw FormatError("Missing problem type declaration."); alpar@402: } alpar@402: alpar@402: alpar@402: kpeter@403: /// DIMACS minimum cost flow reader function. alpar@400: /// kpeter@403: /// This function reads a minimum cost flow instance from DIMACS format, kpeter@403: /// i.e. from a DIMACS file having a line starting with alpar@400: /// \code alpar@400: /// p min alpar@400: /// \endcode alpar@402: /// At the beginning, \c g is cleared by \c g.clear(). The supply alpar@400: /// amount of the nodes are written to \c supply (signed). The alpar@400: /// lower bounds, capacities and costs of the arcs are written to alpar@400: /// \c lower, \c capacity and \c cost. alpar@402: /// alpar@402: /// If the file type was previously evaluated by dimacsType(), then alpar@402: /// the descriptor struct should be given by the \c dest parameter. alpar@400: template alpar@402: void readDimacsMin(std::istream& is, alpar@402: Digraph &g, alpar@402: LowerMap& lower, alpar@402: CapacityMap& capacity, alpar@402: CostMap& cost, alpar@402: SupplyMap& supply, alpar@402: DimacsDescriptor desc=DimacsDescriptor()) alpar@400: { alpar@400: g.clear(); alpar@400: std::vector nodes; alpar@400: typename Digraph::Arc e; alpar@400: std::string problem, str; alpar@400: char c; alpar@400: int i, j; alpar@402: if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); alpar@402: if(desc.type!=DimacsDescriptor::MIN) alpar@402: throw FormatError("Problem type mismatch"); alpar@402: alpar@402: nodes.resize(desc.nodeNum + 1); alpar@402: for (int k = 1; k <= desc.nodeNum; ++k) { alpar@402: nodes[k] = g.addNode(); alpar@402: supply.set(nodes[k], 0); alpar@402: } alpar@402: alpar@400: typename SupplyMap::Value sup; alpar@400: typename CapacityMap::Value low; alpar@400: typename CapacityMap::Value cap; alpar@400: typename CostMap::Value co; alpar@400: while (is >> c) { alpar@400: switch (c) { alpar@400: case 'c': // comment line alpar@400: getline(is, str); alpar@400: break; alpar@400: case 'n': // node definition line alpar@400: is >> i >> sup; alpar@400: getline(is, str); alpar@400: supply.set(nodes[i], sup); alpar@400: break; alpar@400: case 'a': // arc (arc) definition line alpar@400: is >> i >> j >> low >> cap >> co; alpar@400: getline(is, str); alpar@400: e = g.addArc(nodes[i], nodes[j]); alpar@400: lower.set(e, low); alpar@400: if (cap >= 0) alpar@400: capacity.set(e, cap); alpar@400: else alpar@400: capacity.set(e, -1); alpar@400: cost.set(e, co); alpar@400: break; alpar@400: } alpar@400: } alpar@400: } alpar@400: alpar@400: template alpar@402: void _readDimacs(std::istream& is, alpar@402: Digraph &g, alpar@402: CapacityMap& capacity, alpar@402: typename Digraph::Node &s, alpar@402: typename Digraph::Node &t, alpar@402: DimacsDescriptor desc=DimacsDescriptor()) { alpar@400: g.clear(); alpar@402: s=t=INVALID; alpar@400: std::vector nodes; alpar@400: typename Digraph::Arc e; alpar@400: char c, d; alpar@400: int i, j; alpar@400: typename CapacityMap::Value _cap; alpar@400: std::string str; alpar@402: nodes.resize(desc.nodeNum + 1); alpar@402: for (int k = 1; k <= desc.nodeNum; ++k) { alpar@402: nodes[k] = g.addNode(); alpar@402: } alpar@402: alpar@400: while (is >> c) { alpar@400: switch (c) { alpar@400: case 'c': // comment line alpar@400: getline(is, str); alpar@400: break; alpar@400: case 'n': // node definition line alpar@402: if (desc.type==DimacsDescriptor::SP) { // shortest path problem alpar@400: is >> i; alpar@400: getline(is, str); alpar@400: s = nodes[i]; alpar@400: } alpar@402: if (desc.type==DimacsDescriptor::MAX) { // max flow problem alpar@400: is >> i >> d; alpar@400: getline(is, str); alpar@400: if (d == 's') s = nodes[i]; alpar@400: if (d == 't') t = nodes[i]; alpar@400: } alpar@400: break; alpar@400: case 'a': // arc (arc) definition line alpar@402: if (desc.type==DimacsDescriptor::SP || alpar@402: desc.type==DimacsDescriptor::MAX) { alpar@400: is >> i >> j >> _cap; alpar@400: getline(is, str); alpar@400: e = g.addArc(nodes[i], nodes[j]); alpar@400: capacity.set(e, _cap); alpar@400: } else { alpar@400: is >> i >> j; alpar@400: getline(is, str); alpar@400: g.addArc(nodes[i], nodes[j]); alpar@400: } alpar@400: break; alpar@400: } alpar@400: } alpar@400: } alpar@400: kpeter@403: /// DIMACS maximum flow reader function. alpar@402: /// kpeter@403: /// This function reads a maximum flow instance from DIMACS format, kpeter@403: /// i.e. from a DIMACS file having a line starting with alpar@402: /// \code alpar@402: /// p max alpar@402: /// \endcode alpar@402: /// At the beginning, \c g is cleared by \c g.clear(). The arc alpar@402: /// capacities are written to \c capacity and \c s and \c t are alpar@402: /// set to the source and the target nodes. alpar@402: /// alpar@402: /// If the file type was previously evaluated by dimacsType(), then alpar@402: /// the descriptor struct should be given by the \c dest parameter. alpar@402: template alpar@402: void readDimacsMax(std::istream& is, alpar@402: Digraph &g, alpar@402: CapacityMap& capacity, alpar@402: typename Digraph::Node &s, alpar@402: typename Digraph::Node &t, alpar@402: DimacsDescriptor desc=DimacsDescriptor()) { alpar@402: if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); alpar@402: if(desc.type!=DimacsDescriptor::MAX) alpar@402: throw FormatError("Problem type mismatch"); alpar@402: _readDimacs(is,g,capacity,s,t,desc); alpar@402: } alpar@402: alpar@400: /// DIMACS shortest path reader function. alpar@400: /// alpar@400: /// This function reads a shortest path instance from DIMACS format, kpeter@403: /// i.e. from a DIMACS file having a line starting with alpar@400: /// \code alpar@400: /// p sp alpar@400: /// \endcode alpar@402: /// At the beginning, \c g is cleared by \c g.clear(). The arc kpeter@403: /// lengths are written to \c length and \c s is set to the alpar@400: /// source node. alpar@402: /// alpar@402: /// If the file type was previously evaluated by dimacsType(), then alpar@402: /// the descriptor struct should be given by the \c dest parameter. alpar@402: template alpar@402: void readDimacsSp(std::istream& is, alpar@402: Digraph &g, alpar@402: LengthMap& length, alpar@402: typename Digraph::Node &s, alpar@402: DimacsDescriptor desc=DimacsDescriptor()) { alpar@401: typename Digraph::Node t; alpar@402: if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); alpar@402: if(desc.type!=DimacsDescriptor::SP) alpar@402: throw FormatError("Problem type mismatch"); alpar@402: _readDimacs(is, g, length, s, t,desc); alpar@400: } alpar@400: alpar@400: /// DIMACS capacitated digraph reader function. alpar@400: /// alpar@400: /// This function reads an arc capacitated digraph instance from alpar@402: /// DIMACS 'mat' or 'sp' format. alpar@402: /// At the beginning, \c g is cleared by \c g.clear() alpar@402: /// and the arc capacities/lengths are written to \c capacity. alpar@402: /// alpar@402: /// If the file type was previously evaluated by dimacsType(), then alpar@402: /// the descriptor struct should be given by the \c dest parameter. alpar@400: template alpar@402: void readDimacsCap(std::istream& is, alpar@402: Digraph &g, alpar@402: CapacityMap& capacity, alpar@402: DimacsDescriptor desc=DimacsDescriptor()) { alpar@401: typename Digraph::Node u,v; alpar@402: if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); alpar@402: if(desc.type!=DimacsDescriptor::MAX || desc.type!=DimacsDescriptor::SP) alpar@402: throw FormatError("Problem type mismatch"); alpar@402: _readDimacs(is, g, capacity, u, v, desc); alpar@400: } alpar@400: alpar@400: /// DIMACS plain digraph reader function. alpar@400: /// alpar@400: /// This function reads a digraph without any designated nodes and alpar@400: /// maps from DIMACS format, i.e. from DIMACS files having a line alpar@400: /// starting with alpar@400: /// \code alpar@400: /// p mat alpar@400: /// \endcode alpar@402: /// At the beginning, \c g is cleared by \c g.clear(). alpar@402: /// alpar@402: /// If the file type was previously evaluated by dimacsType(), then alpar@402: /// the descriptor struct should be given by the \c dest parameter. alpar@400: template alpar@402: void readDimacsMat(std::istream& is, Digraph &g, alpar@402: DimacsDescriptor desc=DimacsDescriptor()) { alpar@401: typename Digraph::Node u,v; alpar@400: NullMap n; alpar@402: if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); alpar@402: if(desc.type!=DimacsDescriptor::MAT) alpar@402: throw FormatError("Problem type mismatch"); alpar@402: _readDimacs(is, g, n, u, v, desc); alpar@400: } alpar@400: alpar@400: /// DIMACS plain digraph writer function. alpar@400: /// alpar@400: /// This function writes a digraph without any designated nodes and alpar@400: /// maps into DIMACS format, i.e. into DIMACS file having a line alpar@400: /// starting with alpar@400: /// \code alpar@400: /// p mat alpar@400: /// \endcode alpar@402: /// If \c comment is not empty, then it will be printed in the first line alpar@402: /// prefixed by 'c'. alpar@400: template alpar@402: void writeDimacsMat(std::ostream& os, const Digraph &g, alpar@402: std::string comment="") { alpar@400: typedef typename Digraph::NodeIt NodeIt; alpar@400: typedef typename Digraph::ArcIt ArcIt; alpar@400: alpar@463: if(!comment.empty()) alpar@402: os << "c " << comment << std::endl; alpar@400: os << "p mat " << g.nodeNum() << " " << g.arcNum() << std::endl; alpar@400: alpar@400: typename Digraph::template NodeMap nodes(g); alpar@400: int i = 1; alpar@400: for(NodeIt v(g); v != INVALID; ++v) { alpar@400: nodes.set(v, i); alpar@400: ++i; alpar@400: } alpar@400: for(ArcIt e(g); e != INVALID; ++e) { alpar@400: os << "a " << nodes[g.source(e)] << " " << nodes[g.target(e)] alpar@400: << std::endl; alpar@400: } alpar@400: } alpar@400: alpar@400: /// @} alpar@400: alpar@400: } //namespace lemon alpar@400: alpar@400: #endif //LEMON_DIMACS_H