LEMON Tutorial
59
|
The LEMON maps are not only just storage classes, but also they are concepts of any key–value based data access. Beside the standard digraph maps, LEMON contains several "lightweight" map adaptor classes, which perform various operations on the data of the adapted maps when their access operations are called, but without actually copying or modifying the original storage. These classes also conform to the map concepts, thus they can be used like standard LEMON maps.
Maps play a central role in LEMON. As their name suggests, they map a certain range of keys to certain values. Each map has two typedef
's to determine the types of keys and values, like this:
A map can be readable (ReadMap, for short), writable (WriteMap) or both (ReadWriteMap). There also exists a special type of ReadWrite map called reference map. In addition that you can read and write the values of a key, a reference map can also give you a reference to the value belonging to a key, so you have a direct access to the memory address where it is stored.
Each digraph structure in LEMON provides two standard map templates called ArcMap
and NodeMap
. Both are reference maps and you can easily assign data to the nodes and to the arcs of the digraph. For example if you have a digraph g
defined as
and you want to assign a floating point value to each arc, you can do it like this.
Note that you must give the underlying digraph to the constructor.
The value of a readable map can be obtained by operator[]
.
where e
is an instance of ListDigraph::Arc
. (Or anything else that converts to ListDigraph::Arc
, like ListDigraph::ArcIt
or ListDigraph::OutArcIt
etc.)
There are two ways to assign a new value to a key
operator[]
gives you a reference to the value, thus you can use this. set(Key,const Value &)
for this purpose. The first case is more comfortable and if you store complex structures in your map, it might be more efficient. However, there are writable but not reference maps, so if you want to write a generic algorithm, you should insist on the second way.
Readable maps are very frequently used as the input of an algorithm. For this purpose the most straightforward way is the use of the default maps provided by LEMON's digraph structures. Very often however, it is more convenient and/or more efficient to write your own readable map.
You can find some examples below. In these examples Digraph
is the type of the particular digraph structure you use.
This simple map assigns to each arc.
An alternative way to define maps is to use MapBase
Here is a bit more complex example. It provides a length function obtained from a base length function shifted by a potential difference.
Then, you can call e.g. Dijkstra algoritm on this map like this:
In the previous section we discussed digraph topology. That is the skeleton a complex digraph represented data-set needs. But how to assign the data itself to that skeleton?
Here come the maps in.
Maps play a central role in LEMON. As their name suggests, they map a certain range of keys to certain values. In LEMON there is many types of maps. Each map has two typedef's to determine the types of keys and values, like this:
(Except matrix maps, they have two key types.)
To make easy to use them - especially as template parameters - there are map concepts like by digraph classes.
operator
[]. set()
member function. operator
[] to providing you constant or non-constant reference to the value belonging to a key, so you have a direct access to the memory address where it is stored. Every mappable digraph class has two public templates: NodeMap<VALUE> and ArcMap<VALUE> satisfying the DigraphMap concept. If you want to assign data to nodes, just declare a NodeMap with the corresponding type. As an example, think of a arc-weighted digraph.
You can see that the map needs the digraph whose arcs will mapped, but nothing more.
If the digraph class is extendable or erasable the map will automatically follow the changes you make. If a new node is added a default value is mapped to it. You can define the default value by passing a second argument to the map's constructor.
But keep in mind that VALUE
has to have copy constructor.
Of course VALUE
can be a rather complex type.
For practice let's see the following template function (from maps-summary.cc in the demo directory)!
The task is simple. We need the summary of some kind of data assigned to a digraph's nodes. (Whit a little trick the summary can be calculated only to a sub-digraph without changing this code. See SubDigraph techniques - that's LEMON's true potential.)And the usage is simpler than the declaration suggests. The compiler deduces the template specialization, so the usage is like a simple function call.
Most of the time you will probably use digraph maps, but keep in mind, that in LEMON maps are more general and can be used widely.
If you want some 'real-life' examples see the next page, where we discuss algorithms (coming soon) and will use maps hardly. Or if you want to know more about maps read these advanced map techniques.
Here we discuss some advanced map techniques. Like writing your own maps or how to extend/modify a maps functionality with adaptors.
Readable maps are very frequently used as the input of an algorithm. For this purpose the most straightforward way is the use of the default maps provided by LEMON's digraph structures. Very often however, it is more convenient and/or more efficient to write your own readable map.
You can find some examples below. In these examples Digraph
is the type of the particular digraph structure you use.
This simple map assigns to each arc.
An alternative way to define maps is to use MapBase
Here is a bit more complex example. It provides a length function obtained from a base length function shifted by a potential difference.
Then, you can call e.g. Dijkstra algoritm on this map like this:
...
...
See Map Adaptors in the reference manual.
The basic functionality of the algorithms can be highly extended using special purpose map types for their internal data structures. For example, the Dijkstra class stores a ef ProcessedMap, which has to be a writable node map of bool value type. The assigned value of each node is set to true when the node is processed, i.e., its actual distance is found. Applying a special map, LoggerBoolMap, the processed order of the nodes can easily be stored in a standard container.
Such specific map types can be passed to the algorithms using the technique of named template parameters. Similarly to the named function parameters, they allow specifying any subset of the parameters and in arbitrary order.
Let us suppose that we have a traffic network stored in a LEMON digraph structure with two arc maps length
and speed
, which denote the physical length of each arc and the maximum (or average) speed that can be achieved on the corresponding road-section, respectively. If we are interested in the best traveling times, the following code can be used.
The function-type interfaces are considerably simpler, but they can be used in almost all practical cases. Surprisingly, even the above example can also be implemented using the dijkstra() function and named parameters, as follows. Note that the function-type interface has the major advantage that temporary objects can be passed as parameters.
Let us see a bit more complex example to demonstrate Dfs's capabilities.
We will see a program, which solves the problem of topological ordering. We need to know in which order we should put on our clothes. The program will do the following:
set()
method the only thing we need to do is insert the key - that is the node whose processing just finished - into the beginning of the list.LEMON
. But we wanted to show you, how easy is to add additional functionality.
First we declare the needed data structures: the digraph and a map to store the nodes' label.
Now we build a digraph. But keep in mind that it must be DAG because cyclic digraphs has no topological ordering.
We label them... Then add arcs which represent the precedences between those items.See how easy is to access the internal information of this algorithm trough maps. We only need to set our own map as the class's ProcessedMap.
And now comes the third part. Write out the list in reverse order. But the list was composed in reverse way (with push_front()
instead of push_back()
so we just iterate it.
The program is to be found in the demo directory: topological_ordering.cc
LEMON also contains visitor based algorithm classes for BFS and DFS.
Skeleton visitor classes are defined for both BFS and DFS, the concrete implementations can be inherited from them.
In the following example, the discover()} and
<< 6 Basic Graph Utilities | Home | 8 Graph Structures >>