* This file is a part of LEMON, a generic C++ optimization library
* Copyright (C) 2003-2008
* 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 Lemon Graph Format writer.
#ifndef LEMON_LGF_WRITER_H
#define LEMON_LGF_WRITER_H
#include <lemon/assert.h>
#include <lemon/graph_utils.h>
template <typename Value>
struct DefaultConverter {
std::string operator()(const Value& value) {
bool operator<(const T&, const T&) {
throw DataFormatError("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 _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);
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 DataFormatError("Item not found");
bool isWhiteSpace(char c) {
return c == ' ' || c == '\t' || c == '\v' ||
c == '\n' || c == '\r' || c == '\f';
return c == '\\' || c == '\"' || c == '\'' ||
static void writeEscape(std::ostream& os, char c) {
os << '\\' << std::oct << static_cast<int>(c);
bool requireEscape(const std::string& str) {
if (str.empty() || str[0] == '@') return true;
std::istringstream is(str);
if (isWhiteSpace(c) || isEscaped(c)) {
std::ostream& writeToken(std::ostream& os, const std::string& str) {
if (requireEscape(str)) {
for (std::string::const_iterator it = str.begin();
/// \brief 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 std::string. If it is set, it will
/// determine how the map's value type 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>(std::cout, digraph).
/// 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
template <typename _Digraph>
typedef _Digraph Digraph;
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(std::ostream& is, Digraph& digraph)
: _os(&is), local_os(false), _digraph(digraph),
_skip_nodes(false), _skip_arcs(false) {}
/// Construct a directed graph writer, which writes to the given
DigraphWriter(const std::string& fn, Digraph& digraph)
: _os(new std::ofstream(fn.c_str())), local_os(true), _digraph(digraph),
_skip_nodes(false), _skip_arcs(false) {}
/// Construct a directed graph writer, which writes to the given
DigraphWriter(const char* fn, Digraph& digraph)
: _os(new std::ofstream(fn)), local_os(true), _digraph(digraph),
_skip_nodes(false), _skip_arcs(false) {}
/// \brief Copy constructor
/// The copy constructor transfers all data from the other writer,
/// therefore the copied writer will not be usable more.
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;
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) {
DigraphWriter& operator=(const DigraphWriter&);
/// \brief Node map reading rule
/// Add a node map reading 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 Select section by name
/// \brief Set \c \@nodes section to be read
/// Set \c \@nodes section to be read
DigraphWriter& nodes(const std::string& caption) {
_nodes_caption = caption;
/// \brief Set \c \@arcs section to be read
/// Set \c \@arcs section to be read
DigraphWriter& arcs(const std::string& caption) {
/// \brief Set \c \@attributes section to be read
/// Set \c \@attributes section to be read
DigraphWriter& attributes(const std::string& caption) {
_attributes_caption = caption;
/// \name Skipping section
/// \brief Skip writing the node set
/// The \c \@nodes section will be not 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 be not 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<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));
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 Gives back the stream of the writer
/// Gives back the stream of the writer
std::ostream& ostream() {
/// \relates DigraphWriter
template <typename Digraph>
DigraphWriter<Digraph> digraphWriter(std::istream& is, Digraph& digraph) {
return DigraphWriter<Digraph>(is, digraph);
/// \relates DigraphWriter
template <typename Digraph>
DigraphWriter<Digraph> digraphWriter(const std::string& fn,
return DigraphWriter<Digraph>(fn, digraph);
/// \relates DigraphWriter
template <typename Digraph>
DigraphWriter<Digraph> digraphWriter(const char* fn, Digraph& digraph) {
return DigraphWriter<Digraph>(fn, digraph);