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