# HG changeset patch # User Balazs Dezso # Date 1208441925 -3600 # Node ID 1c9a9e2f7d4d1580a93efaceac7c7a75c7cfd726 # Parent e1dd2a70737c13f9cce13450dd182cc508fdef58 Redesigned lgf related tools diff -r e1dd2a70737c -r 1c9a9e2f7d4d demo/Makefile.am --- a/demo/Makefile.am Mon Apr 14 10:46:41 2008 +0200 +++ b/demo/Makefile.am Thu Apr 17 15:18:45 2008 +0100 @@ -4,9 +4,11 @@ if WANT_DEMO noinst_PROGRAMS += \ - demo/arg_parser_demo + demo/arg_parser_demo \ + demo/lgf_demo endif WANT_DEMO demo_arg_parser_demo_SOURCES = demo/arg_parser_demo.cc +demo_lgf_demo_SOURCES = demo/lgf_demo.cc diff -r e1dd2a70737c -r 1c9a9e2f7d4d demo/lgf_demo.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/demo/lgf_demo.cc Thu Apr 17 15:18:45 2008 +0100 @@ -0,0 +1,153 @@ +/* -*- C++ -*- + * + * 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 + * purpose. + * + */ + +///\ingroup demos +///\file +///\brief Demonstrating graph input and output +/// +/// This simple demo program gives an example of how to read and write +/// a graph and additional maps (on the nodes or the edges) from/to a +/// stream. +/// +/// \include reader_writer_demo.cc + +#include +#include +#include +#include +#include + + +using namespace lemon; + +int main(int argc, const char *argv[]) { + const int n = argc > 1 ? std::atoi(argv[1]) : 20; + const int e = argc > 2 ? std::atoi(argv[2]) : static_cast(n * log(n)); + const int m = argc > 3 ? std::atoi(argv[3]) : 100; + + SmartDigraph digraph; + + std::stringstream ss; + + try { + + typedef SmartDigraph Digraph; + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + typedef Digraph::ArcIt ArcIt; + + typedef Digraph::NodeMap PotentialMap; + typedef Digraph::ArcMap CapacityMap; + typedef Digraph::ArcMap NameMap; + + Digraph digraph; + PotentialMap potential(digraph); + CapacityMap capacity(digraph); + NameMap name(digraph); + + std::vector nodes; + for (int i = 0; i < n; ++i) { + Node node = digraph.addNode(); + potential[node] = rnd[m]; + nodes.push_back(node); + } + + std::vector arcs; + for (int i = 0; i < e; ++i) { + int s = rnd[n]; + int t = rnd[n]; + int c = rnd[m]; + Arc arc = digraph.addArc(nodes[s], nodes[t]); + capacity[arc] = c; + std::ostringstream os; + os << "arc \t" << i << std::endl; + name[arc] = os.str(); + arcs.push_back(arc); + } + + + DigraphWriter(ss, digraph). + nodeMap("potential", potential). + arcMap("capacity", capacity). + arcMap("name", name). + node("source", nodes[0]). + node("target", nodes[1]). + arc("bottleneck", arcs[e / 2]). + attribute("creator", "lemon library"). + run(); + + } catch (DataFormatError& error) { + std::cerr << error.what() << std::endl; + } + + try { + + typedef SmartDigraph Digraph; + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + typedef Digraph::ArcIt ArcIt; + + typedef Digraph::NodeMap LabelMap; + typedef Digraph::NodeMap PotentialMap; + typedef Digraph::ArcMap CapacityMap; + typedef Digraph::ArcMap NameMap; + + Digraph digraph; + LabelMap label(digraph); + PotentialMap potential(digraph); + CapacityMap capacity(digraph); + NameMap name(digraph); + + Node s, t; + Arc a; + + std::string creator; + + for (int i = 0; i < n; ++i) { + Node node = digraph.addNode(); + label[node] = i; + } + + DigraphReader(ss, digraph). + useNodes(label). + nodeMap("potential", potential). + arcMap("capacity", capacity). + arcMap("name", name). + node("source", s). + node("target", t). + arc("bottleneck", a). + attribute("creator", creator). + run(); + + DigraphWriter(std::cout, digraph). + nodeMap("potential", potential). + arcMap("capacity", capacity). + arcMap("name", name). + node("source", s). + node("target", t). + arc("bottleneck", a). + attribute("creator", creator). + run(); + + } catch (DataFormatError& error) { + std::cerr << error.what() << std::endl; + } + + + return 0; +} diff -r e1dd2a70737c -r 1c9a9e2f7d4d lemon/Makefile.am --- a/lemon/Makefile.am Mon Apr 14 10:46:41 2008 +0200 +++ b/lemon/Makefile.am Thu Apr 17 15:18:45 2008 +0100 @@ -27,6 +27,7 @@ lemon/error.h \ lemon/graph_utils.h \ lemon/kruskal.h \ + lemon/lgf_reader.h \ lemon/list_graph.h \ lemon/maps.h \ lemon/math.h \ diff -r e1dd2a70737c -r 1c9a9e2f7d4d lemon/lgf_reader.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/lgf_reader.h Thu Apr 17 15:18:45 2008 +0100 @@ -0,0 +1,914 @@ +/* -*- C++ -*- + * + * 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 + * purpose. + * + */ + +///\ingroup lemon_io +///\file +///\brief Lemon Graph Format reader. + + +#ifndef LEMON_LGF_READER_H +#define LEMON_LGF_READER_H + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +namespace lemon { + + namespace _reader_bits { + + template + struct DefaultConverter { + Value operator()(const std::string& str) { + std::istringstream is(str); + Value value; + is >> value; + + char c; + if (is >> std::ws >> c) { + throw DataFormatError("Remaining characters in token"); + } + return value; + } + }; + + template <> + struct DefaultConverter { + std::string operator()(const std::string& str) { + return str; + } + }; + + template + class MapStorageBase { + public: + typedef _Item Item; + + public: + MapStorageBase() {} + virtual ~MapStorageBase() {} + + virtual void set(const Item& item, const std::string& value) = 0; + + }; + + template > + class MapStorage : public MapStorageBase<_Item> { + public: + typedef _Map Map; + typedef _Converter Converter; + typedef _Item Item; + + private: + Map& _map; + Converter _converter; + + public: + MapStorage(Map& map, const Converter& converter = Converter()) + : _map(map), _converter(converter) {} + virtual ~MapStorage() {} + + virtual void set(const Item& item ,const std::string& value) { + _map.set(item, _converter(value)); + } + }; + + class ValueStorageBase { + public: + ValueStorageBase() {} + virtual ~ValueStorageBase() {} + + virtual void set(const std::string&) = 0; + }; + + template > + class ValueStorage : public ValueStorageBase { + public: + typedef _Value Value; + typedef _Converter Converter; + + private: + Value& _value; + Converter _converter; + + public: + ValueStorage(Value& value, const Converter& converter = Converter()) + : _value(value), _converter(converter) {} + + virtual void set(const std::string& value) { + _value = _converter(value); + } + }; + + template + struct MapLookUpConverter { + const std::map& _map; + + MapLookUpConverter(const std::map& map) + : _map(map) {} + + Value operator()(const std::string& str) { + typename std::map::const_iterator it = + _map.find(str); + if (it == _map.end()) { + std::ostringstream msg; + msg << "Item not found: " << str; + throw DataFormatError(msg.str().c_str()); + } + return it->second; + } + }; + + bool isWhiteSpace(char c) { + return c == ' ' || c == '\t' || c == '\v' || + c == '\n' || c == '\r' || c == '\f'; + } + + bool isOct(char c) { + return '0' <= c && c <='7'; + } + + int valueOct(char c) { + LEMON_ASSERT(isOct(c), "The character is not octal."); + return c - '0'; + } + + bool isHex(char c) { + return ('0' <= c && c <= '9') || + ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z'); + } + + int valueHex(char c) { + LEMON_ASSERT(isHex(c), "The character is not hexadecimal."); + if ('0' <= c && c <= '9') return c - '0'; + if ('a' <= c && c <= 'z') return c - 'a' + 10; + return c - 'A' + 10; + } + + bool isIdentifierFirstChar(char c) { + return ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z') || c == '_'; + } + + bool isIdentifierChar(char c) { + return isIdentifierFirstChar(c) || + ('0' <= c && c <= '9'); + } + + char readEscape(std::istream& is) { + char c; + if (!is.get(c)) + throw DataFormatError("Escape format error"); + + switch (c) { + case '\\': + return '\\'; + case '\"': + return '\"'; + case '\'': + return '\''; + case '\?': + return '\?'; + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case 'x': + { + int code; + if (!is.get(c) || !isHex(c)) + throw DataFormatError("Escape format error"); + else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c); + else code = code * 16 + valueHex(c); + return code; + } + default: + { + int code; + if (!isOct(c)) + throw DataFormatError("Escape format error"); + else if (code = valueOct(c), !is.get(c) || !isOct(c)) + is.putback(c); + else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c)) + is.putback(c); + else code = code * 8 + valueOct(c); + return code; + } + } + } + + std::istream& readToken(std::istream& is, std::string& str) { + std::ostringstream os; + + char c; + is >> std::ws; + + if (!is.get(c)) + return is; + + if (c == '\"') { + while (is.get(c) && c != '\"') { + if (c == '\\') + c = readEscape(is); + os << c; + } + if (!is) + throw DataFormatError("Quoted format error"); + } else { + is.putback(c); + while (is.get(c) && !isWhiteSpace(c)) { + if (c == '\\') + c = readEscape(is); + os << c; + } + if (!is) { + is.clear(); + } else { + is.putback(c); + } + } + str = os.str(); + return is; + } + + std::istream& readIdentifier(std::istream& is, std::string& str) { + std::ostringstream os; + + char c; + is >> std::ws; + + if (!is.get(c)) + return is; + + if (!isIdentifierFirstChar(c)) + throw DataFormatError("Wrong char in identifier"); + + os << c; + + while (is.get(c) && !isWhiteSpace(c)) { + if (!isIdentifierChar(c)) + throw DataFormatError("Wrong char in identifier"); + os << c; + } + if (!is) is.clear(); + + str = os.str(); + return is; + } + + } + + /// \e + template + class DigraphReader { + public: + + typedef _Digraph Digraph; + GRAPH_TYPEDEFS(typename Digraph); + + private: + + + std::istream* _is; + bool local_is; + + Digraph& _digraph; + + std::string _nodes_caption; + std::string _arcs_caption; + std::string _attributes_caption; + + typedef std::map NodeIndex; + NodeIndex _node_index; + typedef std::map ArcIndex; + ArcIndex _arc_index; + + typedef std::vector*> > NodeMaps; + NodeMaps _node_maps; + + typedef std::vector*> >ArcMaps; + ArcMaps _arc_maps; + + typedef std::multimap + Attributes; + Attributes _attributes; + + bool _use_nodes; + bool _use_arcs; + + int line_num; + std::istringstream line; + + public: + + /// \e + DigraphReader(std::istream& is, Digraph& digraph) + : _is(&is), local_is(false), _digraph(digraph), + _use_nodes(false), _use_arcs(false) {} + + /// \e + DigraphReader(const std::string& fn, Digraph& digraph) + : _is(new std::ifstream(fn.c_str())), local_is(true), _digraph(digraph), + _use_nodes(false), _use_arcs(false) {} + + + /// \e + DigraphReader(const char* fn, Digraph& digraph) + : _is(new std::ifstream(fn)), local_is(true), _digraph(digraph), + _use_nodes(false), _use_arcs(false) {} + + /// \e + DigraphReader(DigraphReader& other) + : _is(other._is), local_is(other.local_is), _digraph(other._digraph), + _use_nodes(other._use_nodes), _use_arcs(other._use_arcs) { + + other.is = 0; + other.local_is = false; + + _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; + } + + /// \e + ~DigraphReader() { + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + delete it->second; + } + + for (typename ArcMaps::iterator it = _arc_maps.begin(); + it != _arc_maps.end(); ++it) { + delete it->second; + } + + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + delete it->second; + } + + if (local_is) { + delete _is; + } + + } + + private: + + DigraphReader& operator=(const DigraphReader&); + + public: + + /// \e + template + DigraphReader& nodeMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map); + _node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \e + template + DigraphReader& nodeMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map, converter); + _node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \e + template + DigraphReader& arcMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map); + _arc_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \e + template + DigraphReader& arcMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map, converter); + _arc_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \e + template + DigraphReader& attribute(const std::string& caption, Value& value) { + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(value); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \e + template + DigraphReader& attribute(const std::string& caption, Value& value, + const Converter& converter = Converter()) { + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(value, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \e + DigraphReader& node(const std::string& caption, Node& node) { + typedef _reader_bits::MapLookUpConverter Converter; + Converter converter(_node_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(node, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \e + DigraphReader& arc(const std::string& caption, Arc& arc) { + typedef _reader_bits::MapLookUpConverter Converter; + Converter converter(_arc_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(arc, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \e + DigraphReader& nodes(const std::string& caption) { + _nodes_caption = caption; + return *this; + } + + /// \e + DigraphReader& arcs(const std::string& caption) { + _arcs_caption = caption; + return *this; + } + + /// \e + DigraphReader& attributes(const std::string& caption) { + _attributes_caption = caption; + return *this; + } + + /// \e + template + DigraphReader& useNodes(const Map& map) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); + _use_nodes = true; + _writer_bits::DefaultConverter converter; + for (NodeIt n(_digraph); n != INVALID; ++n) { + _node_index.insert(std::make_pair(converter(map[n]), n)); + } + return *this; + } + + /// \e + template + DigraphReader& useNodes(const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); + _use_nodes = true; + for (NodeIt n(_digraph); n != INVALID; ++n) { + _node_index.insert(std::make_pair(converter(map[n]), n)); + } + return *this; + } + + /// \e + template + DigraphReader& useArcs(const Map& map) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_arcs, "Multiple usage of useArcs() member"); + _use_arcs = true; + _writer_bits::DefaultConverter converter; + for (ArcIt a(_digraph); a != INVALID; ++a) { + _arc_index.insert(std::make_pair(converter(map[a]), a)); + } + return *this; + } + + /// \e + template + DigraphReader& useArcs(const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_arcs, "Multiple usage of useArcs() member"); + _use_arcs = true; + for (ArcIt a(_digraph); a != INVALID; ++a) { + _arc_index.insert(std::make_pair(converter(map[a]), a)); + } + return *this; + } + + private: + + bool readLine() { + std::string str; + while(++line_num, std::getline(*_is, str)) { + line.clear(); line.str(str); + char c; + if (line >> std::ws >> c && c != '#') { + line.putback(c); + return true; + } + } + return false; + } + + bool readSuccess() { + return static_cast(*_is); + } + + void skipSection() { + char c; + while (readSuccess() && line >> c && c != '@') { + readLine(); + } + line.putback(c); + } + + void readNodes() { + + std::vector map_index(_node_maps.size()); + int map_num, label_index; + + if (!readLine()) + throw DataFormatError("Cannot find map captions"); + + { + std::map maps; + + std::string map; + int index = 0; + while (_reader_bits::readIdentifier(line, map)) { + if (maps.find(map) != maps.end()) { + std::ostringstream msg; + msg << "Multiple occurence of node map: " << map; + throw DataFormatError(msg.str().c_str()); + } + maps.insert(std::make_pair(map, index)); + ++index; + } + + for (int i = 0; i < static_cast(_node_maps.size()); ++i) { + std::map::iterator jt = + maps.find(_node_maps[i].first); + if (jt == maps.end()) { + std::ostringstream msg; + msg << "Map not found in file: " << _node_maps[i].first; + throw DataFormatError(msg.str().c_str()); + } + map_index[i] = jt->second; + } + + { + std::map::iterator jt = maps.find("label"); + if (jt == maps.end()) + throw DataFormatError("Label map not found in file"); + label_index = jt->second; + } + map_num = maps.size(); + } + + char c; + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::vector tokens(map_num); + for (int i = 0; i < map_num; ++i) { + if (!_reader_bits::readToken(line, tokens[i])) { + std::ostringstream msg; + msg << "Column not found (" << i + 1 << ")"; + throw DataFormatError(msg.str().c_str()); + } + } + if (line >> std::ws >> c) + throw DataFormatError("Extra character on the end of line"); + + Node n; + if (!_use_nodes) { + n = _digraph.addNode(); + _node_index.insert(std::make_pair(tokens[label_index], n)); + } else { + typename std::map::iterator it = + _node_index.find(tokens[label_index]); + if (it == _node_index.end()) { + std::ostringstream msg; + msg << "Node with label not found: " << tokens[label_index]; + throw DataFormatError(msg.str().c_str()); + } + n = it->second; + } + + for (int i = 0; i < static_cast(_node_maps.size()); ++i) { + _node_maps[i].second->set(n, tokens[map_index[i]]); + } + + } + if (readSuccess()) { + line.putback(c); + } + } + + void readArcs() { + + std::vector map_index(_arc_maps.size()); + int map_num, label_index; + + if (!readLine()) + throw DataFormatError("Cannot find map captions"); + + { + std::map maps; + + std::string map; + int index = 0; + while (_reader_bits::readIdentifier(line, map)) { + if (maps.find(map) != maps.end()) { + std::ostringstream msg; + msg << "Multiple occurence of arc map: " << map; + throw DataFormatError(msg.str().c_str()); + } + maps.insert(std::make_pair(map, index)); + ++index; + } + + for (int i = 0; i < static_cast(_arc_maps.size()); ++i) { + std::map::iterator jt = + maps.find(_arc_maps[i].first); + if (jt == maps.end()) { + std::ostringstream msg; + msg << "Map not found in file: " << _arc_maps[i].first; + throw DataFormatError(msg.str().c_str()); + } + map_index[i] = jt->second; + } + + { + std::map::iterator jt = maps.find("label"); + if (jt == maps.end()) + throw DataFormatError("Label map not found in file"); + label_index = jt->second; + } + map_num = maps.size(); + } + + char c; + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::string source_token; + std::string target_token; + + if (!_reader_bits::readToken(line, source_token)) + throw DataFormatError("Source not found"); + + if (!_reader_bits::readToken(line, target_token)) + throw DataFormatError("Source not found"); + + std::vector tokens(map_num); + for (int i = 0; i < map_num; ++i) { + if (!_reader_bits::readToken(line, tokens[i])) { + std::ostringstream msg; + msg << "Column not found (" << i + 1 << ")"; + throw DataFormatError(msg.str().c_str()); + } + } + if (line >> std::ws >> c) + throw DataFormatError("Extra character on the end of line"); + + Arc a; + if (!_use_arcs) { + + typename NodeIndex::iterator it; + + it = _node_index.find(source_token); + if (it == _node_index.end()) { + std::ostringstream msg; + msg << "Item not found: " << source_token; + throw DataFormatError(msg.str().c_str()); + } + Node source = it->second; + + it = _node_index.find(target_token); + if (it == _node_index.end()) { + std::ostringstream msg; + msg << "Item not found: " << target_token; + throw DataFormatError(msg.str().c_str()); + } + Node target = it->second; + + a = _digraph.addArc(source, target); + _arc_index.insert(std::make_pair(tokens[label_index], a)); + } else { + typename std::map::iterator it = + _arc_index.find(tokens[label_index]); + if (it == _arc_index.end()) { + std::ostringstream msg; + msg << "Arc with label not found: " << tokens[label_index]; + throw DataFormatError(msg.str().c_str()); + } + a = it->second; + } + + for (int i = 0; i < static_cast(_arc_maps.size()); ++i) { + _arc_maps[i].second->set(a, tokens[map_index[i]]); + } + + } + if (readSuccess()) { + line.putback(c); + } + } + + void readAttributes() { + + std::set read_attr; + + char c; + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::string attr, token; + if (!_reader_bits::readIdentifier(line, attr)) + throw DataFormatError("Attribute name not found"); + if (!_reader_bits::readToken(line, token)) + throw DataFormatError("Attribute value not found"); + if (line >> c) + throw DataFormatError("Extra character on the end of line"); + + { + std::set::iterator it = read_attr.find(attr); + if (it != read_attr.end()) { + std::ostringstream msg; + msg << "Multiple occurence of attribute " << attr; + throw DataFormatError(msg.str().c_str()); + } + read_attr.insert(attr); + } + + { + typename Attributes::iterator it = _attributes.lower_bound(attr); + while (it != _attributes.end() && it->first == attr) { + it->second->set(token); + ++it; + } + } + + } + if (readSuccess()) { + line.putback(c); + } + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + if (read_attr.find(it->first) == read_attr.end()) { + std::ostringstream msg; + msg << "Attribute not found in file: " << it->first; + throw DataFormatError(msg.str().c_str()); + } + } + } + + public: + + /// \e + void run() { + + LEMON_ASSERT(_is != 0, "This reader assigned to an other reader"); + + bool nodes_done = false; + bool arcs_done = false; + bool attributes_done = false; + + line_num = 0; + readLine(); + + while (readSuccess()) { + skipSection(); + try { + char c; + std::string section, caption; + line >> c; + _reader_bits::readIdentifier(line, section); + _reader_bits::readIdentifier(line, caption); + + if (line >> c) + throw DataFormatError("Extra character on the end of line"); + + if (section == "nodes" && !nodes_done) { + if (_nodes_caption.empty() || _nodes_caption == caption) { + readNodes(); + nodes_done = true; + } + } else if ((section == "arcs" || section == "edges") && + !arcs_done) { + if (_arcs_caption.empty() || _arcs_caption == caption) { + readArcs(); + arcs_done = true; + } + } else if (section == "attributes" && !attributes_done) { + if (_attributes_caption.empty() || _attributes_caption == caption) { + readAttributes(); + attributes_done = true; + } + } else { + readLine(); + skipSection(); + } + } catch (DataFormatError& error) { + error.line(line_num); + throw; + } + } + + if (!nodes_done) { + throw DataFormatError("Section @nodes not found"); + } + + if (!arcs_done) { + throw DataFormatError("Section @arcs not found"); + } + + if (!attributes_done && !_attributes.empty()) { + throw DataFormatError("Section @attributes not found"); + } + + } + + }; + + template + DigraphReader digraphReader(std::istream& is, Digraph& digraph) { + return DigraphReader(is, digraph); + } + + template + DigraphReader digraphReader(const std::string& fn, + Digraph& digraph) { + return DigraphReader(fn, digraph); + } + + template + DigraphReader digraphReader(const char* fn, Digraph& digraph) { + return DigraphReader(fn, digraph); + } +} + +#endif diff -r e1dd2a70737c -r 1c9a9e2f7d4d lemon/lgf_writer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/lgf_writer.h Thu Apr 17 15:18:45 2008 +0100 @@ -0,0 +1,627 @@ +/* -*- C++ -*- + * + * 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 + * purpose. + * + */ + +///\ingroup lemon_io +///\file +///\brief Lemon Graph Format writer. + + +#ifndef LEMON_LGF_WRITER_H +#define LEMON_LGF_WRITER_H + +#include +#include +#include + +#include + +#include +#include + +#include +#include + +namespace lemon { + + namespace _writer_bits { + + template + struct DefaultConverter { + std::string operator()(const Value& value) { + std::ostringstream os; + os << value; + return os.str(); + } + }; + + template + bool operator<(const T&, const T&) { + throw DataFormatError("Label map is not comparable"); + } + + template + class MapLess { + public: + typedef _Map Map; + typedef typename Map::Key Item; + + private: + const Map& _map; + + public: + MapLess(const Map& map) : _map(map) {} + + bool operator()(const Item& left, const Item& right) { + return _map[left] < _map[right]; + } + }; + + template + class MapStorageBase { + public: + typedef _Item Item; + + public: + MapStorageBase() {} + virtual ~MapStorageBase() {} + + virtual std::string get(const Item& item) = 0; + virtual void sort(std::vector&) = 0; + }; + + template > + class MapStorage : public MapStorageBase<_Item> { + public: + typedef _Map Map; + typedef _Converter Converter; + typedef _Item Item; + + private: + const Map& _map; + Converter _converter; + + public: + MapStorage(const Map& map, const Converter& converter = Converter()) + : _map(map), _converter(converter) {} + virtual ~MapStorage() {} + + virtual std::string get(const Item& item) { + return _converter(_map[item]); + } + virtual void sort(std::vector& items) { + MapLess less(_map); + std::sort(items.begin(), items.end(), less); + } + }; + + class ValueStorageBase { + public: + ValueStorageBase() {} + virtual ~ValueStorageBase() {} + + virtual std::string get() = 0; + }; + + template > + class ValueStorage : public ValueStorageBase { + public: + typedef _Value Value; + typedef _Converter Converter; + + private: + const Value& _value; + Converter _converter; + + public: + ValueStorage(const Value& value, const Converter& converter = Converter()) + : _value(value), _converter(converter) {} + + virtual std::string get() { + return _converter(_value); + } + }; + + template + struct MapLookUpConverter { + const std::map& _map; + + MapLookUpConverter(const std::map& map) + : _map(map) {} + + std::string operator()(const Value& str) { + typename std::map::const_iterator it = + _map.find(str); + if (it == _map.end()) { + throw DataFormatError("Item not found"); + } + return it->second; + } + }; + + bool isWhiteSpace(char c) { + return c == ' ' || c == '\t' || c == '\v' || + c == '\n' || c == '\r' || c == '\f'; + } + + bool isEscaped(char c) { + return c == '\\' || c == '\"' || c == '\'' || + c == '\a' || c == '\b'; + } + + static void writeEscape(std::ostream& os, char c) { + switch (c) { + case '\\': + os << "\\\\"; + return; + case '\"': + os << "\\\""; + return; + case '\a': + os << "\\a"; + return; + case '\b': + os << "\\b"; + return; + case '\f': + os << "\\f"; + return; + case '\r': + os << "\\r"; + return; + case '\n': + os << "\\n"; + return; + case '\t': + os << "\\t"; + return; + case '\v': + os << "\\v"; + return; + default: + if (c < 0x20) { + os << '\\' << std::oct << static_cast(c); + } else { + os << c; + } + return; + } + } + + bool requireEscape(const std::string& str) { + std::istringstream is(str); + char c; + while (is.get(c)) { + if (isWhiteSpace(c) || isEscaped(c)) { + return true; + } + } + return false; + } + + std::ostream& writeToken(std::ostream& os, const std::string& str) { + + if (requireEscape(str)) { + os << '\"'; + for (std::string::const_iterator it = str.begin(); + it != str.end(); ++it) { + writeEscape(os, *it); + } + os << '\"'; + } else { + os << str; + } + return os; + } + + } + + /// \e + template + class DigraphWriter { + public: + + typedef _Digraph Digraph; + GRAPH_TYPEDEFS(typename Digraph); + + private: + + + std::ostream* _os; + bool local_os; + + Digraph& _digraph; + + std::string _nodes_caption; + std::string _arcs_caption; + std::string _attributes_caption; + + typedef std::map NodeIndex; + NodeIndex _node_index; + typedef std::map ArcIndex; + ArcIndex _arc_index; + + typedef std::vector* > > NodeMaps; + NodeMaps _node_maps; + + typedef std::vector* > >ArcMaps; + ArcMaps _arc_maps; + + typedef std::vector > Attributes; + Attributes _attributes; + + bool _skip_nodes; + bool _skip_arcs; + + public: + + /// \e + DigraphWriter(std::ostream& is, Digraph& digraph) + : _os(&is), local_os(false), _digraph(digraph), + _skip_nodes(false), _skip_arcs(false) {} + + /// \e + 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) {} + + /// \e + DigraphWriter(const char* fn, Digraph& digraph) + : _os(new std::ofstream(fn)), local_os(true), _digraph(digraph), + _skip_nodes(false), _skip_arcs(false) {} + + DigraphWriter(DigraphWriter& other) + : _os(other._os), local_os(other.local_os), _digraph(other._digraph), + _skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) { + + other.is = 0; + other.local_os = false; + + _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; + } + + /// \e + ~DigraphWriter() { + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + delete it->second; + } + + for (typename ArcMaps::iterator it = _arc_maps.begin(); + it != _arc_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: + + DigraphWriter& operator=(const DigraphWriter&); + + public: + + /// \e + template + DigraphWriter& nodeMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map); + _node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \e + template + DigraphWriter& nodeMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map, converter); + _node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \e + template + DigraphWriter& arcMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map); + _arc_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \e + template + DigraphWriter& arcMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map, converter); + _arc_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \e + template + DigraphWriter& 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; + } + + /// \e + template + DigraphWriter& 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; + } + + /// \e + DigraphWriter& 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; + } + + /// \e + DigraphWriter& arc(const std::string& caption, const Arc& arc) { + typedef _writer_bits::MapLookUpConverter Converter; + Converter converter(_arc_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(arc, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \e + DigraphWriter& nodes(const std::string& caption) { + _nodes_caption = caption; + return *this; + } + + /// \e + DigraphWriter& arcs(const std::string& caption) { + _arcs_caption = caption; + return *this; + } + + /// \e + DigraphWriter& attributes(const std::string& caption) { + _attributes_caption = caption; + return *this; + } + + DigraphWriter& skipNodes() { + LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member"); + return *this; + } + + DigraphWriter& skipArcs() { + LEMON_ASSERT(!_skip_arcs, "Multiple usage of skipArcs() member"); + return *this; + } + + private: + + void writeNodes() { + _writer_bits::MapStorageBase* label = 0; + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + *_os << "@nodes"; + if (!_nodes_caption.empty()) { + *_os << ' ' << _nodes_caption; + } + *_os << std::endl; + + if (label == 0) { + *_os << "label" << '\t'; + } + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + *_os << it->first << '\t'; + } + *_os << std::endl; + + std::vector nodes; + for (NodeIt n(_digraph); n != INVALID; ++n) { + nodes.push_back(n); + } + + if (label == 0) { + IdMap id_map(_digraph); + _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 << _digraph.id(n); + _writer_bits::writeToken(*_os, os.str()); + *_os << '\t'; + _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)); + } + *_os << '\t'; + } + *_os << std::endl; + } + } + + void writeArcs() { + _writer_bits::MapStorageBase* label = 0; + for (typename ArcMaps::iterator it = _arc_maps.begin(); + it != _arc_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + *_os << "@arcs"; + if (!_arcs_caption.empty()) { + *_os << ' ' << _arcs_caption; + } + *_os << std::endl; + + *_os << '\t' << '\t'; + if (label == 0) { + *_os << "label" << '\t'; + } + for (typename ArcMaps::iterator it = _arc_maps.begin(); + it != _arc_maps.end(); ++it) { + *_os << it->first << '\t'; + } + *_os << std::endl; + + std::vector arcs; + for (ArcIt n(_digraph); n != INVALID; ++n) { + arcs.push_back(n); + } + + if (label == 0) { + IdMap id_map(_digraph); + _writer_bits::MapLess > id_less(id_map); + std::sort(arcs.begin(), arcs.end(), id_less); + } else { + label->sort(arcs); + } + + for (int i = 0; i < static_cast(arcs.size()); ++i) { + Arc a = arcs[i]; + _writer_bits::writeToken(*_os, _node_index. + find(_digraph.source(a))->second); + *_os << '\t'; + _writer_bits::writeToken(*_os, _node_index. + find(_digraph.target(a))->second); + *_os << '\t'; + if (label == 0) { + std::ostringstream os; + os << _digraph.id(a); + _writer_bits::writeToken(*_os, os.str()); + *_os << '\t'; + _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)); + } + *_os << '\t'; + } + *_os << std::endl; + } + } + + void writeAttributes() { + if (_attributes.empty()) return; + *_os << "@attributes"; + if (!_attributes_caption.empty()) { + *_os << ' ' << _attributes_caption; + } + *_os << std::endl; + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + *_os << it->first << ' '; + _writer_bits::writeToken(*_os, it->second->get()); + *_os << std::endl; + } + } + + public: + + /// \e + void run() { + if (!_skip_nodes) { + writeNodes(); + } + if (!_skip_arcs) { + writeArcs(); + } + writeAttributes(); + } + + /// \e + std::ostream& stream() { + return *_os; + } + }; + + template + DigraphWriter digraphWriter(std::istream& is, Digraph& digraph) { + return DigraphWriter(is, digraph); + } + + template + DigraphWriter digraphWriter(const std::string& fn, + Digraph& digraph) { + return DigraphWriter(fn, digraph); + } + + template + DigraphWriter digraphWriter(const char* fn, Digraph& digraph) { + return DigraphWriter(fn, digraph); + } +} + +#endif