[Lemon-commits] deba: r3343 - in lemon/trunk: doc lemon

Lemon SVN svn at lemon.cs.elte.hu
Wed Oct 24 18:31:50 CEST 2007


Author: deba
Date: Wed Oct 24 18:31:49 2007
New Revision: 3343

Modified:
   lemon/trunk/doc/graph_io.dox
   lemon/trunk/lemon/graph_reader.h
   lemon/trunk/lemon/graph_writer.h
   lemon/trunk/lemon/lemon_reader.h
   lemon/trunk/lemon/lemon_writer.h

Log:
BpUGraphReader and Writer



Modified: lemon/trunk/doc/graph_io.dox
==============================================================================
--- lemon/trunk/doc/graph_io.dox	(original)
+++ lemon/trunk/doc/graph_io.dox	Wed Oct 24 18:31:49 2007
@@ -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
+ at 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

Modified: lemon/trunk/lemon/graph_reader.h
==============================================================================
--- lemon/trunk/lemon/graph_reader.h	(original)
+++ lemon/trunk/lemon/graph_reader.h	Wed Oct 24 18:31:49 2007
@@ -725,6 +725,469 @@
     AttributeReader<ReaderTraits> 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<ListBpUGraph> 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 <typename _Graph, typename _ReaderTraits = DefaultReaderTraits> 
+  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 <typename Map>
+    BpUGraphReader& readNodeMap(std::string name, Map& map) {
+      nodeset_reader.readNodeMap(name, map);
+      return *this;
+    }
+
+    template <typename Map>
+    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 <typename ItemReader, typename Map>
+    BpUGraphReader& readNodeMap(std::string name, Map& map, 
+                              const ItemReader& ir = ItemReader()) {
+      nodeset_reader.readNodeMap(name, map, ir);
+      return *this;
+    }
+
+    template <typename ItemReader, typename Map>
+    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 <typename ItemReader>
+    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 <typename Map>
+    BpUGraphReader& readANodeMap(std::string name, Map& map) {
+      nodeset_reader.readANodeMap(name, map);
+      return *this;
+    }
+
+    template <typename Map>
+    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 <typename ItemReader, typename Map>
+    BpUGraphReader& readANodeMap(std::string name, Map& map, 
+                              const ItemReader& ir = ItemReader()) {
+      nodeset_reader.readANodeMap(name, map, ir);
+      return *this;
+    }
+
+    template <typename ItemReader, typename Map>
+    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 <typename ItemReader>
+    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 <typename Map>
+    BpUGraphReader& readBNodeMap(std::string name, Map& map) {
+      nodeset_reader.readBNodeMap(name, map);
+      return *this;
+    }
+
+    template <typename Map>
+    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 <typename ItemReader, typename Map>
+    BpUGraphReader& readBNodeMap(std::string name, Map& map, 
+                              const ItemReader& ir = ItemReader()) {
+      nodeset_reader.readBNodeMap(name, map, ir);
+      return *this;
+    }
+
+    template <typename ItemReader, typename Map>
+    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 <typename ItemReader>
+    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 <typename Map>
+    BpUGraphReader& readUEdgeMap(std::string name, Map& map) { 
+      uedgeset_reader.readUEdgeMap(name, map);
+      return *this;
+    }
+
+    template <typename Map>
+    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 <typename ItemReader, typename Map>
+    BpUGraphReader& readUEdgeMap(std::string name, Map& map,
+                               const ItemReader& ir = ItemReader()) {
+      uedgeset_reader.readUEdgeMap(name, map, ir);
+      return *this;
+    }
+
+    template <typename ItemReader, typename Map>
+    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 <typename ItemReader>
+    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 <typename Map>
+    BpUGraphReader& readEdgeMap(std::string name, Map& map) { 
+      uedgeset_reader.readEdgeMap(name, map);
+      return *this;
+    }
+
+    template <typename Map>
+    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 <typename ItemReader, typename Map>
+    BpUGraphReader& readEdgeMap(std::string name, Map& map,
+                              const ItemReader& ir = ItemReader()) {
+      uedgeset_reader.readEdgeMap(name, map, ir);
+      return *this;
+    }
+
+    template <typename ItemReader, typename Map>
+    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 <typename ItemReader>
+    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 <typename Value>
+    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 <typename ItemReader, typename Value>
+    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<Graph, ReaderTraits> nodeset_reader;
+    UEdgeSetReader<Graph, ReaderTraits> uedgeset_reader;
+
+    NodeReader<Graph> node_reader;
+    UEdgeReader<Graph> uedge_reader;
+    
+    AttributeReader<ReaderTraits> attribute_reader;
+  };
+
 
   /// @}
 }

Modified: lemon/trunk/lemon/graph_writer.h
==============================================================================
--- lemon/trunk/lemon/graph_writer.h	(original)
+++ lemon/trunk/lemon/graph_writer.h	Wed Oct 24 18:31:49 2007
@@ -156,7 +156,7 @@
 
     /// \brief Issue a new node map writing command for the writer.
     ///
-   /// This function issues a new <i> node map writing command</i> to the writer.
+    /// This function issues a new <i> node map writing command</i> to the writer.
     template <typename Map>
     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 <i> node map writing command</i> to the writer.
+    /// This function issues a new <i> node map writing command</i> to the writer.
     template <typename ItemWriter, typename Map>
     GraphWriter& writeNodeMap(std::string label, const Map& map, 
 			      const ItemWriter& iw = ItemWriter()) {
@@ -639,6 +639,376 @@
     AttributeWriter<WriterTraits> 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<ListUGraph> 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<ListUGraph, Node> 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<ListGraph, Edge, ListGraph::EdgeMap<int> > 
+  ///   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 <typename _Graph, typename _WriterTraits = DefaultWriterTraits> 
+  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 <i> node map writing command</i> to
+    /// the writer.
+    template <typename Map>
+    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 <i> node map writing command</i> to
+    /// the writer.
+    template <typename ItemWriter, typename Map>
+    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 <i> A-node map writing command</i> to
+    /// the writer.
+    template <typename Map>
+    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 <i> A-node map writing command</i> to
+    /// the writer.
+    template <typename ItemWriter, typename Map>
+    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 <i> B-node map writing command</i> to
+    /// the writer.
+    template <typename Map>
+    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 <i> B-node map writing command</i> to
+    /// the writer.
+    template <typename ItemWriter, typename Map>
+    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 <i> edge map writing command</i> to
+    /// the writer.
+    template <typename Map>
+    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 <i> edge map writing command</i> to
+    /// the writer.
+    template <typename ItemWriter, typename Map>
+    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 <i> undirected edge map writing
+    /// command</i> to the writer.
+    template <typename Map>
+    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 <i> undirected edge map writing
+    /// command</i> to the writer.
+   template <typename ItemWriter, typename Map>
+    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 <i> labeled node writing
+    /// command</i> 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 <i> labeled edge writing
+    /// command</i> 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 <i>labeled undirected edge writing command</i> 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 <i> attribute writing
+    /// command</i> to the writer.
+    template <typename Value>
+    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 <i> attribute writing
+    /// command</i> to the writer.
+    template <typename ItemWriter, typename Value>
+    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<Node>& 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<Edge>& 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<UEdge>& uedges) const {
+      uedgeset_writer.sortByLabel(uedges);
+    }
+
+  private:
+
+    LemonWriter* writer;
+    bool own_writer;
+
+    BpNodeSetWriter<Graph, WriterTraits> nodeset_writer;
+    UEdgeSetWriter<Graph, WriterTraits> uedgeset_writer;
+
+    NodeWriter<Graph> node_writer;
+    UEdgeWriter<Graph> uedge_writer;
+    
+    AttributeWriter<WriterTraits> attribute_writer;
+  };
+
   /// @}
 
 }

Modified: lemon/trunk/lemon/lemon_reader.h
==============================================================================
--- lemon/trunk/lemon/lemon_reader.h	(original)
+++ lemon/trunk/lemon/lemon_reader.h	Wed Oct 24 18:31:49 2007
@@ -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 <typename _Graph, typename _Traits = DefaultReaderTraits>
+  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 <typename Map>
+    BpNodeSetReader& readNodeMap(std::string label, Map& map) {
+      return _readMap<
+	typename Traits::template Reader<typename Map::Value>, Map,
+	typename _reader_bits::Arg<Map>::Type>(label, map);
+    }
+
+    template <typename Map>
+    BpNodeSetReader& readNodeMap(std::string label, const Map& map) {
+      return _readMap<
+	typename Traits::template Reader<typename Map::Value>, Map,
+	typename _reader_bits::Arg<Map>::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 <typename ItemReader, typename Map>
+    BpNodeSetReader& readNodeMap(std::string label, Map& map, 
+			       const ItemReader& ir = ItemReader()) {
+      return _readMap<ItemReader, Map, typename _reader_bits::Arg<Map>::Type>
+	(label, map, ir);
+    }
+
+    template <typename ItemReader, typename Map>
+    BpNodeSetReader& readNodeMap(std::string label, const Map& map, 
+			       const ItemReader& ir = ItemReader()) {
+      return _readMap<ItemReader, Map, typename _reader_bits::Arg<Map>::Type>
+	(label, map, ir);
+    }
+
+  private:
+
+    template <typename ItemReader, typename Map, typename MapParameter>
+    BpNodeSetReader& _readMap(std::string label, MapParameter map, 
+			    const ItemReader& ir = ItemReader()) {
+      checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
+      checkConcept<_reader_bits::ItemReader<typename Map::Value>, 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<Node, Map, ItemReader>(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 <typename Map>
+    BpNodeSetReader& readANodeMap(std::string label, Map& map) {
+      return _readAMap<
+	typename Traits::template Reader<typename Map::Value>, Map,
+	typename _reader_bits::Arg<Map>::Type>(label, map);
+    }
+
+    template <typename Map>
+    BpNodeSetReader& readANodeMap(std::string label, const Map& map) {
+      return _readAMap<
+	typename Traits::template Reader<typename Map::Value>, Map,
+	typename _reader_bits::Arg<Map>::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 <typename ItemReader, typename Map>
+    BpNodeSetReader& readANodeMap(std::string label, Map& map, 
+			       const ItemReader& ir = ItemReader()) {
+      return _readAMap<ItemReader, Map, typename _reader_bits::Arg<Map>::Type>
+	(label, map, ir);
+    }
+
+    template <typename ItemReader, typename Map>
+    BpNodeSetReader& readANodeMap(std::string label, const Map& map, 
+			       const ItemReader& ir = ItemReader()) {
+      return _readAMap<ItemReader, Map, typename _reader_bits::Arg<Map>::Type>
+	(label, map, ir);
+    }
+
+  private:
+
+    template <typename ItemReader, typename Map, typename MapParameter>
+    BpNodeSetReader& _readAMap(std::string label, MapParameter map, 
+			    const ItemReader& ir = ItemReader()) {
+      checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
+      checkConcept<_reader_bits::ItemReader<typename Map::Value>, 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<Node, Map, ItemReader>(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 <typename Map>
+    BpNodeSetReader& readBNodeMap(std::string label, Map& map) {
+      return _readBMap<
+	typename Traits::template Reader<typename Map::Value>, Map,
+	typename _reader_bits::Arg<Map>::Type>(label, map);
+    }
+
+    template <typename Map>
+    BpNodeSetReader& readBNodeMap(std::string label, const Map& map) {
+      return _readBMap<
+	typename Traits::template Reader<typename Map::Value>, Map,
+	typename _reader_bits::Arg<Map>::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 <typename ItemReader, typename Map>
+    BpNodeSetReader& readBNodeMap(std::string label, Map& map, 
+			       const ItemReader& ir = ItemReader()) {
+      return _readBMap<ItemReader, Map, typename _reader_bits::Arg<Map>::Type>
+	(label, map, ir);
+    }
+
+    template <typename ItemReader, typename Map>
+    BpNodeSetReader& readBNodeMap(std::string label, const Map& map, 
+			       const ItemReader& ir = ItemReader()) {
+      return _readBMap<ItemReader, Map, typename _reader_bits::Arg<Map>::Type>
+	(label, map, ir);
+    }
+
+  private:
+
+    template <typename ItemReader, typename Map, typename MapParameter>
+    BpNodeSetReader& _readBMap(std::string label, MapParameter map, 
+			    const ItemReader& ir = ItemReader()) {
+      checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
+      checkConcept<_reader_bits::ItemReader<typename Map::Value>, 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<Node, Map, ItemReader>(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 <typename ItemReader>
+    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<Node, ItemReader>(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 <typename ItemReader>
+    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<Node, ItemReader>(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 <typename ItemReader>
+    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<Node, ItemReader>(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<Node>* > 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<Node>* > 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<std::string, _reader_bits::MapReaderBase<Node>*> 
+    MapReaders;
+    
+    MapReaders areaders, breaders, readers;
+   
+    Graph& graph;
+    std::string name;
+    _reader_bits::SkipReader<Node, DefaultSkipper> skipper;
+
+    std::auto_ptr<_reader_bits::MapInverterBase<Node> > inverter;
+  };
+
+
+  /// \ingroup section_io
   /// \brief SectionReader for reading a graph's edgeset.
   ///
   /// The lemon format can store multiple graph edgesets with several maps.

Modified: lemon/trunk/lemon/lemon_writer.h
==============================================================================
--- lemon/trunk/lemon/lemon_writer.h	(original)
+++ lemon/trunk/lemon/lemon_writer.h	Wed Oct 24 18:31:49 2007
@@ -144,8 +144,8 @@
       }
 
     private:
-      typename Ref<Map>::Type map;
       const Graph& graph;
+      typename Ref<Map>::Type map;
     };
 
     template <typename Graph, typename Map>
@@ -168,8 +168,8 @@
       }
 
     private:
-      typename Ref<Map>::Type map;
       const Graph& graph;
+      typename Ref<Map>::Type map;
     };
 
     template <typename Graph, typename Map>
@@ -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 <typename _Graph, typename _Traits = DefaultWriterTraits>
+  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 <typename Map>
+    BpNodeSetWriter& writeANodeMap(std::string label, const Map& map) {
+      return writeANodeMap<typename Traits::
+	template Writer<typename Map::Value>, 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 <typename ItemWriter, typename Map>
+    BpNodeSetWriter& writeANodeMap(std::string label, const Map& map, 
+				   const ItemWriter& iw = ItemWriter()) {
+      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
+      checkConcept<_writer_bits::ItemWriter<typename Map::Value>,ItemWriter>();
+      if (label == "label") {
+	throw IoParameterError("Label cannot be A-node map");
+      }
+      awriters.push_back(make_pair(label, new _writer_bits::
+				   MapWriter<Node, Map, ItemWriter>(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 <typename Map>
+    BpNodeSetWriter& writeBNodeMap(std::string label, const Map& map) {
+      return writeBNodeMap<typename Traits::
+	template Writer<typename Map::Value>, 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 <typename ItemWriter, typename Map>
+    BpNodeSetWriter& writeBNodeMap(std::string label, const Map& map, 
+				   const ItemWriter& iw = ItemWriter()) {
+      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
+      checkConcept<_writer_bits::ItemWriter<typename Map::Value>,ItemWriter>();
+      if (label == "label") {
+	throw IoParameterError("Label cannot be B-node map");
+      }
+      bwriters.push_back(make_pair(label, new _writer_bits::
+				   MapWriter<Node, Map, ItemWriter>(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 <typename Map>
+    BpNodeSetWriter& writeNodeMap(std::string label, const Map& map) {
+      return writeNodeMap<typename Traits::
+	template Writer<typename Map::Value>, 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 <typename ItemWriter, typename Map>
+    BpNodeSetWriter& writeNodeMap(std::string label, const Map& map, 
+				  const ItemWriter& iw = ItemWriter()) {
+      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
+      checkConcept<_writer_bits::ItemWriter<typename Map::Value>,ItemWriter>();
+      writers.push_back(make_pair(label, new _writer_bits::
+				  MapWriter<Node, Map, ItemWriter>(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<Node> items;
+	for (typename Graph::ANodeIt it(graph); it != INVALID; ++it) {
+	  items.push_back(it);
+	}
+	if (forceSort) {
+	  if (labelMap) {
+	    labelMap->sort(items);
+	  } else {
+	    typedef IdMap<Graph, Node> Map;
+	    Map map(graph);
+	    _writer_bits::ComposeLess<Map> 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<Node>::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<Node> items;
+	for (typename Graph::BNodeIt it(graph); it != INVALID; ++it) {
+	  items.push_back(it);
+	}
+	if (forceSort) {
+	  if (labelMap) {
+	    labelMap->sort(items);
+	  } else {
+	    typedef IdMap<Graph, Node> Map;
+	    Map map(graph);
+	    _writer_bits::ComposeLess<Map> 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<Node>::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<Node>& nodes) const {
+      if (labelMap) {
+	labelMap->sort(nodes);
+      } else {
+	typedef IdMap<Graph, Node> Map;
+	Map map(graph);
+	_writer_bits::ComposeLess<Map> less(map);
+	std::sort(nodes.begin(), nodes.end(), less);
+      }
+    }
+
+  private:
+
+    typedef std::vector<std::pair<std::string, _writer_bits::
+				  MapWriterBase<Node>*> > MapWriters;
+    MapWriters awriters, bwriters, writers;
+    
+    _writer_bits::MapWriterBase<Node>* 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. 



More information about the Lemon-commits mailing list