diff -r 939ee6d1e525 -r b84e68af8248 lemon/lgf_writer.h --- a/lemon/lgf_writer.h Tue Nov 16 08:19:11 2010 +0100 +++ b/lemon/lgf_writer.h Thu Nov 25 22:45:29 2010 +0100 @@ -986,7 +986,7 @@ /// \ingroup lemon_io /// - /// \brief \ref lgf-format "LGF" writer for directed graphs + /// \brief \ref lgf-format "LGF" writer for undirected graphs /// /// This utility writes an \ref lgf-format "LGF" file. /// @@ -1042,15 +1042,15 @@ /// \brief Constructor /// - /// Construct a directed graph writer, which writes to the given - /// output stream. + /// Construct an undirected graph writer, which writes to the + /// given output stream. GraphWriter(const GR& graph, std::ostream& os = std::cout) : _os(&os), local_os(false), _graph(graph), _skip_nodes(false), _skip_edges(false) {} /// \brief Constructor /// - /// Construct a directed graph writer, which writes to the given + /// Construct a undirected graph writer, which writes to the given /// output file. GraphWriter(const GR& graph, const std::string& fn) : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph), @@ -1063,7 +1063,7 @@ /// \brief Constructor /// - /// Construct a directed graph writer, which writes to the given + /// Construct a undirected graph writer, which writes to the given /// output file. GraphWriter(const GR& graph, const char* fn) : _os(new std::ofstream(fn)), local_os(true), _graph(graph), @@ -1289,9 +1289,9 @@ return *this; } - /// \brief Add an additional caption to the \c \@arcs section + /// \brief Add an additional caption to the \c \@edges section /// - /// Add an additional caption to the \c \@arcs section. + /// Add an additional caption to the \c \@edges section. GraphWriter& edges(const std::string& caption) { _edges_caption = caption; return *this; @@ -1608,6 +1608,794 @@ return tmp; } + template + class BpGraphWriter; + + template + BpGraphWriter bpGraphWriter(const TBGR& graph, + std::ostream& os = std::cout); + template + BpGraphWriter bpGraphWriter(const TBGR& graph, const std::string& fn); + template + BpGraphWriter bpGraphWriter(const TBGR& graph, const char* fn); + + /// \ingroup lemon_io + /// + /// \brief \ref lgf-format "LGF" writer for undirected bipartite graphs + /// + /// This utility writes an \ref lgf-format "LGF" file. + /// + /// It can be used almost the same way as \c GraphWriter, but it + /// reads the red and blue nodes from separate sections, and these + /// sections can contain different set of maps. + /// + /// The red and blue maps are written to the corresponding + /// sections. The node maps are written to both of these sections + /// with the same map name. + template + class BpGraphWriter { + public: + + typedef BGR BpGraph; + TEMPLATE_BPGRAPH_TYPEDEFS(BGR); + + private: + + + std::ostream* _os; + bool local_os; + + const BGR& _graph; + + std::string _nodes_caption; + std::string _edges_caption; + std::string _attributes_caption; + + typedef std::map NodeIndex; + NodeIndex _node_index; + typedef std::map EdgeIndex; + EdgeIndex _edge_index; + + typedef std::vector* > > NodeMaps; + NodeMaps _red_maps; + NodeMaps _blue_maps; + + typedef std::vector* > >EdgeMaps; + EdgeMaps _edge_maps; + + typedef std::vector > Attributes; + Attributes _attributes; + + bool _skip_nodes; + bool _skip_edges; + + public: + + /// \brief Constructor + /// + /// Construct a bipartite graph writer, which writes to the given + /// output stream. + BpGraphWriter(const BGR& graph, std::ostream& os = std::cout) + : _os(&os), local_os(false), _graph(graph), + _skip_nodes(false), _skip_edges(false) {} + + /// \brief Constructor + /// + /// Construct a bipartite graph writer, which writes to the given + /// output file. + BpGraphWriter(const BGR& graph, const std::string& fn) + : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph), + _skip_nodes(false), _skip_edges(false) { + if (!(*_os)) { + delete _os; + throw IoError("Cannot write file", fn); + } + } + + /// \brief Constructor + /// + /// Construct a bipartite graph writer, which writes to the given + /// output file. + BpGraphWriter(const BGR& graph, const char* fn) + : _os(new std::ofstream(fn)), local_os(true), _graph(graph), + _skip_nodes(false), _skip_edges(false) { + if (!(*_os)) { + delete _os; + throw IoError("Cannot write file", fn); + } + } + + /// \brief Destructor + ~BpGraphWriter() { + for (typename NodeMaps::iterator it = _red_maps.begin(); + it != _red_maps.end(); ++it) { + delete it->second; + } + + for (typename NodeMaps::iterator it = _blue_maps.begin(); + it != _blue_maps.end(); ++it) { + delete it->second; + } + + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + delete it->second; + } + + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + delete it->second; + } + + if (local_os) { + delete _os; + } + } + + private: + + template + friend BpGraphWriter bpGraphWriter(const TBGR& graph, + std::ostream& os); + template + friend BpGraphWriter bpGraphWriter(const TBGR& graph, + const std::string& fn); + template + friend BpGraphWriter bpGraphWriter(const TBGR& graph, const char *fn); + + BpGraphWriter(BpGraphWriter& other) + : _os(other._os), local_os(other.local_os), _graph(other._graph), + _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) { + + other._os = 0; + other.local_os = false; + + _node_index.swap(other._node_index); + _edge_index.swap(other._edge_index); + + _red_maps.swap(other._red_maps); + _blue_maps.swap(other._blue_maps); + _edge_maps.swap(other._edge_maps); + _attributes.swap(other._attributes); + + _nodes_caption = other._nodes_caption; + _edges_caption = other._edges_caption; + _attributes_caption = other._attributes_caption; + } + + BpGraphWriter& operator=(const BpGraphWriter&); + + public: + + /// \name Writing Rules + /// @{ + + /// \brief Node map writing rule + /// + /// Add a node map writing rule to the writer. + template + BpGraphWriter& nodeMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* red_storage = + new _writer_bits::MapStorage(map); + _red_maps.push_back(std::make_pair(caption, red_storage)); + _writer_bits::MapStorageBase* blue_storage = + new _writer_bits::MapStorage(map); + _blue_maps.push_back(std::make_pair(caption, blue_storage)); + return *this; + } + + /// \brief Node map writing rule + /// + /// Add a node map writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& nodeMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* red_storage = + new _writer_bits::MapStorage(map, converter); + _red_maps.push_back(std::make_pair(caption, red_storage)); + _writer_bits::MapStorageBase* blue_storage = + new _writer_bits::MapStorage(map, converter); + _blue_maps.push_back(std::make_pair(caption, blue_storage)); + return *this; + } + + /// \brief Red map writing rule + /// + /// Add a red map writing rule to the writer. + template + BpGraphWriter& redMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map); + _red_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Red map writing rule + /// + /// Add a red map writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& redMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map, converter); + _red_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Blue map writing rule + /// + /// Add a blue map writing rule to the writer. + template + BpGraphWriter& blueMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map); + _blue_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Blue map writing rule + /// + /// Add a blue map writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& blueMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map, converter); + _blue_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge map writing rule + /// + /// Add an edge map writing rule to the writer. + template + BpGraphWriter& edgeMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map); + _edge_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge map writing rule + /// + /// Add an edge map writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& edgeMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map, converter); + _edge_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc map writing rule + /// + /// Add an arc map writing rule to the writer. + template + BpGraphWriter& arcMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* forward_storage = + new _writer_bits::GraphArcMapStorage(_graph, map); + _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); + _writer_bits::MapStorageBase* backward_storage = + new _writer_bits::GraphArcMapStorage(_graph, map); + _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); + return *this; + } + + /// \brief Arc map writing rule + /// + /// Add an arc map writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& arcMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* forward_storage = + new _writer_bits::GraphArcMapStorage + (_graph, map, converter); + _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); + _writer_bits::MapStorageBase* backward_storage = + new _writer_bits::GraphArcMapStorage + (_graph, map, converter); + _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); + return *this; + } + + /// \brief Attribute writing rule + /// + /// Add an attribute writing rule to the writer. + template + BpGraphWriter& attribute(const std::string& caption, const Value& value) { + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(value); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Attribute writing rule + /// + /// Add an attribute writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& attribute(const std::string& caption, const Value& value, + const Converter& converter = Converter()) { + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(value, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Node writing rule + /// + /// Add a node writing rule to the writer. + BpGraphWriter& node(const std::string& caption, const Node& node) { + typedef _writer_bits::MapLookUpConverter Converter; + Converter converter(_node_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(node, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge writing rule + /// + /// Add an edge writing rule to writer. + BpGraphWriter& edge(const std::string& caption, const Edge& edge) { + typedef _writer_bits::MapLookUpConverter Converter; + Converter converter(_edge_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(edge, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc writing rule + /// + /// Add an arc writing rule to writer. + BpGraphWriter& arc(const std::string& caption, const Arc& arc) { + typedef _writer_bits::GraphArcLookUpConverter Converter; + Converter converter(_graph, _edge_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(arc, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \name Section Captions + /// @{ + + /// \brief Add an additional caption to the \c \@red_nodes and + /// \c \@blue_nodes section + /// + /// Add an additional caption to the \c \@red_nodes and \c + /// \@blue_nodes section. + BpGraphWriter& nodes(const std::string& caption) { + _nodes_caption = caption; + return *this; + } + + /// \brief Add an additional caption to the \c \@edges section + /// + /// Add an additional caption to the \c \@edges section. + BpGraphWriter& edges(const std::string& caption) { + _edges_caption = caption; + return *this; + } + + /// \brief Add an additional caption to the \c \@attributes section + /// + /// Add an additional caption to the \c \@attributes section. + BpGraphWriter& attributes(const std::string& caption) { + _attributes_caption = caption; + return *this; + } + + /// \name Skipping Section + /// @{ + + /// \brief Skip writing the node set + /// + /// The \c \@red_nodes and \c \@blue_nodes section will not be + /// written to the stream. + BpGraphWriter& skipNodes() { + LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member"); + _skip_nodes = true; + return *this; + } + + /// \brief Skip writing edge set + /// + /// The \c \@edges section will not be written to the stream. + BpGraphWriter& skipEdges() { + LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member"); + _skip_edges = true; + return *this; + } + + /// @} + + private: + + void writeRedNodes() { + _writer_bits::MapStorageBase* label = 0; + for (typename NodeMaps::iterator it = _red_maps.begin(); + it != _red_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + *_os << "@red_nodes"; + if (!_nodes_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _nodes_caption); + } + *_os << std::endl; + + if (label == 0) { + *_os << "label" << '\t'; + } + for (typename NodeMaps::iterator it = _red_maps.begin(); + it != _red_maps.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << '\t'; + } + *_os << std::endl; + + std::vector nodes; + for (RedIt n(_graph); n != INVALID; ++n) { + nodes.push_back(n); + } + + if (label == 0) { + IdMap id_map(_graph); + _writer_bits::MapLess > id_less(id_map); + std::sort(nodes.begin(), nodes.end(), id_less); + } else { + label->sort(nodes); + } + + for (int i = 0; i < static_cast(nodes.size()); ++i) { + Node n = nodes[i]; + if (label == 0) { + std::ostringstream os; + os << _graph.id(n); + _writer_bits::writeToken(*_os, os.str()); + *_os << '\t'; + _node_index.insert(std::make_pair(n, os.str())); + } + for (typename NodeMaps::iterator it = _red_maps.begin(); + it != _red_maps.end(); ++it) { + std::string value = it->second->get(n); + _writer_bits::writeToken(*_os, value); + if (it->first == "label") { + _node_index.insert(std::make_pair(n, value)); + } + *_os << '\t'; + } + *_os << std::endl; + } + } + + void writeBlueNodes() { + _writer_bits::MapStorageBase* label = 0; + for (typename NodeMaps::iterator it = _blue_maps.begin(); + it != _blue_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + *_os << "@blue_nodes"; + if (!_nodes_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _nodes_caption); + } + *_os << std::endl; + + if (label == 0) { + *_os << "label" << '\t'; + } + for (typename NodeMaps::iterator it = _blue_maps.begin(); + it != _blue_maps.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << '\t'; + } + *_os << std::endl; + + std::vector nodes; + for (BlueIt n(_graph); n != INVALID; ++n) { + nodes.push_back(n); + } + + if (label == 0) { + IdMap id_map(_graph); + _writer_bits::MapLess > id_less(id_map); + std::sort(nodes.begin(), nodes.end(), id_less); + } else { + label->sort(nodes); + } + + for (int i = 0; i < static_cast(nodes.size()); ++i) { + Node n = nodes[i]; + if (label == 0) { + std::ostringstream os; + os << _graph.id(n); + _writer_bits::writeToken(*_os, os.str()); + *_os << '\t'; + _node_index.insert(std::make_pair(n, os.str())); + } + for (typename NodeMaps::iterator it = _blue_maps.begin(); + it != _blue_maps.end(); ++it) { + std::string value = it->second->get(n); + _writer_bits::writeToken(*_os, value); + if (it->first == "label") { + _node_index.insert(std::make_pair(n, value)); + } + *_os << '\t'; + } + *_os << std::endl; + } + } + + void createRedNodeIndex() { + _writer_bits::MapStorageBase* label = 0; + for (typename NodeMaps::iterator it = _red_maps.begin(); + it != _red_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + if (label == 0) { + for (NodeIt n(_graph); n != INVALID; ++n) { + std::ostringstream os; + os << _graph.id(n); + _node_index.insert(std::make_pair(n, os.str())); + } + } else { + for (NodeIt n(_graph); n != INVALID; ++n) { + std::string value = label->get(n); + _node_index.insert(std::make_pair(n, value)); + } + } + } + + void createBlueNodeIndex() { + _writer_bits::MapStorageBase* label = 0; + for (typename NodeMaps::iterator it = _blue_maps.begin(); + it != _blue_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + if (label == 0) { + for (NodeIt n(_graph); n != INVALID; ++n) { + std::ostringstream os; + os << _graph.id(n); + _node_index.insert(std::make_pair(n, os.str())); + } + } else { + for (NodeIt n(_graph); n != INVALID; ++n) { + std::string value = label->get(n); + _node_index.insert(std::make_pair(n, value)); + } + } + } + + void writeEdges() { + _writer_bits::MapStorageBase* label = 0; + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + *_os << "@edges"; + if (!_edges_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _edges_caption); + } + *_os << std::endl; + + *_os << '\t' << '\t'; + if (label == 0) { + *_os << "label" << '\t'; + } + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << '\t'; + } + *_os << std::endl; + + std::vector edges; + for (EdgeIt n(_graph); n != INVALID; ++n) { + edges.push_back(n); + } + + if (label == 0) { + IdMap id_map(_graph); + _writer_bits::MapLess > id_less(id_map); + std::sort(edges.begin(), edges.end(), id_less); + } else { + label->sort(edges); + } + + for (int i = 0; i < static_cast(edges.size()); ++i) { + Edge e = edges[i]; + _writer_bits::writeToken(*_os, _node_index. + find(_graph.redNode(e))->second); + *_os << '\t'; + _writer_bits::writeToken(*_os, _node_index. + find(_graph.blueNode(e))->second); + *_os << '\t'; + if (label == 0) { + std::ostringstream os; + os << _graph.id(e); + _writer_bits::writeToken(*_os, os.str()); + *_os << '\t'; + _edge_index.insert(std::make_pair(e, os.str())); + } + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + std::string value = it->second->get(e); + _writer_bits::writeToken(*_os, value); + if (it->first == "label") { + _edge_index.insert(std::make_pair(e, value)); + } + *_os << '\t'; + } + *_os << std::endl; + } + } + + void createEdgeIndex() { + _writer_bits::MapStorageBase* label = 0; + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + if (label == 0) { + for (EdgeIt e(_graph); e != INVALID; ++e) { + std::ostringstream os; + os << _graph.id(e); + _edge_index.insert(std::make_pair(e, os.str())); + } + } else { + for (EdgeIt e(_graph); e != INVALID; ++e) { + std::string value = label->get(e); + _edge_index.insert(std::make_pair(e, value)); + } + } + } + + void writeAttributes() { + if (_attributes.empty()) return; + *_os << "@attributes"; + if (!_attributes_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _attributes_caption); + } + *_os << std::endl; + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << ' '; + _writer_bits::writeToken(*_os, it->second->get()); + *_os << std::endl; + } + } + + public: + + /// \name Execution of the Writer + /// @{ + + /// \brief Start the batch processing + /// + /// This function starts the batch processing. + void run() { + if (!_skip_nodes) { + writeRedNodes(); + writeBlueNodes(); + } else { + createRedNodeIndex(); + createBlueNodeIndex(); + } + if (!_skip_edges) { + writeEdges(); + } else { + createEdgeIndex(); + } + writeAttributes(); + } + + /// \brief Give back the stream of the writer + /// + /// Give back the stream of the writer + std::ostream& ostream() { + return *_os; + } + + /// @} + }; + + /// \ingroup lemon_io + /// + /// \brief Return a \ref BpGraphWriter class + /// + /// This function just returns a \ref BpGraphWriter class. + /// + /// With this function a bipartite graph can be write to a file or output + /// stream in \ref lgf-format "LGF" format with several maps and + /// attributes. For example, with the following code a bipartite + /// weighted matching problem can be written to the standard output, + /// i.e. a graph with a \e weight map on the edges: + /// + ///\code + ///ListBpGraph graph; + ///ListBpGraph::EdgeMap weight(graph); + /// // Setting the weight map + ///bpGraphWriter(graph, std::cout). + /// edgeMap("weight", weight). + /// run(); + ///\endcode + /// + /// For a complete documentation, please see the \ref BpGraphWriter + /// class documentation. + /// \warning Don't forget to put the \ref BpGraphWriter::run() "run()" + /// to the end of the parameter list. + /// \relates BpGraphWriter + /// \sa bpGraphWriter(const TBGR& graph, const std::string& fn) + /// \sa bpGraphWriter(const TBGR& graph, const char* fn) + template + BpGraphWriter bpGraphWriter(const TBGR& graph, std::ostream& os) { + BpGraphWriter tmp(graph, os); + return tmp; + } + + /// \brief Return a \ref BpGraphWriter class + /// + /// This function just returns a \ref BpGraphWriter class. + /// \relates BpGraphWriter + /// \sa graphWriter(const TBGR& graph, std::ostream& os) + template + BpGraphWriter bpGraphWriter(const TBGR& graph, const std::string& fn) { + BpGraphWriter tmp(graph, fn); + return tmp; + } + + /// \brief Return a \ref BpGraphWriter class + /// + /// This function just returns a \ref BpGraphWriter class. + /// \relates BpGraphWriter + /// \sa graphWriter(const TBGR& graph, std::ostream& os) + template + BpGraphWriter bpGraphWriter(const TBGR& graph, const char* fn) { + BpGraphWriter tmp(graph, fn); + return tmp; + } + class SectionWriter; SectionWriter sectionWriter(std::istream& is);