# HG changeset patch # User deba # Date 1193243509 0 # Node ID 9c23c3762bc55dd5ad634e36f399bcd7a927bd88 # Parent 1af97781911132b1876ecd8ac456357a27502f9c BpUGraphReader and Writer diff -r 1af977819111 -r 9c23c3762bc5 doc/graph_io.dox --- a/doc/graph_io.dox Sat Oct 20 14:29:12 2007 +0000 +++ b/doc/graph_io.dox Wed Oct 24 16:31:49 2007 +0000 @@ -335,7 +335,7 @@ The specialization of writing is very similar to that of reading. -\section u Undirected graphs +\section undir Undirected and Bipartite graphs In a file describing an undirected graph (ugraph, for short) you find an \c uedgeset section instead of the \c edgeset section. The first line of @@ -343,9 +343,9 @@ next lines describe one undirected edge with the the incident nodes and the values of the map. -The format handles directed edge maps as a syntactical sugar???, if there -are two maps with names being the same with a \c '+' and a \c '-' prefix -then this will be read as a directed map. +The format could store directed edge maps, if there are two maps with +names being the same with a \c '+' and a \c '-' prefix then this could +be read as such a map. \code @uedgeset @@ -386,6 +386,35 @@ reader.readEdge("edge", edge); \endcode +The undirected bipartite graphs could be read with the \c BpUGraph +class and it has specialized nodeset section, which should be start +with \c "@bpnodeset". This section is separated to two +subsections. The header line of these sections start with "&anodeset" +or "&bnodeset" and after that the line contains the names of the +regular and A-node or B-node maps accordingly. The lines of each +section contains the mapped values. The labels of the graph should be +unique overall both subsections. + +\code +@bpnodeset +&anodeset label coords radius + 0 (0, 0) 14.0 + 1 (0, 1) 12.0 +&bnodeset label coords + 2 (1, 0) + 3 (1, 1) +\endcode + +The reading can be done with \ref lemon::BpUGraphReader::readANodeMap() +"readANodeMap()", \ref lemon::BpUGraphReader::readBNodeMap() +"readBNodeMap()" or \ref lemon::BpUGraphReader::readNodeMap() +"readNodeMap()" members. + +\code +reader.readNodeMap("coords", coords); +reader.readAnodeMap("radius", radius); +\endcode + \section advanced Advanced features The graph reader and writer classes give an easy way to read and write diff -r 1af977819111 -r 9c23c3762bc5 lemon/graph_reader.h --- a/lemon/graph_reader.h Sat Oct 20 14:29:12 2007 +0000 +++ b/lemon/graph_reader.h Wed Oct 24 16:31:49 2007 +0000 @@ -725,6 +725,469 @@ AttributeReader attribute_reader; }; + /// \brief The bipartite graph reader class. + /// + /// The \c BpUGraphReader class provides the graph input. + /// Before you read this documentation it might be useful to read the general + /// description of \ref graph-io-page "Graph Input-Output". + /// + /// The given file format may contain several maps and labeled nodes or + /// edges. + /// + /// If you read a graph you need not read all the maps and items just those + /// that you need. The interface of the \c BpUGraphReader is very similar + /// to the BpUGraphWriter but the reading method does not depend on the + /// order of the given commands. + /// + /// The reader object suppose that each not read value does not contain + /// whitespaces, therefore it has some extra possibilities to control how + /// it should skip the values when the string representation contains spaces. + /// + ///\code + /// BpUGraphReader reader(std::cin, graph); + ///\endcode + /// + /// The \c readANodeMap() function reads a map from the A-part of + /// the\c \@bpnodeset section, while the \c readBNodeMap() reads + /// from the B-part of the section. If you use the \c readNodeMap() + /// function, then the given map should appear in both part of the + /// section. If there is a map that you do not want to read from the + /// file and there is whitespace in the string represenation of the + /// values then you should call the \c skipANodeMap(), \c + /// skipBNodeMap() or \c skipNodeMap() template member function with + /// proper parameters. + /// + ///\code + /// reader.readNodeMap("coords", coords); + /// reader.readANodeMap("range", range); + /// reader.readANodeMap("benefit", benefit); + /// + /// reader.skipNodeMap("description", desc); + /// + /// reader.readNodeMap("color", colorMap); + ///\endcode + /// + /// With the \c readUEdgeMap() member function you can give an + /// uedge map reading command similar to the NodeMaps. + /// + ///\code + /// reader.readUEdgeMap("capacity", capacityMap); + /// reader.readEdgeMap("flow", flowMap); + ///\endcode + /// + /// With \c readNode() and \c readUEdge() functions you can read + /// labeled Nodes and UEdges. + /// + ///\code + /// reader.readNode("source", sourceNode); + /// reader.readNode("target", targetNode); + /// + /// reader.readUEdge("observed", uEdge); + ///\endcode + /// + /// With the \c readAttribute() functions you can read an attribute + /// in a variable. You can specify the reader for the attribute as + /// the nodemaps. + /// + /// After you give all read commands you must call the \c run() member + /// function, which execute all the commands. + /// + ///\code + /// reader.run(); + ///\endcode + /// + /// \see GraphReader + /// \see DefaultReaderTraits + /// \see \ref UGraphWriter + /// \see \ref graph-io-page + /// + /// \author Balazs Dezso + template + class BpUGraphReader { + public: + + typedef _Graph Graph; + typedef typename Graph::Node Node; + typedef typename Graph::Edge Edge; + typedef typename Graph::UEdge UEdge; + + typedef _ReaderTraits ReaderTraits; + typedef typename ReaderTraits::Skipper DefaultSkipper; + + /// \brief Construct a new BpUGraphReader. + /// + /// Construct a new BpUGraphReader. It reads into the given graph + /// and it use the given reader as the default skipper. + BpUGraphReader(std::istream& _is, Graph& _graph, + const DefaultSkipper& _skipper = DefaultSkipper()) + : reader(new LemonReader(_is)), own_reader(true), skipper(_skipper), + nodeset_reader(*reader, _graph, std::string(), skipper), + uedgeset_reader(*reader, _graph, nodeset_reader, + std::string(), skipper), + node_reader(*reader, nodeset_reader, std::string()), + uedge_reader(*reader, uedgeset_reader, std::string()), + attribute_reader(*reader, std::string()) {} + + /// \brief Construct a new BpUGraphReader. + /// + /// Construct a new BpUGraphReader. It reads into the given graph + /// and it use the given reader as the default skipper. + BpUGraphReader(const std::string& _filename, Graph& _graph, + const DefaultSkipper& _skipper = DefaultSkipper()) + : reader(new LemonReader(_filename)), own_reader(true), + skipper(_skipper), + nodeset_reader(*reader, _graph, std::string(), skipper), + uedgeset_reader(*reader, _graph, nodeset_reader, + std::string(), skipper), + node_reader(*reader, nodeset_reader, std::string()), + uedge_reader(*reader, uedgeset_reader, std::string()), + attribute_reader(*reader, std::string()) {} + + /// \brief Construct a new BpUGraphReader. + /// + /// Construct a new BpUGraphReader. It reads into the given graph + /// and it use the given reader as the default skipper. + BpUGraphReader(LemonReader& _reader, Graph& _graph, + const DefaultSkipper& _skipper = DefaultSkipper()) + : reader(_reader), own_reader(false), skipper(_skipper), + nodeset_reader(*reader, _graph, std::string(), skipper), + uedgeset_reader(*reader, _graph, nodeset_reader, + std::string(), skipper), + node_reader(*reader, nodeset_reader, std::string()), + uedge_reader(*reader, uedgeset_reader, std::string()), + attribute_reader(*reader, std::string()) {} + + /// \brief Destruct the graph reader. + /// + /// Destruct the graph reader. + ~BpUGraphReader() { + if (own_reader) + delete reader; + } + + /// \brief Give a new node map reading command to the reader. + /// + /// Give a new node map reading command to the reader. + template + BpUGraphReader& readNodeMap(std::string name, Map& map) { + nodeset_reader.readNodeMap(name, map); + return *this; + } + + template + BpUGraphReader& readNodeMap(std::string name, const Map& map) { + nodeset_reader.readNodeMap(name, map); + return *this; + } + + /// \brief Give a new node map reading command to the reader. + /// + /// Give a new node map reading command to the reader. + template + BpUGraphReader& readNodeMap(std::string name, Map& map, + const ItemReader& ir = ItemReader()) { + nodeset_reader.readNodeMap(name, map, ir); + return *this; + } + + template + BpUGraphReader& readNodeMap(std::string name, const Map& map, + const ItemReader& ir = ItemReader()) { + nodeset_reader.readNodeMap(name, map, ir); + return *this; + } + + /// \brief Give a new node map skipping command to the reader. + /// + /// Give a new node map skipping command to the reader. + template + BpUGraphReader& skipNodeMap(std::string name, + const ItemReader& ir = ItemReader()) { + nodeset_reader.skipNodeMap(name, ir); + return *this; + } + + /// \brief Give a new A-node map reading command to the reader. + /// + /// Give a new A-node map reading command to the reader. + template + BpUGraphReader& readANodeMap(std::string name, Map& map) { + nodeset_reader.readANodeMap(name, map); + return *this; + } + + template + BpUGraphReader& readANodeMap(std::string name, const Map& map) { + nodeset_reader.readANodeMap(name, map); + return *this; + } + + /// \brief Give a new A-node map reading command to the reader. + /// + /// Give a new A-node map reading command to the reader. + template + BpUGraphReader& readANodeMap(std::string name, Map& map, + const ItemReader& ir = ItemReader()) { + nodeset_reader.readANodeMap(name, map, ir); + return *this; + } + + template + BpUGraphReader& readANodeMap(std::string name, const Map& map, + const ItemReader& ir = ItemReader()) { + nodeset_reader.readNodeMap(name, map, ir); + return *this; + } + + /// \brief Give a new A-node map skipping command to the reader. + /// + /// Give a new A-node map skipping command to the reader. + template + BpUGraphReader& skipANodeMap(std::string name, + const ItemReader& ir = ItemReader()) { + nodeset_reader.skipANodeMap(name, ir); + return *this; + } + + /// \brief Give a new B-node map reading command to the reader. + /// + /// Give a new B-node map reading command to the reader. + template + BpUGraphReader& readBNodeMap(std::string name, Map& map) { + nodeset_reader.readBNodeMap(name, map); + return *this; + } + + template + BpUGraphReader& readBNodeMap(std::string name, const Map& map) { + nodeset_reader.readBNodeMap(name, map); + return *this; + } + + /// \brief Give a new B-node map reading command to the reader. + /// + /// Give a new B-node map reading command to the reader. + template + BpUGraphReader& readBNodeMap(std::string name, Map& map, + const ItemReader& ir = ItemReader()) { + nodeset_reader.readBNodeMap(name, map, ir); + return *this; + } + + template + BpUGraphReader& readBNodeMap(std::string name, const Map& map, + const ItemReader& ir = ItemReader()) { + nodeset_reader.readNodeMap(name, map, ir); + return *this; + } + + /// \brief Give a new B-node map skipping command to the reader. + /// + /// Give a new B-node map skipping command to the reader. + template + BpUGraphReader& skipBNodeMap(std::string name, + const ItemReader& ir = ItemReader()) { + nodeset_reader.skipBNodeMap(name, ir); + return *this; + } + + /// \brief Give a new undirected edge map reading command to the reader. + /// + /// Give a new undirected edge map reading command to the reader. + template + BpUGraphReader& readUEdgeMap(std::string name, Map& map) { + uedgeset_reader.readUEdgeMap(name, map); + return *this; + } + + template + BpUGraphReader& readUEdgeMap(std::string name, const Map& map) { + uedgeset_reader.readUEdgeMap(name, map); + return *this; + } + + + /// \brief Give a new undirected edge map reading command to the reader. + /// + /// Give a new undirected edge map reading command to the reader. + template + BpUGraphReader& readUEdgeMap(std::string name, Map& map, + const ItemReader& ir = ItemReader()) { + uedgeset_reader.readUEdgeMap(name, map, ir); + return *this; + } + + template + BpUGraphReader& readUEdgeMap(std::string name, const Map& map, + const ItemReader& ir = ItemReader()) { + uedgeset_reader.readUEdgeMap(name, map, ir); + return *this; + } + + /// \brief Give a new undirected edge map skipping command to the reader. + /// + /// Give a new undirected edge map skipping command to the reader. + template + BpUGraphReader& skipUEdgeMap(std::string name, + const ItemReader& ir = ItemReader()) { + uedgeset_reader.skipUMap(name, ir); + return *this; + } + + + /// \brief Give a new edge map reading command to the reader. + /// + /// Give a new edge map reading command to the reader. + template + BpUGraphReader& readEdgeMap(std::string name, Map& map) { + uedgeset_reader.readEdgeMap(name, map); + return *this; + } + + template + BpUGraphReader& readEdgeMap(std::string name, const Map& map) { + uedgeset_reader.readEdgeMap(name, map); + return *this; + } + + + /// \brief Give a new edge map reading command to the reader. + /// + /// Give a new edge map reading command to the reader. + template + BpUGraphReader& readEdgeMap(std::string name, Map& map, + const ItemReader& ir = ItemReader()) { + uedgeset_reader.readEdgeMap(name, map, ir); + return *this; + } + + template + BpUGraphReader& readEdgeMap(std::string name, const Map& map, + const ItemReader& ir = ItemReader()) { + uedgeset_reader.readEdgeMap(name, map, ir); + return *this; + } + + /// \brief Give a new edge map skipping command to the reader. + /// + /// Give a new edge map skipping command to the reader. + template + BpUGraphReader& skipEdgeMap(std::string name, + const ItemReader& ir = ItemReader()) { + uedgeset_reader.skipEdgeMap(name, ir); + return *this; + } + + /// \brief Give a new labeled node reading command to the reader. + /// + /// Give a new labeled node reading command to the reader. + BpUGraphReader& readNode(std::string name, Node& node) { + node_reader.readNode(name, node); + return *this; + } + + /// \brief Give a new labeled edge reading command to the reader. + /// + /// Give a new labeled edge reading command to the reader. + BpUGraphReader& readEdge(std::string name, Edge& edge) { + uedge_reader.readEdge(name, edge); + } + + /// \brief Give a new labeled undirected edge reading command to the + /// reader. + /// + /// Give a new labeled undirected edge reading command to the reader. + BpUGraphReader& readUEdge(std::string name, UEdge& edge) { + uedge_reader.readUEdge(name, edge); + } + + /// \brief Give a new attribute reading command. + /// + /// Give a new attribute reading command. + template + BpUGraphReader& readAttribute(std::string name, Value& value) { + attribute_reader.readAttribute(name, value); + return *this; + } + + /// \brief Give a new attribute reading command. + /// + /// Give a new attribute reading command. + template + BpUGraphReader& readAttribute(std::string name, Value& value, + const ItemReader& ir = ItemReader()) { + attribute_reader.readAttribute(name, value, ir); + return *this; + } + + /// \brief Conversion operator to LemonReader. + /// + /// Conversion operator to LemonReader. It make possible + /// to access the encapsulated \e LemonReader, this way + /// you can attach to this reader new instances of + /// \e LemonReader::SectionReader. + operator LemonReader&() { + return *reader; + } + + /// \brief Executes the reading commands. + /// + /// Executes the reading commands. + void run() { + reader->run(); + } + + + /// \brief Returns true if the reader can give back the items by its label. + /// + /// Returns true if the reader can give back the items by its label. + bool isLabelReader() const { + return nodeset_reader.isLabelReader() && + uedgeset_reader.isLabelReader(); + } + + /// \brief Gives back the node by its label. + /// + /// It reads an label from the stream and gives back which node belongs to + /// it. It is possible only if there was read a "label" named node map. + void readLabel(std::istream& is, Node& node) const { + return nodeset_reader.readLabel(is, node); + } + + /// \brief Gives back the edge by its label + /// + /// It reads an label from the stream and gives back which edge belongs to + /// it. It is possible only if there was read a "label" named edge map. + void readLabel(std::istream& is, Edge& edge) const { + return uedgeset_reader.readLabel(is, edge); + } + + /// \brief Gives back the undirected edge by its label. + /// + /// It reads an label from the stream and gives back which undirected edge + /// belongs to it. It is possible only if there was read a "label" named + /// edge map. + void readLabel(std::istream& is, UEdge& uedge) const { + return uedgeset_reader.readLabel(is, uedge); + } + + + private: + + LemonReader* reader; + bool own_reader; + + DefaultSkipper skipper; + + BpNodeSetReader nodeset_reader; + UEdgeSetReader uedgeset_reader; + + NodeReader node_reader; + UEdgeReader uedge_reader; + + AttributeReader attribute_reader; + }; + /// @} } diff -r 1af977819111 -r 9c23c3762bc5 lemon/graph_writer.h --- a/lemon/graph_writer.h Sat Oct 20 14:29:12 2007 +0000 +++ b/lemon/graph_writer.h Wed Oct 24 16:31:49 2007 +0000 @@ -156,7 +156,7 @@ /// \brief Issue a new node map writing command for the writer. /// - /// This function issues a new node map writing command to the writer. + /// This function issues a new node map writing command to the writer. template GraphWriter& writeNodeMap(std::string label, const Map& map) { nodeset_writer.writeNodeMap(label, map); @@ -166,7 +166,7 @@ /// \brief Issue a new node map writing command for the writer. /// - /// This function issues a new node map writing command to the writer. + /// This function issues a new node map writing command to the writer. template GraphWriter& writeNodeMap(std::string label, const Map& map, const ItemWriter& iw = ItemWriter()) { @@ -639,6 +639,376 @@ AttributeWriter attribute_writer; }; + /// \brief The bipartite graph writer class. + /// + /// The \c BpUGraphWriter class provides the ugraph output. To write + /// a graph you should first give writing commands to the writer. You can + /// declare write command as \c NodeMap, \c EdgeMap or \c UEdgeMap + /// writing and labeled Node, Edge or UEdge writing. + /// + ///\code + /// BpUGraphWriter writer(std::cout, graph); + ///\endcode + /// + /// The \c writeNodeMap() function declares a \c NodeMap writing + /// command in the \c BpUGraphWriter. You should give as parameter + /// the name of the map and the map object. The NodeMap writing + /// command with name "label" should write a unique map because it + /// is regarded as label map. + /// + ///\code + /// IdMap nodeLabelMap; + /// writer.writeNodeMap("label", nodeLabelMap); + /// + /// writer.writeNodeMap("coords", coords); + /// writer.writeNodeMap("color", colorMap); + ///\endcode + /// + /// With the \c writeUEdgeMap() member function you can give an + /// undirected edge map writing command similar to the NodeMaps. + /// + ///\code + /// DescriptorMap > + /// edgeDescMap(graph); + /// writer.writeUEdgeMap("descriptor", edgeDescMap); + /// + /// writer.writeUEdgeMap("weight", weightMap); + /// writer.writeUEdgeMap("label", labelMap); + ///\endcode + /// + /// The EdgeMap handling is just a syntactical sugar. It writes + /// two undirected edge map with '+' and '-' prefix in the name. + /// + ///\code + /// writer.writeEdgeMap("capacity", capacityMap); + ///\endcode + /// + /// + /// With \c writeNode() and \c writeUEdge() functions you can + /// designate nodes and undirected edges in the graph. For example, you can + /// write out the source and target of the graph. + /// + ///\code + /// writer.writeNode("source", sourceNode); + /// writer.writeNode("target", targetNode); + /// + /// writer.writeUEdge("observed", uEdge); + ///\endcode + /// + /// After you give all write commands you must call the \c run() member + /// function, which executes all the writing commands. + /// + ///\code + /// writer.run(); + ///\endcode + /// + /// \see DefaultWriterTraits + /// \see QuotedStringWriter + /// \see IdMap + /// \see DescriptorMap + /// \see \ref GraphWriter + /// \see \ref graph-io-page + /// \author Balazs Dezso + template + class BpUGraphWriter { + public: + + typedef _Graph Graph; + typedef typename Graph::Node Node; + typedef typename Graph::Edge Edge; + typedef typename Graph::UEdge UEdge; + + typedef _WriterTraits WriterTraits; + + /// \brief Construct a new BpUGraphWriter. + /// + /// Construct a new BpUGraphWriter. It writes the given graph + /// to the given stream. + BpUGraphWriter(std::ostream& _os, const Graph& _graph) + : writer(new LemonWriter(_os)), own_writer(true), + nodeset_writer(*writer, _graph, std::string()), + uedgeset_writer(*writer, _graph, nodeset_writer, std::string()), + node_writer(*writer, nodeset_writer, std::string()), + uedge_writer(*writer, uedgeset_writer, std::string()), + attribute_writer(*writer, std::string()) {} + + /// \brief Construct a new BpUGraphWriter. + /// + /// Construct a new BpUGraphWriter. It writes the given graph + /// to the given file. + BpUGraphWriter(const std::string& _filename, const Graph& _graph) + : writer(new LemonWriter(_filename)), own_writer(true), + nodeset_writer(*writer, _graph, std::string()), + uedgeset_writer(*writer, _graph, nodeset_writer, std::string()), + node_writer(*writer, nodeset_writer, std::string()), + uedge_writer(*writer, uedgeset_writer, std::string()), + attribute_writer(*writer, std::string()) {} + + /// \brief Construct a new BpUGraphWriter. + /// + /// Construct a new BpUGraphWriter. It writes the given graph + /// to given LemonWriter. + BpUGraphWriter(LemonWriter& _writer, const Graph& _graph) + : writer(_writer), own_writer(false), + nodeset_writer(*writer, _graph, std::string()), + uedgeset_writer(*writer, _graph, nodeset_writer, std::string()), + node_writer(*writer, nodeset_writer, std::string()), + uedge_writer(*writer, uedgeset_writer, std::string()), + attribute_writer(*writer, std::string()) {} + + /// \brief Destruct the graph writer. + /// + /// Destruct the graph writer. + ~BpUGraphWriter() { + if (own_writer) + delete writer; + } + + /// \brief Issue a new node map writing command to the writer. + /// + /// This function issues a new node map writing command to + /// the writer. + template + BpUGraphWriter& writeNodeMap(std::string label, const Map& map) { + nodeset_writer.writeNodeMap(label, map); + return *this; + } + + /// \brief Issue a new node map writing command to the writer. + /// + /// This function issues a new node map writing command to + /// the writer. + template + BpUGraphWriter& writeNodeMap(std::string label, const Map& map, + const ItemWriter& iw = ItemWriter()) { + nodeset_writer.writeNodeMap(label, map, iw); + return *this; + } + + /// \brief Issue a new A-node map writing command to the writer. + /// + /// This function issues a new A-node map writing command to + /// the writer. + template + BpUGraphWriter& writeANodeMap(std::string label, const Map& map) { + nodeset_writer.writeANodeMap(label, map); + return *this; + } + + /// \brief Issue a new A-node map writing command to the writer. + /// + /// This function issues a new A-node map writing command to + /// the writer. + template + BpUGraphWriter& writeANodeMap(std::string label, const Map& map, + const ItemWriter& iw = ItemWriter()) { + nodeset_writer.writeANodeMap(label, map, iw); + return *this; + } + /// \brief Issue a new B-node map writing command to the writer. + /// + /// This function issues a new B-node map writing command to + /// the writer. + template + BpUGraphWriter& writeBNodeMap(std::string label, const Map& map) { + nodeset_writer.writeBNodeMap(label, map); + return *this; + } + + /// \brief Issue a new B-node map writing command to the writer. + /// + /// This function issues a new B-node map writing command to + /// the writer. + template + BpUGraphWriter& writeBNodeMap(std::string label, const Map& map, + const ItemWriter& iw = ItemWriter()) { + nodeset_writer.writeBNodeMap(label, map, iw); + return *this; + } + + /// \brief Issue a new edge map writing command to the writer. + /// + /// This function issues a new edge map writing command to + /// the writer. + template + BpUGraphWriter& writeEdgeMap(std::string label, const Map& map) { + uedgeset_writer.writeEdgeMap(label, map); + return *this; + } + + /// \brief Issue a new edge map writing command to the writer. + /// + /// This function issues a new edge map writing command to + /// the writer. + template + BpUGraphWriter& writeEdgeMap(std::string label, const Map& map, + const ItemWriter& iw = ItemWriter()) { + uedgeset_writer.writeEdgeMap(label, map, iw); + return *this; + } + + /// \brief Issue a new undirected edge map writing command to the writer. + /// + /// This function issues a new undirected edge map writing + /// command to the writer. + template + BpUGraphWriter& writeUEdgeMap(std::string label, const Map& map) { + uedgeset_writer.writeUEdgeMap(label, map); + return *this; + } + + /// \brief Issue a new undirected edge map writing command to the writer. + /// + /// This function issues a new undirected edge map writing + /// command to the writer. + template + BpUGraphWriter& writeUEdgeMap(std::string label, const Map& map, + const ItemWriter& iw = ItemWriter()) { + uedgeset_writer.writeUEdgeMap(label, map, iw); + return *this; + } + + /// \brief Issue a new labeled node writer to the writer. + /// + /// This function issues a new labeled node writing + /// command to the writer. + BpUGraphWriter& writeNode(std::string label, const Node& node) { + node_writer.writeNode(label, node); + return *this; + } + + /// \brief Issue a new labeled edge writer to the writer. + /// + /// This function issues a new labeled edge writing + /// command to the writer. + BpUGraphWriter& writeEdge(std::string label, const Edge& edge) { + uedge_writer.writeEdge(label, edge); + } + + /// \brief Issue a new labeled undirected edge writing command to + /// the writer. + /// + /// Issue a new labeled undirected edge writing command to + /// the writer. + BpUGraphWriter& writeUEdge(std::string label, const UEdge& edge) { + uedge_writer.writeUEdge(label, edge); + } + + /// \brief Issue a new attribute writing command. + /// + /// This function issues a new attribute writing + /// command to the writer. + template + BpUGraphWriter& writeAttribute(std::string label, const Value& value) { + attribute_writer.writeAttribute(label, value); + return *this; + } + + /// \brief Issue a new attribute writing command. + /// + /// This function issues a new attribute writing + /// command to the writer. + template + BpUGraphWriter& writeAttribute(std::string label, const Value& value, + const ItemWriter& iw = ItemWriter()) { + attribute_writer.writeAttribute(label, value, iw); + return *this; + } + + /// \brief Conversion operator to LemonWriter. + /// + /// Conversion operator to LemonWriter. It makes possible + /// to access the encapsulated \e LemonWriter, this way + /// you can attach to this writer new instances of + /// \e LemonWriter::SectionWriter. + operator LemonWriter&() { + return *writer; + } + + /// \brief Executes the writing commands. + /// + /// Executes the writing commands. + void run() { + writer->run(); + } + + /// \brief Returns true if the writer can give back the labels by the items. + /// + /// Returns true if the writer can give back the the labels by the items. + bool isLabelWriter() const { + return nodeset_writer.isLabelWriter() && + uedgeset_writer.isLabelWriter(); + } + + /// \brief Write the label of the given node. + /// + /// It writes the label of the given node. If there was written a "label" + /// named node map then it will write the map value belonging to the node. + void writeLabel(std::ostream& os, const Node& item) const { + nodeset_writer.writeLabel(os, item); + } + + /// \brief Write the label of the given edge. + /// + /// It writes the label of the given edge. If there was written a "label" + /// named edge map then it will write the map value belonging to the edge. + void writeLabel(std::ostream& os, const Edge& item) const { + uedgeset_writer.writeLabel(os, item); + } + + /// \brief Write the label of the given undirected edge. + /// + /// It writes the label of the given undirected edge. If there was + /// written a "label" named edge map then it will write the map + /// value belonging to the edge. + void writeLabel(std::ostream& os, const UEdge& item) const { + uedgeset_writer.writeLabel(os, item); + } + + /// \brief Sorts the given node vector by label. + /// + /// Sorts the given node vector by label. If there was written an + /// "label" named map then the vector will be sorted by the values + /// of this map. Otherwise if the \c forceLabel parameter was true + /// it will be sorted by its id in the graph. + void sortByLabel(std::vector& nodes) const { + nodeset_writer.sortByLabel(nodes); + } + + /// \brief Sorts the given edge vector by label. + /// + /// Sorts the given edge vector by label. If there was written an + /// "label" named map then the vector will be sorted by the values + /// of this map. Otherwise if the \c forceLabel parameter was true + /// it will be sorted by its id in the graph. + void sortByLabel(std::vector& edges) const { + uedgeset_writer.sortByLabel(edges); + } + + /// \brief Sorts the given undirected edge vector by label. + /// + /// Sorts the given undirected edge vector by label. If there was + /// written an "label" named map then the vector will be sorted by + /// the values of this map. Otherwise if the \c forceLabel + /// parameter was true it will be sorted by its id in the graph. + void sortByLabel(std::vector& uedges) const { + uedgeset_writer.sortByLabel(uedges); + } + + private: + + LemonWriter* writer; + bool own_writer; + + BpNodeSetWriter nodeset_writer; + UEdgeSetWriter uedgeset_writer; + + NodeWriter node_writer; + UEdgeWriter uedge_writer; + + AttributeWriter attribute_writer; + }; + /// @} } diff -r 1af977819111 -r 9c23c3762bc5 lemon/lemon_reader.h --- a/lemon/lemon_reader.h Sat Oct 20 14:29:12 2007 +0000 +++ b/lemon/lemon_reader.h Wed Oct 24 16:31:49 2007 +0000 @@ -311,7 +311,7 @@ MapReaderBase() { _touched = false; } - void touch() { _touched = true; } + void touch(bool value = true) { _touched = value; } bool touched() const { return _touched; } virtual ~MapReaderBase() {} @@ -593,8 +593,7 @@ virtual int_type underflow() { char c; - if (_is.read(&c, 1)) { - _is.putback(c); + if ((c = _is.peek()) != EOF) { if (c == '@') { return EOF; } @@ -603,13 +602,13 @@ } char_type *ptr; for (ptr = base(); ptr != eptr(); ++ptr) { - if (_is.read(&c, 1)) { + if ((c = _is.get()) != EOF) { if (c == '\n') ++_num; if (put_char(c)) { *ptr = c; } else { if (skip_state == after_endl && c == '@') { - _is.putback('@'); + _is.putback(c); break; } --ptr; @@ -638,6 +637,36 @@ }; + static void skipPreSection(std::istream& is, int& line_num) { + enum skip_state_type { skip, after_endl }; + + skip_state_type skip_state = after_endl; + char c; + + while ((c = is.get()) != EOF) { + if (c == '\n') ++line_num; + + switch (skip_state) { + case skip: + if (c == '\n') skip_state = after_endl; + break; + case after_endl: + switch (c) { + case '@': + is.putback(c); + return; + case '\n': + continue; + default: + if (!isspace(c)) { + skip_state = skip; + } + break; + } + } + } + } + public: /// \brief Abstract base class for reading a section. @@ -722,6 +751,7 @@ std::string line; SectionReaders::iterator it; + skipPreSection(*is, line_num); while ((++line_num, getline(*is, line)) && line.find("@end") != 0) { for (it = readers.begin(); it != readers.end(); ++it) { if (it->first->header(line)) { @@ -732,6 +762,7 @@ buffer.pubsetbuf(buf, sizeof(buf)); std::istream ss(&buffer); it->first->read(ss); + skipPreSection(*is, line_num); break; } catch (DataFormatError& error) { error.line(buffer.line_num()); @@ -984,6 +1015,465 @@ }; /// \ingroup section_io + /// \brief SectionReader for reading a bipartite graph's nodeset. + /// + /// The lemon format can store multiple bipartite graph nodesets + /// with several maps. The bipartite graph nodeset section's header + /// line is \c \@bpnodeset \c bpnodeset_name, but the \c bpnodeset_name + /// may be empty. + /// + /// The first line of the section contains \c "&anodeset" and the + /// the names of the A-node maps and regular maps separated with + /// white spaces. Each next lines describes an A-node in the anodeset, + /// and contains the mapped values for each map. If one of the line + /// starts with \c "&bnodeset" then this line contains the names of + /// the B-node maps and the regular node maps. And the remaining lines + /// contains the mapped values to the B-nodes. + /// + /// If there is "label" named map then it should be defined in both + /// nodeset, and it will be regarded as id map. This map should + /// contain only unique values and when the \c readLabel() member + /// will read a value from the given stream it will give back that + /// node which is mapped to this value. + /// + /// \relates LemonReader + template + class BpNodeSetReader : public LemonReader::SectionReader { + typedef LemonReader::SectionReader Parent; + public: + + typedef _Graph Graph; + typedef _Traits Traits; + typedef typename Graph::Node Node; + typedef typename Traits::Skipper DefaultSkipper; + + /// \brief Constructor. + /// + /// Constructor for BpNodeSetReader. It creates the BpNodeSetReader and + /// attach it into the given LemonReader. The nodeset reader will + /// add the read nodes to the given Graph. The reader will read + /// the section when the \c section_name and the \c _name are the same. + BpNodeSetReader(LemonReader& _reader, + Graph& _graph, + const std::string& _name = std::string(), + const DefaultSkipper& _skipper = DefaultSkipper()) + : Parent(_reader), graph(_graph), name(_name), skipper(_skipper) {} + + + /// \brief Destructor. + /// + /// Destructor for BpNodeSetReader. + virtual ~BpNodeSetReader() { + for (typename MapReaders::iterator it = readers.begin(); + it != readers.end(); ++it) { + delete it->second; + } + } + + private: + BpNodeSetReader(const BpNodeSetReader&); + void operator=(const BpNodeSetReader&); + + public: + + /// \brief Add a new node map reader command for the reader. + /// + /// Add a new node map reader command for the reader. + template + BpNodeSetReader& readNodeMap(std::string label, Map& map) { + return _readMap< + typename Traits::template Reader, Map, + typename _reader_bits::Arg::Type>(label, map); + } + + template + BpNodeSetReader& readNodeMap(std::string label, const Map& map) { + return _readMap< + typename Traits::template Reader, Map, + typename _reader_bits::Arg::Type>(label, map); + } + + /// \brief Add a new node map reader command for the reader. + /// + /// Add a new node map reader command for the reader. + template + BpNodeSetReader& readNodeMap(std::string label, Map& map, + const ItemReader& ir = ItemReader()) { + return _readMap::Type> + (label, map, ir); + } + + template + BpNodeSetReader& readNodeMap(std::string label, const Map& map, + const ItemReader& ir = ItemReader()) { + return _readMap::Type> + (label, map, ir); + } + + private: + + template + BpNodeSetReader& _readMap(std::string label, MapParameter map, + const ItemReader& ir = ItemReader()) { + checkConcept, Map>(); + checkConcept<_reader_bits::ItemReader, ItemReader>(); + if (areaders.find(label) != areaders.end() || + breaders.find(label) != breaders.end() || + readers.find(label) != readers.end()) { + ErrorMessage msg; + msg << "Multiple read rule for node map: " << label; + throw IoParameterError(msg.message()); + } + readers.insert(make_pair(label, new _reader_bits:: + MapReader(map, ir))); + return *this; + } + + public: + + /// \brief Add a new A-node map reader command for the reader. + /// + /// Add a new A-node map reader command for the reader. + template + BpNodeSetReader& readANodeMap(std::string label, Map& map) { + return _readAMap< + typename Traits::template Reader, Map, + typename _reader_bits::Arg::Type>(label, map); + } + + template + BpNodeSetReader& readANodeMap(std::string label, const Map& map) { + return _readAMap< + typename Traits::template Reader, Map, + typename _reader_bits::Arg::Type>(label, map); + } + + /// \brief Add a new A-node map reader command for the reader. + /// + /// Add a new A-node map reader command for the reader. + template + BpNodeSetReader& readANodeMap(std::string label, Map& map, + const ItemReader& ir = ItemReader()) { + return _readAMap::Type> + (label, map, ir); + } + + template + BpNodeSetReader& readANodeMap(std::string label, const Map& map, + const ItemReader& ir = ItemReader()) { + return _readAMap::Type> + (label, map, ir); + } + + private: + + template + BpNodeSetReader& _readAMap(std::string label, MapParameter map, + const ItemReader& ir = ItemReader()) { + checkConcept, Map>(); + checkConcept<_reader_bits::ItemReader, ItemReader>(); + if (label == "label") { + throw IoParameterError("Label cannot be A-node map"); + } + if (areaders.find(label) != areaders.end() || + readers.find(label) != readers.end()) { + ErrorMessage msg; + msg << "Multiple read rule for A-node map: " << label; + throw IoParameterError(msg.message()); + } + areaders.insert(make_pair(label, new _reader_bits:: + MapReader(map, ir))); + return *this; + } + + public: + + /// \brief Add a new B-node map reader command for the reader. + /// + /// Add a new B-node map reader command for the reader. + template + BpNodeSetReader& readBNodeMap(std::string label, Map& map) { + return _readBMap< + typename Traits::template Reader, Map, + typename _reader_bits::Arg::Type>(label, map); + } + + template + BpNodeSetReader& readBNodeMap(std::string label, const Map& map) { + return _readBMap< + typename Traits::template Reader, Map, + typename _reader_bits::Arg::Type>(label, map); + } + + /// \brief Add a new B-node map reader command for the reader. + /// + /// Add a new B-node map reader command for the reader. + template + BpNodeSetReader& readBNodeMap(std::string label, Map& map, + const ItemReader& ir = ItemReader()) { + return _readBMap::Type> + (label, map, ir); + } + + template + BpNodeSetReader& readBNodeMap(std::string label, const Map& map, + const ItemReader& ir = ItemReader()) { + return _readBMap::Type> + (label, map, ir); + } + + private: + + template + BpNodeSetReader& _readBMap(std::string label, MapParameter map, + const ItemReader& ir = ItemReader()) { + checkConcept, Map>(); + checkConcept<_reader_bits::ItemReader, ItemReader>(); + if (label == "label") { + throw IoParameterError("Label cannot be B-node map"); + } + if (breaders.find(label) != breaders.end() || + readers.find(label) != readers.end()) { + ErrorMessage msg; + msg << "Multiple read rule for B-node map: " << label; + throw IoParameterError(msg.message()); + } + breaders.insert(make_pair(label, new _reader_bits:: + MapReader(map, ir))); + return *this; + } + + public: + + /// \brief Add a new node map skipper command for the reader. + /// + /// Add a new node map skipper command for the reader. + template + BpNodeSetReader& skipNodeMap(std::string label, + const ItemReader& ir = ItemReader()) { + if (areaders.find(label) != areaders.end() || + breaders.find(label) != breaders.end() || + readers.find(label) != readers.end()) { + ErrorMessage msg; + msg << "Multiple read rule for node map: " << label; + throw IoParameterError(msg.message()); + } + readers.insert(make_pair(label, new _reader_bits:: + SkipReader(ir))); + return *this; + } + + /// \brief Add a new A-node map skipper command for the reader. + /// + /// Add a new A-node map skipper command for the reader. + template + BpNodeSetReader& skipANodeMap(std::string label, + const ItemReader& ir = ItemReader()) { + if (label == "label") { + throw IoParameterError("Label cannot be A-node map"); + } + if (areaders.find(label) != areaders.end() || + readers.find(label) != readers.end()) { + ErrorMessage msg; + msg << "Multiple read rule for A-node map: " << label; + throw IoParameterError(msg.message()); + } + areaders.insert(make_pair(label, new _reader_bits:: + SkipReader(ir))); + return *this; + } + + /// \brief Add a new B-node map skipper command for the reader. + /// + /// Add a new B-node map skipper command for the reader. + template + BpNodeSetReader& skipBNodeMap(std::string label, + const ItemReader& ir = ItemReader()) { + if (label == "label") { + throw IoParameterError("Label cannot be B-node map"); + } + if (breaders.find(label) != breaders.end() || + readers.find(label) != readers.end()) { + ErrorMessage msg; + msg << "Multiple read rule for B-node map: " << label; + throw IoParameterError(msg.message()); + } + breaders.insert(make_pair(label, new _reader_bits:: + SkipReader(ir))); + return *this; + } + + + protected: + + /// \brief Gives back true when the SectionReader can process + /// the section with the given header line. + /// + /// It gives back true when the header line starts with \c \@nodeset, + /// and the header line's name and the nodeset's name are the same. + virtual bool header(const std::string& line) { + std::istringstream ls(line); + std::string command; + std::string id; + ls >> command >> id; + return command == "@bpnodeset" && name == id; + } + + /// \brief Reader function of the section. + /// + /// It reads the content of the section. + virtual void read(std::istream& is) { + std::string line; + { + std::vector<_reader_bits::MapReaderBase* > index; + { + getline(is, line); + std::istringstream ls(line); + std::string id; + ls >> id; + if (id != "&anodeset") { + throw IoParameterError("Cannot find &anodeset subsection"); + } + while (ls >> id) { + typename MapReaders::iterator it = readers.find(id); + typename MapReaders::iterator ait = areaders.find(id); + if (it != readers.end()) { + it->second->touch(); + index.push_back(it->second); + } else if (ait != areaders.end()) { + ait->second->touch(); + index.push_back(ait->second); + } + if (id == "label") { + inverter.reset(index.back()->getInverter()); + index.back() = inverter.get(); + } + } + } + for (typename MapReaders::iterator it = areaders.begin(); + it != areaders.end(); ++it) { + if (!it->second->touched()) { + ErrorMessage msg; + msg << "Map not found in file: " << it->first; + throw IoParameterError(msg.message()); + } + } + for (typename MapReaders::iterator it = readers.begin(); + it != readers.end(); ++it) { + if (!it->second->touched()) { + ErrorMessage msg; + msg << "Map not found in file: " << it->first; + throw IoParameterError(msg.message()); + } + it->second->touch(false); + } + + while (getline(is, line)) { + if (line[0] == '&') { + std::istringstream ls(line); + std::string id; + ls >> id; + if (id == "&bnodeset") break; + } + Node node = graph.addANode(); + std::istringstream ls(line); + for (int i = 0; i < int(index.size()); ++i) { + index[i]->read(ls, node); + } + } + } + + { + std::vector<_reader_bits::MapReaderBase* > index; + { + std::istringstream ls(line); + std::string id; + ls >> id; + if (id != "&bnodeset") { + throw IoParameterError("Cannot find &bnodeset subsection"); + } + while (ls >> id) { + typename MapReaders::iterator it = readers.find(id); + typename MapReaders::iterator bit = breaders.find(id); + if (it != readers.end()) { + it->second->touch(); + index.push_back(it->second); + } else if (bit != breaders.end()) { + bit->second->touch(); + index.push_back(bit->second); + } + if (id == "label" && inverter.get() != 0) { + index.back() = inverter.get(); + } + } + } + for (typename MapReaders::iterator it = breaders.begin(); + it != breaders.end(); ++it) { + if (!it->second->touched()) { + ErrorMessage msg; + msg << "Map not found in file: " << it->first; + throw IoParameterError(msg.message()); + } + } + for (typename MapReaders::iterator it = readers.begin(); + it != readers.end(); ++it) { + if (!it->second->touched()) { + ErrorMessage msg; + msg << "Map not found in file: " << it->first; + throw IoParameterError(msg.message()); + } + } + while (getline(is, line)) { + Node node = graph.addBNode(); + std::istringstream ls(line); + for (int i = 0; i < int(index.size()); ++i) { + index[i]->read(ls, node); + } + } + } + } + + virtual void missing() { + if (readers.empty()) return; + ErrorMessage msg; + msg << "BpNodeSet section not found in file: @bpnodeset " << name; + throw IoParameterError(msg.message()); + } + + public: + + /// \brief Returns true if the nodeset can give back the node by its label. + /// + /// Returns true if the nodeset can give back the node by its label. + /// It is possible only if an "label" named map was read. + bool isLabelReader() const { + return inverter.get() != 0; + } + + /// \brief Gives back the node by its label. + /// + /// It reads an id from the stream and gives back which node belongs to + /// it. It is possible only if there was read an "label" named map. + void readLabel(std::istream& is, Node& node) const { + node = inverter->read(is); + } + + private: + + typedef std::map*> + MapReaders; + + MapReaders areaders, breaders, readers; + + Graph& graph; + std::string name; + _reader_bits::SkipReader skipper; + + std::auto_ptr<_reader_bits::MapInverterBase > inverter; + }; + + + /// \ingroup section_io /// \brief SectionReader for reading a graph's edgeset. /// /// The lemon format can store multiple graph edgesets with several maps. diff -r 1af977819111 -r 9c23c3762bc5 lemon/lemon_writer.h --- a/lemon/lemon_writer.h Sat Oct 20 14:29:12 2007 +0000 +++ b/lemon/lemon_writer.h Wed Oct 24 16:31:49 2007 +0000 @@ -144,8 +144,8 @@ } private: + const Graph& graph; typename Ref::Type map; - const Graph& graph; }; template @@ -168,8 +168,8 @@ } private: + const Graph& graph; typename Ref::Type map; - const Graph& graph; }; template @@ -502,7 +502,7 @@ /// \c writeLabel() member will be called with a node it will write it's /// label. Otherwise if the \c _forceLabelMap constructor parameter is true /// then the label map will be the id in the graph. In addition if the - /// the \c _forceSort is true then the writer will write the edges + /// the \c _forceSort is true then the writer will write the nodes /// sorted by the labels. /// /// \relates LemonWriter @@ -680,6 +680,300 @@ }; /// \ingroup section_io + /// \brief SectionWriter for writing a bipartite graph's nodeset. + /// + /// The lemon format can store multiple bipartite graph nodesets + /// with several maps. The nodeset section's header line is \c + /// \@bpnodeset \c bpnodeset_name, but the \c bpnodeset_name may be empty. + /// + /// The first line of the section contains the names of the maps separated + /// with white spaces. Each next lines describes a node in the nodeset, and + /// contains the mapped values for each map. + /// + /// If the nodeset contains an \c "label" named map then it will be regarded + /// as label map. This map should contain only unique values and when the + /// \c writeLabel() member will be called with a node it will write it's + /// label. Otherwise if the \c _forceLabelMap constructor parameter is true + /// then the label map will be the id in the graph. In addition if the + /// the \c _forceSort is true then the writer will write the edges + /// sorted by the labels. + /// + /// \relates LemonWriter + template + class BpNodeSetWriter : public LemonWriter::SectionWriter { + typedef LemonWriter::SectionWriter Parent; + public: + + typedef _Graph Graph; + typedef _Traits Traits; + typedef typename Graph::Node Node; + + /// \brief Constructor. + /// + /// Constructor for BpNodeSetWriter. It creates the BpNodeSetWriter and + /// attach it into the given LemonWriter. If the \c _forceLabelMap + /// parameter is true then the writer will write own label map when + /// the user does not give "label" named map. In addition if the + /// the \c _forceSort is true then the writer will write the nodes + /// sorted by the labels. + BpNodeSetWriter(LemonWriter& _writer, const Graph& _graph, + const std::string& _name = std::string(), + bool _forceLabelMap = true, bool _forceSort = true) + : Parent(_writer), labelMap(0), forceLabelMap(_forceLabelMap), + forceSort(_forceSort), graph(_graph), name(_name) {} + + /// \brief Destructor. + /// + /// Destructor for BpNodeSetWriter. + virtual ~BpNodeSetWriter() { + typename MapWriters::iterator it; + for (it = writers.begin(); it != writers.end(); ++it) { + delete it->second; + } + } + + private: + BpNodeSetWriter(const BpNodeSetWriter&); + void operator=(const BpNodeSetWriter&); + + public: + + /// \brief Add a new A-node map writer command for the writer. + /// + /// Add a new A-node map writer command for the writer. + template + BpNodeSetWriter& writeANodeMap(std::string label, const Map& map) { + return writeANodeMap, Map>(label, map); + } + + /// \brief Add a new A-node map writer command for the writer. + /// + /// Add a new A-node map writer command for the writer. + template + BpNodeSetWriter& writeANodeMap(std::string label, const Map& map, + const ItemWriter& iw = ItemWriter()) { + checkConcept, Map>(); + checkConcept<_writer_bits::ItemWriter,ItemWriter>(); + if (label == "label") { + throw IoParameterError("Label cannot be A-node map"); + } + awriters.push_back(make_pair(label, new _writer_bits:: + MapWriter(map, iw))); + return *this; + } + + /// \brief Add a new B-node map writer command for the writer. + /// + /// Add a new B-node map writer command for the writer. + template + BpNodeSetWriter& writeBNodeMap(std::string label, const Map& map) { + return writeBNodeMap, Map>(label, map); + } + + /// \brief Add a new B-node map writer command for the writer. + /// + /// Add a new B-node map writer command for the writer. + template + BpNodeSetWriter& writeBNodeMap(std::string label, const Map& map, + const ItemWriter& iw = ItemWriter()) { + checkConcept, Map>(); + checkConcept<_writer_bits::ItemWriter,ItemWriter>(); + if (label == "label") { + throw IoParameterError("Label cannot be B-node map"); + } + bwriters.push_back(make_pair(label, new _writer_bits:: + MapWriter(map, iw))); + return *this; + } + + /// \brief Add a new node map writer command for the writer. + /// + /// Add a new node map writer command for the writer. + template + BpNodeSetWriter& writeNodeMap(std::string label, const Map& map) { + return writeNodeMap, Map>(label, map); + } + + /// \brief Add a new node map writer command for the writer. + /// + /// Add a new node map writer command for the writer. + template + BpNodeSetWriter& writeNodeMap(std::string label, const Map& map, + const ItemWriter& iw = ItemWriter()) { + checkConcept, Map>(); + checkConcept<_writer_bits::ItemWriter,ItemWriter>(); + writers.push_back(make_pair(label, new _writer_bits:: + MapWriter(map, iw))); + return *this; + } + + protected: + + /// \brief The header of the section. + /// + /// It gives back the header of the section. + virtual std::string header() { + return "@bpnodeset " + name; + } + + /// \brief Writer function of the section. + /// + /// Write the content of the section. + virtual void write(std::ostream& os) { + for (int i = 0; i < int(writers.size()); ++i) { + if (writers[i].first == "label") { + labelMap = writers[i].second; + forceLabelMap = false; + break; + } + } + { + os << "&anodeset "; + std::vector items; + for (typename Graph::ANodeIt it(graph); it != INVALID; ++it) { + items.push_back(it); + } + if (forceSort) { + if (labelMap) { + labelMap->sort(items); + } else { + typedef IdMap Map; + Map map(graph); + _writer_bits::ComposeLess less(map); + std::sort(items.begin(), items.end(), less); + } + } + if (forceLabelMap) { + os << "label\t"; + } + for (int i = 0; i < int(writers.size()); ++i) { + os << writers[i].first << '\t'; + } + for (int i = 0; i < int(awriters.size()); ++i) { + os << awriters[i].first << '\t'; + } + os << std::endl; + for (typename std::vector::iterator it = items.begin(); + it != items.end(); ++it) { + if (forceLabelMap) { + os << graph.id(*it) << '\t'; + } + for (int i = 0; i < int(writers.size()); ++i) { + writers[i].second->write(os, *it); + os << '\t'; + } + for (int i = 0; i < int(awriters.size()); ++i) { + awriters[i].second->write(os, *it); + os << '\t'; + } + os << std::endl; + } + } + { + os << "&bnodeset "; + std::vector items; + for (typename Graph::BNodeIt it(graph); it != INVALID; ++it) { + items.push_back(it); + } + if (forceSort) { + if (labelMap) { + labelMap->sort(items); + } else { + typedef IdMap Map; + Map map(graph); + _writer_bits::ComposeLess less(map); + std::sort(items.begin(), items.end(), less); + } + } + if (forceLabelMap) { + os << "label\t"; + } + for (int i = 0; i < int(writers.size()); ++i) { + os << writers[i].first << '\t'; + } + for (int i = 0; i < int(bwriters.size()); ++i) { + os << bwriters[i].first << '\t'; + } + os << std::endl; + for (typename std::vector::iterator it = items.begin(); + it != items.end(); ++it) { + if (forceLabelMap) { + os << graph.id(*it) << '\t'; + } + for (int i = 0; i < int(writers.size()); ++i) { + writers[i].second->write(os, *it); + os << '\t'; + } + for (int i = 0; i < int(bwriters.size()); ++i) { + bwriters[i].second->write(os, *it); + os << '\t'; + } + os << std::endl; + } + } + } + + public: + + /// \brief Returns true if the nodeset can write the labels of the nodes. + /// + /// Returns true if the nodeset can write the labels of the nodes. + /// It is possible only if a "label" named map was written or the + /// \c _forceLabelMap constructor parameter was true. + bool isLabelWriter() const { + return labelMap != 0 || forceLabelMap; + } + + /// \brief Write the label of the given node. + /// + /// It writes the label of the given node. If there was written a "label" + /// named map then it will write the map value belongs to the node. + /// Otherwise if the \c forceLabel parameter was true it will write + /// its label in the graph. + void writeLabel(std::ostream& os, const Node& item) const { + if (forceLabelMap) { + os << graph.id(item); + } else { + labelMap->write(os, item); + } + } + + /// \brief Sorts the given node vector by label. + /// + /// Sorts the given node vector by label. If there was written an + /// "label" named map then the vector will be sorted by the values + /// of this map. Otherwise if the \c forceLabel parameter was true + /// it will be sorted by its id in the graph. + void sortByLabel(std::vector& nodes) const { + if (labelMap) { + labelMap->sort(nodes); + } else { + typedef IdMap Map; + Map map(graph); + _writer_bits::ComposeLess less(map); + std::sort(nodes.begin(), nodes.end(), less); + } + } + + private: + + typedef std::vector*> > MapWriters; + MapWriters awriters, bwriters, writers; + + _writer_bits::MapWriterBase* labelMap; + bool forceLabelMap; + bool forceSort; + + const Graph& graph; + std::string name; + + }; + + /// \ingroup section_io /// \brief SectionWriter for writing a graph's edgesets. /// /// The lemon format can store multiple graph edgesets with several maps.