doc/graph_io.dox
author deba
Wed, 01 Mar 2006 10:25:30 +0000
changeset 1991 d7442141d9ef
parent 1909 2d806130e700
child 2100 6fbe90faf02a
permissions -rw-r--r--
The graph adadptors can be alteration observed.
In most cases it uses the adapted graph alteration notifiers.
Only special case is now the UndirGraphAdaptor, where
we have to proxy the signals from the graph.

The SubBidirGraphAdaptor is removed, because it doest not
gives more feature than the EdgeSubGraphAdaptor<UndirGraphAdaptor<Graph>>.

The ResGraphAdaptor is based on this composition.
alpar@1118
     1
namespace lemon {
deba@1114
     2
/*!
deba@1114
     3
deba@1114
     4
deba@1114
     5
\page graph-io-page Graph Input-Output
deba@1114
     6
athos@1540
     7
The standard graph IO enables one to store graphs and additional maps
athos@1540
     8
(i.e. functions on the nodes or edges) in a flexible and efficient way. 
athos@1540
     9
Before you read this page you should be familiar with LEMON 
athos@1540
    10
\ref graphs "graphs" and \ref maps-page "maps".
deba@1114
    11
deba@1114
    12
\section format The general file format
deba@1114
    13
deba@1532
    14
The file contains sections in the following order:
deba@1114
    15
deba@1114
    16
\li nodeset
deba@1114
    17
\li edgeset
deba@1114
    18
\li nodes
deba@1114
    19
\li edges
deba@1532
    20
\li attributes
deba@1114
    21
athos@1540
    22
Some of these sections can be omitted, but you will basicly need the nodeset
athos@1540
    23
section (unless your graph has no nodes at all) and the edgeset section
athos@1540
    24
(unless your graph has no edges at all). 
athos@1540
    25
athos@1540
    26
The nodeset section describes the nodes of your graph: it identifies the nodes
athos@1540
    27
and gives the maps defined on them, if any. It starts with the
athos@1540
    28
following line:
athos@1522
    29
athos@1522
    30
<tt>\@nodeset</tt>
athos@1522
    31
athos@1522
    32
The next line contains the names of the nodemaps, separated by whitespaces.  Each
athos@1522
    33
following line describes a node in the graph: it contains the values of the
deba@1901
    34
maps in the right order. The map named "label" should contain unique values
deba@1901
    35
because it is regarded as a label map. These labels need not be numbers but they
athos@1540
    36
must identify the nodes uniquely for later reference. For example:
deba@1114
    37
deba@1114
    38
\code
deba@1114
    39
@nodeset
deba@1901
    40
label  x-coord  y-coord  color
deba@1114
    41
3   1.0      4.0      blue
deba@1114
    42
5   2.3      5.7      red
deba@1114
    43
12  7.8      2.3      green
deba@1114
    44
\endcode
deba@1114
    45
deba@1114
    46
The edgeset section is very similar to the nodeset section, it has
athos@1522
    47
the same coloumn oriented structure. It starts with the line 
athos@1522
    48
athos@1522
    49
<tt>\@edgeset</tt>
athos@1522
    50
athos@1540
    51
The next line contains the whitespace separated list of names of the edge
athos@1540
    52
maps.  Each of the next lines describes one edge. The first two elements in
deba@1901
    53
the line are the labels of the source and target (or tail and head) nodes of the
deba@1901
    54
edge as they occur in the label node map of the nodeset section. You can also
deba@1901
    55
have an optional label map on the edges for later reference (which has to be
athos@1540
    56
unique in this case).
deba@1114
    57
deba@1114
    58
\code
deba@1114
    59
@edgeset
deba@1901
    60
             label      weight   note
deba@1901
    61
3   5        a          4.3      a-edge
deba@1901
    62
5   12       c          2.6      c-edge
deba@1901
    63
3   12       g          3.4      g-edge
deba@1114
    64
\endcode
deba@1114
    65
athos@1540
    66
The \e nodes section contains <em>labeled (distinguished) nodes</em> 
athos@1540
    67
(i.e. nodes having a special
alpar@1118
    68
label on them). The section starts with
athos@1522
    69
athos@1522
    70
<tt> \@nodes </tt>
athos@1522
    71
athos@1522
    72
Each of the next lines contains a label for a node in the graph 
deba@1901
    73
and then the label as described in the \e nodeset section.
deba@1114
    74
deba@1114
    75
\code
deba@1114
    76
@nodes 
deba@1114
    77
source 3
deba@1114
    78
target 12
deba@1114
    79
\endcode
deba@1114
    80
athos@1540
    81
The last section describes the <em>labeled (distinguished) edges</em>
deba@1333
    82
(i.e. edges having a special label on them). It starts with \c \@edges
deba@1901
    83
and then each line contains the name of the edge and the label.
deba@1114
    84
deba@1114
    85
\code
athos@1540
    86
@edges 
deba@1114
    87
observed c
deba@1114
    88
\endcode
deba@1114
    89
deba@1114
    90
deba@1114
    91
The file may contain empty lines and comment lines. The comment lines
deba@1114
    92
start with an \c # character.
deba@1114
    93
deba@1532
    94
The attributes section can handle some information about the graph. It
athos@1540
    95
contains key-value pairs in each line (a key and the mapped value to key). The
athos@1540
    96
key should be a string without whitespaces, the value can be of various types.
deba@1532
    97
deba@1532
    98
\code
deba@1532
    99
@attributes
alpar@1959
   100
title "Four colored planar graph"
deba@1532
   101
author "Balazs DEZSO"
deba@1532
   102
copyright "Lemon Library"
deba@1532
   103
version 12
deba@1532
   104
\endcode
deba@1532
   105
deba@1901
   106
Finally, the file should be closed with \c \@end line.
athos@1522
   107
deba@1114
   108
deba@1114
   109
\section use Using graph input-output
athos@1540
   110
athos@1540
   111
athos@1540
   112
The graph input and output is based on <em> reading and writing
athos@1540
   113
commands</em>. The user gives reading and writing commands to the reader or
athos@1540
   114
writer class, then he calls the \c run() method that executes all the given
athos@1540
   115
commands.
deba@1114
   116
deba@1114
   117
\subsection write Writing a graph
deba@1114
   118
alpar@1631
   119
The \ref lemon::GraphWriter "GraphWriter" template class
alpar@1631
   120
provides the graph output. To write a graph
athos@1526
   121
you should first give writing commands to the writer. You can declare
athos@1540
   122
writing command as \c NodeMap or \c EdgeMap writing and labeled Node and
deba@1114
   123
Edge writing.
deba@1114
   124
deba@1114
   125
\code
deba@1333
   126
GraphWriter<ListGraph> writer(std::cout, graph);
deba@1114
   127
\endcode
deba@1114
   128
alpar@1631
   129
The \ref lemon::GraphWriter::writeNodeMap() "writeNodeMap()"
alpar@1631
   130
function declares a \c NodeMap writing command in the
alpar@1631
   131
\ref lemon::GraphWriter "GraphWriter".
alpar@1631
   132
You should give a name to the map and the map
deba@1901
   133
object as parameters. The NodeMap writing command with name "label" should write a 
deba@1901
   134
unique map because it will be regarded as a label map.
deba@1114
   135
deba@1114
   136
\see IdMap, DescriptorMap  
deba@1114
   137
deba@1114
   138
\code
deba@1901
   139
IdMap<ListGraph, Node> nodeLabelMap;
deba@1901
   140
writer.writeNodeMap("label", nodeLabelMap);
deba@1114
   141
deba@1394
   142
writer.writeNodeMap("x-coord", xCoordMap);
deba@1394
   143
writer.writeNodeMap("y-coord", yCoordMap);
deba@1394
   144
writer.writeNodeMap("color", colorMap);
deba@1114
   145
\endcode
deba@1114
   146
alpar@1631
   147
With the \ref lemon::GraphWriter::writeEdgeMap() "writeEdgeMap()"
alpar@1631
   148
member function you can give an edge map
deba@1333
   149
writing command similar to the NodeMaps.
deba@1114
   150
deba@1114
   151
\see IdMap, DescriptorMap  
athos@1522
   152
deba@1114
   153
\code
deba@1114
   154
DescriptorMap<ListGraph, Edge, ListGraph::EdgeMap<int> > edgeDescMap(graph);
deba@1394
   155
writer.writeEdgeMap("descriptor", edgeDescMap);
deba@1114
   156
deba@1394
   157
writer.writeEdgeMap("weight", weightMap);
deba@1901
   158
writer.writeEdgeMap("note", noteMap);
deba@1114
   159
\endcode
deba@1114
   160
alpar@1631
   161
With \ref lemon::GraphWriter::writeNode() "writeNode()"
alpar@1631
   162
and \ref lemon::GraphWriter::writeEdge() "writeEdge()"
alpar@1631
   163
functions you can designate Nodes and
athos@1522
   164
Edges in the graph. For example, you can write out the source and target node
athos@1522
   165
of a maximum flow instance.
deba@1114
   166
deba@1114
   167
\code
deba@1394
   168
writer.writeNode("source", sourceNode);
deba@1394
   169
writer.writeNode("target", targetNode);
deba@1114
   170
deba@1394
   171
writer.writeEdge("observed", edge);
deba@1114
   172
\endcode
deba@1114
   173
alpar@1631
   174
With \ref lemon::GraphWriter::writeAttribute() "writeAttribute()"
alpar@1631
   175
function you can write an attribute to the file.
deba@1532
   176
deba@1532
   177
\code
deba@1532
   178
writer.writeAttribute("author", "Balazs DEZSO");
deba@1532
   179
writer.writeAttribute("version", 12);
deba@1532
   180
\endcode
deba@1532
   181
alpar@1631
   182
After you give all write commands you must call the
alpar@1631
   183
\ref lemon::GraphWriter::run() "run()" member
athos@1522
   184
function, which executes all the writing commands.
deba@1114
   185
deba@1114
   186
\code
deba@1114
   187
writer.run();
deba@1114
   188
\endcode
deba@1114
   189
deba@1114
   190
\subsection reading Reading a graph
deba@1114
   191
athos@1540
   192
The file to be read may contain several maps and labeled nodes or edges.
deba@1114
   193
If you read a graph you need not read all the maps and items just those
alpar@1631
   194
that you need. The interface of the \ref lemon::GraphReader "GraphReader"
alpar@1631
   195
is very similar to
alpar@1631
   196
the \ref lemon::GraphWriter "GraphWriter"
alpar@1631
   197
but the reading method does not depend on the order of the
deba@1114
   198
given commands.
deba@1114
   199
athos@1522
   200
The reader object assumes that each not readed value does not contain 
alpar@1118
   201
whitespaces, therefore it has some extra possibilities to control how
alpar@1118
   202
it should skip the values when the string representation contains spaces.
deba@1114
   203
deba@1114
   204
\code
deba@1333
   205
GraphReader<ListGraph> reader(std::cin, graph);
deba@1114
   206
\endcode
deba@1114
   207
alpar@1631
   208
The \ref lemon::GraphReader::readNodeMap() "readNodeMap()"
alpar@1631
   209
function reads a map from the \c nodeset section.
athos@1522
   210
If there is a map that you do not want to read from the file and there are
athos@1522
   211
whitespaces in the string represenation of the values then you should
alpar@1631
   212
call the \ref lemon::GraphReader::skipNodeMap() "skipNodeMap()"
alpar@1631
   213
template member function with proper parameters.
deba@1114
   214
deba@1114
   215
\see QuotedStringReader
athos@1522
   216
deba@1114
   217
\code
deba@1394
   218
reader.readNodeMap("x-coord", xCoordMap);
deba@1394
   219
reader.readNodeMap("y-coord", yCoordMap);
deba@1114
   220
deba@1394
   221
reader.readNodeMap<QuotedStringReader>("label", labelMap);
deba@1114
   222
reader.skipNodeMap<QuotedStringReader>("description");
deba@1114
   223
deba@1394
   224
reader.readNodeMap("color", colorMap);
deba@1114
   225
\endcode
deba@1114
   226
alpar@1631
   227
With the \ref lemon::GraphReader::readEdgeMap() "readEdgeMap()"
alpar@1631
   228
member function you can give an edge map
deba@1114
   229
reading command similar to the NodeMaps. 
deba@1114
   230
deba@1114
   231
\code
deba@1394
   232
reader.readEdgeMap("weight", weightMap);
deba@1394
   233
reader.readEdgeMap("label", labelMap);
deba@1114
   234
\endcode
deba@1114
   235
alpar@1631
   236
With \ref lemon::GraphReader::readNode() "readNode()"
alpar@1631
   237
and \ref lemon::GraphReader::readEdge() "readEdge()"
alpar@1631
   238
functions you can read labeled Nodes and
deba@1114
   239
Edges.
deba@1114
   240
deba@1114
   241
\code
deba@1394
   242
reader.readNode("source", sourceNode);
deba@1394
   243
reader.readNode("target", targetNode);
deba@1114
   244
deba@1394
   245
reader.readEdge("observed", edge);
deba@1114
   246
\endcode
deba@1114
   247
alpar@1631
   248
With \ref lemon::GraphReader::readAttribute() "readAttribute()"
alpar@1631
   249
function you can read an attribute from the file.
deba@1532
   250
deba@1532
   251
\code
deba@1532
   252
std::string author;
deba@1532
   253
writer.readAttribute("author", author);
deba@1532
   254
int version;
deba@1532
   255
writer.writeAttribute("version", version);
deba@1532
   256
\endcode
deba@1532
   257
alpar@1631
   258
After you give all read commands you must call the
alpar@1631
   259
\ref lemon::GraphReader::run() "run()" member
athos@1522
   260
function, which executes all the commands.
deba@1114
   261
deba@1114
   262
\code
deba@1114
   263
reader.run();
deba@1114
   264
\endcode
deba@1114
   265
athos@1540
   266
\anchor rwbackground
athos@1527
   267
\section types Background of Reading and Writing
athos@1540
   268
athos@1540
   269
athos@1527
   270
To read a map (on the nodes or edges)
alpar@1631
   271
the \ref lemon::GraphReader "GraphReader"
alpar@1631
   272
should know how to read a Value from the given map.
deba@1114
   273
By the default implementation the input operator reads a value from
deba@1114
   274
the stream and the type of the readed value is the value type of the given map.
deba@1114
   275
When the reader should skip a value in the stream, because you do not
athos@1527
   276
want to store it in a map, the reader skips a character sequence without 
athos@1540
   277
whitespaces. 
deba@1114
   278
deba@1114
   279
If you want to change the functionality of the reader, you can use
deba@1114
   280
template parameters to specialize it. When you give a reading
deba@1114
   281
command for a map you can give a Reader type as template parameter.
deba@1333
   282
With this template parameter you can control how the Reader reads
deba@1114
   283
a value from the stream.
deba@1114
   284
deba@1114
   285
The reader has the next structure: 
deba@1114
   286
\code
deba@1114
   287
struct TypeReader {
deba@1114
   288
  typedef TypeName Value;
deba@1114
   289
deba@1114
   290
  void read(std::istream& is, Value& value);
deba@1114
   291
};
deba@1114
   292
\endcode
deba@1114
   293
athos@1527
   294
For example, the \c "strings" nodemap contains strings and you do not need
athos@1540
   295
the value of the string just the length. Then you can implement an own Reader
deba@1114
   296
struct.
deba@1114
   297
deba@1114
   298
\code
deba@1114
   299
struct LengthReader {
deba@1114
   300
  typedef int Value;
deba@1114
   301
deba@1114
   302
  void read(std::istream& is, Value& value) {
deba@1114
   303
    std::string tmp;
deba@1114
   304
    is >> tmp;
deba@1114
   305
    value = tmp.length();
deba@1114
   306
  }
deba@1114
   307
};
deba@1114
   308
...
deba@1394
   309
reader.readNodeMap<LengthReader>("strings", lengthMap);
deba@1114
   310
\endcode  
deba@1114
   311
deba@1114
   312
The global functionality of the reader class can be changed by giving a
athos@1526
   313
special template parameter to the GraphReader class. By default, the
alpar@1118
   314
template parameter is \c DefaultReaderTraits. A reader traits class 
deba@1901
   315
should provide a nested template class Reader for each type, and a 
deba@1114
   316
DefaultReader for skipping a value.
deba@1114
   317
deba@1901
   318
The specialization of writing is very similar to that of reading.
deba@1114
   319
klao@1909
   320
\section u Undirected graphs
deba@1532
   321
klao@1909
   322
In a file describing an undirected graph (ugraph, for short) you find an
klao@1909
   323
\c uedgeset section instead of the \c edgeset section. The first line of
athos@1540
   324
the section describes the names of the maps on the undirected egdes and all
athos@1540
   325
next lines describe one undirected edge with the the incident nodes and the
athos@1540
   326
values of the map.
deba@1532
   327
athos@1540
   328
The format handles directed edge maps as a syntactical sugar???, if there
athos@1540
   329
are two maps with names being the same with a \c '+' and a \c '-' prefix
athos@1540
   330
then this will be read as a directed map.
deba@1532
   331
deba@1532
   332
\code
klao@1909
   333
@uedgeset
deba@1901
   334
             label      capacity        +flow   -flow
deba@1901
   335
32   2       1          4.3             2.0     0.0
deba@1901
   336
21   21      5          2.6             0.0     2.6
deba@1901
   337
21   12      8          3.4             0.0     0.0
deba@1532
   338
\endcode
deba@1532
   339
klao@1909
   340
The \c edges section is changed to \c uedges section. This section
deba@1532
   341
describes labeled edges and undirected edges. The directed edge label
athos@1540
   342
should start with a \c '+' or a \c '-' prefix to decide the direction
deba@1532
   343
of the edge. 
deba@1532
   344
deba@1532
   345
\code
klao@1909
   346
@uedges
klao@1909
   347
uedge 1
deba@1532
   348
+edge 5
deba@1532
   349
-back 5
deba@1532
   350
\endcode
deba@1532
   351
alpar@1631
   352
There are similar classes to the \ref lemon::GraphReader "GraphReader" and
alpar@1631
   353
\ref lemon::GraphWriter "GraphWriter" which
alpar@1631
   354
handle the undirected graphs. These classes are
klao@1909
   355
the \ref lemon::UGraphReader "UGraphReader"
klao@1909
   356
and \ref lemon::UGraphWriter "UGraphWriter".
deba@1532
   357
klao@1909
   358
The \ref lemon::UGraphReader::readUEdgeMap() "readUEdgeMap()"
alpar@1631
   359
function reads an undirected map and the
klao@1909
   360
\ref lemon::UGraphReader::readUEdge() "readUEdge()"
alpar@1631
   361
reads an undirected edge from the file, 
deba@1532
   362
deba@1532
   363
\code
klao@1909
   364
reader.readUEdgeMap("capacity", capacityMap);
deba@1532
   365
reader.readEdgeMap("flow", flowMap);
deba@1532
   366
...
klao@1909
   367
reader.readUEdge("u_edge", u_edge);
deba@1532
   368
reader.readEdge("edge", edge);
deba@1532
   369
\endcode
deba@1532
   370
deba@1532
   371
\section advanced Advanced features
deba@1532
   372
athos@1540
   373
The graph reader and writer classes give an easy way to read and write
athos@1540
   374
graphs. But sometimes we want more advanced features. In this case we can
athos@1540
   375
use the more general <tt>lemon reader and writer</tt> interface.
deba@1532
   376
athos@1540
   377
The LEMON file format is a section oriented file format. It contains one or
athos@1540
   378
more sections, each starting with a line identifying its type 
athos@1540
   379
(the word starting with the \c \@  character).
deba@1532
   380
The content of the section this way cannot contain line with \c \@ first
deba@1532
   381
character. The file may contains comment lines with \c # first character.
deba@1532
   382
alpar@1631
   383
The \ref lemon::LemonReader "LemonReader"
alpar@1631
   384
and \ref lemon::LemonWriter "LemonWriter"
alpar@1631
   385
gives a framework to read and
deba@1532
   386
write sections. There are various section reader and section writer
alpar@1631
   387
classes which can be attached to a \ref lemon::LemonReader "LemonReader"
alpar@1631
   388
or a \ref lemon::LemonWriter "LemonWriter".
deba@1532
   389
deba@1532
   390
There are default section readers and writers for reading and writing
athos@1540
   391
item sets, and labeled items in the graph. These read and write
deba@1532
   392
the format described above. Other type of data can be handled with own
deba@1532
   393
section reader and writer classes which are inherited from the
alpar@1631
   394
\c LemonReader::SectionReader or the
alpar@1631
   395
\ref lemon::LemonWriter::SectionWriter "LemonWriter::SectionWriter"
alpar@1631
   396
classes.
deba@1532
   397
deba@1532
   398
The next example defines a special section reader which reads the
deba@1532
   399
\c \@description sections into a string:
deba@1532
   400
deba@1532
   401
\code 
deba@1532
   402
class DescriptionReader : LemonReader::SectionReader {
deba@1532
   403
protected:
deba@1532
   404
  virtual bool header(const std::string& line) {
deba@1532
   405
    std::istringstream ls(line);
deba@1532
   406
    std::string head;
deba@1532
   407
    ls >> head;
deba@1532
   408
    return head == "@description";
deba@1532
   409
  }
deba@1532
   410
deba@1532
   411
  virtual void read(std::istream& is) {
deba@1532
   412
    std::string line;
deba@1532
   413
    while (getline(is, line)) {
deba@1532
   414
      desc += line;
deba@1532
   415
    }
deba@1532
   416
  }
deba@1532
   417
public:
deba@1532
   418
deba@1532
   419
  typedef LemonReader::SectionReader Parent;
deba@1532
   420
  
deba@1532
   421
  DescriptionReader(LemonReader& reader) : Parent(reader) {}
deba@1532
   422
deba@1532
   423
  const std::string& description() const {
deba@1532
   424
    return description;
deba@1532
   425
  }
deba@1532
   426
deba@1532
   427
private:
deba@1532
   428
  std::string desc;
deba@1532
   429
};
deba@1532
   430
\endcode
deba@1532
   431
deba@1532
   432
The other advanced stuff of the generalized file format is that 
deba@1532
   433
multiple edgesets can be stored to the same nodeset. It can be used 
athos@1540
   434
for example as a network traffic matrix.
deba@1532
   435
athos@1540
   436
In our example there is a network with symmetric links and there are assymetric
deba@1532
   437
traffic request on the network. This construction can be stored in an
deba@1842
   438
undirected graph and in a directed \c ListEdgeSet class. The example
alpar@1631
   439
shows the input with the \ref lemon::LemonReader "LemonReader" class:
deba@1532
   440
deba@1532
   441
\code
klao@1909
   442
ListUGraph network;
klao@1909
   443
ListUGraph::UEdgeMap<double> capacity;
klao@1909
   444
ListEdgeSet<ListUGraph> traffic(network);
klao@1909
   445
ListEdgeSet<ListUGraph>::EdgeMap<double> request(network);
deba@1532
   446
deba@1532
   447
LemonReader reader(std::cin);
klao@1909
   448
NodeSetReader<ListUGraph> nodesetReader(reader, network);
klao@1909
   449
UEdgeSetReader<ListUGraph> 
klao@1909
   450
  uEdgesetReader(reader, network, nodesetReader);
klao@1909
   451
uEdgesetReader.readEdgeMap("capacity", capacity);
klao@1909
   452
EdgeSetReader<ListEdgeSet<ListUGraph> > 
deba@1848
   453
  edgesetReader(reader, traffic, nodesetReader, "traffic");
deba@1532
   454
edgesetReader.readEdgeMap("request", request);
deba@1532
   455
deba@1532
   456
reader.run();
deba@1532
   457
\endcode
deba@1532
   458
alpar@1631
   459
Because both the \ref lemon::GraphReader "GraphReader"
klao@1909
   460
and the \ref lemon::UGraphReader "UGraphReader" can be converted
alpar@1631
   461
to \ref lemon::LemonReader "LemonReader"
deba@1901
   462
and it can resolve the label's of the items, the previous
klao@1909
   463
result can be achived with the \ref lemon::UGraphReader "UGraphReader"
alpar@1631
   464
class, too.
deba@1532
   465
deba@1532
   466
deba@1532
   467
\code
klao@1909
   468
ListUGraph network;
klao@1909
   469
ListUGraph::UEdgeSet<double> capacity;
klao@1909
   470
ListEdgeSet<ListUGraph> traffic(network);
klao@1909
   471
ListEdgeSet<ListUGraph>::EdgeMap<double> request(network);
deba@1532
   472
klao@1909
   473
UGraphReader<ListUGraph> reader(std::cin, network);
deba@1532
   474
reader.readEdgeMap("capacity", capacity);
klao@1909
   475
EdgeSetReader<ListEdgeSet<ListUGraph> > 
deba@1848
   476
  edgesetReader(reader, traffic, reader, "traffic");
deba@1532
   477
edgesetReader.readEdgeMap("request", request);
deba@1532
   478
deba@1532
   479
reader.run();
deba@1532
   480
\endcode
deba@1532
   481
deba@1333
   482
\author Balazs Dezso
deba@1114
   483
*/
alpar@1631
   484
}