gravatar
alpar (Alpar Juttner)
alpar@cs.elte.hu
More flexible header names in .lgf + largely improved doc
0 4 1
default
5 files changed with 387 insertions and 100 deletions:
↑ Collapse diff ↑
Ignore white space 16384 line context
1
/* -*- C++ -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library
4
 *
5
 * Copyright (C) 2003-2008
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
namespace lemon {
20
/*!
21

	
22

	
23

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

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

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

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

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

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

	
58
\code
59
 @nodes
60
 label   coordinates size    title
61
 1       (10,20)     10      "First node"
62
 2       (80,80)     8       "Second node"
63
 3       (40,10)     10      "Third node"
64
\endcode
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 arc,
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
71
values. The source and target tokens must be node labels.
72

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

	
81
The \c \@edges is just a synonym of \c \@arcs.
82

	
83
The \c \@attributes section contains key-value pairs, each line
84
consists of two tokens, an attribute name, and then an attribute value.
85

	
86
\code
87
 @attributes
88
 source 1
89
 target 3
90
 caption "LEMON test digraph"
91
\endcode
92

	
93
*/
94
}
95

	
96
//  LocalWords:  whitespace whitespaces
Ignore white space 6 line context
1 1
EXTRA_DIST += \
2 2
	doc/Doxyfile.in \
3 3
	doc/coding_style.dox \
4 4
	doc/dirs.dox \
5 5
	doc/groups.dox \
6
	doc/lgf.dox \
6 7
	doc/license.dox \
7 8
	doc/mainpage.dox \
8 9
	doc/namespaces.dox \
9 10
	doc/html
10 11

	
11 12
DOC_EPS_IMAGES18 = \
12 13
	nodeshape_0.eps \
13 14
	nodeshape_1.eps \
14 15
	nodeshape_2.eps \
15 16
	nodeshape_3.eps \
16 17
	nodeshape_4.eps
17 18

	
18 19
DOC_EPS_IMAGES = \
19 20
	$(DOC_EPS_IMAGES18)
20 21

	
21 22
DOC_PNG_IMAGES = \
22 23
	$(DOC_EPS_IMAGES:%.eps=doc/gen-images/%.png)
23 24

	
24 25
EXTRA_DIST += $(DOC_EPS_IMAGES:%=doc/images/%)
25 26

	
26 27
doc/html:
27 28
	$(MAKE) $(AM_MAKEFLAGS) html
28 29

	
29 30
GS_COMMAND=gs -dNOPAUSE -dBATCH -q -dEPSCrop -dTextAlphaBits=4 -dGraphicsAlphaBits=4
30 31

	
31 32
$(DOC_EPS_IMAGES18:%.eps=doc/gen-images/%.png): doc/gen-images/%.png: doc/images/%.eps
32 33
	-mkdir doc/gen-images
33 34
	if test ${gs_found} = yes; then \
34 35
	  $(GS_COMMAND) -sDEVICE=pngalpha -r18 -sOutputFile=$@ $<; \
35 36
	else \
36 37
	  echo; \
37 38
	  echo "Ghostscript not found."; \
38 39
	  echo; \
39 40
	  exit 1; \
40 41
	fi
41 42

	
42 43
html-local: $(DOC_PNG_IMAGES)
43 44
	if test ${doxygen_found} = yes; then \
44 45
	  cd doc; \
45 46
	  doxygen Doxyfile; \
46 47
	  cd ..; \
47 48
	else \
48 49
	  echo; \
49 50
	  echo "Doxygen not found."; \
50 51
	  echo; \
51 52
	  exit 1; \
52 53
	fi
53 54

	
54 55
clean-local:
55 56
	-rm -rf doc/html
56 57
	-rm -f doc/doxygen.log
57 58
	-rm -f $(DOC_PNG_IMAGES)
58 59
	-rm -rf doc/gen-images
59 60

	
60 61
update-external-tags:
61 62
	wget -O doc/libstdc++.tag.tmp http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/libstdc++.tag && \
62 63
	mv doc/libstdc++.tag.tmp doc/libstdc++.tag || \
63 64
	rm doc/libstdc++.tag.tmp
64 65

	
65 66
install-html-local: doc/html
66 67
	@$(NORMAL_INSTALL)
67 68
	$(mkinstalldirs) $(DESTDIR)$(htmldir)/docs
68 69
	for p in doc/html/*.{html,css,png,map,gif,tag} ; do \
69 70
	  f="`echo $$p | sed -e 's|^.*/||'`"; \
70 71
	  echo " $(INSTALL_DATA) $$p $(DESTDIR)$(htmldir)/docs/$$f"; \
71 72
	  $(INSTALL_DATA) $$p $(DESTDIR)$(htmldir)/docs/$$f; \
72 73
	done
73 74

	
74 75
uninstall-local:
75 76
	@$(NORMAL_UNINSTALL)
76 77
	for p in doc/html/*.{html,css,png,map,gif,tag} ; do \
77 78
	  f="`echo $$p | sed -e 's|^.*/||'`"; \
78 79
	  echo " rm -f $(DESTDIR)$(htmldir)/docs/$$f"; \
79 80
	  rm -f $(DESTDIR)$(htmldir)/docs/$$f; \
80 81
	done
81 82

	
82 83
.PHONY: update-external-tags
Ignore white space 6 line context
1 1
/* -*- C++ -*-
2 2
 *
3 3
 * This file is a part of LEMON, a generic C++ optimization library
4 4
 *
5 5
 * Copyright (C) 2003-2008
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
/**
20 20
@defgroup datas Data Structures
21 21
This group describes the several data structures implemented in LEMON.
22 22
*/
23 23

	
24 24
/**
25 25
@defgroup graphs Graph Structures
26 26
@ingroup datas
27 27
\brief Graph structures implemented in LEMON.
28 28

	
29 29
The implementation of combinatorial algorithms heavily relies on 
30 30
efficient graph implementations. LEMON offers data structures which are 
31 31
planned to be easily used in an experimental phase of implementation studies, 
32 32
and thereafter the program code can be made efficient by small modifications. 
33 33

	
34 34
The most efficient implementation of diverse applications require the
35 35
usage of different physical graph implementations. These differences
36 36
appear in the size of graph we require to handle, memory or time usage
37 37
limitations or in the set of operations through which the graph can be
38 38
accessed.  LEMON provides several physical graph structures to meet
39 39
the diverging requirements of the possible users.  In order to save on
40 40
running time or on memory usage, some structures may fail to provide
41 41
some graph features like arc/edge or node deletion.
42 42

	
43 43
Alteration of standard containers need a very limited number of 
44 44
operations, these together satisfy the everyday requirements. 
45 45
In the case of graph structures, different operations are needed which do 
46 46
not alter the physical graph, but gives another view. If some nodes or 
47 47
arcs have to be hidden or the reverse oriented graph have to be used, then
48 48
this is the case. It also may happen that in a flow implementation 
49 49
the residual graph can be accessed by another algorithm, or a node-set 
50 50
is to be shrunk for another algorithm. 
51 51
LEMON also provides a variety of graphs for these requirements called 
52 52
\ref graph_adaptors "graph adaptors". Adaptors cannot be used alone but only 
53 53
in conjunction with other graph representations. 
54 54

	
55 55
You are free to use the graph structure that fit your requirements
56 56
the best, most graph algorithms and auxiliary data structures can be used
57 57
with any graph structures. 
58 58
*/
59 59

	
60 60
/**
61 61
@defgroup semi_adaptors Semi-Adaptor Classes for Graphs
62 62
@ingroup graphs
63 63
\brief Graph types between real graphs and graph adaptors.
64 64

	
65 65
This group describes some graph types between real graphs and graph adaptors.
66 66
These classes wrap graphs to give new functionality as the adaptors do it. 
67 67
On the other hand they are not light-weight structures as the adaptors.
68 68
*/
69 69

	
70 70
/**
71 71
@defgroup maps Maps 
72 72
@ingroup datas
73 73
\brief Map structures implemented in LEMON.
74 74

	
75 75
This group describes the map structures implemented in LEMON.
76 76

	
77 77
LEMON provides several special purpose maps that e.g. combine
78 78
new maps from existing ones.
79 79
*/
80 80

	
81 81
/**
82 82
@defgroup graph_maps Graph Maps 
83 83
@ingroup maps
84 84
\brief Special graph-related maps.
85 85

	
86 86
This group describes maps that are specifically designed to assign
87 87
values to the nodes and arcs of graphs.
88 88
*/
89 89

	
90 90

	
91 91
/**
92 92
\defgroup map_adaptors Map Adaptors
93 93
\ingroup maps
94 94
\brief Tools to create new maps from existing ones
95 95

	
96 96
This group describes map adaptors that are used to create "implicit"
97 97
maps from other maps.
98 98

	
99 99
Most of them are \ref lemon::concepts::ReadMap "read-only maps".
100 100
They can make arithmetic and logical operations between one or two maps
101 101
(negation, shifting, addition, multiplication, logical 'and', 'or',
102 102
'not' etc.) or e.g. convert a map to another one of different Value type.
103 103

	
104 104
The typical usage of this classes is passing implicit maps to
105 105
algorithms.  If a function type algorithm is called then the function
106 106
type map adaptors can be used comfortable. For example let's see the
107 107
usage of map adaptors with the \c digraphToEps() function.
108 108
\code
109 109
  Color nodeColor(int deg) {
110 110
    if (deg >= 2) {
111 111
      return Color(0.5, 0.0, 0.5);
112 112
    } else if (deg == 1) {
113 113
      return Color(1.0, 0.5, 1.0);
114 114
    } else {
115 115
      return Color(0.0, 0.0, 0.0);
116 116
    }
117 117
  }
118 118
  
119 119
  Digraph::NodeMap<int> degree_map(graph);
120 120
  
121 121
  digraphToEps(graph, "graph.eps")
122 122
    .coords(coords).scaleToA4().undirected()
123 123
    .nodeColors(composeMap(functorToMap(nodeColor), degree_map))
124 124
    .run();
125 125
\endcode 
126 126
The \c functorToMap() function makes an \c int to \c Color map from the
127 127
\e nodeColor() function. The \c composeMap() compose the \e degree_map
128 128
and the previously created map. The composed map is a proper function to
129 129
get the color of each node.
130 130

	
131 131
The usage with class type algorithms is little bit harder. In this
132 132
case the function type map adaptors can not be used, because the
133 133
function map adaptors give back temporary objects.
134 134
\code
135 135
  Digraph graph;
136 136

	
137 137
  typedef Digraph::ArcMap<double> DoubleArcMap;
138 138
  DoubleArcMap length(graph);
139 139
  DoubleArcMap speed(graph);
140 140

	
141 141
  typedef DivMap<DoubleArcMap, DoubleArcMap> TimeMap;
142 142
  TimeMap time(length, speed);
143 143
  
144 144
  Dijkstra<Digraph, TimeMap> dijkstra(graph, time);
145 145
  dijkstra.run(source, target);
146 146
\endcode
147 147
We have a length map and a maximum speed map on the arcs of a digraph.
148 148
The minimum time to pass the arc can be calculated as the division of
149 149
the two maps which can be done implicitly with the \c DivMap template
150 150
class. We use the implicit minimum time map as the length map of the
151 151
\c Dijkstra algorithm.
152 152
*/
153 153

	
154 154
/**
155 155
@defgroup matrices Matrices 
156 156
@ingroup datas
157 157
\brief Two dimensional data storages implemented in LEMON.
158 158

	
159 159
This group describes two dimensional data storages implemented in LEMON.
160 160
*/
161 161

	
162 162
/**
163 163
@defgroup paths Path Structures
164 164
@ingroup datas
165 165
\brief Path structures implemented in LEMON.
166 166

	
167 167
This group describes the path structures implemented in LEMON.
168 168

	
169 169
LEMON provides flexible data structures to work with paths.
170 170
All of them have similar interfaces and they can be copied easily with
171 171
assignment operators and copy constructors. This makes it easy and
172 172
efficient to have e.g. the Dijkstra algorithm to store its result in
173 173
any kind of path structure.
174 174

	
175 175
\sa lemon::concepts::Path
176 176

	
177 177
*/
178 178

	
179 179
/**
180 180
@defgroup auxdat Auxiliary Data Structures
181 181
@ingroup datas
182 182
\brief Auxiliary data structures implemented in LEMON.
183 183

	
184 184
This group describes some data structures implemented in LEMON in
185 185
order to make it easier to implement combinatorial algorithms.
186 186
*/
187 187

	
188 188

	
189 189
/**
190 190
@defgroup algs Algorithms
191 191
\brief This group describes the several algorithms
192 192
implemented in LEMON.
193 193

	
194 194
This group describes the several algorithms
195 195
implemented in LEMON.
196 196
*/
197 197

	
198 198
/**
199 199
@defgroup search Graph Search
200 200
@ingroup algs
201 201
\brief Common graph search algorithms.
202 202

	
203 203
This group describes the common graph search algorithms like 
204 204
Breadth-first search (Bfs) and Depth-first search (Dfs).
205 205
*/
206 206

	
207 207
/**
208 208
@defgroup shortest_path Shortest Path algorithms
209 209
@ingroup algs
210 210
\brief Algorithms for finding shortest paths.
211 211

	
212 212
This group describes the algorithms for finding shortest paths in graphs.
213 213
*/
214 214

	
215 215
/** 
216 216
@defgroup max_flow Maximum Flow algorithms 
217 217
@ingroup algs 
218 218
\brief Algorithms for finding maximum flows.
219 219

	
220 220
This group describes the algorithms for finding maximum flows and
221 221
feasible circulations.
222 222

	
223 223
The maximum flow problem is to find a flow between a single source and
224 224
a single target that is maximum. Formally, there is a \f$G=(V,A)\f$
225 225
directed graph, an \f$c_a:A\rightarrow\mathbf{R}^+_0\f$ capacity
226 226
function and given \f$s, t \in V\f$ source and target node. The
227 227
maximum flow is the \f$f_a\f$ solution of the next optimization problem:
228 228

	
229 229
\f[ 0 \le f_a \le c_a \f]
230 230
\f[ \sum_{v\in\delta^{-}(u)}f_{vu}=\sum_{v\in\delta^{+}(u)}f_{uv} \qquad \forall u \in V \setminus \{s,t\}\f]
231 231
\f[ \max \sum_{v\in\delta^{+}(s)}f_{uv} - \sum_{v\in\delta^{-}(s)}f_{vu}\f]
232 232

	
233 233
LEMON contains several algorithms for solving maximum flow problems:
234 234
- \ref lemon::EdmondsKarp "Edmonds-Karp" 
235 235
- \ref lemon::Preflow "Goldberg's Preflow algorithm"
236 236
- \ref lemon::DinitzSleatorTarjan "Dinitz's blocking flow algorithm with dynamic trees"
237 237
- \ref lemon::GoldbergTarjan "Preflow algorithm with dynamic trees"
238 238

	
239 239
In most cases the \ref lemon::Preflow "Preflow" algorithm provides the
240 240
fastest method to compute the maximum flow. All impelementations
241 241
provides functions to query the minimum cut, which is the dual linear
242 242
programming problem of the maximum flow.
243 243

	
244 244
*/
245 245

	
246 246
/**
247 247
@defgroup min_cost_flow Minimum Cost Flow algorithms
248 248
@ingroup algs
249 249

	
250 250
\brief Algorithms for finding minimum cost flows and circulations.
251 251

	
252 252
This group describes the algorithms for finding minimum cost flows and
253 253
circulations.  
254 254
*/
255 255

	
256 256
/**
257 257
@defgroup min_cut Minimum Cut algorithms 
258 258
@ingroup algs 
259 259

	
260 260
\brief Algorithms for finding minimum cut in graphs.
261 261

	
262 262
This group describes the algorithms for finding minimum cut in graphs.
263 263

	
264 264
The minimum cut problem is to find a non-empty and non-complete
265 265
\f$X\f$ subset of the vertices with minimum overall capacity on
266 266
outgoing arcs. Formally, there is \f$G=(V,A)\f$ directed graph, an
267 267
\f$c_a:A\rightarrow\mathbf{R}^+_0\f$ capacity function. The minimum
268 268
cut is the \f$X\f$ solution of the next optimization problem:
269 269

	
270 270
\f[ \min_{X \subset V, X\not\in \{\emptyset, V\}}\sum_{uv\in A, u\in X, v\not\in X}c_{uv}\f]
271 271

	
272 272
LEMON contains several algorithms related to minimum cut problems:
273 273

	
274 274
- \ref lemon::HaoOrlin "Hao-Orlin algorithm" to calculate minimum cut
275 275
  in directed graphs  
276 276
- \ref lemon::NagamochiIbaraki "Nagamochi-Ibaraki algorithm" to
277 277
  calculate minimum cut in undirected graphs
278 278
- \ref lemon::GomoryHuTree "Gomory-Hu tree computation" to calculate all
279 279
  pairs minimum cut in undirected graphs
280 280

	
281 281
If you want to find minimum cut just between two distinict nodes,
282 282
please see the \ref max_flow "Maximum Flow page".
283 283

	
284 284
*/
285 285

	
286 286
/**
287 287
@defgroup graph_prop Connectivity and other graph properties
288 288
@ingroup algs
289 289
\brief Algorithms for discovering the graph properties
290 290

	
291 291
This group describes the algorithms for discovering the graph properties
292 292
like connectivity, bipartiteness, euler property, simplicity etc.
293 293

	
294 294
\image html edge_biconnected_components.png
295 295
\image latex edge_biconnected_components.eps "bi-edge-connected components" width=\textwidth
296 296
*/
297 297

	
298 298
/**
299 299
@defgroup planar Planarity embedding and drawing
300 300
@ingroup algs
301 301
\brief Algorithms for planarity checking, embedding and drawing
302 302

	
303 303
This group describes the algorithms for planarity checking, embedding and drawing.
304 304

	
305 305
\image html planar.png
306 306
\image latex planar.eps "Plane graph" width=\textwidth
307 307
*/
308 308

	
309 309
/**
310 310
@defgroup matching Matching algorithms 
311 311
@ingroup algs
312 312
\brief Algorithms for finding matchings in graphs and bipartite graphs.
313 313

	
314 314
This group contains algorithm objects and functions to calculate
315 315
matchings in graphs and bipartite graphs. The general matching problem is
316 316
finding a subset of the arcs which does not shares common endpoints.
317 317
 
318 318
There are several different algorithms for calculate matchings in
319 319
graphs.  The matching problems in bipartite graphs are generally
320 320
easier than in general graphs. The goal of the matching optimization
321 321
can be the finding maximum cardinality, maximum weight or minimum cost
322 322
matching. The search can be constrained to find perfect or
323 323
maximum cardinality matching.
324 324

	
325 325
Lemon contains the next algorithms:
326 326
- \ref lemon::MaxBipartiteMatching "MaxBipartiteMatching" Hopcroft-Karp 
327 327
  augmenting path algorithm for calculate maximum cardinality matching in 
328 328
  bipartite graphs
329 329
- \ref lemon::PrBipartiteMatching "PrBipartiteMatching" Push-Relabel 
330 330
  algorithm for calculate maximum cardinality matching in bipartite graphs 
331 331
- \ref lemon::MaxWeightedBipartiteMatching "MaxWeightedBipartiteMatching" 
332 332
  Successive shortest path algorithm for calculate maximum weighted matching 
333 333
  and maximum weighted bipartite matching in bipartite graph
334 334
- \ref lemon::MinCostMaxBipartiteMatching "MinCostMaxBipartiteMatching" 
335 335
  Successive shortest path algorithm for calculate minimum cost maximum 
336 336
  matching in bipartite graph
337 337
- \ref lemon::MaxMatching "MaxMatching" Edmond's blossom shrinking algorithm
338 338
  for calculate maximum cardinality matching in general graph
339 339
- \ref lemon::MaxWeightedMatching "MaxWeightedMatching" Edmond's blossom
340 340
  shrinking algorithm for calculate maximum weighted matching in general
341 341
  graph
342 342
- \ref lemon::MaxWeightedPerfectMatching "MaxWeightedPerfectMatching"
343 343
  Edmond's blossom shrinking algorithm for calculate maximum weighted
344 344
  perfect matching in general graph
345 345

	
346 346
\image html bipartite_matching.png
347 347
\image latex bipartite_matching.eps "Bipartite Matching" width=\textwidth
348 348

	
349 349
*/
350 350

	
351 351
/**
352 352
@defgroup spantree Minimum Spanning Tree algorithms
353 353
@ingroup algs
354 354
\brief Algorithms for finding a minimum cost spanning tree in a graph.
355 355

	
356 356
This group describes the algorithms for finding a minimum cost spanning
357 357
tree in a graph
358 358
*/
359 359

	
360 360

	
361 361
/**
362 362
@defgroup auxalg Auxiliary algorithms
363 363
@ingroup algs
364 364
\brief Auxiliary algorithms implemented in LEMON.
365 365

	
366 366
This group describes some algorithms implemented in LEMON
367 367
in order to make it easier to implement complex algorithms.
368 368
*/
369 369

	
370 370
/**
371 371
@defgroup approx Approximation algorithms
372 372
\brief Approximation algorithms.
373 373

	
374 374
This group describes the approximation and heuristic algorithms
375 375
implemented in LEMON.
376 376
*/
377 377

	
378 378
/**
379 379
@defgroup gen_opt_group General Optimization Tools
380 380
\brief This group describes some general optimization frameworks
381 381
implemented in LEMON.
382 382

	
383 383
This group describes some general optimization frameworks
384 384
implemented in LEMON.
385 385

	
386 386
*/
387 387

	
388 388
/**
389 389
@defgroup lp_group Lp and Mip solvers
390 390
@ingroup gen_opt_group
391 391
\brief Lp and Mip solver interfaces for LEMON.
392 392

	
393 393
This group describes Lp and Mip solver interfaces for LEMON. The
394 394
various LP solvers could be used in the same manner with this
395 395
interface.
396 396

	
397 397
*/
398 398

	
399 399
/** 
400 400
@defgroup lp_utils Tools for Lp and Mip solvers 
401 401
@ingroup lp_group
402 402
\brief Helper tools to the Lp and Mip solvers.
403 403

	
404 404
This group adds some helper tools to general optimization framework
405 405
implemented in LEMON.
406 406
*/
407 407

	
408 408
/**
409 409
@defgroup metah Metaheuristics
410 410
@ingroup gen_opt_group
411 411
\brief Metaheuristics for LEMON library.
412 412

	
413 413
This group describes some metaheuristic optimization tools.
414 414
*/
415 415

	
416 416
/**
417 417
@defgroup utils Tools and Utilities 
418 418
\brief Tools and utilities for programming in LEMON
419 419

	
420 420
Tools and utilities for programming in LEMON.
421 421
*/
422 422

	
423 423
/**
424 424
@defgroup gutils Basic Graph Utilities
425 425
@ingroup utils
426 426
\brief Simple basic graph utilities.
427 427

	
428 428
This group describes some simple basic graph utilities.
429 429
*/
430 430

	
431 431
/**
432 432
@defgroup misc Miscellaneous Tools
433 433
@ingroup utils
434 434
\brief Tools for development, debugging and testing.
435 435

	
436 436
This group describes several useful tools for development,
437 437
debugging and testing.
438 438
*/
439 439

	
440 440
/**
441 441
@defgroup timecount Time measuring and Counting
442 442
@ingroup misc
443 443
\brief Simple tools for measuring the performance of algorithms.
444 444

	
445 445
This group describes simple tools for measuring the performance
446 446
of algorithms.
447 447
*/
448 448

	
449 449
/**
450 450
@defgroup graphbits Tools for Graph Implementation
451 451
@ingroup utils
452 452
\brief Tools to make it easier to create graphs.
453 453

	
454 454
This group describes the tools that makes it easier to create graphs and
455 455
the maps that dynamically update with the graph changes.
456 456
*/
457 457

	
458 458
/**
459 459
@defgroup exceptions Exceptions
460 460
@ingroup utils
461 461
\brief Exceptions defined in LEMON.
462 462

	
463 463
This group describes the exceptions defined in LEMON.
464 464
*/
465 465

	
466 466
/**
467 467
@defgroup io_group Input-Output
468 468
\brief Graph Input-Output methods
469 469

	
470 470
This group describes the tools for importing and exporting graphs 
471 471
and graph related data. Now it supports the LEMON format, the
472 472
\c DIMACS format and the encapsulated postscript (EPS) format.
473 473
*/
474 474

	
475 475
/**
476 476
@defgroup lemon_io Lemon Input-Output
477 477
@ingroup io_group
478 478
\brief Reading and writing LEMON format
479 479

	
480 480
This group describes methods for reading and writing LEMON format. 
481 481
You can find more about this format on the \ref graph-io-page "Graph Input-Output"
482 482
tutorial pages.
483 483
*/
484 484

	
485 485
/**
486
@defgroup section_io Section readers and writers
487
@ingroup lemon_io
488
\brief Section readers and writers for LEMON Input-Output.
489

	
490
This group describes section reader and writer classes that can be 
491
attached to \ref LemonReader and \ref LemonWriter.
492
*/
493

	
494
/**
495
@defgroup item_io Item readers and writers
496
@ingroup lemon_io
497
\brief Item readers and writers for LEMON Input-Output.
498

	
499
This group describes reader and writer classes for various data types
500
(e.g. map or attribute values). These classes can be attached to
501
\ref LemonReader and \ref LemonWriter.
502
*/
503

	
504
/**
505 486
@defgroup eps_io Postscript exporting
506 487
@ingroup io_group
507 488
\brief General \c EPS drawer and graph exporter
508 489

	
509 490
This group describes general \c EPS drawing methods and special
510 491
graph exporting tools. 
511 492
*/
512 493

	
513 494

	
514 495
/**
515 496
@defgroup concept Concepts
516 497
\brief Skeleton classes and concept checking classes
517 498

	
518 499
This group describes the data/algorithm skeletons and concept checking
519 500
classes implemented in LEMON.
520 501

	
521 502
The purpose of the classes in this group is fourfold.
522 503
 
523 504
- These classes contain the documentations of the concepts. In order
524 505
  to avoid document multiplications, an implementation of a concept
525 506
  simply refers to the corresponding concept class.
526 507

	
527 508
- These classes declare every functions, <tt>typedef</tt>s etc. an
528 509
  implementation of the concepts should provide, however completely
529 510
  without implementations and real data structures behind the
530 511
  interface. On the other hand they should provide nothing else. All
531 512
  the algorithms working on a data structure meeting a certain concept
532 513
  should compile with these classes. (Though it will not run properly,
533 514
  of course.) In this way it is easily to check if an algorithm
534 515
  doesn't use any extra feature of a certain implementation.
535 516

	
536 517
- The concept descriptor classes also provide a <em>checker class</em>
537 518
  that makes it possible to check whether a certain implementation of a
538 519
  concept indeed provides all the required features.
539 520

	
540 521
- Finally, They can serve as a skeleton of a new implementation of a concept.
541 522

	
542 523
*/
543 524

	
544 525

	
545 526
/**
546 527
@defgroup graph_concepts Graph Structure Concepts
547 528
@ingroup concept
548 529
\brief Skeleton and concept checking classes for graph structures
549 530

	
550 531
This group describes the skeletons and concept checking classes of LEMON's
551 532
graph structures and helper classes used to implement these.
552 533
*/
553 534

	
554 535
/* --- Unused group
555 536
@defgroup experimental Experimental Structures and Algorithms
556 537
This group describes some Experimental structures and algorithms.
557 538
The stuff here is subject to change.
558 539
*/
559 540

	
560 541
/**
561 542
\anchor demoprograms
562 543

	
563 544
@defgroup demos Demo programs
564 545

	
565 546
Some demo programs are listed here. Their full source codes can be found in
566 547
the \c demo subdirectory of the source tree.
567 548

	
568 549
It order to compile them, use <tt>--enable-demo</tt> configure option when
569 550
build the library.
570 551
*/
571 552

	
572 553
/**
573 554
@defgroup tools Standalone utility applications
574 555

	
575 556
Some utility applications are listed here. 
576 557

	
577 558
The standard compilation procedure (<tt>./configure;make</tt>) will compile
578 559
them, as well. 
579 560
*/
580 561

	
Ignore white space 6 line context
1 1
/* -*- C++ -*-
2 2
 *
3 3
 * This file is a part of LEMON, a generic C++ optimization library
4 4
 *
5 5
 * Copyright (C) 2003-2008
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 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/assert.h>
35 35
#include <lemon/graph_utils.h>
36 36

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

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

	
42 42
namespace lemon {
43 43

	
44 44
  namespace _reader_bits {
45 45

	
46 46
    template <typename Value>
47 47
    struct DefaultConverter {
48 48
      Value operator()(const std::string& str) {
49 49
	std::istringstream is(str);
50 50
	Value value;
51 51
	is >> value;
52 52

	
53 53
	char c;
54 54
	if (is >> std::ws >> c) {
55 55
	  throw DataFormatError("Remaining characters in token");
56 56
	}
57 57
	return value;
58 58
      }
59 59
    };
60 60

	
61 61
    template <>
62 62
    struct DefaultConverter<std::string> {
63 63
      std::string operator()(const std::string& str) {
64 64
	return str;
65 65
      }
66 66
    };
67 67

	
68 68
    template <typename _Item>    
69 69
    class MapStorageBase {
70 70
    public:
71 71
      typedef _Item Item;
72 72

	
73 73
    public:
74 74
      MapStorageBase() {}
75 75
      virtual ~MapStorageBase() {}
76 76

	
77 77
      virtual void set(const Item& item, const std::string& value) = 0;
78 78

	
79 79
    };
80 80

	
81 81
    template <typename _Item, typename _Map, 
82 82
	      typename _Converter = DefaultConverter<typename _Map::Value> >
83 83
    class MapStorage : public MapStorageBase<_Item> {
84 84
    public:
85 85
      typedef _Map Map;
86 86
      typedef _Converter Converter;
87 87
      typedef _Item Item;
88 88
      
89 89
    private:
90 90
      Map& _map;
91 91
      Converter _converter;
92 92

	
93 93
    public:
94 94
      MapStorage(Map& map, const Converter& converter = Converter()) 
95 95
	: _map(map), _converter(converter) {}
96 96
      virtual ~MapStorage() {}
97 97

	
98 98
      virtual void set(const Item& item ,const std::string& value) {
99 99
	_map.set(item, _converter(value));
100 100
      }
101 101
    };
102 102

	
103 103
    class ValueStorageBase {
104 104
    public:
105 105
      ValueStorageBase() {}
106 106
      virtual ~ValueStorageBase() {}
107 107

	
108 108
      virtual void set(const std::string&) = 0;
109 109
    };
110 110

	
111 111
    template <typename _Value, typename _Converter = DefaultConverter<_Value> >
112 112
    class ValueStorage : public ValueStorageBase {
113 113
    public:
114 114
      typedef _Value Value;
115 115
      typedef _Converter Converter;
116 116

	
117 117
    private:
118 118
      Value& _value;
119 119
      Converter _converter;
120 120

	
121 121
    public:
122 122
      ValueStorage(Value& value, const Converter& converter = Converter())
123 123
 	: _value(value), _converter(converter) {}
124 124

	
125 125
      virtual void set(const std::string& value) {
126 126
	_value = _converter(value);
127 127
      }
128 128
    };
129 129

	
130 130
    template <typename Value>
131 131
    struct MapLookUpConverter {
132 132
      const std::map<std::string, Value>& _map;
133 133

	
134 134
      MapLookUpConverter(const std::map<std::string, Value>& map)
135 135
        : _map(map) {}
136 136

	
137 137
      Value operator()(const std::string& str) {
138 138
        typename std::map<std::string, Value>::const_iterator it =
139 139
          _map.find(str);
140 140
        if (it == _map.end()) {
141 141
          std::ostringstream msg;
142 142
          msg << "Item not found: " << str;
143 143
          throw DataFormatError(msg.str().c_str());
144 144
        }
145 145
        return it->second;
146 146
      }
147 147
    };
148 148

	
149 149
    bool isWhiteSpace(char c) {
150 150
      return c == ' ' || c == '\t' || c == '\v' || 
151 151
        c == '\n' || c == '\r' || c == '\f'; 
152 152
    }
153 153
    
154 154
    bool isOct(char c) {
155 155
      return '0' <= c && c <='7'; 
156 156
    }
157 157
    
158 158
    int valueOct(char c) {
159 159
      LEMON_ASSERT(isOct(c), "The character is not octal.");
160 160
      return c - '0';
161 161
    }
162 162

	
163 163
    bool isHex(char c) {
164 164
      return ('0' <= c && c <= '9') || 
165 165
	('a' <= c && c <= 'z') || 
166 166
	('A' <= c && c <= 'Z'); 
167 167
    }
168 168
    
169 169
    int valueHex(char c) {
170 170
      LEMON_ASSERT(isHex(c), "The character is not hexadecimal.");
171 171
      if ('0' <= c && c <= '9') return c - '0';
172 172
      if ('a' <= c && c <= 'z') return c - 'a' + 10;
173 173
      return c - 'A' + 10;
174 174
    }
175 175

	
176 176
    bool isIdentifierFirstChar(char c) {
177 177
      return ('a' <= c && c <= 'z') ||
178 178
	('A' <= c && c <= 'Z') || c == '_';
179 179
    }
180 180

	
181 181
    bool isIdentifierChar(char c) {
182 182
      return isIdentifierFirstChar(c) ||
183 183
	('0' <= c && c <= '9');
184 184
    }
185 185

	
186 186
    char readEscape(std::istream& is) {
187 187
      char c;
188 188
      if (!is.get(c))
189 189
	throw DataFormatError("Escape format error");
190 190

	
191 191
      switch (c) {
192 192
      case '\\':
193 193
	return '\\';
194 194
      case '\"':
195 195
	return '\"';
196 196
      case '\'':
197 197
	return '\'';
198 198
      case '\?':
199 199
	return '\?';
200 200
      case 'a':
201 201
	return '\a';
202 202
      case 'b':
203 203
	return '\b';
204 204
      case 'f':
205 205
	return '\f';
206 206
      case 'n':
207 207
	return '\n';
208 208
      case 'r':
209 209
	return '\r';
210 210
      case 't':
211 211
	return '\t';
212 212
      case 'v':
213 213
	return '\v';
214 214
      case 'x':
215 215
	{
216 216
	  int code;
217 217
	  if (!is.get(c) || !isHex(c)) 
218 218
	    throw DataFormatError("Escape format error");
219 219
	  else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c);
220 220
	  else code = code * 16 + valueHex(c);
221 221
	  return code;
222 222
	}
223 223
      default:
224 224
	{
225 225
	  int code;
226 226
	  if (!isOct(c)) 
227 227
	    throw DataFormatError("Escape format error");
228 228
	  else if (code = valueOct(c), !is.get(c) || !isOct(c)) 
229 229
	    is.putback(c);
230 230
	  else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c)) 
231 231
	    is.putback(c);
232 232
	  else code = code * 8 + valueOct(c);
233 233
	  return code;
234 234
	}	      
235 235
      } 
236 236
    }
237 237
    
238 238
    std::istream& readToken(std::istream& is, std::string& str) {
239 239
      std::ostringstream os;
240 240

	
241 241
      char c;
242 242
      is >> std::ws;
243 243
      
244 244
      if (!is.get(c)) 
245 245
	return is;
246 246

	
247 247
      if (c == '\"') {
248 248
	while (is.get(c) && c != '\"') {
249 249
	  if (c == '\\') 
250 250
	    c = readEscape(is);
251 251
	  os << c;
252 252
	}
253 253
	if (!is) 
254 254
	  throw DataFormatError("Quoted format error");
255 255
      } else {
256 256
	is.putback(c);
257 257
	while (is.get(c) && !isWhiteSpace(c)) {
258 258
	  if (c == '\\') 
259 259
	    c = readEscape(is);
260 260
	  os << c;
261 261
	}
262 262
	if (!is) {
263 263
	  is.clear();
264 264
	} else {
265 265
	  is.putback(c);
266 266
	}
267 267
      }
268 268
      str = os.str();
269 269
      return is;
270 270
    }
271

	
272
    std::istream& readIdentifier(std::istream& is, std::string& str) {
273
      std::ostringstream os;
274

	
275
      char c;
276
      is >> std::ws;
277
      
278
      if (!is.get(c))
279
	return is;
280

	
281
      if (!isIdentifierFirstChar(c))
282
	throw DataFormatError("Wrong char in identifier");
283
      
284
      os << c;
285
      
286
      while (is.get(c) && !isWhiteSpace(c)) {
287
	if (!isIdentifierChar(c)) 
288
	  throw DataFormatError("Wrong char in identifier");	  
289
	os << c;
290
      }
291
      if (!is) is.clear();
292
     
293
      str = os.str();
294
      return is;
295
    }
296 271
    
297 272
  }
298
  
299
  /// \e
273

	
274
  /// \ingroup lemon_io
275
  ///  
276
  /// \brief LGF reader for directed graphs
277
  ///
278
  /// This utility reads an \ref lgf-format "LGF" file.
279
  ///
280
  /// The reading method does a batch processing. The user creates a
281
  /// reader object, then various reading rules can be added to the
282
  /// reader, and eventually the reading is executed with the \c run()
283
  /// member function. A map reading rule can be added to the reader
284
  /// with the \c nodeMap() or \c arcMap() members. An optional
285
  /// converter parameter can also be added as a standard functor converting from
286
  /// std::string to the value type of the map. If it is set, it will
287
  /// determine how the tokens in the file should be is converted to the map's
288
  /// value type. If the functor is not set, then a default conversion
289
  /// will be used. One map can be read into multiple map objects at the
290
  /// same time. The \c attribute(), \c node() and \c arc() functions
291
  /// are used to add attribute reading rules.
292
  ///
293
  ///\code
294
  ///     DigraphReader<Digraph>(std::cin, digraph).
295
  ///       nodeMap("coordinates", coord_map).
296
  ///       arcMap("capacity", cap_map).
297
  ///       node("source", src).
298
  ///       node("target", trg).
299
  ///       attribute("caption", caption).
300
  ///       run();
301
  ///\endcode
302
  ///
303
  /// By default the reader uses the first section in the file of the
304
  /// proper type. If a section has an optional name, then it can be
305
  /// selected for reading by giving an optional name parameter to
306
  /// the \c nodes(), \c arcs() or \c attributes()
307
  /// functions.
308
  ///
309
  /// The \c useNodes() and \c useArcs() functions are used to tell the reader
310
  /// that the nodes or arcs should not be constructed (added to the
311
  /// graph) during the reading, but instead the label map of the items
312
  /// are given as a parameter of these functions. An
313
  /// application of these function is multipass reading, which is
314
  /// important if two \e \@arcs sections must be read from the
315
  /// file. In this example the first phase would read the node set and one
316
  /// of the arc sets, while the second phase would read the second arc
317
  /// set into an \e ArcSet class (\c SmartArcSet or \c ListArcSet).
318
  /// The previously read label node map should be passed to the \c
319
  /// useNodes() functions. Another application of multipass reading when
320
  /// paths are given as a node map or an arc map. It is impossible read this in
321
  /// a single pass, because the arcs are not constructed when the node
322
  /// maps are read.
300 323
  template <typename _Digraph>
301 324
  class DigraphReader {
302 325
  public:
303 326

	
304 327
    typedef _Digraph Digraph;
305 328
    TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
306 329
    
307 330
  private:
308 331

	
309 332

	
310 333
    std::istream* _is;
311 334
    bool local_is;
312 335

	
313 336
    Digraph& _digraph;
314 337

	
315 338
    std::string _nodes_caption;
316 339
    std::string _arcs_caption;
317 340
    std::string _attributes_caption;
318 341

	
319 342
    typedef std::map<std::string, Node> NodeIndex;
320 343
    NodeIndex _node_index;
321 344
    typedef std::map<std::string, Arc> ArcIndex;
322 345
    ArcIndex _arc_index;
323 346
    
324 347
    typedef std::vector<std::pair<std::string, 
325 348
      _reader_bits::MapStorageBase<Node>*> > NodeMaps;    
326 349
    NodeMaps _node_maps; 
327 350

	
328 351
    typedef std::vector<std::pair<std::string,
329 352
      _reader_bits::MapStorageBase<Arc>*> >ArcMaps;
330 353
    ArcMaps _arc_maps;
331 354

	
332 355
    typedef std::multimap<std::string, _reader_bits::ValueStorageBase*> 
333 356
      Attributes;
334 357
    Attributes _attributes;
335 358

	
336 359
    bool _use_nodes;
337 360
    bool _use_arcs;
338 361

	
339 362
    int line_num;
340 363
    std::istringstream line;
341 364

	
342 365
  public:
343 366

	
344
    /// \e
367
    /// \brief Constructor
368
    ///
369
    /// Construct a directed graph reader, which reads from the given
370
    /// input stream.
345 371
    DigraphReader(std::istream& is, Digraph& digraph) 
346 372
      : _is(&is), local_is(false), _digraph(digraph),
347 373
	_use_nodes(false), _use_arcs(false) {}
348 374

	
349
    /// \e
375
    /// \brief Constructor
376
    ///
377
    /// Construct a directed graph reader, which reads from the given
378
    /// file.
350 379
    DigraphReader(const std::string& fn, Digraph& digraph) 
351 380
      : _is(new std::ifstream(fn.c_str())), local_is(true), _digraph(digraph),
352 381
    	_use_nodes(false), _use_arcs(false) {}
353

	
354

	
355
    /// \e
382
    
383
    /// \brief Constructor
384
    ///
385
    /// Construct a directed graph reader, which reads from the given
386
    /// file.
356 387
    DigraphReader(const char* fn, Digraph& digraph) 
357 388
      : _is(new std::ifstream(fn)), local_is(true), _digraph(digraph),
358 389
    	_use_nodes(false), _use_arcs(false) {}
359 390

	
360
    /// \e
391
    /// \brief Copy constructor
392
    ///
393
    /// The copy constructor transfers all data from the other reader,
394
    /// therefore the copied reader will not be usable more. 
361 395
    DigraphReader(DigraphReader& other) 
362 396
      : _is(other._is), local_is(other.local_is), _digraph(other._digraph),
363 397
	_use_nodes(other._use_nodes), _use_arcs(other._use_arcs) {
364 398

	
365 399
      other.is = 0;
366 400
      other.local_is = false;
367 401
      
368 402
      _node_index.swap(other._node_index);
369 403
      _arc_index.swap(other._arc_index);
370 404

	
371 405
      _node_maps.swap(other._node_maps);
372 406
      _arc_maps.swap(other._arc_maps);
373 407
      _attributes.swap(other._attributes);
374 408

	
375 409
      _nodes_caption = other._nodes_caption;
376 410
      _arcs_caption = other._arcs_caption;
377 411
      _attributes_caption = other._attributes_caption;
378 412
    }
379 413

	
380
    /// \e
414
    /// \brief Destructor
381 415
    ~DigraphReader() {
382 416
      for (typename NodeMaps::iterator it = _node_maps.begin(); 
383 417
	   it != _node_maps.end(); ++it) {
384 418
	delete it->second;
385 419
      }
386 420

	
387 421
      for (typename ArcMaps::iterator it = _arc_maps.begin(); 
388 422
	   it != _arc_maps.end(); ++it) {
389 423
	delete it->second;
390 424
      }
391 425

	
392 426
      for (typename Attributes::iterator it = _attributes.begin(); 
393 427
	   it != _attributes.end(); ++it) {
394 428
	delete it->second;
395 429
      }
396 430

	
397 431
      if (local_is) {
398 432
	delete _is;
399 433
      }
400 434

	
401 435
    }
402 436

	
403 437
  private:
404 438
    
405 439
    DigraphReader& operator=(const DigraphReader&);
406 440

	
407 441
  public:
408 442

	
409
    /// \e
443
    /// \name Reading rules
444
    /// @{
445
    
446
    /// \brief Node map reading rule
447
    ///
448
    /// Add a node map reading rule to the reader.
410 449
    template <typename Map>
411 450
    DigraphReader& nodeMap(const std::string& caption, Map& map) {
412 451
      checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
413 452
      _reader_bits::MapStorageBase<Node>* storage = 
414 453
	new _reader_bits::MapStorage<Node, Map>(map);
415 454
      _node_maps.push_back(std::make_pair(caption, storage));
416 455
      return *this;
417 456
    }
418 457

	
419
    /// \e
458
    /// \brief Node map reading rule
459
    ///
460
    /// Add a node map reading rule with specialized converter to the
461
    /// reader.
420 462
    template <typename Map, typename Converter>
421 463
    DigraphReader& nodeMap(const std::string& caption, Map& map, 
422 464
			   const Converter& converter = Converter()) {
423 465
      checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
424 466
      _reader_bits::MapStorageBase<Node>* storage = 
425 467
	new _reader_bits::MapStorage<Node, Map, Converter>(map, converter);
426 468
      _node_maps.push_back(std::make_pair(caption, storage));
427 469
      return *this;
428 470
    }
429 471

	
430
    /// \e
472
    /// \brief Arc map reading rule
473
    ///
474
    /// Add an arc map reading rule to the reader.
431 475
    template <typename Map>
432 476
    DigraphReader& arcMap(const std::string& caption, Map& map) {
433 477
      checkConcept<concepts::WriteMap<Arc, typename Map::Value>, Map>();
434 478
      _reader_bits::MapStorageBase<Arc>* storage = 
435 479
	new _reader_bits::MapStorage<Arc, Map>(map);
436 480
      _arc_maps.push_back(std::make_pair(caption, storage));
437 481
      return *this;
438 482
    }
439 483

	
440
    /// \e
484
    /// \brief Arc map reading rule
485
    ///
486
    /// Add an arc map reading rule with specialized converter to the
487
    /// reader.
441 488
    template <typename Map, typename Converter>
442 489
    DigraphReader& arcMap(const std::string& caption, Map& map, 
443 490
			  const Converter& converter = Converter()) {
444 491
      checkConcept<concepts::WriteMap<Arc, typename Map::Value>, Map>();
445 492
      _reader_bits::MapStorageBase<Arc>* storage = 
446 493
	new _reader_bits::MapStorage<Arc, Map, Converter>(map, converter);
447 494
      _arc_maps.push_back(std::make_pair(caption, storage));
448 495
      return *this;
449 496
    }
450 497

	
451
    /// \e
498
    /// \brief Attribute reading rule
499
    ///
500
    /// Add an attribute reading rule to the reader.
452 501
    template <typename Value>
453 502
    DigraphReader& attribute(const std::string& caption, Value& value) {
454 503
      _reader_bits::ValueStorageBase* storage = 
455 504
	new _reader_bits::ValueStorage<Value>(value);
456 505
      _attributes.insert(std::make_pair(caption, storage));
457 506
      return *this;
458 507
    }
459 508

	
460
    /// \e
509
    /// \brief Attribute reading rule
510
    ///
511
    /// Add an attribute reading rule with specialized converter to the
512
    /// reader.
461 513
    template <typename Value, typename Converter>
462 514
    DigraphReader& attribute(const std::string& caption, Value& value, 
463 515
			     const Converter& converter = Converter()) {
464 516
      _reader_bits::ValueStorageBase* storage = 
465 517
	new _reader_bits::ValueStorage<Value, Converter>(value, converter);
466 518
      _attributes.insert(std::make_pair(caption, storage));
467 519
      return *this;
468 520
    }
469 521

	
470
    /// \e
522
    /// \brief Node reading rule
523
    ///
524
    /// Add a node reading rule to reader.
471 525
    DigraphReader& node(const std::string& caption, Node& node) {
472 526
      typedef _reader_bits::MapLookUpConverter<Node> Converter;
473 527
      Converter converter(_node_index);
474 528
      _reader_bits::ValueStorageBase* storage = 
475 529
	new _reader_bits::ValueStorage<Node, Converter>(node, converter);
476 530
      _attributes.insert(std::make_pair(caption, storage));
477 531
      return *this;
478 532
    }
479 533

	
480
    /// \e
534
    /// \brief Arc reading rule
535
    ///
536
    /// Add an arc reading rule to reader.
481 537
    DigraphReader& arc(const std::string& caption, Arc& arc) {
482 538
      typedef _reader_bits::MapLookUpConverter<Arc> Converter;
483 539
      Converter converter(_arc_index);
484 540
      _reader_bits::ValueStorageBase* storage = 
485 541
	new _reader_bits::ValueStorage<Arc, Converter>(arc, converter);
486 542
      _attributes.insert(std::make_pair(caption, storage));
487 543
      return *this;
488 544
    }
489 545

	
490
    /// \e
546
    /// @}
547

	
548
    /// \name Select section by name
549
    /// @{
550

	
551
    /// \brief Set \c \@nodes section to be read
552
    ///
553
    /// Set \c \@nodes section to be read
491 554
    DigraphReader& nodes(const std::string& caption) {
492 555
      _nodes_caption = caption;
493 556
      return *this;
494 557
    }
495 558

	
496
    /// \e
559
    /// \brief Set \c \@arcs section to be read
560
    ///
561
    /// Set \c \@arcs section to be read
497 562
    DigraphReader& arcs(const std::string& caption) {
498 563
      _arcs_caption = caption;
499 564
      return *this;
500 565
    }
501 566

	
502
    /// \e
567
    /// \brief Set \c \@attributes section to be read
568
    ///
569
    /// Set \c \@attributes section to be read
503 570
    DigraphReader& attributes(const std::string& caption) {
504 571
      _attributes_caption = caption;
505 572
      return *this;
506 573
    }
507 574

	
508
    /// \e
575
    /// @}
576

	
577
    /// \name Using previously constructed node or arc set
578
    /// @{
579

	
580
    /// \brief Use previously constructed node set
581
    ///
582
    /// Use previously constructed node set, and specify the node
583
    /// label map.
509 584
    template <typename Map>
510 585
    DigraphReader& useNodes(const Map& map) {
511 586
      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
512 587
      LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); 
513 588
      _use_nodes = true;
514 589
      _writer_bits::DefaultConverter<typename Map::Value> converter;
515 590
      for (NodeIt n(_digraph); n != INVALID; ++n) {
516 591
	_node_index.insert(std::make_pair(converter(map[n]), n));
517 592
      }
518 593
      return *this;
519 594
    }
520 595

	
521
    /// \e
596
    /// \brief Use previously constructed node set
597
    ///
598
    /// Use previously constructed node set, and specify the node
599
    /// label map and a functor which converts the label map values to
600
    /// std::string.
522 601
    template <typename Map, typename Converter>
523 602
    DigraphReader& useNodes(const Map& map, 
524 603
			    const Converter& converter = Converter()) {
525 604
      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
526 605
      LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); 
527 606
      _use_nodes = true;
528 607
      for (NodeIt n(_digraph); n != INVALID; ++n) {
529 608
	_node_index.insert(std::make_pair(converter(map[n]), n));
530 609
      }
531 610
      return *this;
532 611
    }
533 612

	
534
    /// \e
613
    /// \brief Use previously constructed arc set
614
    ///
615
    /// Use previously constructed arc set, and specify the arc
616
    /// label map.
535 617
    template <typename Map>
536 618
    DigraphReader& useArcs(const Map& map) {
537 619
      checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
538 620
      LEMON_ASSERT(!_use_arcs, "Multiple usage of useArcs() member");
539 621
      _use_arcs = true;
540 622
      _writer_bits::DefaultConverter<typename Map::Value> converter;
541 623
      for (ArcIt a(_digraph); a != INVALID; ++a) {
542 624
	_arc_index.insert(std::make_pair(converter(map[a]), a));
543 625
      }
544 626
      return *this;
545 627
    }
546 628

	
547
    /// \e
629
    /// \brief Use previously constructed arc set
630
    ///
631
    /// Use previously constructed arc set, and specify the arc
632
    /// label map and a functor which converts the label map values to
633
    /// std::string.
548 634
    template <typename Map, typename Converter>
549 635
    DigraphReader& useArcs(const Map& map, 
550 636
			    const Converter& converter = Converter()) {
551 637
      checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
552 638
      LEMON_ASSERT(!_use_arcs, "Multiple usage of useArcs() member"); 
553 639
      _use_arcs = true;
554 640
      for (ArcIt a(_digraph); a != INVALID; ++a) {
555 641
	_arc_index.insert(std::make_pair(converter(map[a]), a));
556 642
      }
557 643
      return *this;
558 644
    }
559 645

	
646
    /// @}
647

	
560 648
  private:
561 649

	
562 650
    bool readLine() {
563 651
      std::string str;
564 652
      while(++line_num, std::getline(*_is, str)) {
565 653
	line.clear(); line.str(str);
566 654
	char c;
567 655
	if (line >> std::ws >> c && c != '#') {
568 656
	  line.putback(c);
569 657
	  return true;
570 658
	}
571 659
      }
572 660
      return false;
573 661
    }
574 662

	
575 663
    bool readSuccess() {
576 664
      return static_cast<bool>(*_is);
577 665
    }
578 666
    
579 667
    void skipSection() {
580 668
      char c;
581 669
      while (readSuccess() && line >> c && c != '@') {
582 670
	readLine();
583 671
      }
584 672
      line.putback(c);
585 673
    }
586 674

	
587 675
    void readNodes() {
588 676

	
589 677
      std::vector<int> map_index(_node_maps.size());
590 678
      int map_num, label_index;
591 679

	
592 680
      if (!readLine()) 
593 681
	throw DataFormatError("Cannot find map captions");
594 682
      
595 683
      {
596 684
	std::map<std::string, int> maps;
597 685
	
598 686
	std::string map;
599 687
	int index = 0;
600
	while (_reader_bits::readIdentifier(line, map)) {
688
	while (_reader_bits::readToken(line, map)) {
601 689
	  if (maps.find(map) != maps.end()) {
602 690
	    std::ostringstream msg;
603 691
	    msg << "Multiple occurence of node map: " << map;
604 692
	    throw DataFormatError(msg.str().c_str());
605 693
	  }
606 694
	  maps.insert(std::make_pair(map, index));
607 695
	  ++index;
608 696
	}
609 697
	
610 698
	for (int i = 0; i < static_cast<int>(_node_maps.size()); ++i) {
611 699
	  std::map<std::string, int>::iterator jt = 
612 700
	    maps.find(_node_maps[i].first);
613 701
	  if (jt == maps.end()) {
614 702
	    std::ostringstream msg;
615 703
	    msg << "Map not found in file: " << _node_maps[i].first;
616 704
	    throw DataFormatError(msg.str().c_str());
617 705
	  }
618 706
	  map_index[i] = jt->second;
619 707
	}
620 708

	
621 709
	{
622 710
	  std::map<std::string, int>::iterator jt = maps.find("label");
623 711
	  if (jt == maps.end())
624 712
	    throw DataFormatError("Label map not found in file");
625 713
	  label_index = jt->second;
626 714
	}
627 715
	map_num = maps.size();
628 716
      }
629 717

	
630 718
      char c;
631 719
      while (readLine() && line >> c && c != '@') {
632 720
	line.putback(c);
633 721

	
634 722
	std::vector<std::string> tokens(map_num);
635 723
	for (int i = 0; i < map_num; ++i) {
636 724
	  if (!_reader_bits::readToken(line, tokens[i])) {
637 725
	    std::ostringstream msg;
638 726
	    msg << "Column not found (" << i + 1 << ")";
639 727
	    throw DataFormatError(msg.str().c_str());
640 728
	  }
641 729
	}
642 730
	if (line >> std::ws >> c)
643 731
	  throw DataFormatError("Extra character on the end of line");
644 732
	
645 733
	Node n;
646 734
	if (!_use_nodes) {
647 735
	  n = _digraph.addNode();
648 736
	  _node_index.insert(std::make_pair(tokens[label_index], n));
649 737
	} else {
650 738
	  typename std::map<std::string, Node>::iterator it =
651 739
	    _node_index.find(tokens[label_index]);
652 740
	  if (it == _node_index.end()) {
653 741
	    std::ostringstream msg;
654 742
	    msg << "Node with label not found: " << tokens[label_index];
655 743
	    throw DataFormatError(msg.str().c_str());	    
656 744
	  }
657 745
	  n = it->second;
658 746
	}
659 747

	
660 748
	for (int i = 0; i < static_cast<int>(_node_maps.size()); ++i) {
661 749
	  _node_maps[i].second->set(n, tokens[map_index[i]]);
662 750
	}
663 751

	
664 752
      }
665 753
      if (readSuccess()) {
666 754
	line.putback(c);
667 755
      }
668 756
    }
669 757

	
670 758
    void readArcs() {
671 759

	
672 760
      std::vector<int> map_index(_arc_maps.size());
673 761
      int map_num, label_index;
674 762

	
675 763
      if (!readLine()) 
676 764
	throw DataFormatError("Cannot find map captions");
677 765
      
678 766
      {
679 767
	std::map<std::string, int> maps;
680 768
	
681 769
	std::string map;
682 770
	int index = 0;
683
	while (_reader_bits::readIdentifier(line, map)) {
771
	while (_reader_bits::readToken(line, map)) {
684 772
	  if (maps.find(map) != maps.end()) {
685 773
	    std::ostringstream msg;
686 774
	    msg << "Multiple occurence of arc map: " << map;
687 775
	    throw DataFormatError(msg.str().c_str());
688 776
	  }
689 777
	  maps.insert(std::make_pair(map, index));
690 778
	  ++index;
691 779
	}
692 780
	
693 781
	for (int i = 0; i < static_cast<int>(_arc_maps.size()); ++i) {
694 782
	  std::map<std::string, int>::iterator jt = 
695 783
	    maps.find(_arc_maps[i].first);
696 784
	  if (jt == maps.end()) {
697 785
	    std::ostringstream msg;
698 786
	    msg << "Map not found in file: " << _arc_maps[i].first;
699 787
	    throw DataFormatError(msg.str().c_str());
700 788
	  }
701 789
	  map_index[i] = jt->second;
702 790
	}
703 791

	
704 792
	{
705 793
	  std::map<std::string, int>::iterator jt = maps.find("label");
706 794
	  if (jt == maps.end())
707 795
	    throw DataFormatError("Label map not found in file");
708 796
	  label_index = jt->second;
709 797
	}
710 798
	map_num = maps.size();
711 799
      }
712 800

	
713 801
      char c;
714 802
      while (readLine() && line >> c && c != '@') {
715 803
	line.putback(c);
716 804

	
717 805
	std::string source_token;
718 806
	std::string target_token;
719 807

	
720 808
	if (!_reader_bits::readToken(line, source_token))
721 809
	  throw DataFormatError("Source not found");
722 810

	
723 811
	if (!_reader_bits::readToken(line, target_token))
724 812
	  throw DataFormatError("Source not found");
725 813
	
726 814
	std::vector<std::string> tokens(map_num);
727 815
	for (int i = 0; i < map_num; ++i) {
728 816
	  if (!_reader_bits::readToken(line, tokens[i])) {
729 817
	    std::ostringstream msg;
730 818
	    msg << "Column not found (" << i + 1 << ")";
731 819
	    throw DataFormatError(msg.str().c_str());
732 820
	  }
733 821
	}
734 822
	if (line >> std::ws >> c)
735 823
	  throw DataFormatError("Extra character on the end of line");
736 824
	
737 825
	Arc a;
738 826
	if (!_use_arcs) {
739 827

	
740 828
          typename NodeIndex::iterator it;
741 829
 
742 830
          it = _node_index.find(source_token);
743 831
          if (it == _node_index.end()) {
744 832
            std::ostringstream msg;
745 833
            msg << "Item not found: " << source_token;
746 834
            throw DataFormatError(msg.str().c_str());
747 835
          }
748 836
          Node source = it->second;
749 837

	
750 838
          it = _node_index.find(target_token);
751 839
          if (it == _node_index.end()) {       
752 840
            std::ostringstream msg;            
753 841
            msg << "Item not found: " << target_token;
754 842
            throw DataFormatError(msg.str().c_str());
755 843
          }                                          
756 844
          Node target = it->second;                            
757 845

	
758 846
	  a = _digraph.addArc(source, target);
759 847
	  _arc_index.insert(std::make_pair(tokens[label_index], a));
760 848
	} else {
761 849
	  typename std::map<std::string, Arc>::iterator it =
762 850
	    _arc_index.find(tokens[label_index]);
763 851
	  if (it == _arc_index.end()) {
764 852
	    std::ostringstream msg;
765 853
	    msg << "Arc with label not found: " << tokens[label_index];
766 854
	    throw DataFormatError(msg.str().c_str());	    
767 855
	  }
768 856
	  a = it->second;
769 857
	}
770 858

	
771 859
	for (int i = 0; i < static_cast<int>(_arc_maps.size()); ++i) {
772 860
	  _arc_maps[i].second->set(a, tokens[map_index[i]]);
773 861
	}
774 862

	
775 863
      }
776 864
      if (readSuccess()) {
777 865
	line.putback(c);
778 866
      }
779 867
    }
780 868

	
781 869
    void readAttributes() {
782 870

	
783 871
      std::set<std::string> read_attr;
784 872

	
785 873
      char c;
786 874
      while (readLine() && line >> c && c != '@') {
787 875
	line.putback(c);
788 876
	
789 877
	std::string attr, token;
790
	if (!_reader_bits::readIdentifier(line, attr))
878
	if (!_reader_bits::readToken(line, attr))
791 879
	  throw DataFormatError("Attribute name not found");
792 880
	if (!_reader_bits::readToken(line, token))
793 881
	  throw DataFormatError("Attribute value not found");
794 882
	if (line >> c)
795 883
	  throw DataFormatError("Extra character on the end of line");	  
796 884

	
797 885
	{
798 886
	  std::set<std::string>::iterator it = read_attr.find(attr);
799 887
	  if (it != read_attr.end()) {
800 888
	    std::ostringstream msg;
801 889
	    msg << "Multiple occurence of attribute " << attr;
802 890
	    throw DataFormatError(msg.str().c_str());
803 891
	  }
804 892
	  read_attr.insert(attr);
805 893
	}
806 894
	
807 895
	{
808 896
	  typename Attributes::iterator it = _attributes.lower_bound(attr);
809 897
	  while (it != _attributes.end() && it->first == attr) {
810 898
	    it->second->set(token);
811 899
	    ++it;
812 900
	  }
813 901
	}
814 902

	
815 903
      }
816 904
      if (readSuccess()) {
817 905
	line.putback(c);
818 906
      }
819 907
      for (typename Attributes::iterator it = _attributes.begin();
820 908
	   it != _attributes.end(); ++it) {
821 909
	if (read_attr.find(it->first) == read_attr.end()) {
822 910
	  std::ostringstream msg;
823 911
	  msg << "Attribute not found in file: " << it->first;
824 912
	  throw DataFormatError(msg.str().c_str());
825 913
	}	
826 914
      }
827 915
    }
828 916

	
829 917
  public:
830
    
831
    /// \e
918

	
919
    /// \name Execution of the reader    
920
    /// @{
921

	
922
    /// \brief Start the batch processing
923
    ///
924
    /// This function starts the batch processing
832 925
    void run() {
833 926
      
834 927
      LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
835 928
      
836 929
      bool nodes_done = false;
837 930
      bool arcs_done = false;
838 931
      bool attributes_done = false;
839 932

	
840 933
      line_num = 0;      
841 934
      readLine();
842 935

	
843 936
      while (readSuccess()) {
844 937
	skipSection();
845 938
	try {
846 939
	  char c;
847 940
	  std::string section, caption;
848 941
	  line >> c;
849
	  _reader_bits::readIdentifier(line, section);
850
	  _reader_bits::readIdentifier(line, caption);
942
	  _reader_bits::readToken(line, section);
943
	  _reader_bits::readToken(line, caption);
851 944

	
852 945
	  if (line >> c) 
853 946
	    throw DataFormatError("Extra character on the end of line");
854 947

	
855 948
	  if (section == "nodes" && !nodes_done) {
856 949
	    if (_nodes_caption.empty() || _nodes_caption == caption) {
857 950
	      readNodes();
858 951
	      nodes_done = true;
859 952
	    }
860 953
	  } else if ((section == "arcs" || section == "edges") && 
861 954
		     !arcs_done) {
862 955
	    if (_arcs_caption.empty() || _arcs_caption == caption) {
863 956
	      readArcs();
864 957
	      arcs_done = true;
865 958
	    }
866 959
	  } else if (section == "attributes" && !attributes_done) {
867 960
	    if (_attributes_caption.empty() || _attributes_caption == caption) {
868 961
	      readAttributes();
869 962
	      attributes_done = true;
870 963
	    }
871 964
	  } else {
872 965
	    readLine();
873 966
	    skipSection();
874 967
	  }
875 968
	} catch (DataFormatError& error) {
876 969
	  error.line(line_num);
877 970
	  throw;
878 971
	}	
879 972
      }
880 973

	
881 974
      if (!nodes_done) {
882 975
	throw DataFormatError("Section @nodes not found");
883 976
      }
884 977

	
885 978
      if (!arcs_done) {
886 979
	throw DataFormatError("Section @arcs not found");
887 980
      }
888 981

	
889 982
      if (!attributes_done && !_attributes.empty()) {
890 983
	throw DataFormatError("Section @attributes not found");
891 984
      }
892 985

	
893 986
    }
987

	
988
    /// @}
894 989
    
895 990
  };
896 991

	
992
  /// \relates DigraphReader
897 993
  template <typename Digraph>
898 994
  DigraphReader<Digraph> digraphReader(std::istream& is, Digraph& digraph) {
899 995
    return DigraphReader<Digraph>(is, digraph);
900 996
  }
901 997

	
998
  /// \relates DigraphReader
902 999
  template <typename Digraph>
903 1000
  DigraphReader<Digraph> digraphReader(const std::string& fn, 
904 1001
				       Digraph& digraph) {
905 1002
    return DigraphReader<Digraph>(fn, digraph);
906 1003
  }
907 1004

	
1005
  /// \relates DigraphReader
908 1006
  template <typename Digraph>
909 1007
  DigraphReader<Digraph> digraphReader(const char* fn, Digraph& digraph) {
910 1008
    return DigraphReader<Digraph>(fn, digraph);
911 1009
  }
912 1010
}
913 1011

	
914 1012
#endif
Ignore white space 6 line context
1 1
/* -*- C++ -*-
2 2
 *
3 3
 * This file is a part of LEMON, a generic C++ optimization library
4 4
 *
5 5
 * Copyright (C) 2003-2008
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 Lemon Graph Format writer.
22 22

	
23 23

	
24 24
#ifndef LEMON_LGF_WRITER_H
25 25
#define LEMON_LGF_WRITER_H
26 26

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

	
31 31
#include <algorithm>
32 32

	
33 33
#include <vector>
34 34
#include <functional>
35 35

	
36 36
#include <lemon/assert.h>
37 37
#include <lemon/graph_utils.h>
38 38

	
39 39
namespace lemon {
40 40

	
41 41
  namespace _writer_bits {
42 42

	
43 43
    template <typename Value>
44 44
    struct DefaultConverter {
45 45
      std::string operator()(const Value& value) {
46 46
	std::ostringstream os;
47 47
	os << value;
48 48
	return os.str();
49 49
      }
50 50
    };
51 51

	
52 52
    template <typename T>
53 53
    bool operator<(const T&, const T&) {
54 54
      throw DataFormatError("Label map is not comparable");
55 55
    }
56 56

	
57 57
    template <typename _Map>
58 58
    class MapLess {
59 59
    public:
60 60
      typedef _Map Map;
61 61
      typedef typename Map::Key Item;
62 62

	
63 63
    private:
64 64
      const Map& _map;
65 65
      
66 66
    public:
67 67
      MapLess(const Map& map) : _map(map) {}
68 68

	
69 69
      bool operator()(const Item& left, const Item& right) {
70 70
	return _map[left] < _map[right];
71 71
      }
72 72
    };
73 73

	
74 74
    template <typename _Item>    
75 75
    class MapStorageBase {
76 76
    public:
77 77
      typedef _Item Item;
78 78

	
79 79
    public:
80 80
      MapStorageBase() {}
81 81
      virtual ~MapStorageBase() {}
82 82

	
83 83
      virtual std::string get(const Item& item) = 0;
84 84
      virtual void sort(std::vector<Item>&) = 0;
85 85
    };
86 86

	
87 87
    template <typename _Item, typename _Map, 
88 88
	      typename _Converter = DefaultConverter<typename _Map::Value> >
89 89
    class MapStorage : public MapStorageBase<_Item> {
90 90
    public:
91 91
      typedef _Map Map;
92 92
      typedef _Converter Converter;
93 93
      typedef _Item Item;
94 94
      
95 95
    private:
96 96
      const Map& _map;
97 97
      Converter _converter;
98 98

	
99 99
    public:
100 100
      MapStorage(const Map& map, const Converter& converter = Converter()) 
101 101
	: _map(map), _converter(converter) {}
102 102
      virtual ~MapStorage() {}
103 103

	
104 104
      virtual std::string get(const Item& item) {
105 105
	return _converter(_map[item]);
106 106
      }
107 107
      virtual void sort(std::vector<Item>& items) {
108 108
	MapLess<Map> less(_map);
109 109
	std::sort(items.begin(), items.end(), less);
110 110
      }
111 111
    };
112 112

	
113 113
    class ValueStorageBase {
114 114
    public:
115 115
      ValueStorageBase() {}
116 116
      virtual ~ValueStorageBase() {}
117 117

	
118 118
      virtual std::string get() = 0;      
119 119
    };
120 120

	
121 121
    template <typename _Value, typename _Converter = DefaultConverter<_Value> >
122 122
    class ValueStorage : public ValueStorageBase {
123 123
    public:
124 124
      typedef _Value Value;
125 125
      typedef _Converter Converter;
126 126

	
127 127
    private:
128 128
      const Value& _value;
129 129
      Converter _converter;
130 130

	
131 131
    public:
132 132
      ValueStorage(const Value& value, const Converter& converter = Converter())
133 133
 	: _value(value), _converter(converter) {}
134 134

	
135 135
      virtual std::string get() {
136 136
	return _converter(_value);
137 137
      }
138 138
    };
139 139

	
140 140
    template <typename Value>
141 141
    struct MapLookUpConverter {
142 142
      const std::map<Value, std::string>& _map;
143 143
      
144 144
      MapLookUpConverter(const std::map<Value, std::string>& map) 
145 145
	: _map(map) {}
146 146
      
147 147
      std::string operator()(const Value& str) {
148 148
	typename std::map<Value, std::string>::const_iterator it = 
149 149
	  _map.find(str);
150 150
	if (it == _map.end()) {
151 151
	  throw DataFormatError("Item not found");
152 152
	}
153 153
	return it->second;
154 154
      }
155 155
    };
156 156

	
157 157
    bool isWhiteSpace(char c) {
158 158
      return c == ' ' || c == '\t' || c == '\v' || 
159 159
        c == '\n' || c == '\r' || c == '\f'; 
160 160
    }
161 161

	
162 162
    bool isEscaped(char c) {
163 163
      return c == '\\' || c == '\"' || c == '\'' || 
164 164
	c == '\a' || c == '\b';
165 165
    }
166 166

	
167 167
    static void writeEscape(std::ostream& os, char c) {
168 168
      switch (c) {
169 169
      case '\\':
170 170
	os << "\\\\";
171 171
	return;
172 172
      case '\"':
173 173
	os << "\\\"";
174 174
	return;
175 175
      case '\a':
176 176
	os << "\\a";
177 177
	return;
178 178
      case '\b':
179 179
	os << "\\b";
180 180
	return;
181 181
      case '\f':
182 182
	os << "\\f";
183 183
	return;
184 184
      case '\r':
185 185
	os << "\\r";
186 186
	return;
187 187
      case '\n':
188 188
	os << "\\n";
189 189
	return;
190 190
      case '\t':
191 191
	os << "\\t";
192 192
	return;
193 193
      case '\v':
194 194
	os << "\\v";
195 195
	return;
196 196
      default:
197 197
	if (c < 0x20) {
198 198
	  os << '\\' << std::oct << static_cast<int>(c);
199 199
	} else {
200 200
	  os << c;
201 201
	}
202 202
	return;
203 203
      }     
204 204
    }
205 205

	
206 206
    bool requireEscape(const std::string& str) {
207
      if (str.empty() || str[0] == '@') return true;
207 208
      std::istringstream is(str);
208 209
      char c;
209 210
      while (is.get(c)) {
210 211
	if (isWhiteSpace(c) || isEscaped(c)) {
211 212
	  return true;
212 213
	}
213 214
      }
214 215
      return false;
215 216
    }
216 217
    
217 218
    std::ostream& writeToken(std::ostream& os, const std::string& str) {
218 219

	
219 220
      if (requireEscape(str)) {
220 221
	os << '\"';
221 222
	for (std::string::const_iterator it = str.begin(); 
222 223
	     it != str.end(); ++it) {
223 224
	  writeEscape(os, *it);
224 225
	}	
225 226
	os << '\"';
226 227
      } else {
227 228
	os << str;
228 229
      }
229 230
      return os;
230 231
    }
231 232

	
232 233
  }
233 234
  
234
  /// \e
235
  /// \ingroup lemon_io
236
  ///  
237
  /// \brief LGF writer for directed graphs
238
  ///
239
  /// This utility writes an \ref lgf-format "LGF" file.
240
  ///
241
  /// The writing method does a batch processing. The user creates a
242
  /// writer object, then various writing rules can be added to the
243
  /// writer, and eventually the writing is executed with the \c run()
244
  /// member function. A map writing rule can be added to the writer
245
  /// with the \c nodeMap() or \c arcMap() members. An optional
246
  /// converter parameter can also be added as a standard functor converting from
247
  /// the value type of the map to std::string. If it is set, it will
248
  /// determine how the map's value type is written to the output
249
  /// stream. If the functor is not set, then a default conversion
250
  /// will be used. The \c attribute(), \c node() and \c arc() functions
251
  /// are used to add attribute writing rules.
252
  ///
253
  ///\code
254
  ///     DigraphWriter<Digraph>(std::cout, digraph).
255
  ///       nodeMap("coordinates", coord_map).
256
  ///       nodeMap("size", size).
257
  ///       nodeMap("title", title).
258
  ///       arcMap("capacity", cap_map).
259
  ///       node("source", src).
260
  ///       node("target", trg).
261
  ///       attribute("caption", caption).
262
  ///       run();
263
  ///\endcode
264
  ///
265
  ///
266
  /// By default, the writer does not write additional captions to the
267
  /// sections, but they can be give as an optional parameter of
268
  /// the \c nodes(), \c arcs() or \c
269
  /// attributes() functions.
270
  ///
271
  /// The \c skipNodes() and \c skipArcs() functions forbid the
272
  /// writing of the sections. If two arc sections should be written to the
273
  /// output, it can be done in two passes, the first pass writes the
274
  /// node section and the first arc section, then the second pass
275
  /// skips the node section and writes just the arc section to the
276
  /// stream. The output stream can be retrieved with the \c ostream()
277
  /// function, hence the second pass can append its output to the output of the
278
  /// first pass.
235 279
  template <typename _Digraph>
236 280
  class DigraphWriter {
237 281
  public:
238 282

	
239 283
    typedef _Digraph Digraph;
240 284
    TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
241 285
    
242 286
  private:
243 287

	
244 288

	
245 289
    std::ostream* _os;
246 290
    bool local_os;
247 291

	
248 292
    Digraph& _digraph;
249 293

	
250 294
    std::string _nodes_caption;
251 295
    std::string _arcs_caption;
252 296
    std::string _attributes_caption;
253 297
    
254 298
    typedef std::map<Node, std::string> NodeIndex;
255 299
    NodeIndex _node_index;
256 300
    typedef std::map<Arc, std::string> ArcIndex;
257 301
    ArcIndex _arc_index;
258 302

	
259 303
    typedef std::vector<std::pair<std::string, 
260 304
      _writer_bits::MapStorageBase<Node>* > > NodeMaps;    
261 305
    NodeMaps _node_maps; 
262 306

	
263 307
    typedef std::vector<std::pair<std::string, 
264 308
      _writer_bits::MapStorageBase<Arc>* > >ArcMaps;
265 309
    ArcMaps _arc_maps;
266 310

	
267 311
    typedef std::vector<std::pair<std::string, 
268 312
      _writer_bits::ValueStorageBase*> > Attributes;
269 313
    Attributes _attributes;
270 314

	
271 315
    bool _skip_nodes;
272 316
    bool _skip_arcs;
273 317

	
274 318
  public:
275 319

	
276
    /// \e
320
    /// \brief Constructor
321
    ///
322
    /// Construct a directed graph writer, which writes to the given
323
    /// output stream.
277 324
    DigraphWriter(std::ostream& is, Digraph& digraph) 
278 325
      : _os(&is), local_os(false), _digraph(digraph),
279 326
	_skip_nodes(false), _skip_arcs(false) {}
280 327

	
281
    /// \e
328
    /// \brief Constructor
329
    ///
330
    /// Construct a directed graph writer, which writes to the given
331
    /// output file.
282 332
    DigraphWriter(const std::string& fn, Digraph& digraph) 
283 333
      : _os(new std::ofstream(fn.c_str())), local_os(true), _digraph(digraph),
284 334
	_skip_nodes(false), _skip_arcs(false) {}
285 335

	
286
    /// \e
336
    /// \brief Constructor
337
    ///
338
    /// Construct a directed graph writer, which writes to the given
339
    /// output file.
287 340
    DigraphWriter(const char* fn, Digraph& digraph) 
288 341
      : _os(new std::ofstream(fn)), local_os(true), _digraph(digraph),
289 342
	_skip_nodes(false), _skip_arcs(false) {}
290 343

	
344
    /// \brief Copy constructor
345
    ///
346
    /// The copy constructor transfers all data from the other writer,
347
    /// therefore the copied writer will not be usable more. 
291 348
    DigraphWriter(DigraphWriter& other) 
292 349
      : _os(other._os), local_os(other.local_os), _digraph(other._digraph),
293 350
	_skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) {
294 351

	
295 352
      other.is = 0;
296 353
      other.local_os = false;
297 354

	
298 355
      _node_index.swap(other._node_index);
299 356
      _arc_index.swap(other._arc_index);
300 357

	
301 358
      _node_maps.swap(other._node_maps);
302 359
      _arc_maps.swap(other._arc_maps);
303 360
      _attributes.swap(other._attributes);
304 361

	
305 362
      _nodes_caption = other._nodes_caption;
306 363
      _arcs_caption = other._arcs_caption;
307 364
      _attributes_caption = other._attributes_caption;
308 365
    }
309 366

	
310
    /// \e
367
    /// \brief Destructor
311 368
    ~DigraphWriter() {
312 369
      for (typename NodeMaps::iterator it = _node_maps.begin(); 
313 370
	   it != _node_maps.end(); ++it) {
314 371
	delete it->second;
315 372
      }
316 373

	
317 374
      for (typename ArcMaps::iterator it = _arc_maps.begin(); 
318 375
	   it != _arc_maps.end(); ++it) {
319 376
	delete it->second;
320 377
      }
321 378

	
322 379
      for (typename Attributes::iterator it = _attributes.begin(); 
323 380
	   it != _attributes.end(); ++it) {
324 381
	delete it->second;
325 382
      }
326 383

	
327 384
      if (local_os) {
328 385
	delete _os;
329 386
      }
330 387
    }
331 388

	
332 389
  private:
333 390
    
334 391
    DigraphWriter& operator=(const DigraphWriter&);
335 392

	
336 393
  public:
337 394

	
338
    /// \e
395
    /// \name Writing rules
396
    /// @{
397
    
398
    /// \brief Node map reading rule
399
    ///
400
    /// Add a node map reading rule to the writer.
339 401
    template <typename Map>
340 402
    DigraphWriter& nodeMap(const std::string& caption, const Map& map) {
341 403
      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
342 404
      _writer_bits::MapStorageBase<Node>* storage = 
343 405
	new _writer_bits::MapStorage<Node, Map>(map);
344 406
      _node_maps.push_back(std::make_pair(caption, storage));
345 407
      return *this;
346 408
    }
347 409

	
348
    /// \e
410
    /// \brief Node map writing rule
411
    ///
412
    /// Add a node map writing rule with specialized converter to the
413
    /// writer.
349 414
    template <typename Map, typename Converter>
350 415
    DigraphWriter& nodeMap(const std::string& caption, const Map& map, 
351 416
			   const Converter& converter = Converter()) {
352 417
      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
353 418
      _writer_bits::MapStorageBase<Node>* storage = 
354 419
	new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
355 420
      _node_maps.push_back(std::make_pair(caption, storage));
356 421
      return *this;
357 422
    }
358 423

	
359
    /// \e
424
    /// \brief Arc map writing rule
425
    ///
426
    /// Add an arc map writing rule to the writer.
360 427
    template <typename Map>
361 428
    DigraphWriter& arcMap(const std::string& caption, const Map& map) {
362 429
      checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
363 430
      _writer_bits::MapStorageBase<Arc>* storage = 
364 431
	new _writer_bits::MapStorage<Arc, Map>(map);
365 432
      _arc_maps.push_back(std::make_pair(caption, storage));
366 433
      return *this;
367 434
    }
368 435

	
369
    /// \e
436
    /// \brief Arc map writing rule
437
    ///
438
    /// Add an arc map writing rule with specialized converter to the
439
    /// writer.
370 440
    template <typename Map, typename Converter>
371 441
    DigraphWriter& arcMap(const std::string& caption, const Map& map, 
372 442
			  const Converter& converter = Converter()) {
373 443
      checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
374 444
      _writer_bits::MapStorageBase<Arc>* storage = 
375 445
	new _writer_bits::MapStorage<Arc, Map, Converter>(map, converter);
376 446
      _arc_maps.push_back(std::make_pair(caption, storage));
377 447
      return *this;
378 448
    }
379 449

	
380
    /// \e
450
    /// \brief Attribute writing rule
451
    ///
452
    /// Add an attribute writing rule to the writer.
381 453
    template <typename Value>
382 454
    DigraphWriter& attribute(const std::string& caption, const Value& value) {
383 455
      _writer_bits::ValueStorageBase* storage = 
384 456
	new _writer_bits::ValueStorage<Value>(value);
385 457
      _attributes.push_back(std::make_pair(caption, storage));
386 458
      return *this;
387 459
    }
388 460

	
389
    /// \e
461
    /// \brief Attribute writing rule
462
    ///
463
    /// Add an attribute writing rule with specialized converter to the
464
    /// writer.
390 465
    template <typename Value, typename Converter>
391 466
    DigraphWriter& attribute(const std::string& caption, const Value& value, 
392 467
			     const Converter& converter = Converter()) {
393 468
      _writer_bits::ValueStorageBase* storage = 
394 469
	new _writer_bits::ValueStorage<Value, Converter>(value, converter);
395 470
      _attributes.push_back(std::make_pair(caption, storage));
396 471
      return *this;
397 472
    }
398 473

	
399
    /// \e
474
    /// \brief Node writing rule
475
    ///
476
    /// Add a node writing rule to the writer.
400 477
    DigraphWriter& node(const std::string& caption, const Node& node) {
401 478
      typedef _writer_bits::MapLookUpConverter<Node> Converter;
402 479
      Converter converter(_node_index);
403 480
      _writer_bits::ValueStorageBase* storage = 
404 481
	new _writer_bits::ValueStorage<Node, Converter>(node, converter);
405 482
      _attributes.push_back(std::make_pair(caption, storage));
406 483
      return *this;
407 484
    }
408 485

	
409
    /// \e
486
    /// \brief Arc writing rule
487
    ///
488
    /// Add an arc writing rule to writer.
410 489
    DigraphWriter& arc(const std::string& caption, const Arc& arc) {
411 490
      typedef _writer_bits::MapLookUpConverter<Arc> Converter;
412 491
      Converter converter(_arc_index);
413 492
      _writer_bits::ValueStorageBase* storage = 
414 493
	new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
415 494
      _attributes.push_back(std::make_pair(caption, storage));
416 495
      return *this;
417 496
    }
418 497

	
419
    /// \e
498
    /// \name Select section by name
499
    /// @{
500

	
501
    /// \brief Set \c \@nodes section to be read
502
    ///
503
    /// Set \c \@nodes section to be read
420 504
    DigraphWriter& nodes(const std::string& caption) {
421 505
      _nodes_caption = caption;
422 506
      return *this;
423 507
    }
424 508

	
425
    /// \e
509
    /// \brief Set \c \@arcs section to be read
510
    ///
511
    /// Set \c \@arcs section to be read
426 512
    DigraphWriter& arcs(const std::string& caption) {
427 513
      _arcs_caption = caption;
428 514
      return *this;
429 515
    }
430 516

	
431
    /// \e
517
    /// \brief Set \c \@attributes section to be read
518
    ///
519
    /// Set \c \@attributes section to be read
432 520
    DigraphWriter& attributes(const std::string& caption) {
433 521
      _attributes_caption = caption;
434 522
      return *this;
435 523
    }
436 524

	
525
    /// \name Skipping section
526
    /// @{
527

	
528
    /// \brief Skip writing the node set
529
    ///
530
    /// The \c \@nodes section will be not written to the stream.
437 531
    DigraphWriter& skipNodes() {
438 532
      LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
439 533
      return *this;
440 534
    }
441 535

	
536
    /// \brief Skip writing arc set
537
    ///
538
    /// The \c \@arcs section will be not written to the stream.
442 539
    DigraphWriter& skipArcs() {
443 540
      LEMON_ASSERT(!_skip_arcs, "Multiple usage of skipArcs() member");
444 541
      return *this;
445 542
    }
446 543

	
544
    /// @}
545

	
447 546
  private:
448 547

	
449 548
    void writeNodes() {
450 549
      _writer_bits::MapStorageBase<Node>* label = 0;
451 550
      for (typename NodeMaps::iterator it = _node_maps.begin();
452 551
	   it != _node_maps.end(); ++it) {
453 552
        if (it->first == "label") {
454 553
	  label = it->second;
455 554
	  break;
456 555
	}
457 556
      }
458 557

	
459 558
      *_os << "@nodes";
460 559
      if (!_nodes_caption.empty()) {
461
	*_os << ' ' << _nodes_caption;
560
	_writer_bits::writeToken(*_os << ' ', _nodes_caption);
462 561
      }
463 562
      *_os << std::endl;
464 563

	
465 564
      if (label == 0) {
466 565
	*_os << "label" << '\t';
467 566
      }
468 567
      for (typename NodeMaps::iterator it = _node_maps.begin();
469 568
	   it != _node_maps.end(); ++it) {
470
	*_os << it->first << '\t';
569
	_writer_bits::writeToken(*_os, it->first) << '\t';
471 570
      }
472 571
      *_os << std::endl;
473 572

	
474 573
      std::vector<Node> nodes;
475 574
      for (NodeIt n(_digraph); n != INVALID; ++n) {
476 575
	nodes.push_back(n);
477 576
      }
478 577
      
479 578
      if (label == 0) {
480 579
	IdMap<Digraph, Node> id_map(_digraph);
481 580
	_writer_bits::MapLess<IdMap<Digraph, Node> > id_less(id_map);
482 581
	std::sort(nodes.begin(), nodes.end(), id_less);
483 582
      } else {
484 583
	label->sort(nodes);
485 584
      }
486 585

	
487 586
      for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
488 587
	Node n = nodes[i];
489 588
	if (label == 0) {
490 589
	  std::ostringstream os;
491 590
	  os << _digraph.id(n);
492 591
	  _writer_bits::writeToken(*_os, os.str());
493 592
	  *_os << '\t';
494 593
	  _node_index.insert(std::make_pair(n, os.str()));
495 594
	}
496 595
	for (typename NodeMaps::iterator it = _node_maps.begin();
497 596
	     it != _node_maps.end(); ++it) {
498 597
	  std::string value = it->second->get(n);
499 598
	  _writer_bits::writeToken(*_os, value);
500 599
	  if (it->first == "label") {
501 600
	    _node_index.insert(std::make_pair(n, value));
502 601
	  }
503 602
	  *_os << '\t';
504 603
	}
505 604
	*_os << std::endl;
506 605
      }
507 606
    }
508 607

	
509 608
    void writeArcs() {
510 609
      _writer_bits::MapStorageBase<Arc>* label = 0;
511 610
      for (typename ArcMaps::iterator it = _arc_maps.begin();
512 611
	   it != _arc_maps.end(); ++it) {
513 612
        if (it->first == "label") {
514 613
	  label = it->second;
515 614
	  break;
516 615
	}
517 616
      }
518 617

	
519 618
      *_os << "@arcs";
520 619
      if (!_arcs_caption.empty()) {
521
	*_os << ' ' << _arcs_caption;
620
	_writer_bits::writeToken(*_os << ' ', _arcs_caption);
522 621
      }
523 622
      *_os << std::endl;
524 623

	
525 624
      *_os << '\t' << '\t';
526 625
      if (label == 0) {
527 626
	*_os << "label" << '\t';
528 627
      }
529 628
      for (typename ArcMaps::iterator it = _arc_maps.begin();
530 629
	   it != _arc_maps.end(); ++it) {
531
	*_os << it->first << '\t';
630
	_writer_bits::writeToken(*_os, it->first) << '\t';
532 631
      }
533 632
      *_os << std::endl;
534 633

	
535 634
      std::vector<Arc> arcs;
536 635
      for (ArcIt n(_digraph); n != INVALID; ++n) {
537 636
	arcs.push_back(n);
538 637
      }
539 638
      
540 639
      if (label == 0) {
541 640
	IdMap<Digraph, Arc> id_map(_digraph);
542 641
	_writer_bits::MapLess<IdMap<Digraph, Arc> > id_less(id_map);
543 642
	std::sort(arcs.begin(), arcs.end(), id_less);
544 643
      } else {
545 644
	label->sort(arcs);
546 645
      }
547 646

	
548 647
      for (int i = 0; i < static_cast<int>(arcs.size()); ++i) {
549 648
	Arc a = arcs[i];
550 649
	_writer_bits::writeToken(*_os, _node_index.
551 650
				 find(_digraph.source(a))->second);
552 651
	*_os << '\t';
553 652
	_writer_bits::writeToken(*_os, _node_index.
554 653
				 find(_digraph.target(a))->second);
555 654
	*_os << '\t';
556 655
	if (label == 0) {
557 656
	  std::ostringstream os;
558 657
	  os << _digraph.id(a);
559 658
	  _writer_bits::writeToken(*_os, os.str());
560 659
	  *_os << '\t';
561 660
	  _arc_index.insert(std::make_pair(a, os.str()));
562 661
	}
563 662
	for (typename ArcMaps::iterator it = _arc_maps.begin();
564 663
	     it != _arc_maps.end(); ++it) {
565 664
	  std::string value = it->second->get(a);
566 665
	  _writer_bits::writeToken(*_os, value);
567 666
	  if (it->first == "label") {
568 667
	    _arc_index.insert(std::make_pair(a, value));
569 668
	  }
570 669
	  *_os << '\t';
571 670
	}
572 671
	*_os << std::endl;
573 672
      }
574 673
    }
575 674

	
576 675
    void writeAttributes() {
577 676
      if (_attributes.empty()) return;
578 677
      *_os << "@attributes";
579 678
      if (!_attributes_caption.empty()) {
580
	*_os << ' ' << _attributes_caption;
679
	_writer_bits::writeToken(*_os << ' ', _attributes_caption);
581 680
      }
582 681
      *_os << std::endl;
583 682
      for (typename Attributes::iterator it = _attributes.begin();
584 683
	   it != _attributes.end(); ++it) {
585
	*_os << it->first << ' ';
684
	_writer_bits::writeToken(*_os, it->first) << ' ';
586 685
	_writer_bits::writeToken(*_os, it->second->get());
587 686
	*_os << std::endl;
588 687
      }
589 688
    }
590 689
    
591 690
  public:
592 691
    
593
    /// \e
692
    /// \name Execution of the writer    
693
    /// @{
694

	
695
    /// \brief Start the batch processing
696
    ///
697
    /// This function starts the batch processing
594 698
    void run() {
595 699
      if (!_skip_nodes) {
596 700
	writeNodes();
597 701
      }
598 702
      if (!_skip_arcs) {      
599 703
	writeArcs();
600 704
      }
601 705
      writeAttributes();
602 706
    }
603 707

	
604
    /// \e
605
    std::ostream& stream() {
708
    /// \brief Gives back the stream of the writer
709
    ///
710
    /// Gives back the stream of the writer
711
    std::ostream& ostream() {
606 712
      return *_os;
607 713
    }
714

	
715
    /// @}
608 716
  };
609 717

	
718
  /// \relates DigraphWriter
610 719
  template <typename Digraph>
611 720
  DigraphWriter<Digraph> digraphWriter(std::istream& is, Digraph& digraph) {
612 721
    return DigraphWriter<Digraph>(is, digraph);
613 722
  }
614 723

	
724
  /// \relates DigraphWriter
615 725
  template <typename Digraph>
616 726
  DigraphWriter<Digraph> digraphWriter(const std::string& fn, 
617 727
				       Digraph& digraph) {
618 728
    return DigraphWriter<Digraph>(fn, digraph);
619 729
  }
620 730

	
731
  /// \relates DigraphWriter
621 732
  template <typename Digraph>
622 733
  DigraphWriter<Digraph> digraphWriter(const char* fn, Digraph& digraph) {
623 734
    return DigraphWriter<Digraph>(fn, digraph);
624 735
  }
625 736
}
626 737

	
627 738
#endif
0 comments (0 inline)