src/lemon/lemon_writer.h
changeset 1428 9ba88ddc629c
parent 1411 5d161e08bda8
child 1429 4283998fb2be
equal deleted inserted replaced
1:9030f35bc73b 2:4c5e124f6dfd
    29 #include <map>
    29 #include <map>
    30 #include <memory>
    30 #include <memory>
    31 
    31 
    32 #include <lemon/error.h>
    32 #include <lemon/error.h>
    33 #include <lemon/invalid.h>
    33 #include <lemon/invalid.h>
       
    34 #include <lemon/graph_utils.h>
    34 #include <lemon/bits/item_writer.h>
    35 #include <lemon/bits/item_writer.h>
       
    36 #include <lemon/utility.h>
       
    37 #include <lemon/maps.h>
    35 
    38 
    36 
    39 
    37 namespace lemon {
    40 namespace lemon {
    38 
    41 
    39   /// \ingroup io_group
    42   /// \ingroup io_group
   161     /// Constructor for CommonSectionWriterBase. It attach this writer to
   164     /// Constructor for CommonSectionWriterBase. It attach this writer to
   162     /// the given LemonWriter.
   165     /// the given LemonWriter.
   163     CommonSectionWriterBase(LemonWriter& _writer) 
   166     CommonSectionWriterBase(LemonWriter& _writer) 
   164       : Parent(_writer) {}
   167       : Parent(_writer) {}
   165 
   168 
   166     // Writers
       
   167 
       
   168     template <typename _Item>    
   169     template <typename _Item>    
   169     class WriterBase {
   170     class WriterBase {
   170     public:
   171     public:
   171       typedef _Item Item;
   172       typedef _Item Item;
   172 
   173 
   182       typedef _Map Map;
   183       typedef _Map Map;
   183       typedef _Writer Writer;
   184       typedef _Writer Writer;
   184       typedef typename Writer::Value Value;
   185       typedef typename Writer::Value Value;
   185       typedef _Item Item;
   186       typedef _Item Item;
   186       
   187       
   187       const Map& map;
   188       typename SmartConstReference<Map>::Type map;
   188       Writer writer;
   189       Writer writer;
   189 
   190 
   190       MapWriter(const Map& _map, const Writer& _writer) 
   191       MapWriter(const Map& _map, const Writer& _writer) 
   191 	: map(_map), writer(_writer) {}
   192 	: map(_map), writer(_writer) {}
   192 
   193 
   304 
   305 
   305     /// \brief Add a new node map writer command for the writer.
   306     /// \brief Add a new node map writer command for the writer.
   306     ///
   307     ///
   307     /// Add a new node map writer command for the writer.
   308     /// Add a new node map writer command for the writer.
   308     template <typename Map>
   309     template <typename Map>
   309     NodeSetWriter& writeMap(std::string name, const Map& map) {
   310     NodeSetWriter& writeNodeMap(std::string name, const Map& map) {
   310       return writeMap<typename Traits::
   311       return writeNodeMap<typename Traits::
   311 	template Writer<typename Map::Value>, Map>(name, map);
   312 	template Writer<typename Map::Value>, Map>(name, map);
   312     }
   313     }
   313 
   314 
   314     /// \brief Add a new node map writer command for the writer.
   315     /// \brief Add a new node map writer command for the writer.
   315     ///
   316     ///
   316     /// Add a new node map writer command for the writer.
   317     /// Add a new node map writer command for the writer.
   317     template <typename Writer, typename Map>
   318     template <typename Writer, typename Map>
   318     NodeSetWriter& writeMap(std::string name, const Map& map, 
   319     NodeSetWriter& writeNodeMap(std::string name, const Map& map, 
   319 			     const Writer& writer = Writer()) {
   320 			    const Writer& writer = Writer()) {
   320       writers.push_back(
   321       writers.push_back(
   321 	make_pair(name, new MapWriter<Item, Map, Writer>(map, writer)));
   322 	make_pair(name, new MapWriter<Item, Map, Writer>(map, writer)));
   322       return *this;
   323       return *this;
   323     }
   324     }
   324 
   325 
   392     MapWriters writers;
   393     MapWriters writers;
   393 
   394 
   394     WriterBase<Item>* idMap;
   395     WriterBase<Item>* idMap;
   395     bool forceIdMap;
   396     bool forceIdMap;
   396    
   397    
   397     const Graph& graph;   
   398     typename SmartConstReference<Graph>::Type graph;   
   398     std::string id;
   399     std::string id;
   399 
   400 
   400   };
   401   };
   401 
   402 
   402   /// \ingroup io_group
   403   /// \ingroup io_group
   403   /// \brief SectionWriter for writing a graph's edgeset.
   404   /// \brief SectionWriter for writing a graph's edgesets.
   404   ///
   405   ///
   405   /// The lemon format can store multiple graph edgesets with several maps.
   406   /// The lemon format can store multiple graph edgesets with several maps. 
   406   /// The edgeset section's header line is \c \@edgeset \c edgeset_id, but the
   407   /// The edgeset section's header line is \c \@edgeset \c edgeset_id, but the
   407   /// \c edgeset_id may be empty.
   408   /// \c edgeset_id may be empty.
   408   ///
   409   ///
   409   /// The first line of the section contains the names of the maps separated
   410   /// The first line of the section contains the names of the maps separated
   410   /// with white spaces. Each next lines describes a edge in the edgeset. The
   411   /// with white spaces. Each next lines describes a edge in the edgeset. The
   411   /// line contains the source and the target nodes' id and the mapped 
   412   /// line contains the source and the target nodes' id and the mapped 
   412   /// values for each map.
   413   /// values for each map.
   413   ///
   414   ///
   414   /// If the edgeset contains an \c "id" named map then it will be regarded
   415   /// If the edgeset contains an \c "id" named map then it will be regarded
   415   /// as id map. This map should contain only unique values and when the 
   416   /// as id map. This map should contain only unique values and when the 
   416   /// \c writeId() member will be called with a edge it will write it's id.
   417   /// \c writeId() member will be called with an edge it will write it's id.
   417   /// Otherwise if the \c _forceIdMap constructor parameter is true then
   418   /// Otherwise if the \c _forceIdMap constructor parameter is true then
   418   /// the id map will be the id in the graph.
   419   /// the id map will be the id in the graph.
   419   ///
   420   ///
   420   /// The edgeset writer needs a node id writer to identify which nodes
   421   /// The edgeset writer needs a node id writer to identify which nodes
   421   /// have to be connected. If a NodeSetWriter can write the nodes' id,
   422   /// have to be connected. If a NodeSetWriter can write the nodes' id,
   434     /// \brief Constructor.
   435     /// \brief Constructor.
   435     ///
   436     ///
   436     /// Constructor for EdgeSetWriter. It creates the EdgeSetWriter and
   437     /// Constructor for EdgeSetWriter. It creates the EdgeSetWriter and
   437     /// attach it into the given LemonWriter. It will write node ids by
   438     /// attach it into the given LemonWriter. It will write node ids by
   438     /// the \c _nodeIdWriter. If the \c _forceIdMap parameter is true 
   439     /// the \c _nodeIdWriter. If the \c _forceIdMap parameter is true 
   439     /// then the writer will write own id map when the user does not give 
   440     /// then the writer will write own id map if the user does not give 
   440     /// "id" named map.
   441     /// "id" named map.
   441     template <typename NodeIdWriter>
   442     template <typename NodeIdWriter>
   442     EdgeSetWriter(LemonWriter& _writer, const Graph& _graph, 
   443     EdgeSetWriter(LemonWriter& _writer, const Graph& _graph, 
   443 		  const NodeIdWriter& _nodeIdWriter, 
   444 		  const NodeIdWriter& _nodeIdWriter, 
   444 		  const std::string& _id = std::string(),
   445 		  const std::string& _id = std::string(),
   462     EdgeSetWriter(const EdgeSetWriter&);
   463     EdgeSetWriter(const EdgeSetWriter&);
   463     void operator=(const EdgeSetWriter&);
   464     void operator=(const EdgeSetWriter&);
   464 
   465 
   465   public:
   466   public:
   466 
   467 
   467     /// \brief Add a new node map writer command for the writer.
   468     /// \brief Add a new edge map writer command for the writer.
   468     ///
   469     ///
   469     /// Add a new node map writer command for the writer.
   470     /// Add a new edge map writer command for the writer.
   470     template <typename Map>
   471     template <typename Map>
   471     EdgeSetWriter& writeMap(std::string name, const Map& map) {
   472     EdgeSetWriter& writeEdgeMap(std::string name, const Map& map) {
   472       return writeMap<typename Traits::
   473       return writeEdgeMap<typename Traits::
   473 	template Writer<typename Map::Value>, Map>(name, map);
   474 	template Writer<typename Map::Value>, Map>(name, map);
   474     }
   475     }
   475 
   476 
   476     /// \brief Add a new node map writer command for the writer.
   477     /// \brief Add a new edge map writer command for the writer.
   477     ///
   478     ///
   478     /// Add a new node map writer command for the writer.
   479     /// Add a new edge map writer command for the writer.
   479     template <typename Writer, typename Map>
   480     template <typename Writer, typename Map>
   480     EdgeSetWriter& writeMap(std::string name, const Map& map, 
   481     EdgeSetWriter& writeEdgeMap(std::string name, const Map& map, 
   481 			     const Writer& writer = Writer()) {
   482 			    const Writer& writer = Writer()) {
   482       writers.push_back(
   483       writers.push_back(
   483 	make_pair(name, new MapWriter<Item, Map, Writer>(map, writer)));
   484 	make_pair(name, new MapWriter<Item, Map, Writer>(map, writer)));
   484       return *this;
   485       return *this;
   485     }
   486     }
   486 
   487 
   559     MapWriters writers;
   560     MapWriters writers;
   560 
   561 
   561     WriterBase<Item>* idMap;
   562     WriterBase<Item>* idMap;
   562     bool forceIdMap;
   563     bool forceIdMap;
   563    
   564    
   564     const Graph& graph;   
   565     typename SmartConstReference<Graph>::Type graph;   
       
   566     std::string id;
       
   567 
       
   568     std::auto_ptr<IdWriterBase<typename Graph::Node> > nodeIdWriter;
       
   569   };
       
   570 
       
   571   /// \ingroup io_group
       
   572   /// \brief SectionWriter for writing a undirected edgeset.
       
   573   ///
       
   574   /// The lemon format can store multiple undirected edgesets with several 
       
   575   /// maps. The undirected edgeset section's header line is \c \@undiredgeset 
       
   576   /// \c undiredgeset_id, but the \c undiredgeset_id may be empty.
       
   577   ///
       
   578   /// The first line of the section contains the names of the maps separated
       
   579   /// with white spaces. Each next lines describes an undirected edge in the 
       
   580   /// edgeset. The line contains the two connected nodes' id and the mapped 
       
   581   /// values for each undirected map.
       
   582   ///
       
   583   /// The section can handle the directed as a syntactical sugar. Two
       
   584   /// undirected edge map describes one directed edge map. This two maps
       
   585   /// are the forward map and the backward map and the names of this map
       
   586   /// is near the same just with a prefix \c '+' or \c '-' character 
       
   587   /// difference.
       
   588   ///
       
   589   /// If the edgeset contains an \c "id" named map then it will be regarded
       
   590   /// as id map. This map should contain only unique values and when the 
       
   591   /// \c writeId() member will be called with an undirected edge it will 
       
   592   /// write it's id. Otherwise if the \c _forceIdMap constructor parameter
       
   593   /// is true then the id map will be the id in the graph.
       
   594   ///
       
   595   /// The undirected edgeset writer needs a node id writer to identify 
       
   596   /// which nodes have to be connected. If a NodeSetWriter can write the 
       
   597   /// nodes' id, it will be able to use with this class.
       
   598   ///
       
   599   /// \relates LemonWriter
       
   600   template <typename _Graph, typename _Traits = DefaultWriterTraits>
       
   601   class UndirEdgeSetWriter : public CommonSectionWriterBase {
       
   602     typedef CommonSectionWriterBase Parent;
       
   603   public:
       
   604 
       
   605     typedef _Graph Graph;
       
   606     typedef _Traits Traits;
       
   607     typedef typename Graph::UndirEdge Item;
       
   608 
       
   609     /// \brief Constructor.
       
   610     ///
       
   611     /// Constructor for UndirEdgeSetWriter. It creates the UndirEdgeSetWriter
       
   612     /// and attach it into the given LemonWriter. It will write node ids by
       
   613     /// the \c _nodeIdWriter. If the \c _forceIdMap parameter is true 
       
   614     /// then the writer will write own id map if the user does not give 
       
   615     /// "id" named map.
       
   616     template <typename NodeIdWriter>
       
   617     UndirEdgeSetWriter(LemonWriter& _writer, const Graph& _graph, 
       
   618 		       const NodeIdWriter& _nodeIdWriter, 
       
   619 		       const std::string& _id = std::string(),
       
   620 		       bool _forceIdMap = true)
       
   621       : Parent(_writer), idMap(0), forceIdMap(_forceIdMap),
       
   622 	graph(_graph), id(_id),
       
   623 	nodeIdWriter(new IdWriter<typename Graph::Node, NodeIdWriter>
       
   624 		     (_nodeIdWriter)) {} 
       
   625 
       
   626     /// \brief Destructor.
       
   627     ///
       
   628     /// Destructor for UndirEdgeSetWriter.
       
   629     virtual ~UndirEdgeSetWriter() {
       
   630       typename MapWriters::iterator it;
       
   631       for (it = writers.begin(); it != writers.end(); ++it) {
       
   632 	delete it->second;
       
   633       }
       
   634     }
       
   635 
       
   636   private:
       
   637     UndirEdgeSetWriter(const UndirEdgeSetWriter&);
       
   638     void operator=(const UndirEdgeSetWriter&);
       
   639 
       
   640   public:
       
   641 
       
   642     /// \brief Add a new undirected edge map writer command for the writer.
       
   643     ///
       
   644     /// Add a new undirected map writer command for the writer.
       
   645     template <typename Map>
       
   646     UndirEdgeSetWriter& writeUndirEdgeMap(std::string name, const Map& map) {
       
   647       return writeUndirEdgeMap<typename Traits::
       
   648 	template Writer<typename Map::Value>, Map>(name, map);
       
   649     }
       
   650 
       
   651     /// \brief Add a new undirected map writer command for the writer.
       
   652     ///
       
   653     /// Add a new undirected map writer command for the writer.
       
   654     template <typename Writer, typename Map>
       
   655     UndirEdgeSetWriter& writeUndirEdgeMap(std::string name, const Map& map, 
       
   656 					  const Writer& writer = Writer()) {
       
   657       writers.push_back(
       
   658 	make_pair(name, new MapWriter<Item, Map, Writer>(map, writer)));
       
   659       return *this;
       
   660     }
       
   661 
       
   662     /// \brief Add a new directed edge map writer command for the writer.
       
   663     ///
       
   664     /// Add a new directed map writer command for the writer.
       
   665     template <typename Map>
       
   666     UndirEdgeSetWriter& writeEdgeMap(std::string name, const Map& map) {
       
   667       writeUndirEdgeMap("+" + name, composeMap(forwardMap(graph), map));
       
   668       writeUndirEdgeMap("-" + name, composeMap(backwardMap(graph), map));
       
   669       return *this;
       
   670     }
       
   671 
       
   672     /// \brief Add a new directed map writer command for the writer.
       
   673     ///
       
   674     /// Add a new directed map writer command for the writer.
       
   675     template <typename Writer, typename Map>
       
   676     UndirEdgeSetWriter& writeEdgeMap(std::string name, const Map& map, 
       
   677 				     const Writer& writer = Writer()) {
       
   678       writeUndirEdge("+" + name, composeMap(forwardMap(graph), map), writer);
       
   679       writeUndirEdge("-" + name, composeMap(forwardMap(graph), map), writer);
       
   680       return *this;
       
   681     }
       
   682 
       
   683   protected:
       
   684 
       
   685     /// \brief The header of the section.
       
   686     ///
       
   687     /// It gives back the header of the section.
       
   688     virtual std::string header() {
       
   689       return "@undiredgeset " + id;
       
   690     }
       
   691 
       
   692     /// \brief  Writer function of the section.
       
   693     ///
       
   694     /// Write the content of the section.
       
   695     virtual void write(std::ostream& os) {
       
   696       for (int i = 0; i < (int)writers.size(); ++i) {
       
   697 	if (writers[i].first == "id") {
       
   698 	  idMap = writers[i].second;
       
   699 	  forceIdMap = false;
       
   700 	  break;
       
   701 	}
       
   702       }
       
   703       os << "\t\t";
       
   704       if (forceIdMap) {
       
   705 	os << "id\t";
       
   706       }
       
   707       for (int i = 0; i < (int)writers.size(); ++i) {
       
   708 	os << writers[i].first << '\t';
       
   709       }
       
   710       os << std::endl;
       
   711       for (typename Graph::UndirEdgeIt it(graph); it != INVALID; ++it) {
       
   712 	nodeIdWriter->write(os, graph.source(it));
       
   713 	os << '\t';
       
   714 	nodeIdWriter->write(os, graph.target(it));
       
   715 	os << '\t';
       
   716 	if (forceIdMap) {
       
   717 	  os << graph.id(it) << '\t';
       
   718 	}
       
   719 	for (int i = 0; i < (int)writers.size(); ++i) {
       
   720 	  writers[i].second->write(os, it);
       
   721 	  os << '\t';
       
   722 	}
       
   723 	os << std::endl;
       
   724       }
       
   725     }
       
   726 
       
   727   public:
       
   728 
       
   729     /// \brief Returns true if the undirected edgeset can write the ids of 
       
   730     /// the edges.
       
   731     ///
       
   732     /// Returns true if the undirected edgeset can write the ids of the 
       
   733     /// undirected edges. It is possible only if an "id" named map was 
       
   734     /// written or the \c _forceIdMap constructor parameter was true.
       
   735     bool isIdWriter() const {
       
   736       return forceIdMap || idMap != 0;
       
   737     }
       
   738 
       
   739     /// \brief Write the id of the given undirected edge.
       
   740     ///
       
   741     /// It writes the id of the given undirected edge. If there was written 
       
   742     /// an "id" named map then it will write the map value belongs to the 
       
   743     /// undirected edge. Otherwise if the \c forceId parameter was true it 
       
   744     /// will write its id in the graph. 
       
   745     void writeId(std::ostream& os, const Item& item) const {
       
   746       if (forceIdMap) {
       
   747 	os << graph.id(item);
       
   748       } else {
       
   749 	idMap->write(os, item);
       
   750       }
       
   751     } 
       
   752 
       
   753   private:
       
   754 
       
   755     typedef std::vector<std::pair<std::string, WriterBase<Item>*> > MapWriters;
       
   756     MapWriters writers;
       
   757 
       
   758     WriterBase<Item>* idMap;
       
   759     bool forceIdMap;
       
   760    
       
   761     typename SmartConstReference<Graph>::Type graph;   
   565     std::string id;
   762     std::string id;
   566 
   763 
   567     std::auto_ptr<IdWriterBase<typename Graph::Node> > nodeIdWriter;
   764     std::auto_ptr<IdWriterBase<typename Graph::Node> > nodeIdWriter;
   568   };
   765   };
   569 
   766 
   615 
   812 
   616   protected:
   813   protected:
   617 
   814 
   618     /// \brief Header checking function.
   815     /// \brief Header checking function.
   619     ///
   816     ///
   620     /// It gives back true when the header line start with \c @nodes,
   817     /// It gives back true when the header line start with \c \@nodes,
   621     /// and the header line's id and the writer's id are the same.
   818     /// and the header line's id and the writer's id are the same.
   622     virtual std::string header() {
   819     virtual std::string header() {
   623       return "@nodes " + id;
   820       return "@nodes " + id;
   624     }
   821     }
   625 
   822 
   642     ItemWriters writers;
   839     ItemWriters writers;
   643     std::auto_ptr<IdWriterBase<Item> > idWriter;
   840     std::auto_ptr<IdWriterBase<Item> > idWriter;
   644   };
   841   };
   645 
   842 
   646   /// \ingroup io_group
   843   /// \ingroup io_group
   647   /// \brief SectionWriter for writeing labeled edges.
   844   /// \brief SectionWriter for writing labeled edges.
   648   ///
   845   ///
   649   /// The edges section's header line is \c \@edges \c edges_id, but the
   846   /// The edges section's header line is \c \@edges \c edges_id, but the
   650   /// \c edges_id may be empty.
   847   /// \c edges_id may be empty.
   651   ///
   848   ///
   652   /// Each line in the section contains the label of the edge and 
   849   /// Each line in the section contains the label of the edge and 
   679     EdgeWriter(const EdgeWriter&);
   876     EdgeWriter(const EdgeWriter&);
   680     void operator=(const EdgeWriter&);
   877     void operator=(const EdgeWriter&);
   681 
   878 
   682   public:
   879   public:
   683 
   880 
   684     /// \brief Add an edge writer command for the NodeWriter.
   881     /// \brief Add an edge writer command for the EdgeWriter.
   685     ///
   882     ///
   686     /// Add an edge writer command for the NodeWriter.
   883     /// Add an edge writer command for the EdgeWriter.
   687     void writeEdge(const std::string& name, const Item& item) {
   884     void writeEdge(const std::string& name, const Item& item) {
   688       writers.push_back(make_pair(name, &item));
   885       writers.push_back(make_pair(name, &item));
   689     }
   886     }
   690 
   887 
   691   protected:
   888   protected:
   692 
   889 
   693     /// \brief Header checking function.
   890     /// \brief Header checking function.
   694     ///
   891     ///
   695     /// It gives back true when the header line start with \c @nodes,
   892     /// It gives back true when the header line start with \c \@edges,
       
   893     /// and the header line's id and the writer's id are the same.
       
   894     virtual std::string header() {
       
   895       return "@edges " + id;
       
   896     }
       
   897 
       
   898     /// \brief  Writer function of the section.
       
   899     ///
       
   900     /// Write the content of the section.
       
   901     virtual void write(std::ostream& os) {
       
   902       for (int i = 0; i < (int)writers.size(); ++i) {
       
   903 	os << writers[i].first << ' ';
       
   904 	idWriter->write(os, *(writers[i].second));
       
   905 	os << std::endl;
       
   906       }
       
   907     }
       
   908     
       
   909   private:
       
   910 
       
   911     std::string id;
       
   912 
       
   913     typedef std::vector<std::pair<std::string, const Item*> > ItemWriters;
       
   914     ItemWriters writers;
       
   915 
       
   916     std::auto_ptr<IdWriterBase<Item> > idWriter;
       
   917   };
       
   918 
       
   919   /// \ingroup io_group
       
   920   /// \brief SectionWriter for writing labeled undirected edges.
       
   921   ///
       
   922   /// The undirected edges section's header line is \c \@undiredges 
       
   923   /// \c undiredges_id, but the \c undiredges_id may be empty.
       
   924   ///
       
   925   /// Each line in the section contains the label of the undirected edge and 
       
   926   /// then the undirected edge id. 
       
   927   ///
       
   928   /// \relates LemonWriter
       
   929   template <typename _Graph>
       
   930   class UndirEdgeWriter : public CommonSectionWriterBase {
       
   931     typedef CommonSectionWriterBase Parent;
       
   932     typedef _Graph Graph;
       
   933     typedef typename Graph::UndirEdge Item;
       
   934   public:
       
   935     
       
   936     /// \brief Constructor.
       
   937     ///
       
   938     /// Constructor for UndirEdgeWriter. It creates the UndirEdgeWriter and
       
   939     /// attach it into the given LemonWriter. The given \c _IdWriter
       
   940     /// will write the undirected edges' id what can be an undirected 
       
   941     /// edgeset writer.
       
   942     template <typename _IdWriter>
       
   943     UndirEdgeWriter(LemonWriter& _writer, const _IdWriter& _idWriter, 
       
   944 	       const std::string& _id = std::string()) 
       
   945       : Parent(_writer), id(_id), 
       
   946 	idWriter(new IdWriter<typename Graph::UndirEdge, _IdWriter>
       
   947 		 (_idWriter)) {} 
       
   948 
       
   949     /// \brief Destructor.
       
   950     ///
       
   951     /// Destructor for UndirEdgeWriter.
       
   952     virtual ~UndirEdgeWriter() {}
       
   953   private:
       
   954     UndirEdgeWriter(const UndirEdgeWriter&);
       
   955     void operator=(const UndirEdgeWriter&);
       
   956 
       
   957   public:
       
   958 
       
   959     /// \brief Add an undirected edge writer command for the UndirEdgeWriter.
       
   960     ///
       
   961     /// Add an edge writer command for the UndirEdgeWriter.
       
   962     void writeUndirEdge(const std::string& name, const Item& item) {
       
   963       writers.push_back(make_pair(name, &item));
       
   964     }
       
   965 
       
   966   protected:
       
   967 
       
   968     /// \brief Header checking function.
       
   969     ///
       
   970     /// It gives back true when the header line start with \c \@undiredges,
   696     /// and the header line's id and the writer's id are the same.
   971     /// and the header line's id and the writer's id are the same.
   697     virtual std::string header() {
   972     virtual std::string header() {
   698       return "@edges " + id;
   973       return "@edges " + id;
   699     }
   974     }
   700 
   975