gravatar
alpar (Alpar Juttner)
alpar@cs.elte.hu
Merge #382 to branch 1.0
0 4 1
merge 1.0
1 file changed with 204 insertions and 7 deletions:
↑ Collapse diff ↑
Ignore white space 6 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2011
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#include <lemon/list_graph.h>
20
#include <lemon/lgf_reader.h>
21
#include "test_tools.h"
22

	
23
using namespace lemon;
24

	
25
char test_lgf[] =
26
  "@nodes\n"
27
  "label\n"
28
  "0\n"
29
  "1\n"
30
  "@arcs\n"
31
  "     label\n"
32
  "0 1  0\n"
33
  "1 0  1\n"
34
  "@attributes\n"
35
  "source 0\n"
36
  "target 1\n";
37

	
38
char test_lgf_nomap[] =
39
  "@nodes\n"
40
  "label\n"
41
  "0\n"
42
  "1\n"
43
  "@arcs\n"
44
  "     -\n"
45
  "0 1\n";
46

	
47
char test_lgf_bad1[] =
48
  "@nodes\n"
49
  "label\n"
50
  "0\n"
51
  "1\n"
52
  "@arcs\n"
53
  "     - another\n"
54
  "0 1\n";
55

	
56
char test_lgf_bad2[] =
57
  "@nodes\n"
58
  "label\n"
59
  "0\n"
60
  "1\n"
61
  "@arcs\n"
62
  "     label -\n"
63
  "0 1\n";
64

	
65

	
66
int main() 
67
{
68
  {
69
    ListDigraph d; 
70
    ListDigraph::Node s,t;
71
    ListDigraph::ArcMap<int> label(d);
72
    std::istringstream input(test_lgf);
73
    digraphReader(d, input).
74
      node("source", s).
75
      node("target", t).
76
      arcMap("label", label).
77
      run();
78
    check(countNodes(d) == 2,"There should be 2 nodes");
79
    check(countArcs(d) == 2,"There should be 2 arcs");
80
  }
81
  {
82
    ListGraph g;
83
    ListGraph::Node s,t;
84
    ListGraph::EdgeMap<int> label(g);
85
    std::istringstream input(test_lgf);
86
    graphReader(g, input).
87
      node("source", s).
88
      node("target", t).
89
      edgeMap("label", label).
90
      run();
91
    check(countNodes(g) == 2,"There should be 2 nodes");
92
    check(countEdges(g) == 2,"There should be 2 arcs");
93
  }
94

	
95
  {
96
    ListDigraph d; 
97
    std::istringstream input(test_lgf_nomap);
98
    digraphReader(d, input).
99
      run();
100
    check(countNodes(d) == 2,"There should be 2 nodes");
101
    check(countArcs(d) == 1,"There should be 1 arc");
102
  }
103
  {
104
    ListGraph g;
105
    std::istringstream input(test_lgf_nomap);
106
    graphReader(g, input).
107
      run();
108
    check(countNodes(g) == 2,"There should be 2 nodes");
109
    check(countEdges(g) == 1,"There should be 1 edge");
110
  }
111

	
112
  {
113
    ListDigraph d; 
114
    std::istringstream input(test_lgf_bad1);
115
    bool ok=false;
116
    try {
117
      digraphReader(d, input).
118
        run();
119
    }
120
    catch (FormatError& error) 
121
      {
122
        ok = true;
123
      }
124
    check(ok,"FormatError exception should have occured");
125
  }
126
  {
127
    ListGraph g;
128
    std::istringstream input(test_lgf_bad1);
129
    bool ok=false;
130
    try {
131
      graphReader(g, input).
132
        run();
133
    }
134
    catch (FormatError& error)
135
      {
136
        ok = true;
137
      }
138
    check(ok,"FormatError exception should have occured");
139
  }
140

	
141
  {
142
    ListDigraph d; 
143
    std::istringstream input(test_lgf_bad2);
144
    bool ok=false;
145
    try {
146
      digraphReader(d, input).
147
        run();
148
    }
149
    catch (FormatError& error)
150
      {
151
        ok = true;
152
      }
153
    check(ok,"FormatError exception should have occured");
154
  }
155
  {
156
    ListGraph g;
157
    std::istringstream input(test_lgf_bad2);
158
    bool ok=false;
159
    try {
160
      graphReader(g, input).
161
        run();
162
    }
163
    catch (FormatError& error)
164
      {
165
        ok = true;
166
      }
167
    check(ok,"FormatError exception should have occured");
168
  }
169
}
Ignore white space 6 line context
... ...
@@ -18,90 +18,101 @@
18 18

	
19 19
namespace lemon {
20 20
/*!
21 21

	
22 22

	
23 23

	
24 24
\page lgf-format LEMON Graph Format (LGF)
25 25

	
26 26
The \e LGF is a <em>column oriented</em>
27 27
file format for storing graphs and associated data like
28 28
node and edge maps.
29 29

	
30 30
Each line with \c '#' first non-whitespace
31 31
character is considered as a comment line.
32 32

	
33 33
Otherwise the file consists of sections starting with
34 34
a header line. The header lines starts with an \c '@' character followed by the
35 35
type of section. The standard section types are \c \@nodes, \c
36 36
\@arcs and \c \@edges
37 37
and \@attributes. Each header line may also have an optional
38 38
\e name, which can be use to distinguish the sections of the same
39 39
type.
40 40

	
41 41
The standard sections are column oriented, each line consists of
42 42
<em>token</em>s separated by whitespaces. A token can be \e plain or
43 43
\e quoted. A plain token is just a sequence of non-whitespace characters,
44 44
while a quoted token is a
45 45
character sequence surrounded by double quotes, and it can also
46 46
contain whitespaces and escape sequences.
47 47

	
48 48
The \c \@nodes section describes a set of nodes and associated
49 49
maps. The first is a header line, its columns are the names of the
50 50
maps appearing in the following lines.
51 51
One of the maps must be called \c
52 52
"label", which plays special role in the file.
53 53
The following
54 54
non-empty lines until the next section describes nodes of the
55 55
graph. Each line contains the values of the node maps
56 56
associated to the current node.
57 57

	
58 58
\code
59 59
 @nodes
60 60
 label  coordinates  size    title
61 61
 1      (10,20)      10      "First node"
62 62
 2      (80,80)      8       "Second node"
63 63
 3      (40,10)      10      "Third node"
64 64
\endcode
65 65

	
66
The \c \@arcs section is very similar to the \c \@nodes section,
67
it again starts with a header line describing the names of the maps,
68
but the \c "label" map is not obligatory here. The following lines
69
describe the arcs. The first two tokens of each line are
70
the source and the target node of the arc, respectively, then come the map
66
The \c \@arcs section is very similar to the \c \@nodes section, it
67
again starts with a header line describing the names of the maps, but
68
the \c "label" map is not obligatory here. The following lines
69
describe the arcs. The first two tokens of each line are the source
70
and the target node of the arc, respectively, then come the map
71 71
values. The source and target tokens must be node labels.
72 72

	
73 73
\code
74 74
 @arcs
75 75
         capacity
76 76
 1   2   16
77 77
 1   3   12
78 78
 2   3   18
79 79
\endcode
80 80

	
81
If there is no map in the \c \@arcs section at all, then it must be
82
indicated by a sole '-' sign in the first line.
83

	
84
\code
85
 @arcs
86
         -
87
 1   2
88
 1   3
89
 2   3
90
\endcode
91

	
81 92
The \c \@edges is just a synonym of \c \@arcs. The \@arcs section can
82 93
also store the edge set of an undirected graph. In such case there is
83 94
a conventional method for store arc maps in the file, if two columns
84
has the same caption with \c '+' and \c '-' prefix, then these columns
95
have the same caption with \c '+' and \c '-' prefix, then these columns
85 96
can be regarded as the values of an arc map.
86 97

	
87 98
The \c \@attributes section contains key-value pairs, each line
88 99
consists of two tokens, an attribute name, and then an attribute
89 100
value. The value of the attribute could be also a label value of a
90 101
node or an edge, or even an edge label prefixed with \c '+' or \c '-',
91 102
which regards to the forward or backward directed arc of the
92 103
corresponding edge.
93 104

	
94 105
\code
95 106
 @attributes
96 107
 source 1
97 108
 target 3
98 109
 caption "LEMON test digraph"
99 110
\endcode
100 111

	
101 112
The \e LGF can contain extra sections, but there is no restriction on
102 113
the format of such sections.
103 114

	
104 115
*/
105 116
}
106 117

	
107 118
//  LocalWords:  whitespace whitespaces
Ignore white space 6 line context
1 1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 2
 *
3 3
 * This file is a part of LEMON, a generic C++ optimization library.
4 4
 *
5
 * Copyright (C) 2003-2008
5
 * Copyright (C) 2003-2011
6 6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 8
 *
9 9
 * Permission to use, modify and distribute this software is granted
10 10
 * provided that this copyright notice appears in all copies. For
11 11
 * precise terms see the accompanying LICENSE file.
12 12
 *
13 13
 * This software is provided "AS IS" with no warranty of any kind,
14 14
 * express or implied, and with no claim as to its suitability for any
15 15
 * purpose.
16 16
 *
17 17
 */
18 18

	
19 19
///\ingroup lemon_io
20 20
///\file
21 21
///\brief \ref lgf-format "LEMON Graph Format" reader.
22 22

	
23 23

	
24 24
#ifndef LEMON_LGF_READER_H
25 25
#define LEMON_LGF_READER_H
26 26

	
27 27
#include <iostream>
28 28
#include <fstream>
29 29
#include <sstream>
30 30

	
31 31
#include <set>
32 32
#include <map>
33 33

	
34 34
#include <lemon/core.h>
35 35

	
36 36
#include <lemon/lgf_writer.h>
37 37

	
38 38
#include <lemon/concept_check.h>
39 39
#include <lemon/concepts/maps.h>
40 40

	
41 41
namespace lemon {
42 42

	
43 43
  namespace _reader_bits {
44 44

	
45 45
    template <typename Value>
46 46
    struct DefaultConverter {
47 47
      Value operator()(const std::string& str) {
48 48
        std::istringstream is(str);
49 49
        Value value;
50 50
        if (!(is >> value)) {
51 51
          throw FormatError("Cannot read token");
52 52
        }
53 53

	
... ...
@@ -920,96 +920,103 @@
920 920
        Node n;
921 921
        if (!_use_nodes) {
922 922
          n = _digraph.addNode();
923 923
          if (label_index != -1)
924 924
            _node_index.insert(std::make_pair(tokens[label_index], n));
925 925
        } else {
926 926
          if (label_index == -1)
927 927
            throw FormatError("Label map not found");
928 928
          typename std::map<std::string, Node>::iterator it =
929 929
            _node_index.find(tokens[label_index]);
930 930
          if (it == _node_index.end()) {
931 931
            std::ostringstream msg;
932 932
            msg << "Node with label not found: " << tokens[label_index];
933 933
            throw FormatError(msg.str());
934 934
          }
935 935
          n = it->second;
936 936
        }
937 937

	
938 938
        for (int i = 0; i < static_cast<int>(_node_maps.size()); ++i) {
939 939
          _node_maps[i].second->set(n, tokens[map_index[i]]);
940 940
        }
941 941

	
942 942
      }
943 943
      if (readSuccess()) {
944 944
        line.putback(c);
945 945
      }
946 946
    }
947 947

	
948 948
    void readArcs() {
949 949

	
950 950
      std::vector<int> map_index(_arc_maps.size());
951 951
      int map_num, label_index;
952 952

	
953 953
      char c;
954 954
      if (!readLine() || !(line >> c) || c == '@') {
955 955
        if (readSuccess() && line) line.putback(c);
956 956
        if (!_arc_maps.empty())
957 957
          throw FormatError("Cannot find map names");
958 958
        return;
959 959
      }
960 960
      line.putback(c);
961 961

	
962 962
      {
963 963
        std::map<std::string, int> maps;
964 964

	
965 965
        std::string map;
966 966
        int index = 0;
967 967
        while (_reader_bits::readToken(line, map)) {
968
          if(map == "-") {
969
              if(index!=0)
970
                throw FormatError("'-' is not allowed as a map name");
971
              else if (line >> std::ws >> c)
972
                throw FormatError("Extra character at the end of line");
973
              else break;
974
            }
968 975
          if (maps.find(map) != maps.end()) {
969 976
            std::ostringstream msg;
970 977
            msg << "Multiple occurence of arc map: " << map;
971 978
            throw FormatError(msg.str());
972 979
          }
973 980
          maps.insert(std::make_pair(map, index));
974 981
          ++index;
975 982
        }
976 983

	
977 984
        for (int i = 0; i < static_cast<int>(_arc_maps.size()); ++i) {
978 985
          std::map<std::string, int>::iterator jt =
979 986
            maps.find(_arc_maps[i].first);
980 987
          if (jt == maps.end()) {
981 988
            std::ostringstream msg;
982 989
            msg << "Map not found: " << _arc_maps[i].first;
983 990
            throw FormatError(msg.str());
984 991
          }
985 992
          map_index[i] = jt->second;
986 993
        }
987 994

	
988 995
        {
989 996
          std::map<std::string, int>::iterator jt = maps.find("label");
990 997
          if (jt != maps.end()) {
991 998
            label_index = jt->second;
992 999
          } else {
993 1000
            label_index = -1;
994 1001
          }
995 1002
        }
996 1003
        map_num = maps.size();
997 1004
      }
998 1005

	
999 1006
      while (readLine() && line >> c && c != '@') {
1000 1007
        line.putback(c);
1001 1008

	
1002 1009
        std::string source_token;
1003 1010
        std::string target_token;
1004 1011

	
1005 1012
        if (!_reader_bits::readToken(line, source_token))
1006 1013
          throw FormatError("Source not found");
1007 1014

	
1008 1015
        if (!_reader_bits::readToken(line, target_token))
1009 1016
          throw FormatError("Target not found");
1010 1017

	
1011 1018
        std::vector<std::string> tokens(map_num);
1012 1019
        for (int i = 0; i < map_num; ++i) {
1013 1020
          if (!_reader_bits::readToken(line, tokens[i])) {
1014 1021
            std::ostringstream msg;
1015 1022
            msg << "Column not found (" << i + 1 << ")";
... ...
@@ -1762,96 +1769,103 @@
1762 1769
        Node n;
1763 1770
        if (!_use_nodes) {
1764 1771
          n = _graph.addNode();
1765 1772
          if (label_index != -1)
1766 1773
            _node_index.insert(std::make_pair(tokens[label_index], n));
1767 1774
        } else {
1768 1775
          if (label_index == -1)
1769 1776
            throw FormatError("Label map not found");
1770 1777
          typename std::map<std::string, Node>::iterator it =
1771 1778
            _node_index.find(tokens[label_index]);
1772 1779
          if (it == _node_index.end()) {
1773 1780
            std::ostringstream msg;
1774 1781
            msg << "Node with label not found: " << tokens[label_index];
1775 1782
            throw FormatError(msg.str());
1776 1783
          }
1777 1784
          n = it->second;
1778 1785
        }
1779 1786

	
1780 1787
        for (int i = 0; i < static_cast<int>(_node_maps.size()); ++i) {
1781 1788
          _node_maps[i].second->set(n, tokens[map_index[i]]);
1782 1789
        }
1783 1790

	
1784 1791
      }
1785 1792
      if (readSuccess()) {
1786 1793
        line.putback(c);
1787 1794
      }
1788 1795
    }
1789 1796

	
1790 1797
    void readEdges() {
1791 1798

	
1792 1799
      std::vector<int> map_index(_edge_maps.size());
1793 1800
      int map_num, label_index;
1794 1801

	
1795 1802
      char c;
1796 1803
      if (!readLine() || !(line >> c) || c == '@') {
1797 1804
        if (readSuccess() && line) line.putback(c);
1798 1805
        if (!_edge_maps.empty())
1799 1806
          throw FormatError("Cannot find map names");
1800 1807
        return;
1801 1808
      }
1802 1809
      line.putback(c);
1803 1810

	
1804 1811
      {
1805 1812
        std::map<std::string, int> maps;
1806 1813

	
1807 1814
        std::string map;
1808 1815
        int index = 0;
1809 1816
        while (_reader_bits::readToken(line, map)) {
1817
          if(map == "-") {
1818
              if(index!=0)
1819
                throw FormatError("'-' is not allowed as a map name");
1820
              else if (line >> std::ws >> c)
1821
                throw FormatError("Extra character at the end of line");
1822
              else break;
1823
            }
1810 1824
          if (maps.find(map) != maps.end()) {
1811 1825
            std::ostringstream msg;
1812 1826
            msg << "Multiple occurence of edge map: " << map;
1813 1827
            throw FormatError(msg.str());
1814 1828
          }
1815 1829
          maps.insert(std::make_pair(map, index));
1816 1830
          ++index;
1817 1831
        }
1818 1832

	
1819 1833
        for (int i = 0; i < static_cast<int>(_edge_maps.size()); ++i) {
1820 1834
          std::map<std::string, int>::iterator jt =
1821 1835
            maps.find(_edge_maps[i].first);
1822 1836
          if (jt == maps.end()) {
1823 1837
            std::ostringstream msg;
1824 1838
            msg << "Map not found: " << _edge_maps[i].first;
1825 1839
            throw FormatError(msg.str());
1826 1840
          }
1827 1841
          map_index[i] = jt->second;
1828 1842
        }
1829 1843

	
1830 1844
        {
1831 1845
          std::map<std::string, int>::iterator jt = maps.find("label");
1832 1846
          if (jt != maps.end()) {
1833 1847
            label_index = jt->second;
1834 1848
          } else {
1835 1849
            label_index = -1;
1836 1850
          }
1837 1851
        }
1838 1852
        map_num = maps.size();
1839 1853
      }
1840 1854

	
1841 1855
      while (readLine() && line >> c && c != '@') {
1842 1856
        line.putback(c);
1843 1857

	
1844 1858
        std::string source_token;
1845 1859
        std::string target_token;
1846 1860

	
1847 1861
        if (!_reader_bits::readToken(line, source_token))
1848 1862
          throw FormatError("Node u not found");
1849 1863

	
1850 1864
        if (!_reader_bits::readToken(line, target_token))
1851 1865
          throw FormatError("Node v not found");
1852 1866

	
1853 1867
        std::vector<std::string> tokens(map_num);
1854 1868
        for (int i = 0; i < map_num; ++i) {
1855 1869
          if (!_reader_bits::readToken(line, tokens[i])) {
1856 1870
            std::ostringstream msg;
1857 1871
            msg << "Column not found (" << i + 1 << ")";
Ignore white space 96 line context
1 1
INCLUDE_DIRECTORIES(
2 2
  ${CMAKE_SOURCE_DIR}
3 3
  ${PROJECT_BINARY_DIR}
4 4
)
5 5

	
6 6
LINK_DIRECTORIES(${CMAKE_BINARY_DIR}/lemon)
7 7

	
8 8
SET(TESTS
9 9
  bfs_test
10 10
  counter_test
11 11
  dfs_test
12 12
  digraph_test
13 13
  dijkstra_test
14 14
  dim_test
15 15
  error_test
16 16
  graph_copy_test
17 17
  graph_test
18 18
  graph_utils_test
19 19
  heap_test
20 20
  kruskal_test
21
  lgf_test
21 22
  maps_test
22 23
  random_test
23 24
  path_test
24 25
  time_measure_test
25 26
  unionfind_test)
26 27

	
27 28
FOREACH(TEST_NAME ${TESTS})
28 29
  ADD_EXECUTABLE(${TEST_NAME} ${TEST_NAME}.cc)
29 30
  TARGET_LINK_LIBRARIES(${TEST_NAME} lemon)
30 31
  ADD_TEST(${TEST_NAME} ${TEST_NAME})
31 32
ENDFOREACH(TEST_NAME)
Ignore white space 6 line context
1 1
EXTRA_DIST += \
2 2
	test/CMakeLists.txt
3 3

	
4 4
noinst_HEADERS += \
5 5
	test/graph_test.h \
6 6
        test/test_tools.h
7 7

	
8 8
check_PROGRAMS += \
9 9
	test/bfs_test \
10 10
        test/counter_test \
11 11
	test/dfs_test \
12 12
	test/digraph_test \
13 13
	test/dijkstra_test \
14 14
        test/dim_test \
15 15
	test/error_test \
16 16
	test/graph_copy_test \
17 17
	test/graph_test \
18 18
	test/graph_utils_test \
19 19
	test/heap_test \
20 20
	test/kruskal_test \
21
	test/lgf_test \
21 22
        test/maps_test \
22 23
        test/random_test \
23 24
        test/path_test \
24 25
        test/test_tools_fail \
25 26
        test/test_tools_pass \
26 27
        test/time_measure_test \
27 28
	test/unionfind_test
28 29

	
29 30
TESTS += $(check_PROGRAMS)
30 31
XFAIL_TESTS += test/test_tools_fail$(EXEEXT)
31 32

	
32 33
test_bfs_test_SOURCES = test/bfs_test.cc
33 34
test_counter_test_SOURCES = test/counter_test.cc
34 35
test_dfs_test_SOURCES = test/dfs_test.cc
35 36
test_digraph_test_SOURCES = test/digraph_test.cc
36 37
test_dijkstra_test_SOURCES = test/dijkstra_test.cc
37 38
test_dim_test_SOURCES = test/dim_test.cc
38 39
test_error_test_SOURCES = test/error_test.cc
39 40
test_graph_copy_test_SOURCES = test/graph_copy_test.cc
40 41
test_graph_test_SOURCES = test/graph_test.cc
41 42
test_graph_utils_test_SOURCES = test/graph_utils_test.cc
42 43
test_heap_test_SOURCES = test/heap_test.cc
43 44
test_kruskal_test_SOURCES = test/kruskal_test.cc
45
test_lgf_test_SOURCES = test/lgf_test.cc
44 46
test_maps_test_SOURCES = test/maps_test.cc
45 47
test_path_test_SOURCES = test/path_test.cc
46 48
test_random_test_SOURCES = test/random_test.cc
47 49
test_test_tools_fail_SOURCES = test/test_tools_fail.cc
48 50
test_test_tools_pass_SOURCES = test/test_tools_pass.cc
49 51
test_time_measure_test_SOURCES = test/time_measure_test.cc
50 52
test_unionfind_test_SOURCES = test/unionfind_test.cc
0 comments (0 inline)