Skip to content

Commit 76a7ddc

Browse files
committed
docs: imrove visitors description
1 parent a1aed63 commit 76a7ddc

File tree

3 files changed

+166
-109
lines changed

3 files changed

+166
-109
lines changed

doc/reference/algorithms.md

Lines changed: 1 addition & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -20,112 +20,6 @@ and <code><i>path-target</i>(<i>p</i>)</code> = v that has the smallest value of
2020
* if there exists an edge _e_ with target(_e_) = v, then it is source(_e_),
2121
* otherwise it is `v`.
2222

23-
## Visitors
24-
25-
A number of functions in this section take a _visitor_ as an optional argument.
26-
As different _events_, related to vertices and edges, occur during the execution of an algorithm,
27-
a corresponding member function, if present, is called for the visitor.
28-
29-
Each algorithm defines the events that it supports. Visitor functions corresponding to not supported events, even if present in the visitor are ignored.
30-
31-
If an algorithm supports a given event but the specified visitor does not provide the corresponding valid member function, no runtime overhead related to processing this event is incurred.
32-
33-
34-
### <code><em>GraphVisitor</em></code> requirements
35-
36-
The following lists the visitation events and the corresponding visitor member functions.
37-
For each of the events the visitor may choose to support it via making the corresponding member
38-
function valid.
39-
40-
The notation used:
41-
42-
| name | type | definition |
43-
|-------|------|-------------|
44-
| `vis` | | the visitor |
45-
| `G` | | the type of the graph that the algorithm is instantiated for |
46-
| `vd` | `vertex_info<vertex_id_t<G>, vertex_reference_t<G>, void>` | visited vertex |
47-
| `ed` | `edge_info<vertex_id_t<G>, true, edge_reference_t<G>, void>` | visited edge |
48-
49-
```c++
50-
vis.on_discover_vertex(vd)
51-
```
52-
53-
If valid, it is called whenever a new vertex is identified for future examination in the
54-
course of executing an algorithm.
55-
56-
(Note: the vertices provided as _sources_ to algorithms are initially discovered.)
57-
58-
```c++
59-
vis.on_examine_vertex(vd)
60-
```
61-
62-
If valid, it is called whenever a previously discovered vertex is started being examined.
63-
64-
(Note: examining a vertex usually triggers the discovery of other vertices and edges.)
65-
66-
```c++
67-
vis.on_finish_vertex(vd)
68-
```
69-
70-
If valid, it is called whenever an algorithm finishes examining the vertex.
71-
72-
(Note: If the graph is unbalanced and another path to this vertex has a lower accumulated
73-
weight, the algorithm will process `vd` again.
74-
A consequence is that `on_examine_vertex` could be called twice (or more) on the
75-
same vertex.)
76-
77-
```c++
78-
vis.on_examine_edge(ed)
79-
```
80-
81-
If valid, it is called whenever a new edge is started being examined.
82-
83-
84-
85-
86-
```c++
87-
vis.on_edge_relaxed(ed)
88-
```
89-
90-
If valid, it is called whenever an edge is _relaxed_. Relaxing an edge means reducing
91-
the stored minimum accumulated distance found so far from the given source to the target
92-
of the examined edge `ed`.
93-
94-
95-
```c++
96-
vis.on_edge_not_relaxed(ed)
97-
```
98-
99-
If valid, it is called whenever a new edge `ed` is inspected but not relaxed (because
100-
the stored accumulated distance to the target of `ed` found so far is smaller than the path via `ed`.)
101-
102-
```c++
103-
vis.on_edge_minimized(ed)
104-
```
105-
106-
If valid, it is called when no cycles have been detected while examining the edge `ed`.
107-
108-
109-
```c++
110-
vis.on_edge_not_minimized(ed)
111-
```
112-
113-
If valid, it is called when a cycles have been detected while examining the edge `ed`.
114-
This happens in shortest paths algorithms that accept negative weights, and means that
115-
no finite minimum exists.
116-
117-
118-
### `empty_visitor`
119-
120-
This library comes with an empty class `empty_visitor`:
121-
122-
```c++
123-
namespace graph {
124-
struct empty_visitor{};
125-
}
126-
```
127-
128-
It is used as the default visitor type for the algorithms. This visitor supports no events, and therefore triggers no runtime overhead on any event.
12923

13024

13125
## `dijkstra_shortest_paths`
@@ -183,7 +77,7 @@ constexpr void dijkstra_shortest_distances(
18377
* `std::size(distances) >= num_vertices(g)` is `true`,
18478
* `std::size(predecessor) >= num_vertices(g)` is `true`.
18579
186-
*Effects:* Supports the following visitation events: `on_initialize_vertex`, `on_discover_vertex`,
80+
*Effects:* Supports the following [visitation](./visitors.md) events: `on_initialize_vertex`, `on_discover_vertex`,
18781
`on_examine_vertex`, `on_finish_vertex`, `on_examine_edge`, `on_edge_relaxed`, and `on_edge_not_relaxed`.
18882
18983
*Postconditions:* For each <code><i>i</i></code> in range [`0`; `num_vertices(g)`):

doc/reference/visitors.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Visitors
2+
3+
A number of functions in this section take a _visitor_ as an optional argument.
4+
As different _events_, related to vertices and edges, occur during the execution of an algorithm,
5+
a corresponding member function, if present, is called for the visitor.
6+
7+
Each algorithm defines the events that it supports. Visitor functions corresponding to not
8+
supported events, even if present in the visitor are ignored.
9+
10+
If an algorithm supports a given event but the specified visitor does not provide the corresponding valid member function, no runtime overhead related to processing this event is incurred.
11+
12+
13+
## <code><em>GraphVisitor</em></code> requirements
14+
15+
The following lists the visitation events and the corresponding visitor member functions.
16+
For each of the events the visitor may choose to support it via making the corresponding member
17+
function valid.
18+
19+
The notation used:
20+
21+
| name | type | definition |
22+
|-------|------|-------------|
23+
| `vis` | | the visitor |
24+
| `G` | | the type of the graph that the algorithm is instantiated for |
25+
| `vd` | `vertex_info<vertex_id_t<G>, vertex_reference_t<G>, void>` | visited vertex |
26+
| `ed` | `edge_info<vertex_id_t<G>, true, edge_reference_t<G>, void>` | visited edge |
27+
28+
```c++
29+
vis.on_discover_vertex(vd)
30+
```
31+
32+
If valid, it is called whenever a new vertex is identified for future examination in the
33+
course of executing an algorithm.
34+
35+
(Note: the vertices provided as _sources_ to algorithms are initially discovered.)
36+
37+
```c++
38+
vis.on_examine_vertex(vd)
39+
```
40+
41+
If valid, it is called whenever a previously discovered vertex is started being examined.
42+
43+
(Note: examining a vertex usually triggers the discovery of other vertices and edges.)
44+
45+
```c++
46+
vis.on_finish_vertex(vd)
47+
```
48+
49+
If valid, it is called whenever an algorithm finishes examining the vertex.
50+
51+
(Note: If the graph is unbalanced and another path to this vertex has a lower accumulated
52+
weight, the algorithm will process `vd` again.
53+
A consequence is that `on_examine_vertex` could be called twice (or more) on the
54+
same vertex.)
55+
56+
```c++
57+
vis.on_examine_edge(ed)
58+
```
59+
60+
If valid, it is called whenever a new edge is started being examined.
61+
62+
63+
64+
65+
```c++
66+
vis.on_edge_relaxed(ed)
67+
```
68+
69+
If valid, it is called whenever an edge is _relaxed_. Relaxing an edge means reducing
70+
the stored minimum accumulated distance found so far from the given source to the target
71+
of the examined edge `ed`.
72+
73+
74+
```c++
75+
vis.on_edge_not_relaxed(ed)
76+
```
77+
78+
If valid, it is called whenever a new edge `ed` is inspected but not relaxed (because
79+
the stored accumulated distance to the target of `ed` found so far is smaller than the path via `ed`.)
80+
81+
```c++
82+
vis.on_edge_minimized(ed)
83+
```
84+
85+
If valid, it is called when no cycles have been detected while examining the edge `ed`.
86+
87+
88+
```c++
89+
vis.on_edge_not_minimized(ed)
90+
```
91+
92+
If valid, it is called when a cycles have been detected while examining the edge `ed`.
93+
This happens in shortest paths algorithms that accept negative weights, and means that
94+
no finite minimum exists.
95+
96+
97+
## `empty_visitor`
98+
99+
This library comes with an empty class `empty_visitor`:
100+
101+
```c++
102+
namespace graph {
103+
struct empty_visitor{};
104+
}
105+
```
106+
107+
It is used as the default visitor type for the algorithms. This visitor supports no events, and therefore triggers no runtime overhead on any event.

doc/tutorial/algorithms.md

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Algorithms
44
This library offers a number of generic algorithms.
55
Due to the nature of graph algorithms, the way they communicate the results requires some additional code.
66

7-
Let's use the following graph representation, naively recognized by this library,
7+
Let's use the following graph representation, natively recognized by this library,
88
that is able to store a weight for each edge:
99

1010
```c++
@@ -56,4 +56,60 @@ auto path = [&predecessors](int from, int to)
5656
assert((path(0, 5) == std::vector{3, 4, 1, 2, 5}));
5757
```
5858

59-
The algorithms from this library are described in section [Algorithms](../reference/algorithms.md).
59+
The algorithms from this library are described in section [Algorithms](../reference/algorithms.md).
60+
61+
62+
Index-based access
63+
------------------
64+
65+
You will notice that a lot of function arguments passed to the algorithms takes
66+
vectors as "output" arguments, such as `predecessors` or `distances` in the above examples.
67+
They do not have to be vectors, but they need to be something that is *indexable* by an integral
68+
number. This is how the algorithms are able to fill in some data associated with a given vertex.
69+
Vertices are here represented by a *vertex index*. This requires that graph representations
70+
that interact with the algorithms need to be able to provide an *index* uniquely identifying each
71+
vertex. This requirement is encoded in the concept `index_adjacency_list`.
72+
73+
74+
Visitors
75+
--------
76+
77+
Sometimes, when working with the algorithms, there is a need to get more than just the result.
78+
For troubleshooting or debugging reasons we may want to know what indices and edges are processed,
79+
and in what order. We might also want to display the progress of the algorithm (like, "25% done")
80+
before the algorithm finishes.
81+
82+
To address this need some of the algorithms provide a notion of a *visitor*. A visitor is
83+
like a set of callbacks that you can pass as an optional parameter to an algorithm. Whenever
84+
an *event* occurs during the execution of the algorithm – such as "new vertex discovered"
85+
or "a step through an edge taken" – a corresponding callback is invoked.
86+
87+
for illustration, consider that in the above example, we want the algorithm to display the
88+
progress to `STDOUT` upon every third vertex processed. We would have to create our custom
89+
visitor, tell it which event we are interested in intercepting, and what we want to do then.
90+
91+
```c++
92+
class ShowProgress
93+
{
94+
using G = std::vector<std::vector<std::tuple<int, double>>>;
95+
using VD = graph::vertex_info<graph::vertex_id_t<G>, graph::vertex_reference_t<G>, void>;
96+
int vertex_count = 0;
97+
98+
public:
99+
void on_discover_vertex(VD const& v)
100+
{
101+
if (vertex_count % 3 == 0)
102+
std::cout << "processing vertex " << v.id << "\n";
103+
++vertex_count;
104+
}
105+
};
106+
```
107+
108+
And then pass it to the algorithm:
109+
110+
```c++
111+
graph::dijkstra_shortest_paths(g, 0, distances, predecessors, weight, ShowProgress{});
112+
```
113+
114+
Name `on_discover_vertex` is one of the event handlers in visitors. For a comprehensive
115+
list, see section [Visitors](../reference/visitors.md).

0 commit comments

Comments
 (0)