deba@1137: /* -*- C++ -*- deba@1137: * src/lemon/graph_writer.h - Part of LEMON, a generic C++ optimization library deba@1137: * alpar@1164: * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport deba@1137: * (Egervary Combinatorial Optimization Research Group, EGRES). deba@1137: * deba@1137: * Permission to use, modify and distribute this software is granted deba@1137: * provided that this copyright notice appears in all copies. For deba@1137: * precise terms see the accompanying LICENSE file. deba@1137: * deba@1137: * This software is provided "AS IS" with no warranty of any kind, deba@1137: * express or implied, and with no claim as to its suitability for any deba@1137: * purpose. deba@1137: * deba@1137: */ deba@1137: alpar@1287: ///\ingroup io_group deba@1137: ///\file alpar@1287: ///\brief Lemon Graph Format writer. deba@1137: deba@1214: #ifndef LEMON_GRAPH_WRITER_H deba@1214: #define LEMON_GRAPH_WRITER_H deba@1137: deba@1137: #include deba@1137: #include deba@1137: deba@1137: #include deba@1137: #include deba@1137: deba@1137: #include deba@1137: deba@1208: #include deba@1214: deba@1137: #include deba@1137: #include deba@1137: deba@1137: deba@1137: namespace lemon { deba@1137: deba@1333: /// \addtogroup io_group deba@1333: /// @{ deba@1333: deba@1137: /// \brief Standard WriterTraits for the GraphWriter class. deba@1137: /// deba@1137: /// Standard WriterTraits for the GraphWriter class. deba@1137: /// It defines standard writing method for all type of value. deba@1333: /// \author Balazs Dezso deba@1137: struct DefaultWriterTraits { deba@1137: deba@1137: /// \brief Template class for writing an value. deba@1137: /// deba@1137: /// Template class for writing an value. deba@1333: /// \author Balazs Dezso deba@1137: template deba@1137: struct Writer { deba@1137: /// The value type. deba@1137: typedef _Value Value; deba@1137: deba@1188: /// \brief Writes a value to the given stream. deba@1137: /// deba@1188: /// Writes a value to the given stream. deba@1137: void write(std::ostream& os, const Value& value) { deba@1137: os << value << '\t'; deba@1137: } deba@1137: }; deba@1137: deba@1333: /// \brief Returns wheter this name is an ID map name. deba@1333: /// deba@1333: /// Returns wheter this name is an ID map name. deba@1333: static bool idMapName(const std::string& name) { deba@1333: return name == "id"; deba@1333: } deba@1333: deba@1137: }; deba@1137: deba@1137: deba@1137: /// \brief Writer class for quoted strings. deba@1137: /// deba@1137: /// Writer class for quoted strings. It can process the escape deba@1137: /// sequences in the string. deba@1333: /// \author Balazs Dezso deba@1137: class QuotedStringWriter { deba@1137: public: deba@1137: typedef std::string Value; deba@1137: deba@1137: /// \brief Constructor for the writer. deba@1137: /// deba@1137: /// Constructor for the writer. If the given parameter is true deba@1137: /// the writer creates escape sequences from special characters. deba@1137: QuotedStringWriter(bool _escaped = true) : escaped(_escaped) {} deba@1137: deba@1188: /// \brief Writes a quoted string to the given stream. deba@1137: /// deba@1188: /// Writes a quoted string to the given stream. deba@1137: void write(std::ostream& os, const std::string& value) { deba@1137: os << "\""; deba@1137: if (escaped) { deba@1311: std::ostringstream ls; deba@1137: for (int i = 0; i < (int)value.size(); ++i) { deba@1137: writeEscape(ls, value[i]); deba@1137: } deba@1137: os << ls.str(); deba@1137: } else { deba@1137: os << value; deba@1137: } deba@1137: os << "\""; deba@1137: } deba@1137: deba@1137: private: deba@1137: deba@1137: static void writeEscape(std::ostream& os, char c) { deba@1137: switch (c) { deba@1137: case '\\': deba@1137: os << "\\\\"; deba@1137: return; deba@1137: case '\"': deba@1137: os << "\\\""; deba@1137: return; deba@1137: case '\'': deba@1137: os << "\\\'"; deba@1137: return; deba@1137: case '\?': deba@1137: os << "\\\?"; deba@1137: return; deba@1137: case '\a': deba@1137: os << "\\a"; deba@1137: return; deba@1137: case '\b': deba@1137: os << "\\b"; deba@1137: return; deba@1137: case '\f': deba@1137: os << "\\f"; deba@1137: return; deba@1137: case '\r': deba@1137: os << "\\r"; deba@1137: return; deba@1137: case '\n': deba@1137: os << "\\n"; deba@1137: return; deba@1137: case '\t': deba@1137: os << "\\t"; deba@1137: return; deba@1137: case '\v': deba@1137: os << "\\v"; deba@1137: return; deba@1137: default: deba@1137: if (c < 0x20) { deba@1311: os << '\\' << std::oct << (int)c; deba@1137: } else { deba@1137: os << c; deba@1137: } deba@1137: return; deba@1137: } deba@1137: } deba@1137: private: deba@1137: bool escaped; deba@1137: }; deba@1137: deba@1137: deba@1137: /// \brief The graph writer class. deba@1137: /// deba@1333: /// The \c GraphWriter class provides the graph output. To write a graph deba@1333: /// you should first give writing commands for the writer. You can declare deba@1333: /// write command as \c NodeMap or \c EdgeMap writing and labeled Node and deba@1333: /// Edge writing. deba@1333: /// deba@1333: /// \code deba@1333: /// GraphWriter writer(std::cout, graph); deba@1333: /// \endcode deba@1333: /// deba@1333: /// The \c addNodeMap() function declares a \c NodeMap writing command in the deba@1333: /// \c GraphWriter. You should give as parameter the name of the map and the deba@1333: /// map object. The NodeMap writing command with name "id" should write a deba@1333: /// unique map because it is regarded as ID map. deba@1333: /// deba@1333: /// \code deba@1333: /// IdMap nodeIdMap; deba@1333: /// writer.addNodeMap("id", nodeIdMap); deba@1333: /// deba@1333: /// writer.addNodeMap("x-coord", xCoordMap); deba@1333: /// writer.addNodeMap("y-coord", yCoordMap); deba@1333: /// writer.addNodeMap("color", colorMap); deba@1333: /// \endcode deba@1333: /// deba@1333: /// With the \c addEdgeMap() member function you can give an edge map deba@1333: /// writing command similar to the NodeMaps. deba@1333: /// deba@1333: /// \code deba@1333: /// DescriptorMap > deba@1333: /// edgeDescMap(graph); deba@1333: /// writer.addEdgeMap("descriptor", edgeDescMap); deba@1333: /// deba@1333: /// writer.addEdgeMap("weight", weightMap); deba@1333: /// writer.addEdgeMap("label", labelMap); deba@1333: /// \endcode deba@1333: /// deba@1333: /// With \c addNode() and \c addEdge() functions you can point out Nodes and deba@1333: /// Edges in the graph. By example, you can write out the source and target deba@1333: /// of the graph. deba@1333: /// deba@1333: /// \code deba@1333: /// writer.addNode("source", sourceNode); deba@1333: /// writer.addNode("target", targetNode); deba@1333: /// deba@1333: /// writer.addEdge("observed", edge); deba@1333: /// \endcode deba@1333: /// deba@1333: /// After you give all write commands you must call the \c run() member deba@1333: /// function, which execute all the writer commands. deba@1333: /// deba@1333: /// \code deba@1333: /// writer.run(); deba@1333: /// \endcode deba@1333: /// alpar@1287: /// \see DefaultWriterTraits alpar@1287: /// \see QuotedStringWriter deba@1333: /// \see IdMap deba@1333: /// \see DescriptorMap alpar@1138: /// \see \ref GraphReader alpar@1138: /// \see \ref graph-io-page deba@1333: /// \author Balazs Dezso deba@1137: template deba@1137: class GraphWriter { deba@1137: public: deba@1137: deba@1137: typedef _Graph Graph; deba@1137: typedef typename Graph::Node Node; deba@1137: typedef typename Graph::NodeIt NodeIt; deba@1137: typedef typename Graph::Edge Edge; deba@1137: typedef typename Graph::EdgeIt EdgeIt; deba@1137: deba@1137: typedef _WriterTraits WriterTraits; deba@1137: deba@1137: /// \brief Construct a new GraphWriter. deba@1137: /// deba@1137: /// Construct a new GraphWriter. It writes from the given map, deba@1137: /// it constructs the given map and it use the given writer as the deba@1137: /// default skipper. deba@1208: GraphWriter(std::ostream& _os, const Graph& _graph) deba@1208: : os(_os), graph(_graph) {} deba@1137: deba@1137: deba@1137: /// \brief Destruct the graph writer. deba@1137: /// deba@1137: /// Destruct the graph writer. deba@1137: ~GraphWriter() { deba@1137: for (typename NodeMapWriters::iterator it = node_map_writers.begin(); deba@1137: it != node_map_writers.end(); ++it) { deba@1137: delete it->second; deba@1137: } deba@1137: deba@1137: for (typename EdgeMapWriters::iterator it = edge_map_writers.begin(); deba@1137: it != edge_map_writers.end(); ++it) { deba@1137: delete it->second; deba@1137: } deba@1137: deba@1137: } deba@1137: deba@1137: // Node map rules deba@1137: deba@1137: /// \brief Add a new node map writer command for the writer. deba@1137: /// deba@1137: /// Add a new node map writer command for the writer. deba@1137: template deba@1137: GraphWriter& addNodeMap(std::string name, const Map& map) { deba@1137: return addNodeMap, Map>(name, map); deba@1137: } deba@1137: deba@1137: /// \brief Add a new node map writer command for the writer. deba@1137: /// deba@1137: /// Add a new node map writer command for the writer. deba@1137: template deba@1137: GraphWriter& addNodeMap(std::string name, const Map& map, deba@1137: const Writer& writer = Writer()) { deba@1137: node_map_writers.push_back( deba@1137: make_pair(name, new MapWriter(map, writer))); deba@1137: return *this; deba@1137: } deba@1137: deba@1137: // Edge map rules deba@1137: deba@1137: /// \brief Add a new edge map writer command for the writer. deba@1137: /// deba@1137: /// Add a new edge map writer command for the writer. deba@1137: template deba@1137: GraphWriter& addEdgeMap(std::string name, const Map& map) { deba@1137: return addEdgeMap, Map>(name, map); deba@1137: } deba@1137: deba@1137: deba@1137: /// \brief Add a new edge map writer command for the writer. deba@1137: /// deba@1137: /// Add a new edge map writer command for the writer. deba@1137: template deba@1137: GraphWriter& addEdgeMap(std::string name, deba@1137: const Map& map, const Writer& writer = Writer()) { deba@1137: edge_map_writers.push_back(make_pair(name, deba@1137: new MapWriter(map, writer))); deba@1137: return *this; deba@1137: } deba@1137: deba@1137: /// \brief Add a new labeled node writer for the writer. deba@1137: /// deba@1137: /// Add a new labeled node writer for the writer. deba@1137: GraphWriter& addNode(std::string name, const Node& node) { deba@1137: node_writers.push_back(make_pair(name, node)); deba@1137: return *this; deba@1137: } deba@1137: deba@1137: /// \brief Add a new labeled edge writer for the writer. deba@1137: /// deba@1137: /// Add a new labeled edge writer for the writer. deba@1137: GraphWriter& addEdge(std::string name, const Edge& edge) { deba@1137: edge_writers.push_back(make_pair(name, edge)); deba@1137: return *this; deba@1137: } deba@1137: deba@1137: /// \brief Executes the writer commands. deba@1137: /// deba@1137: /// Executes the writer commands. deba@1137: void run() { deba@1333: WriterBase* nodeWriter = 0; deba@1333: WriterBase* edgeWriter = 0; deba@1333: writeNodeSet(nodeWriter); deba@1333: writeEdgeSet(nodeWriter, edgeWriter); deba@1333: writeNodes(nodeWriter); deba@1333: writeEdges(edgeWriter); deba@1137: os << "@end" << std::endl; deba@1137: } deba@1137: deba@1137: private: deba@1137: deba@1137: template deba@1137: class WriterBase { deba@1137: public: deba@1137: typedef _Item Item; deba@1137: virtual void write(std::ostream&, const Item&) = 0; deba@1137: }; deba@1137: deba@1137: template deba@1137: class MapWriter : public WriterBase<_Item> { deba@1137: public: deba@1137: typedef _Map Map; deba@1137: typedef _Writer Writer; deba@1137: typedef typename Writer::Value Value; deba@1137: typedef _Item Item; deba@1137: deba@1137: const Map& map; deba@1137: Writer writer; deba@1137: deba@1137: MapWriter(const Map& _map, const Writer& _writer) deba@1137: : map(_map), writer(_writer) {} deba@1137: deba@1137: deba@1137: virtual void write(std::ostream& os, const Item& item) { deba@1137: writer.write(os, map[item]); deba@1137: } deba@1137: deba@1137: }; deba@1137: deba@1333: void writeNodeSet(WriterBase* & nodeWriter) { deba@1333: if (node_map_writers.size() == 0) return; deba@1333: os << "@nodeset" << std::endl; deba@1333: for (int i = 0; i < (int)node_map_writers.size(); ++i) { deba@1333: const std::string& id = node_map_writers[i].first; deba@1333: os << id << '\t'; deba@1333: if (WriterTraits::idMapName(id) && nodeWriter == 0) { deba@1333: nodeWriter = node_map_writers[i].second; deba@1333: } deba@1333: } deba@1333: os << std::endl; deba@1333: for (NodeIt it(graph); it != INVALID; ++it) { deba@1333: for (int i = 0; i < (int)node_map_writers.size(); ++i) { deba@1333: node_map_writers[i].second->write(os, it); deba@1333: } deba@1333: os << std::endl; deba@1333: } deba@1333: deba@1333: } deba@1333: deba@1333: void writeEdgeSet(WriterBase* nodeWriter, deba@1333: WriterBase* & edgeWriter) { deba@1333: if (nodeWriter == 0) { deba@1333: throw DataFormatError("Cannot find node id map"); deba@1333: } deba@1333: os << "@edgeset" << std::endl; deba@1333: os << "\t\t"; deba@1333: for (int i = 0; i < (int)edge_map_writers.size(); ++i) { deba@1333: const std::string& id = edge_map_writers[i].first; deba@1333: os << id << '\t'; deba@1333: if (WriterTraits::idMapName(id) && edgeWriter == 0) { deba@1333: edgeWriter = edge_map_writers[i].second; deba@1333: } deba@1333: } deba@1333: os << std::endl; deba@1333: for (EdgeIt it(graph); it != INVALID; ++it) { deba@1333: nodeWriter->write(os, graph.source(it)); deba@1333: nodeWriter->write(os, graph.target(it)); deba@1333: for (int i = 0; i < (int)edge_map_writers.size(); ++i) { deba@1333: edge_map_writers[i].second->write(os, it); deba@1333: } deba@1333: os << std::endl; deba@1333: } deba@1333: } deba@1333: deba@1333: void writeNodes(WriterBase* nodeWriter) { deba@1333: if (nodeWriter == 0) { deba@1333: throw DataFormatError("Cannot find node id map"); deba@1333: } deba@1333: os << "@nodes" << std::endl; deba@1333: for (int i = 0; i < (int)node_writers.size(); ++i) { deba@1333: os << node_writers[i].first << '\t'; deba@1333: nodeWriter->write(os, node_writers[i].second); deba@1333: os << std::endl; deba@1333: } deba@1333: } deba@1333: deba@1333: void writeEdges(WriterBase* edgeWriter) { deba@1333: if (edgeWriter == 0) { deba@1333: throw DataFormatError("Cannot find node id map"); deba@1333: } deba@1333: os << "@edges" << std::endl; deba@1333: for (int i = 0; i < (int)edge_writers.size(); ++i) { deba@1333: os << edge_writers[i].first << '\t'; deba@1333: edgeWriter->write(os, edge_writers[i].second); deba@1333: os << std::endl; deba@1333: } deba@1333: } deba@1333: deba@1333: deba@1137: deba@1137: deba@1137: typedef std::vector< std::pair*> > deba@1137: NodeMapWriters; deba@1137: NodeMapWriters node_map_writers; deba@1137: deba@1137: typedef std::vector< std::pair*> > deba@1137: EdgeMapWriters; deba@1137: EdgeMapWriters edge_map_writers; deba@1137: deba@1137: typedef std::vector > NodeWriters; deba@1137: NodeWriters node_writers; deba@1137: deba@1137: typedef std::vector > EdgeWriters; deba@1137: EdgeWriters edge_writers; deba@1137: deba@1137: std::ostream& os; deba@1208: const Graph& graph; deba@1137: deba@1137: }; deba@1137: deba@1333: /// \brief Write a graph to the output. deba@1333: /// deba@1333: /// Write a graph to the output. deba@1333: /// \param os The output stream. deba@1333: /// \param g The graph. deba@1333: /// \param capacity The capacity map. deba@1333: /// \param s The source node. deba@1333: /// \param t The target node. deba@1333: /// \param cost The cost map. deba@1208: template deba@1208: void writeGraph(std::ostream& os, const Graph &g, deba@1208: const CapacityMap& capacity, const typename Graph::Node &s, deba@1208: const typename Graph::Node &t, const CostMap& cost) { deba@1208: GraphWriter reader(os, g); deba@1208: IdMap nodeIdMap(g); deba@1208: reader.addNodeMap("id", nodeIdMap); deba@1208: IdMap edgeIdMap(g); deba@1208: reader.addEdgeMap("id", edgeIdMap); deba@1208: reader.addEdgeMap("capacity", capacity); deba@1208: reader.addEdgeMap("cost", cost); deba@1208: reader.addNode("source", s); deba@1208: reader.addNode("target", t); deba@1208: reader.run(); deba@1208: } deba@1208: deba@1333: /// \brief Write a graph to the output. deba@1333: /// deba@1333: /// Write a graph to the output. deba@1333: /// \param os The output stream. deba@1333: /// \param g The graph. deba@1333: /// \param capacity The capacity map. deba@1333: /// \param s The source node. deba@1333: /// \param t The target node. deba@1297: template deba@1208: void writeGraph(std::ostream& os, const Graph &g, deba@1208: const CapacityMap& capacity, const typename Graph::Node &s, deba@1208: const typename Graph::Node &t) { deba@1208: GraphWriter reader(os, g); deba@1208: IdMap nodeIdMap(g); deba@1208: reader.addNodeMap("id", nodeIdMap); deba@1208: IdMap edgeIdMap(g); deba@1208: reader.addEdgeMap("id", edgeIdMap); deba@1208: reader.addEdgeMap("capacity", capacity); deba@1208: reader.addNode("source", s); deba@1208: reader.addNode("target", t); deba@1208: reader.run(); deba@1208: } deba@1208: deba@1333: /// \brief Write a graph to the output. deba@1333: /// deba@1333: /// Write a graph to the output. deba@1333: /// \param os The output stream. deba@1333: /// \param g The graph. deba@1333: /// \param capacity The capacity map. deba@1333: /// \param s The source node. deba@1208: template deba@1208: void writeGraph(std::ostream& os, const Graph &g, deba@1208: const CapacityMap& capacity, const typename Graph::Node &s) { deba@1208: GraphWriter reader(os, g); deba@1208: IdMap nodeIdMap(g); deba@1208: reader.addNodeMap("id", nodeIdMap); deba@1208: IdMap edgeIdMap(g); deba@1208: reader.addEdgeMap("id", edgeIdMap); deba@1208: reader.addEdgeMap("capacity", capacity); deba@1208: reader.addNode("source", s); deba@1208: reader.run(); deba@1208: } deba@1333: deba@1333: /// \brief Write a graph to the output. deba@1333: /// deba@1333: /// Write a graph to the output. deba@1333: /// \param os The output stream. deba@1333: /// \param g The graph. deba@1333: /// \param capacity The capacity map. deba@1208: template deba@1208: void writeGraph(std::ostream& os, const Graph &g, deba@1208: const CapacityMap& capacity) { deba@1208: GraphWriter reader(os, g); deba@1208: IdMap nodeIdMap(g); deba@1208: reader.addNodeMap("id", nodeIdMap); deba@1208: IdMap edgeIdMap(g); deba@1208: reader.addEdgeMap("id", edgeIdMap); deba@1208: reader.addEdgeMap("capacity", capacity); deba@1208: reader.run(); deba@1208: } deba@1333: deba@1333: /// \brief Write a graph to the output. deba@1333: /// deba@1333: /// Write a graph to the output. deba@1333: /// \param os The output stream. deba@1333: /// \param g The graph. deba@1208: template deba@1208: void writeGraph(std::ostream& os, const Graph &g) { deba@1208: GraphWriter reader(os, g); deba@1208: IdMap nodeIdMap(g); deba@1208: reader.addNodeMap("id", nodeIdMap); deba@1208: IdMap edgeIdMap(g); deba@1208: reader.addEdgeMap("id", edgeIdMap); deba@1208: reader.run(); deba@1208: } deba@1208: deba@1333: /// @} deba@1137: deba@1137: } deba@1214: deba@1214: #endif