/* -*- mode: C++; indent-tabs-mode: nil; -*-
* This file is a part of LEMON, a generic C++ optimization library.
* Copyright (C) 2003-2009
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
///\brief \ref lgf-format "LEMON Graph Format" writer.
#ifndef LEMON_LGF_WRITER_H
#define LEMON_LGF_WRITER_H
#include <lemon/concept_check.h>
#include <lemon/concepts/maps.h>
template <typename Value>
struct DefaultConverter {
std::string operator()(const Value& value) {
bool operator<(const T&, const T&) {
throw FormatError("Label map is not comparable");
typedef typename Map::Key Item;
MapLess(const Map& map) : _map(map) {}
bool operator()(const Item& left, const Item& right) {
return _map[left] < _map[right];
template <typename _Graph, bool _dir, typename _Map>
typedef typename Graph::Edge Item;
GraphArcMapLess(const Graph& graph, const Map& map)
: _graph(graph), _map(map) {}
bool operator()(const Item& left, const Item& right) {
return _map[_graph.direct(left, _dir)] <
_map[_graph.direct(right, _dir)];
template <typename _Item>
virtual ~MapStorageBase() {}
virtual std::string get(const Item& item) = 0;
virtual void sort(std::vector<Item>&) = 0;
template <typename _Item, typename _Map,
typename _Converter = DefaultConverter<typename _Map::Value> >
class MapStorage : public MapStorageBase<_Item> {
typedef _Converter Converter;
MapStorage(const Map& map, const Converter& converter = Converter())
: _map(map), _converter(converter) {}
virtual std::string get(const Item& item) {
return _converter(_map[item]);
virtual void sort(std::vector<Item>& items) {
std::sort(items.begin(), items.end(), less);
template <typename _Graph, bool _dir, typename _Map,
typename _Converter = DefaultConverter<typename _Map::Value> >
class GraphArcMapStorage : public MapStorageBase<typename _Graph::Edge> {
typedef _Converter Converter;
typedef typename Graph::Edge Item;
static const bool dir = _dir;
GraphArcMapStorage(const Graph& graph, const Map& map,
const Converter& converter = Converter())
: _graph(graph), _map(map), _converter(converter) {}
virtual ~GraphArcMapStorage() {}
virtual std::string get(const Item& item) {
return _converter(_map[_graph.direct(item, dir)]);
virtual void sort(std::vector<Item>& items) {
GraphArcMapLess<Graph, dir, Map> less(_graph, _map);
std::sort(items.begin(), items.end(), less);
virtual ~ValueStorageBase() {}
virtual std::string get() = 0;
template <typename _Value, typename _Converter = DefaultConverter<_Value> >
class ValueStorage : public ValueStorageBase {
typedef _Converter Converter;
ValueStorage(const Value& value, const Converter& converter = Converter())
: _value(value), _converter(converter) {}
virtual std::string get() {
return _converter(_value);
template <typename Value>
struct MapLookUpConverter {
const std::map<Value, std::string>& _map;
MapLookUpConverter(const std::map<Value, std::string>& map)
std::string operator()(const Value& str) {
typename std::map<Value, std::string>::const_iterator it =
throw FormatError("Item not found");
template <typename Graph>
struct GraphArcLookUpConverter {
const std::map<typename Graph::Edge, std::string>& _map;
GraphArcLookUpConverter(const Graph& graph,
const std::map<typename Graph::Edge,
: _graph(graph), _map(map) {}
std::string operator()(const typename Graph::Arc& val) {
typename std::map<typename Graph::Edge, std::string>
::const_iterator it = _map.find(val);
throw FormatError("Item not found");
return (_graph.direction(val) ? '+' : '-') + it->second;
inline bool isWhiteSpace(char c) {
return c == ' ' || c == '\t' || c == '\v' ||
c == '\n' || c == '\r' || c == '\f';
inline bool isEscaped(char c) {
return c == '\\' || c == '\"' || c == '\'' ||
inline static void writeEscape(std::ostream& os, char c) {
std::ios::fmtflags flags = os.flags();
os << '\\' << std::oct << static_cast<int>(c);
inline bool requireEscape(const std::string& str) {
if (str.empty() || str[0] == '@') return true;
std::istringstream is(str);
if (isWhiteSpace(c) || isEscaped(c)) {
inline std::ostream& writeToken(std::ostream& os, const std::string& str) {
if (requireEscape(str)) {
for (std::string::const_iterator it = str.begin();
virtual void process(std::ostream& os) = 0;
template <typename Functor>
class LineSection : public Section {
LineSection(const Functor& functor) : _functor(functor) {}
virtual ~LineSection() {}
virtual void process(std::ostream& os) {
while (!(line = _functor()).empty()) os << line << std::endl;
template <typename Functor>
class StreamSection : public Section {
StreamSection(const Functor& functor) : _functor(functor) {}
virtual ~StreamSection() {}
virtual void process(std::ostream& os) {
template <typename Digraph>
template <typename Digraph>
DigraphWriter<Digraph> digraphWriter(const Digraph& digraph,
std::ostream& os = std::cout);
template <typename Digraph>
DigraphWriter<Digraph> digraphWriter(const Digraph& digraph,
template <typename Digraph>
DigraphWriter<Digraph> digraphWriter(const Digraph& digraph,
/// \brief \ref lgf-format "LGF" writer for directed graphs
/// This utility writes an \ref lgf-format "LGF" file.
/// The writing method does a batch processing. The user creates a
/// writer object, then various writing rules can be added to the
/// writer, and eventually the writing is executed with the \c run()
/// member function. A map writing rule can be added to the writer
/// with the \c nodeMap() or \c arcMap() members. An optional
/// converter parameter can also be added as a standard functor
/// converting from the value type of the map to \c std::string. If it
/// is set, it will determine how the value type of the map is written to
/// the output stream. If the functor is not set, then a default
/// conversion will be used. The \c attribute(), \c node() and \c
/// arc() functions are used to add attribute writing rules.
/// DigraphWriter<Digraph>(digraph, std::cout).
/// nodeMap("coordinates", coord_map).
/// nodeMap("size", size).
/// nodeMap("title", title).
/// arcMap("capacity", cap_map).
/// attribute("caption", caption).
/// By default, the writer does not write additional captions to the
/// sections, but they can be give as an optional parameter of
/// the \c nodes(), \c arcs() or \c
/// attributes() functions.
/// The \c skipNodes() and \c skipArcs() functions forbid the
/// writing of the sections. If two arc sections should be written
/// to the output, it can be done in two passes, the first pass
/// writes the node section and the first arc section, then the
/// second pass skips the node section and writes just the arc
/// section to the stream. The output stream can be retrieved with
/// the \c ostream() function, hence the second pass can append its
/// output to the output of the first pass.
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
std::string _nodes_caption;
std::string _arcs_caption;
std::string _attributes_caption;
typedef std::map<Node, std::string> NodeIndex;
typedef std::map<Arc, std::string> ArcIndex;
typedef std::vector<std::pair<std::string,
_writer_bits::MapStorageBase<Node>* > > NodeMaps;
typedef std::vector<std::pair<std::string,
_writer_bits::MapStorageBase<Arc>* > >ArcMaps;
typedef std::vector<std::pair<std::string,
_writer_bits::ValueStorageBase*> > Attributes;
/// Construct a directed graph writer, which writes to the given
DigraphWriter(const Digraph& digraph, std::ostream& os = std::cout)
: _os(&os), local_os(false), _digraph(digraph),
_skip_nodes(false), _skip_arcs(false) {}
/// Construct a directed graph writer, which writes to the given
DigraphWriter(const Digraph& digraph, const std::string& fn)
: _os(new std::ofstream(fn.c_str())), local_os(true), _digraph(digraph),
_skip_nodes(false), _skip_arcs(false) {
throw IoError("Cannot write file", fn);
/// Construct a directed graph writer, which writes to the given
DigraphWriter(const Digraph& digraph, const char* fn)
: _os(new std::ofstream(fn)), local_os(true), _digraph(digraph),
_skip_nodes(false), _skip_arcs(false) {
throw IoError("Cannot write file", fn);
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
for (typename ArcMaps::iterator it = _arc_maps.begin();
it != _arc_maps.end(); ++it) {
for (typename Attributes::iterator it = _attributes.begin();
it != _attributes.end(); ++it) {
friend DigraphWriter<DGR> digraphWriter(const DGR& digraph,
friend DigraphWriter<DGR> digraphWriter(const DGR& digraph,
friend DigraphWriter<DGR> digraphWriter(const DGR& digraph,
DigraphWriter(DigraphWriter& other)
: _os(other._os), local_os(other.local_os), _digraph(other._digraph),
_skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) {
_node_index.swap(other._node_index);
_arc_index.swap(other._arc_index);
_node_maps.swap(other._node_maps);
_arc_maps.swap(other._arc_maps);
_attributes.swap(other._attributes);
_nodes_caption = other._nodes_caption;
_arcs_caption = other._arcs_caption;
_attributes_caption = other._attributes_caption;
DigraphWriter& operator=(const DigraphWriter&);
/// \brief Node map writing rule
/// Add a node map writing rule to the writer.
DigraphWriter& nodeMap(const std::string& caption, const Map& map) {
checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Node>* storage =
new _writer_bits::MapStorage<Node, Map>(map);
_node_maps.push_back(std::make_pair(caption, storage));
/// \brief Node map writing rule
/// Add a node map writing rule with specialized converter to the
template <typename Map, typename Converter>
DigraphWriter& nodeMap(const std::string& caption, const Map& map,
const Converter& converter = Converter()) {
checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Node>* storage =
new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
_node_maps.push_back(std::make_pair(caption, storage));
/// \brief Arc map writing rule
/// Add an arc map writing rule to the writer.
DigraphWriter& arcMap(const std::string& caption, const Map& map) {
checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Arc>* storage =
new _writer_bits::MapStorage<Arc, Map>(map);
_arc_maps.push_back(std::make_pair(caption, storage));
/// \brief Arc map writing rule
/// Add an arc map writing rule with specialized converter to the
template <typename Map, typename Converter>
DigraphWriter& arcMap(const std::string& caption, const Map& map,
const Converter& converter = Converter()) {
checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Arc>* storage =
new _writer_bits::MapStorage<Arc, Map, Converter>(map, converter);
_arc_maps.push_back(std::make_pair(caption, storage));
/// \brief Attribute writing rule
/// Add an attribute writing rule to the writer.
template <typename Value>
DigraphWriter& attribute(const std::string& caption, const Value& value) {
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Value>(value);
_attributes.push_back(std::make_pair(caption, storage));
/// \brief Attribute writing rule
/// Add an attribute writing rule with specialized converter to the
template <typename Value, typename Converter>
DigraphWriter& attribute(const std::string& caption, const Value& value,
const Converter& converter = Converter()) {
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Value, Converter>(value, converter);
_attributes.push_back(std::make_pair(caption, storage));
/// \brief Node writing rule
/// Add a node writing rule to the writer.
DigraphWriter& node(const std::string& caption, const Node& node) {
typedef _writer_bits::MapLookUpConverter<Node> Converter;
Converter converter(_node_index);
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Node, Converter>(node, converter);
_attributes.push_back(std::make_pair(caption, storage));
/// \brief Arc writing rule
/// Add an arc writing rule to writer.
DigraphWriter& arc(const std::string& caption, const Arc& arc) {
typedef _writer_bits::MapLookUpConverter<Arc> Converter;
Converter converter(_arc_index);
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
_attributes.push_back(std::make_pair(caption, storage));
/// \name Section captions
/// \brief Add an additional caption to the \c \@nodes section
/// Add an additional caption to the \c \@nodes section.
DigraphWriter& nodes(const std::string& caption) {
_nodes_caption = caption;
/// \brief Add an additional caption to the \c \@arcs section
/// Add an additional caption to the \c \@arcs section.
DigraphWriter& arcs(const std::string& caption) {
/// \brief Add an additional caption to the \c \@attributes section
/// Add an additional caption to the \c \@attributes section.
DigraphWriter& attributes(const std::string& caption) {
_attributes_caption = caption;
/// \name Skipping section
/// \brief Skip writing the node set
/// The \c \@nodes section will not be written to the stream.
DigraphWriter& skipNodes() {
LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
/// \brief Skip writing arc set
/// The \c \@arcs section will not be written to the stream.
DigraphWriter& skipArcs() {
LEMON_ASSERT(!_skip_arcs, "Multiple usage of skipArcs() member");
_writer_bits::MapStorageBase<Node>* label = 0;
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
if (it->first == "label") {
if (!_nodes_caption.empty()) {
_writer_bits::writeToken(*_os << ' ', _nodes_caption);
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
_writer_bits::writeToken(*_os, it->first) << '\t';
for (NodeIt n(_digraph); n != INVALID; ++n) {
IdMap<Digraph, Node> id_map(_digraph);
_writer_bits::MapLess<IdMap<Digraph, Node> > id_less(id_map);
std::sort(nodes.begin(), nodes.end(), id_less);
for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
_writer_bits::writeToken(*_os, os.str());
_node_index.insert(std::make_pair(n, os.str()));
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_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));
_writer_bits::MapStorageBase<Node>* label = 0;
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
if (it->first == "label") {
for (NodeIt n(_digraph); n != INVALID; ++n) {
_node_index.insert(std::make_pair(n, os.str()));
for (NodeIt n(_digraph); n != INVALID; ++n) {
std::string value = label->get(n);
_node_index.insert(std::make_pair(n, value));
_writer_bits::MapStorageBase<Arc>* label = 0;
for (typename ArcMaps::iterator it = _arc_maps.begin();
it != _arc_maps.end(); ++it) {
if (it->first == "label") {
if (!_arcs_caption.empty()) {
_writer_bits::writeToken(*_os << ' ', _arcs_caption);
for (typename ArcMaps::iterator it = _arc_maps.begin();
it != _arc_maps.end(); ++it) {
_writer_bits::writeToken(*_os, it->first) << '\t';
for (ArcIt n(_digraph); n != INVALID; ++n) {
IdMap<Digraph, Arc> id_map(_digraph);
_writer_bits::MapLess<IdMap<Digraph, Arc> > id_less(id_map);
std::sort(arcs.begin(), arcs.end(), id_less);
for (int i = 0; i < static_cast<int>(arcs.size()); ++i) {
_writer_bits::writeToken(*_os, _node_index.
find(_digraph.source(a))->second);
_writer_bits::writeToken(*_os, _node_index.
find(_digraph.target(a))->second);
_writer_bits::writeToken(*_os, os.str());
_arc_index.insert(std::make_pair(a, os.str()));
for (typename ArcMaps::iterator it = _arc_maps.begin();
it != _arc_maps.end(); ++it) {
std::string value = it->second->get(a);
_writer_bits::writeToken(*_os, value);
if (it->first == "label") {
_arc_index.insert(std::make_pair(a, value));
_writer_bits::MapStorageBase<Arc>* label = 0;
for (typename ArcMaps::iterator it = _arc_maps.begin();
it != _arc_maps.end(); ++it) {
if (it->first == "label") {
for (ArcIt a(_digraph); a != INVALID; ++a) {
_arc_index.insert(std::make_pair(a, os.str()));
for (ArcIt a(_digraph); a != INVALID; ++a) {
std::string value = label->get(a);
_arc_index.insert(std::make_pair(a, value));
if (_attributes.empty()) return;
if (!_attributes_caption.empty()) {
_writer_bits::writeToken(*_os << ' ', _attributes_caption);
for (typename Attributes::iterator it = _attributes.begin();
it != _attributes.end(); ++it) {
_writer_bits::writeToken(*_os, it->first) << ' ';
_writer_bits::writeToken(*_os, it->second->get());
/// \name Execution of the writer
/// \brief Start the batch processing
/// This function starts the batch processing.
/// \brief Give back the stream of the writer
/// Give back the stream of the writer.
std::ostream& ostream() {
/// \brief Return a \ref DigraphWriter class
/// This function just returns a \ref DigraphWriter class.
/// \relates DigraphWriter
template <typename Digraph>
DigraphWriter<Digraph> digraphWriter(const Digraph& digraph,
DigraphWriter<Digraph> tmp(digraph, os);
/// \brief Return a \ref DigraphWriter class
/// This function just returns a \ref DigraphWriter class.
/// \relates DigraphWriter
template <typename Digraph>
DigraphWriter<Digraph> digraphWriter(const Digraph& digraph,
DigraphWriter<Digraph> tmp(digraph, fn);
/// \brief Return a \ref DigraphWriter class
/// This function just returns a \ref DigraphWriter class.
/// \relates DigraphWriter
template <typename Digraph>
DigraphWriter<Digraph> digraphWriter(const Digraph& digraph,
DigraphWriter<Digraph> tmp(digraph, fn);
template <typename Graph>
template <typename Graph>
GraphWriter<Graph> graphWriter(const Graph& graph,
std::ostream& os = std::cout);
template <typename Graph>
GraphWriter<Graph> graphWriter(const Graph& graph, const std::string& fn);
template <typename Graph>
GraphWriter<Graph> graphWriter(const Graph& graph, const char* fn);
/// \brief \ref lgf-format "LGF" writer for directed graphs
/// This utility writes an \ref lgf-format "LGF" file.
/// It can be used almost the same way as \c DigraphWriter.
/// The only difference is that this class can handle edges and
/// edge maps as well as arcs and arc maps.
/// The arc maps are written into the file as two columns, the
/// caption of the columns are the name of the map prefixed with \c
/// '+' and \c '-'. The arcs are written into the \c \@attributes
/// section as a \c '+' or a \c '-' prefix (depends on the direction
/// of the arc) and the label of corresponding edge.
TEMPLATE_GRAPH_TYPEDEFS(Graph);
std::string _nodes_caption;
std::string _edges_caption;
std::string _attributes_caption;
typedef std::map<Node, std::string> NodeIndex;
typedef std::map<Edge, std::string> EdgeIndex;
typedef std::vector<std::pair<std::string,
_writer_bits::MapStorageBase<Node>* > > NodeMaps;
typedef std::vector<std::pair<std::string,
_writer_bits::MapStorageBase<Edge>* > >EdgeMaps;
typedef std::vector<std::pair<std::string,
_writer_bits::ValueStorageBase*> > Attributes;
/// Construct a directed graph writer, which writes to the given
GraphWriter(const Graph& graph, std::ostream& os = std::cout)
: _os(&os), local_os(false), _graph(graph),
_skip_nodes(false), _skip_edges(false) {}
/// Construct a directed graph writer, which writes to the given
GraphWriter(const Graph& graph, const std::string& fn)
: _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph),
_skip_nodes(false), _skip_edges(false) {
throw IoError("Cannot write file", fn);
/// Construct a directed graph writer, which writes to the given
GraphWriter(const Graph& graph, const char* fn)
: _os(new std::ofstream(fn)), local_os(true), _graph(graph),
_skip_nodes(false), _skip_edges(false) {
throw IoError("Cannot write file", fn);
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
for (typename EdgeMaps::iterator it = _edge_maps.begin();
it != _edge_maps.end(); ++it) {
for (typename Attributes::iterator it = _attributes.begin();
it != _attributes.end(); ++it) {
template <typename Graph>
friend GraphWriter<Graph> graphWriter(const Graph& graph,
template <typename Graph>
friend GraphWriter<Graph> graphWriter(const Graph& graph,
template <typename Graph>
friend GraphWriter<Graph> graphWriter(const Graph& graph,
GraphWriter(GraphWriter& other)
: _os(other._os), local_os(other.local_os), _graph(other._graph),
_skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) {
_node_index.swap(other._node_index);
_edge_index.swap(other._edge_index);
_node_maps.swap(other._node_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;
GraphWriter& operator=(const GraphWriter&);
/// \brief Node map writing rule
/// Add a node map writing rule to the writer.
GraphWriter& nodeMap(const std::string& caption, const Map& map) {
checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Node>* storage =
new _writer_bits::MapStorage<Node, Map>(map);
_node_maps.push_back(std::make_pair(caption, storage));
/// \brief Node map writing rule
/// Add a node map writing rule with specialized converter to the
template <typename Map, typename Converter>
GraphWriter& nodeMap(const std::string& caption, const Map& map,
const Converter& converter = Converter()) {
checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Node>* storage =
new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
_node_maps.push_back(std::make_pair(caption, storage));
/// \brief Edge map writing rule
/// Add an edge map writing rule to the writer.
GraphWriter& edgeMap(const std::string& caption, const Map& map) {
checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Edge>* storage =
new _writer_bits::MapStorage<Edge, Map>(map);
_edge_maps.push_back(std::make_pair(caption, storage));
/// \brief Edge map writing rule
/// Add an edge map writing rule with specialized converter to the
template <typename Map, typename Converter>
GraphWriter& edgeMap(const std::string& caption, const Map& map,
const Converter& converter = Converter()) {
checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Edge>* storage =
new _writer_bits::MapStorage<Edge, Map, Converter>(map, converter);
_edge_maps.push_back(std::make_pair(caption, storage));
/// \brief Arc map writing rule
/// Add an arc map writing rule to the writer.
GraphWriter& arcMap(const std::string& caption, const Map& map) {
checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Edge>* forward_storage =
new _writer_bits::GraphArcMapStorage<Graph, true, Map>(_graph, map);
_edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
_writer_bits::MapStorageBase<Edge>* backward_storage =
new _writer_bits::GraphArcMapStorage<Graph, false, Map>(_graph, map);
_edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
/// \brief Arc map writing rule
/// Add an arc map writing rule with specialized converter to the
template <typename Map, typename Converter>
GraphWriter& arcMap(const std::string& caption, const Map& map,
const Converter& converter = Converter()) {
checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Edge>* forward_storage =
new _writer_bits::GraphArcMapStorage<Graph, true, Map, Converter>
(_graph, map, converter);
_edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
_writer_bits::MapStorageBase<Edge>* backward_storage =
new _writer_bits::GraphArcMapStorage<Graph, false, Map, Converter>
(_graph, map, converter);
_edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
/// \brief Attribute writing rule
/// Add an attribute writing rule to the writer.
template <typename Value>
GraphWriter& attribute(const std::string& caption, const Value& value) {
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Value>(value);
_attributes.push_back(std::make_pair(caption, storage));
/// \brief Attribute writing rule
/// Add an attribute writing rule with specialized converter to the
template <typename Value, typename Converter>
GraphWriter& attribute(const std::string& caption, const Value& value,
const Converter& converter = Converter()) {
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Value, Converter>(value, converter);
_attributes.push_back(std::make_pair(caption, storage));
/// \brief Node writing rule
/// Add a node writing rule to the writer.
GraphWriter& node(const std::string& caption, const Node& node) {
typedef _writer_bits::MapLookUpConverter<Node> Converter;
Converter converter(_node_index);
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Node, Converter>(node, converter);
_attributes.push_back(std::make_pair(caption, storage));
/// \brief Edge writing rule
/// Add an edge writing rule to writer.
GraphWriter& edge(const std::string& caption, const Edge& edge) {
typedef _writer_bits::MapLookUpConverter<Edge> Converter;
Converter converter(_edge_index);
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Edge, Converter>(edge, converter);
_attributes.push_back(std::make_pair(caption, storage));
/// \brief Arc writing rule
/// Add an arc writing rule to writer.
GraphWriter& arc(const std::string& caption, const Arc& arc) {
typedef _writer_bits::GraphArcLookUpConverter<Graph> Converter;
Converter converter(_graph, _edge_index);
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
_attributes.push_back(std::make_pair(caption, storage));
/// \name Section captions
/// \brief Add an additional caption to the \c \@nodes section
/// Add an additional caption to the \c \@nodes section.
GraphWriter& nodes(const std::string& caption) {
_nodes_caption = caption;
/// \brief Add an additional caption to the \c \@arcs section
/// Add an additional caption to the \c \@arcs section.
GraphWriter& edges(const std::string& caption) {
_edges_caption = caption;
/// \brief Add an additional caption to the \c \@attributes section
/// Add an additional caption to the \c \@attributes section.
GraphWriter& attributes(const std::string& caption) {
_attributes_caption = caption;
/// \name Skipping section
/// \brief Skip writing the node set
/// The \c \@nodes section will not be written to the stream.
GraphWriter& skipNodes() {
LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
/// \brief Skip writing edge set
/// The \c \@edges section will not be written to the stream.
GraphWriter& skipEdges() {
LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member");
_writer_bits::MapStorageBase<Node>* label = 0;
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
if (it->first == "label") {
if (!_nodes_caption.empty()) {
_writer_bits::writeToken(*_os << ' ', _nodes_caption);
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
_writer_bits::writeToken(*_os, it->first) << '\t';
for (NodeIt n(_graph); n != INVALID; ++n) {
IdMap<Graph, Node> id_map(_graph);
_writer_bits::MapLess<IdMap<Graph, Node> > id_less(id_map);
std::sort(nodes.begin(), nodes.end(), id_less);
for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
_writer_bits::writeToken(*_os, os.str());
_node_index.insert(std::make_pair(n, os.str()));
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_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));
_writer_bits::MapStorageBase<Node>* label = 0;
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
if (it->first == "label") {
for (NodeIt n(_graph); n != INVALID; ++n) {
_node_index.insert(std::make_pair(n, os.str()));
for (NodeIt n(_graph); n != INVALID; ++n) {
std::string value = label->get(n);
_node_index.insert(std::make_pair(n, value));
_writer_bits::MapStorageBase<Edge>* label = 0;
for (typename EdgeMaps::iterator it = _edge_maps.begin();
it != _edge_maps.end(); ++it) {
if (it->first == "label") {
if (!_edges_caption.empty()) {
_writer_bits::writeToken(*_os << ' ', _edges_caption);
for (typename EdgeMaps::iterator it = _edge_maps.begin();
it != _edge_maps.end(); ++it) {
_writer_bits::writeToken(*_os, it->first) << '\t';
for (EdgeIt n(_graph); n != INVALID; ++n) {
IdMap<Graph, Edge> id_map(_graph);
_writer_bits::MapLess<IdMap<Graph, Edge> > id_less(id_map);
std::sort(edges.begin(), edges.end(), id_less);
for (int i = 0; i < static_cast<int>(edges.size()); ++i) {
_writer_bits::writeToken(*_os, _node_index.
find(_graph.u(e))->second);
_writer_bits::writeToken(*_os, _node_index.
find(_graph.v(e))->second);
_writer_bits::writeToken(*_os, os.str());
_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));
_writer_bits::MapStorageBase<Edge>* label = 0;
for (typename EdgeMaps::iterator it = _edge_maps.begin();
it != _edge_maps.end(); ++it) {
if (it->first == "label") {
for (EdgeIt e(_graph); e != INVALID; ++e) {
_edge_index.insert(std::make_pair(e, os.str()));
for (EdgeIt e(_graph); e != INVALID; ++e) {
std::string value = label->get(e);
_edge_index.insert(std::make_pair(e, value));
if (_attributes.empty()) return;
if (!_attributes_caption.empty()) {
_writer_bits::writeToken(*_os << ' ', _attributes_caption);
for (typename Attributes::iterator it = _attributes.begin();
it != _attributes.end(); ++it) {
_writer_bits::writeToken(*_os, it->first) << ' ';
_writer_bits::writeToken(*_os, it->second->get());
/// \name Execution of the writer
/// \brief Start the batch processing
/// This function starts the batch processing.
/// \brief Give back the stream of the writer
/// Give back the stream of the writer
std::ostream& ostream() {
/// \brief Return a \ref GraphWriter class
/// This function just returns a \ref GraphWriter class.
template <typename Graph>
GraphWriter<Graph> graphWriter(const Graph& graph,
GraphWriter<Graph> tmp(graph, os);
/// \brief Return a \ref GraphWriter class
/// This function just returns a \ref GraphWriter class.
template <typename Graph>
GraphWriter<Graph> graphWriter(const Graph& graph, const std::string& fn) {
GraphWriter<Graph> tmp(graph, fn);
/// \brief Return a \ref GraphWriter class
/// This function just returns a \ref GraphWriter class.
template <typename Graph>
GraphWriter<Graph> graphWriter(const Graph& graph, const char* fn) {
GraphWriter<Graph> tmp(graph, fn);
SectionWriter sectionWriter(std::istream& is);
SectionWriter sectionWriter(const std::string& fn);
SectionWriter sectionWriter(const char* fn);
/// \brief Section writer class
/// In the \ref lgf-format "LGF" file extra sections can be placed,
/// which contain any data in arbitrary format. Such sections can be
/// written with this class. A writing rule can be added to the
/// class with two different functions. With the \c sectionLines()
/// function a generator can write the section line-by-line, while
/// with the \c sectionStream() member the section can be written to
typedef std::vector<std::pair<std::string, _writer_bits::Section*> >
/// Construct a section writer, which writes to the given output
SectionWriter(std::ostream& os)
: _os(&os), local_os(false) {}
/// Construct a section writer, which writes into the given file.
SectionWriter(const std::string& fn)
: _os(new std::ofstream(fn.c_str())), local_os(true) {
throw IoError("Cannot write file", fn);
/// Construct a section writer, which writes into the given file.
SectionWriter(const char* fn)
: _os(new std::ofstream(fn)), local_os(true) {
throw IoError("Cannot write file", fn);
for (Sections::iterator it = _sections.begin();
it != _sections.end(); ++it) {
friend SectionWriter sectionWriter(std::ostream& os);
friend SectionWriter sectionWriter(const std::string& fn);
friend SectionWriter sectionWriter(const char* fn);
SectionWriter(SectionWriter& other)
: _os(other._os), local_os(other.local_os) {
_sections.swap(other._sections);
SectionWriter& operator=(const SectionWriter&);
/// \name Section writers
/// \brief Add a section writer with line oriented writing
/// The first parameter is the type descriptor of the section, the
/// second is a generator with std::string values. At the writing
/// process, the returned \c std::string will be written into the
/// output file until it is an empty string.
/// For example, an integer vector is written into a section.
/// The generator is implemented as a struct.
/// struct NumberSection {
/// std::vector<int>::const_iterator _it, _end;
/// NumberSection(const std::vector<int>& data)
/// : _it(data.begin()), _end(data.end()) {}
/// std::string operator()() {
/// std::ostringstream ls;
/// while (rem_in_line > 0 && _it != _end) {
/// ls << *(_it++) << ' ';
/// writer.sectionLines("numbers", NumberSection(vec));
template <typename Functor>
SectionWriter& sectionLines(const std::string& type, Functor functor) {
LEMON_ASSERT(!type.empty(), "Type is empty.");
_sections.push_back(std::make_pair(type,
new _writer_bits::LineSection<Functor>(functor)));
/// \brief Add a section writer with stream oriented writing
/// The first parameter is the type of the section, the second is
/// a functor, which takes a \c std::ostream& parameter. The
/// functor writes the section to the output stream.
/// \warning The last line must be closed with end-line character.
template <typename Functor>
SectionWriter& sectionStream(const std::string& type, Functor functor) {
LEMON_ASSERT(!type.empty(), "Type is empty.");
_sections.push_back(std::make_pair(type,
new _writer_bits::StreamSection<Functor>(functor)));
/// \name Execution of the writer
/// \brief Start the batch processing
/// This function starts the batch processing.
LEMON_ASSERT(_os != 0, "This writer is assigned to an other writer");
for (Sections::iterator it = _sections.begin();
it != _sections.end(); ++it) {
(*_os) << '@' << it->first << std::endl;
it->second->process(*_os);
/// \brief Give back the stream of the writer
/// Returns the stream of the writer
std::ostream& ostream() {
/// \brief Return a \ref SectionWriter class
/// This function just returns a \ref SectionWriter class.
/// \relates SectionWriter
inline SectionWriter sectionWriter(std::ostream& os) {
/// \brief Return a \ref SectionWriter class
/// This function just returns a \ref SectionWriter class.
/// \relates SectionWriter
inline SectionWriter sectionWriter(const std::string& fn) {
/// \brief Return a \ref SectionWriter class
/// This function just returns a \ref SectionWriter class.
/// \relates SectionWriter
inline SectionWriter sectionWriter(const char* fn) {