2 * lemon/graph_reader.h - Part of LEMON, a generic C++ optimization library
4 * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
5 * (Egervary Research Group on Combinatorial Optimization, EGRES).
7 * Permission to use, modify and distribute this software is granted
8 * provided that this copyright notice appears in all copies. For
9 * precise terms see the accompanying LICENSE file.
11 * This software is provided "AS IS" with no warranty of any kind,
12 * express or implied, and with no claim as to its suitability for any
19 ///\brief Lemon Graph Format reader.
21 #ifndef LEMON_GRAPH_READER_H
22 #define LEMON_GRAPH_READER_H
26 #include <lemon/error.h>
27 #include <lemon/lemon_reader.h>
31 /// \addtogroup io_group
34 /// \brief The graph reader class.
36 /// The \c GraphReader class provides the graph input.
37 /// Before you read this documentation it might be useful to read the general
38 /// description of \ref graph-io-page "Graph Input-Output".
39 /// If you don't need very sophisticated
40 /// behaviour then you can use the versions of the public function
41 /// \ref readGraph() to read a graph (or a max flow instance etc).
43 /// The given file format may contain several maps and labeled nodes or
46 /// If you read a graph you need not read all the maps and items just those
47 /// that you need. The interface of the \c GraphReader is very similar to
48 /// the GraphWriter but the reading method does not depend on the order the
51 /// The reader object suppose that each not readed value does not contain
52 /// whitespaces, therefore it has some extra possibilities to control how
53 /// it should skip the values when the string representation contains spaces.
56 /// GraphReader<ListGraph> reader(std::cin, graph);
59 /// The \c readNodeMap() function reads a map from the \c \@nodeset section.
60 /// If there is a map that you do not want to read from the file and there is
61 /// whitespace in the string represenation of the values then you should
62 /// call the \c skipNodeMap() template member function with proper
66 /// reader.readNodeMap("coords", coords);
68 /// reader.readNodeMap<QuotedStringReader>("label", labelMap);
69 /// reader.skipNodeMap<QuotedStringReader>("description");
71 /// reader.readNodeMap("color", colorMap);
74 /// With the \c readEdgeMap() member function you can give an edge map
75 /// reading command similar to the NodeMaps.
78 /// reader.readEdgeMap("weight", weightMap);
79 /// reader.readEdgeMap("label", labelMap);
82 /// With \c readNode() and \c readEdge() functions you can read
83 /// labeled Nodes and Edges.
86 /// reader.readNode("source", sourceNode);
87 /// reader.readNode("target", targetNode);
89 /// reader.readEdge("observed", edge);
92 /// With the \c readAttribute() functions you can read an attribute
93 /// in a variable. You can specify the reader for the attribute as
96 /// After you give all read commands you must call the \c run() member
97 /// function, which execute all the commands.
103 /// \see DefaultReaderTraits
104 /// \see QuotedStringReader
105 /// \see \ref GraphWriter
106 /// \see \ref graph-io-page
107 /// \author Balazs Dezso
108 template <typename _Graph, typename _ReaderTraits = DefaultReaderTraits>
112 typedef _Graph Graph;
113 typedef typename Graph::Node Node;
114 typedef typename Graph::Edge Edge;
116 typedef _ReaderTraits ReaderTraits;
117 typedef typename ReaderTraits::Skipper DefaultSkipper;
119 /// \brief Construct a new GraphReader.
121 /// Construct a new GraphReader. It reads into the given graph
122 /// and it use the given reader as the default skipper.
123 GraphReader(std::istream& _is,
124 typename SmartParameter<Graph>::Type _graph,
125 const DefaultSkipper& _skipper = DefaultSkipper())
126 : reader(new LemonReader(_is)), own_reader(true), skipper(_skipper),
127 nodeset_reader(*reader, _graph, std::string(), skipper),
128 edgeset_reader(*reader, _graph, nodeset_reader,
129 std::string(), skipper),
130 node_reader(*reader, nodeset_reader, std::string()),
131 edge_reader(*reader, edgeset_reader, std::string()),
132 attribute_reader(*reader, std::string()) {}
134 /// \brief Construct a new GraphReader.
136 /// Construct a new GraphReader. It reads into the given graph
137 /// and it use the given reader as the default skipper.
138 GraphReader(const std::string& _filename,
139 typename SmartParameter<Graph>::Type _graph,
140 const DefaultSkipper& _skipper = DefaultSkipper())
141 : reader(new LemonReader(_filename)), own_reader(true),
143 nodeset_reader(*reader, _graph, std::string(), skipper),
144 edgeset_reader(*reader, _graph, nodeset_reader,
145 std::string(), skipper),
146 node_reader(*reader, nodeset_reader, std::string()),
147 edge_reader(*reader, edgeset_reader, std::string()),
148 attribute_reader(*reader, std::string()) {}
150 /// \brief Construct a new GraphReader.
152 /// Construct a new GraphReader. It reads into the given graph
153 /// and it use the given reader as the default skipper.
154 GraphReader(LemonReader& _reader,
155 typename SmartParameter<Graph>::Type _graph,
156 const DefaultSkipper& _skipper = DefaultSkipper())
157 : reader(_reader), own_reader(false), skipper(_skipper),
158 nodeset_reader(*reader, _graph, std::string(), skipper),
159 edgeset_reader(*reader, _graph, nodeset_reader,
160 std::string(), skipper),
161 node_reader(*reader, nodeset_reader, std::string()),
162 edge_reader(*reader, edgeset_reader, std::string()),
163 attribute_reader(*reader, std::string()) {}
165 /// \brief Destruct the graph reader.
167 /// Destruct the graph reader.
173 /// \brief Add a new node map reader command for the reader.
175 /// Add a new node map reader command for the reader.
176 template <typename Map>
177 GraphReader& readNodeMap(std::string name, Map& map) {
178 nodeset_reader.readNodeMap(name, map);
182 template <typename Map>
183 GraphReader& readNodeMap(std::string name, const Map& map) {
184 nodeset_reader.readNodeMap(name, map);
188 /// \brief Add a new node map reader command for the reader.
190 /// Add a new node map reader command for the reader.
191 template <typename Reader, typename Map>
192 GraphReader& readNodeMap(std::string name, Map& map,
193 const Reader& reader = Reader()) {
194 nodeset_reader.readNodeMap(name, map, reader);
198 template <typename Reader, typename Map>
199 GraphReader& readNodeMap(std::string name, const Map& map,
200 const Reader& reader = Reader()) {
201 nodeset_reader.readNodeMap(name, map, reader);
205 /// \brief Add a new node map skipper command for the reader.
207 /// Add a new node map skipper command for the reader.
208 template <typename Reader>
209 GraphReader& skipNodeMap(std::string name,
210 const Reader& reader = Reader()) {
211 nodeset_reader.skipNodeMap(name, reader);
215 /// \brief Add a new edge map reader command for the reader.
217 /// Add a new edge map reader command for the reader.
218 template <typename Map>
219 GraphReader& readEdgeMap(std::string name, Map& map) {
220 edgeset_reader.readEdgeMap(name, map);
224 template <typename Map>
225 GraphReader& readEdgeMap(std::string name, const Map& map) {
226 edgeset_reader.readEdgeMap(name, map);
231 /// \brief Add a new edge map reader command for the reader.
233 /// Add a new edge map reader command for the reader.
234 template <typename Reader, typename Map>
235 GraphReader& readEdgeMap(std::string name, Map& map,
236 const Reader& reader = Reader()) {
237 edgeset_reader.readEdgeMap(name, map, reader);
241 template <typename Reader, typename Map>
242 GraphReader& readEdgeMap(std::string name, const Map& map,
243 const Reader& reader = Reader()) {
244 edgeset_reader.readEdgeMap(name, map, reader);
248 /// \brief Add a new edge map skipper command for the reader.
250 /// Add a new edge map skipper command for the reader.
251 template <typename Reader>
252 GraphReader& skipEdgeMap(std::string name,
253 const Reader& reader = Reader()) {
254 edgeset_reader.skipEdgeMap(name, reader);
258 /// \brief Add a new labeled node reader for the reader.
260 /// Add a new labeled node reader for the reader.
261 GraphReader& readNode(std::string name, Node& node) {
262 node_reader.readNode(name, node);
266 /// \brief Add a new labeled edge reader for the reader.
268 /// Add a new labeled edge reader for the reader.
269 GraphReader& readEdge(std::string name, Edge& edge) {
270 edge_reader.readEdge(name, edge);
274 /// \brief Add a new attribute reader command.
276 /// Add a new attribute reader command.
277 template <typename Value>
278 GraphReader& readAttribute(std::string name, Value& value) {
279 attribute_reader.readAttribute(name, value);
283 /// \brief Add a new attribute reader command.
285 /// Add a new attribute reader command.
286 template <typename Reader, typename Value>
287 GraphReader& readAttribute(std::string name, Value& value,
288 const Reader& reader) {
289 attribute_reader.readAttribute<Reader>(name, value, reader);
293 /// \brief Conversion operator to LemonReader.
295 /// Conversion operator to LemonReader. It make possible
296 /// to access the encapsulated \e LemonReader, this way
297 /// you can attach to this reader new instances of
298 /// \e LemonReader::SectionReader.
299 operator LemonReader&() {
303 /// \brief Executes the reader commands.
305 /// Executes the reader commands.
310 /// \brief Gives back the node by its id.
312 /// It reads an id from the stream and gives back which node belongs to
313 /// it. It is possible only if there was read an "id" named node map.
314 Node readId(std::istream& is, Node) const {
315 return nodeset_reader.readId(is, Node());
318 /// \brief Gives back the edge by its id.
320 /// It reads an id from the stream and gives back which edge belongs to
321 /// it. It is possible only if there was read an "id" named edge map.
322 Edge readId(std::istream& is, Edge) const {
323 return edgeset_reader.readId(is, Edge());
331 DefaultSkipper skipper;
333 NodeSetReader<Graph, ReaderTraits> nodeset_reader;
334 EdgeSetReader<Graph, ReaderTraits> edgeset_reader;
336 NodeReader<Graph> node_reader;
337 EdgeReader<Graph> edge_reader;
339 AttributeReader<ReaderTraits> attribute_reader;
343 ///\anchor readGraph()
345 /// \brief Read a graph from an input stream.
347 /// Read a graph from an input stream.
348 /// \param is The input stream.
349 /// \param g The graph.
350 template<typename Graph>
351 void readGraph(std::istream& is, Graph &g) {
352 GraphReader<Graph> reader(is, g);
356 /// \brief Read a capacitated graph instance from an input stream.
358 /// Read a capacitated graph (graph+capacity on the
359 /// edges) from an input stream.
360 /// \param is The input stream.
361 /// \param g The graph.
362 /// \param capacity The capacity map.
363 template<typename Graph, typename CapacityMap>
364 void readGraph(std::istream& is, Graph &g, CapacityMap& capacity) {
365 GraphReader<Graph> reader(is, g);
366 reader.readEdgeMap("capacity", capacity);
370 /// \brief Read a shortest path instance from an input stream.
372 /// Read a shortest path instance (graph+capacity on the
373 /// edges+designated source) from an input stream.
374 /// \param is The input stream.
375 /// \param g The graph.
376 /// \param capacity The capacity map.
377 /// \param s The source node.
378 template<typename Graph, typename CapacityMap>
379 void readGraph(std::istream& is, Graph &g, CapacityMap& capacity,
380 typename Graph::Node &s) {
381 GraphReader<Graph> reader(is, g);
382 reader.readEdgeMap("capacity", capacity);
383 reader.readNode("source", s);
389 /// \brief Read a max flow instance from an input stream.
391 /// Read a max flow instance (graph+capacity on the
392 /// edges+designated source and target) from an input stream.
394 /// \param is The input stream.
395 /// \param g The graph.
396 /// \param capacity The capacity map.
397 /// \param s The source node.
398 /// \param t The target node.
399 template<typename Graph, typename CapacityMap>
400 void readGraph(std::istream& is, Graph &g, CapacityMap& capacity,
401 typename Graph::Node &s, typename Graph::Node &t) {
402 GraphReader<Graph> reader(is, g);
403 reader.readEdgeMap("capacity", capacity);
404 reader.readNode("source", s);
405 reader.readNode("target", t);
409 /// \brief Read a min cost flow instance from an input stream.
411 /// Read a min cost flow instance (graph+capacity on the edges+cost
412 /// function on the edges+designated source and target) from an input stream.
414 /// \param is The input stream.
415 /// \param g The graph.
416 /// \param capacity The capacity map.
417 /// \param s The source node.
418 /// \param t The target node.
419 /// \param cost The cost map.
420 template<typename Graph, typename CapacityMap, typename CostMap>
421 void readGraph(std::istream& is, Graph &g, CapacityMap& capacity,
422 typename Graph::Node &s, typename Graph::Node &t,
424 GraphReader<Graph> reader(is, g);
425 reader.readEdgeMap("capacity", capacity);
426 reader.readEdgeMap("cost", cost);
427 reader.readNode("source", s);
428 reader.readNode("target", t);
433 /// \brief The undir graph reader class.
435 /// The given file format may contain several maps and labeled nodes or
438 /// If you read a graph you need not read all the maps and items just those
439 /// that you need. The interface of the \c GraphReader is very similar to
440 /// the GraphWriter but the reading method does not depend on the order the
443 /// The reader object suppose that each not readed value does not contain
444 /// whitespaces, therefore it has some extra possibilities to control how
445 /// it should skip the values when the string representation contains spaces.
448 /// UndirGraphReader<UndirListGraph> reader(std::cin, graph);
451 /// The \c readNodeMap() function reads a map from the \c \@nodeset section.
452 /// If there is a map that you do not want to read from the file and there is
453 /// whitespace in the string represenation of the values then you should
454 /// call the \c skipNodeMap() template member function with proper
458 /// reader.readNodeMap("coords", coords);
460 /// reader.readNodeMap<QuotedStringReader>("label", labelMap);
461 /// reader.skipNodeMap<QuotedStringReader>("description");
463 /// reader.readNodeMap("color", colorMap);
466 /// With the \c readUndirEdgeMap() member function you can give an
467 /// undir edge map reading command similar to the NodeMaps.
470 /// reader.readUndirEdgeMap("capacity", capacityMap);
473 /// The reading of the directed edge maps is just a syntactical sugar.
474 /// It reads two undirected edgemaps into a directed edge map. The
475 /// undirected edge maps' name should be start with the \c '+' and the
476 /// \c '-' character and the same.
479 /// reader.readEdgeMap("flow", flowMap);
482 /// With \c readNode() and \c readUndirEdge() functions you can read
483 /// labeled Nodes and UndirEdges.
486 /// reader.readNode("source", sourceNode);
487 /// reader.readNode("target", targetNode);
489 /// reader.readUndirEdge("observed", undirEdge);
492 /// With the \c readAttribute() functions you can read an attribute
493 /// in a variable. You can specify the reader for the attribute as
496 /// After you give all read commands you must call the \c run() member
497 /// function, which execute all the commands.
504 /// \see DefaultReaderTraits
505 /// \see \ref UndirGraphWriter
506 /// \see \ref graph-io-page
508 /// \author Balazs Dezso
509 template <typename _Graph, typename _ReaderTraits = DefaultReaderTraits>
510 class UndirGraphReader {
513 typedef _Graph Graph;
514 typedef typename Graph::Node Node;
515 typedef typename Graph::Edge Edge;
516 typedef typename Graph::UndirEdge UndirEdge;
518 typedef _ReaderTraits ReaderTraits;
519 typedef typename ReaderTraits::Skipper DefaultSkipper;
521 /// \brief Construct a new UndirGraphReader.
523 /// Construct a new UndirGraphReader. It reads into the given graph
524 /// and it use the given reader as the default skipper.
525 UndirGraphReader(std::istream& _is, Graph& _graph,
526 const DefaultSkipper& _skipper = DefaultSkipper())
527 : reader(new LemonReader(_is)), own_reader(true), skipper(_skipper),
528 nodeset_reader(*reader, _graph, std::string(), skipper),
529 undir_edgeset_reader(*reader, _graph, nodeset_reader,
530 std::string(), skipper),
531 node_reader(*reader, nodeset_reader, std::string()),
532 undir_edge_reader(*reader, undir_edgeset_reader, std::string()),
533 attribute_reader(*reader, std::string()) {}
535 /// \brief Construct a new UndirGraphReader.
537 /// Construct a new UndirGraphReader. It reads into the given graph
538 /// and it use the given reader as the default skipper.
539 UndirGraphReader(const std::string& _filename, Graph& _graph,
540 const DefaultSkipper& _skipper = DefaultSkipper())
541 : reader(new LemonReader(_filename)), own_reader(true),
543 nodeset_reader(*reader, _graph, std::string(), skipper),
544 undir_edgeset_reader(*reader, _graph, nodeset_reader,
545 std::string(), skipper),
546 node_reader(*reader, nodeset_reader, std::string()),
547 undir_edge_reader(*reader, undir_edgeset_reader, std::string()),
548 attribute_reader(*reader, std::string()) {}
550 /// \brief Construct a new UndirGraphReader.
552 /// Construct a new UndirGraphReader. It reads into the given graph
553 /// and it use the given reader as the default skipper.
554 UndirGraphReader(LemonReader& _reader, Graph& _graph,
555 const DefaultSkipper& _skipper = DefaultSkipper())
556 : reader(_reader), own_reader(false), skipper(_skipper),
557 nodeset_reader(*reader, _graph, std::string(), skipper),
558 undir_edgeset_reader(*reader, _graph, nodeset_reader,
559 std::string(), skipper),
560 node_reader(*reader, nodeset_reader, std::string()),
561 undir_edge_reader(*reader, undir_edgeset_reader, std::string()),
562 attribute_reader(*reader, std::string()) {}
564 /// \brief Destruct the graph reader.
566 /// Destruct the graph reader.
567 ~UndirGraphReader() {
572 /// \brief Add a new node map reader command for the reader.
574 /// Add a new node map reader command for the reader.
575 template <typename Map>
576 UndirGraphReader& readNodeMap(std::string name, Map& map) {
577 nodeset_reader.readNodeMap(name, map);
581 template <typename Map>
582 UndirGraphReader& readNodeMap(std::string name, const Map& map) {
583 nodeset_reader.readNodeMap(name, map);
587 /// \brief Add a new node map reader command for the reader.
589 /// Add a new node map reader command for the reader.
590 template <typename Reader, typename Map>
591 UndirGraphReader& readNodeMap(std::string name, Map& map,
592 const Reader& reader = Reader()) {
593 nodeset_reader.readNodeMap(name, map, reader);
597 template <typename Reader, typename Map>
598 UndirGraphReader& readNodeMap(std::string name, const Map& map,
599 const Reader& reader = Reader()) {
600 nodeset_reader.readNodeMap(name, map, reader);
604 /// \brief Add a new node map skipper command for the reader.
606 /// Add a new node map skipper command for the reader.
607 template <typename Reader>
608 UndirGraphReader& skipNodeMap(std::string name,
609 const Reader& reader = Reader()) {
610 nodeset_reader.skipNodeMap(name, reader);
614 /// \brief Add a new undirected edge map reader command for the reader.
616 /// Add a new undirected edge map reader command for the reader.
617 template <typename Map>
618 UndirGraphReader& readUndirEdgeMap(std::string name, Map& map) {
619 undir_edgeset_reader.readUndirEdgeMap(name, map);
623 template <typename Map>
624 UndirGraphReader& readUndirEdgeMap(std::string name, const Map& map) {
625 undir_edgeset_reader.readUndirEdgeMap(name, map);
630 /// \brief Add a new undirected edge map reader command for the reader.
632 /// Add a new undirected edge map reader command for the reader.
633 template <typename Reader, typename Map>
634 UndirGraphReader& readUndirEdgeMap(std::string name, Map& map,
635 const Reader& reader = Reader()) {
636 undir_edgeset_reader.readUndirEdgeMap(name, map, reader);
640 template <typename Reader, typename Map>
641 UndirGraphReader& readUndirEdgeMap(std::string name, const Map& map,
642 const Reader& reader = Reader()) {
643 undir_edgeset_reader.readUndirEdgeMap(name, map, reader);
647 /// \brief Add a new undirected edge map skipper command for the reader.
649 /// Add a new undirected edge map skipper command for the reader.
650 template <typename Reader>
651 UndirGraphReader& skipUndirEdgeMap(std::string name,
652 const Reader& reader = Reader()) {
653 undir_edgeset_reader.skipUndirMap(name, reader);
658 /// \brief Add a new edge map reader command for the reader.
660 /// Add a new edge map reader command for the reader.
661 template <typename Map>
662 UndirGraphReader& readEdgeMap(std::string name, Map& map) {
663 undir_edgeset_reader.readEdgeMap(name, map);
667 template <typename Map>
668 UndirGraphReader& readEdgeMap(std::string name, const Map& map) {
669 undir_edgeset_reader.readEdgeMap(name, map);
674 /// \brief Add a new edge map reader command for the reader.
676 /// Add a new edge map reader command for the reader.
677 template <typename Reader, typename Map>
678 UndirGraphReader& readEdgeMap(std::string name, Map& map,
679 const Reader& reader = Reader()) {
680 undir_edgeset_reader.readEdgeMap(name, map, reader);
684 template <typename Reader, typename Map>
685 UndirGraphReader& readEdgeMap(std::string name, const Map& map,
686 const Reader& reader = Reader()) {
687 undir_edgeset_reader.readEdgeMap(name, map, reader);
691 /// \brief Add a new edge map skipper command for the reader.
693 /// Add a new edge map skipper command for the reader.
694 template <typename Reader>
695 UndirGraphReader& skipEdgeMap(std::string name,
696 const Reader& reader = Reader()) {
697 undir_edgeset_reader.skipEdgeMap(name, reader);
701 /// \brief Add a new labeled node reader for the reader.
703 /// Add a new labeled node reader for the reader.
704 UndirGraphReader& readNode(std::string name, Node& node) {
705 node_reader.readNode(name, node);
709 /// \brief Add a new labeled edge reader for the reader.
711 /// Add a new labeled edge reader for the reader.
712 UndirGraphReader& readEdge(std::string name, Edge& edge) {
713 undir_edge_reader.readEdge(name, edge);
716 /// \brief Add a new labeled undirected edge reader for the reader.
718 /// Add a new labeled undirected edge reader for the reader.
719 UndirGraphReader& readUndirEdge(std::string name, UndirEdge& edge) {
720 undir_edge_reader.readUndirEdge(name, edge);
723 /// \brief Add a new attribute reader command.
725 /// Add a new attribute reader command.
726 template <typename Value>
727 UndirGraphReader& readAttribute(std::string name, Value& value) {
728 attribute_reader.readAttribute(name, value);
732 /// \brief Add a new attribute reader command.
734 /// Add a new attribute reader command.
735 template <typename Reader, typename Value>
736 UndirGraphReader& readAttribute(std::string name, Value& value,
737 const Reader& reader) {
738 attribute_reader.readAttribute<Reader>(name, value, reader);
742 /// \brief Conversion operator to LemonReader.
744 /// Conversion operator to LemonReader. It make possible
745 /// to access the encapsulated \e LemonReader, this way
746 /// you can attach to this reader new instances of
747 /// \e LemonReader::SectionReader.
748 operator LemonReader&() {
752 /// \brief Executes the reader commands.
754 /// Executes the reader commands.
759 /// \brief Gives back the node by its id.
761 /// It reads an id from the stream and gives back which node belongs to
762 /// it. It is possible only if there was read an "id" named node map.
763 Node readId(std::istream& is, Node) const {
764 return nodeset_reader.readId(is, Node());
767 /// \brief Gives back the edge by its id.
769 /// It reads an id from the stream and gives back which edge belongs to
770 /// it. It is possible only if there was read an "id" named edge map.
771 Edge readId(std::istream& is, Edge) const {
772 return undir_edgeset_reader.readId(is, Edge());
775 /// \brief Gives back the undirected edge by its id.
777 /// It reads an id from the stream and gives back which undirected edge
778 /// belongs to it. It is possible only if there was read an "id" named
780 UndirEdge readId(std::istream& is, UndirEdge) const {
781 return undir_edgeset_reader.readId(is, UndirEdge());
790 DefaultSkipper skipper;
792 NodeSetReader<Graph, ReaderTraits> nodeset_reader;
793 UndirEdgeSetReader<Graph, ReaderTraits> undir_edgeset_reader;
795 NodeReader<Graph> node_reader;
796 UndirEdgeReader<Graph> undir_edge_reader;
798 AttributeReader<ReaderTraits> attribute_reader;
801 /// \brief Read an undirected graph from an input stream.
803 /// Read an undirected graph from an input stream.
804 /// \param is The input stream.
805 /// \param g The graph.
806 template<typename Graph>
807 void readUndirGraph(std::istream& is, Graph &g) {
808 UndirGraphReader<Graph> reader(is, g);
812 /// \brief Read an undirected multigraph (undirected graph + capacity
813 /// map on the edges) from an input stream.
815 /// Read an undirected multigraph (undirected graph + capacity
816 /// map on the edges) from an input stream.
817 /// \param is The input stream.
818 /// \param g The graph.
819 /// \param capacity The capacity map.
820 template<typename Graph, typename CapacityMap>
821 void readUndirGraph(std::istream& is, Graph &g, CapacityMap& capacity) {
822 UndirGraphReader<Graph> reader(is, g);
823 reader.readUndirEdgeMap("capacity", capacity);