0% found this document useful (0 votes)
156 views156 pages

BG

This document is a tutorial on using the Boost.Graph library to build and manipulate graphs. It begins with an introduction and outlines the sections. Section 2 discusses building graphs without properties, including creating empty graphs, adding vertices and edges, and examples. Section 3 covers working with such graphs, like finding degrees and connectivity. Section 4 introduces building graphs with bundled vertices. Section 5 discusses operations on these bundled vertex graphs.

Uploaded by

dustuumistuu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
156 views156 pages

BG

This document is a tutorial on using the Boost.Graph library to build and manipulate graphs. It begins with an introduction and outlines the sections. Section 2 discusses building graphs without properties, including creating empty graphs, adding vertices and edges, and examples. Section 3 covers working with such graphs, like finding degrees and connectivity. Section 4 introduces building graphs with bundled vertices. Section 5 discusses operations on these bundled vertex graphs.

Uploaded by

dustuumistuu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 156

Boost.

Graph Cookbook 1: Basics


Richel Bilderbeek
May 10, 2018

Contents
1 Introduction 5
1.1 Why this tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2 Tutorial style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3 Coding style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.4 License . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.5 Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.6 Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.7 Outline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

2 Building graphs without properties 9


2.1 Creating an empty (directed) graph . . . . . . . . . . . . . . . . 12
2.2 Creating an empty undirected graph . . . . . . . . . . . . . . . . 14
2.3 Counting the number of vertices . . . . . . . . . . . . . . . . . . 15
2.4 Counting the number of edges . . . . . . . . . . . . . . . . . . . . 16
2.5 Adding a vertex . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.6 Vertex descriptors . . . . . . . . . . . . . . . . . . . . . . . . . . 18

1
2.7 Get the vertex iterators . . . . . . . . . . . . . . . . . . . . . . . 19
2.8 Get all vertex descriptors . . . . . . . . . . . . . . . . . . . . . . 20
2.9 Add an edge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.10 boost::add_edge result . . . . . . . . . . . . . . . . . . . . . . . . 23
2.11 Getting the edge iterators . . . . . . . . . . . . . . . . . . . . . . 23
2.12 Edge descriptors . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.13 Get all edge descriptors . . . . . . . . . . . . . . . . . . . . . . . 25
2.14 Creating a directed graph . . . . . . . . . . . . . . . . . . . . . . 26
2.14.1 Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.14.2 Function to create such a graph . . . . . . . . . . . . . . . 27
2.14.3 Creating such a graph . . . . . . . . . . . . . . . . . . . . 27
2.14.4 The .dot file produced . . . . . . . . . . . . . . . . . . . . 28
2.14.5 The .svg file produced . . . . . . . . . . . . . . . . . . . . 28
2.15 Creating K2 , a fully connected undirected graph with two vertices 29
2.15.1 Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.15.2 Function to create such a graph . . . . . . . . . . . . . . . 29
2.15.3 Creating such a graph . . . . . . . . . . . . . . . . . . . . 30
2.15.4 The .dot file produced . . . . . . . . . . . . . . . . . . . . 31

d
2.15.5 The .svg file produced . . . . . . . . . . . . . . . . . . . . 31
2.16 Creating K3 , a fully connected undirected graph with three
vertices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.16.1 Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.16.2 Function to create such a graph . . . . . . . . . . . . . . . 32
2.16.3 Creating such a graph . . . . . . . . . . . . . . . . . . . . 33
2.16.4 The .dot file produced . . . . . . . . . . . . . . . . . . . . 33

d
2.16.5 The .svg file produced . . . . . . . . . . . . . . . . . . . . 34
2.17 Creating a path graph . . . . . . . . . . . . . . . . . . . . . . 34
2.17.1 Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.17.2 Function to create such a graph . . . . . . . . . . . . . . . 35
2.17.3 Creating such a graph . . . . . . . . . . . . . . . . . . . . 35
2.17.4 The .dot file produced . . . . . . . . . . . . . . . . . . . . 36

d
2.17.5 The .svg file produced . . . . . . . . . . . . . . . . . . . . 36
2.18 Creating a Peterson graph . . . . . . . . . . . . . . . . . . . . 37
2.18.1 Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.18.2 Function to create such a graph . . . . . . . . . . . . . . . 38
2.18.3 Creating such a graph . . . . . . . . . . . . . . . . . . . . 39
2.18.4 The .dot file produced . . . . . . . . . . . . . . . . . . . . 40
2.18.5 The .svg file produced . . . . . . . . . . . . . . . . . . . . 41

3 Working on graphs without properties 42

d
3.1 Getting the vertices’ out degree . . . . . . . . . . . . . . . . . . . 43

d
3.2 Is there an edge between two vertices? . . . . . . . . . . . . . 45

dd
3.3 Get the edge between two vertices . . . . . . . . . . . . . . . . 46

dd
3.4 Create a direct-neighbour subgraph from a vertex descriptor 48
3.5 Create a direct-neighbour subgraph from a vertex descriptor
including inward edges . . . . . . . . . . . . . . . . . . . . . . . . 50

2
3.6 dd Creating all direct-neighbour subgraphs from a graph with-
3.7 d Are two graphs isomorphic? . . . . . . . . . . . . . . . . . . .
out properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

3.8 dd Count the number of connected components in an directed


53

3.9 dd Count the number of connected components in an undi-


graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

3.10 dd Count the number of levels in an undirected graph . . . . .


rected graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
58
3.11 Saving a graph to a .dot file . . . . . . . . . . . . . . . . . . . . 60
3.12 Loading a directed graph from a .dot . . . . . . . . . . . . . . . 61
3.13 Loading an undirected graph from a .dot file . . . . . . . . . . . 63

4 Building graphs with bundled vertices 65


4.1 Creating the bundled vertex class . . . . . . . . . . . . . . . . . . 66
4.2 Create the empty directed graph with bundled vertices . . . . . . 67
4.3 Create the empty undirected graph with bundled vertices . . . . 68
4.4 Add a bundled vertex . . . . . . . . . . . . . . . . . . . . . . . . 68
4.5 Getting the bundled vertices’ my_vertexes1 . . . . . . . . . . . . 69
4.6 Creating a two-state Markov chain with bundled vertices . . . . . 69
4.6.1 Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
4.6.2 Function to create such a graph . . . . . . . . . . . . . . . 70
4.6.3 Creating such a graph . . . . . . . . . . . . . . . . . . . . 71
4.6.4 The .dot file produced . . . . . . . . . . . . . . . . . . . . 72
4.6.5 The .svg file produced . . . . . . . . . . . . . . . . . . . . 74
4.7 Creating K2 with bundled vertices . . . . . . . . . . . . . . . . . 75
4.7.1 Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.7.2 Function to create such a graph . . . . . . . . . . . . . . . 76
4.7.3 Creating such a graph . . . . . . . . . . . . . . . . . . . . 76
4.7.4 The .dot file produced . . . . . . . . . . . . . . . . . . . . 77
4.7.5 The .svg file produced . . . . . . . . . . . . . . . . . . . . 79

5 Working on graphs with bundled vertices 80


5.1 Has a bundled vertex with a my_bundled_vertex . . . . . . . . 80
5.2 Find a bundled vertex with a certain my_bundled_vertex . . . . 82
5.3 Get a bundled vertex its ‘my_bundled_vertex’ . . . . . . . . . . 84
5.4 Set a bundled vertex its my_vertex . . . . . . . . . . . . . . . . . 85
5.5 Setting all bundled vertices’ my_vertex objects . . . . . . . . . . 86
5.6 Storing a graph with bundled vertices as a .dot . . . . . . . . . . 87
5.7 Loading a directed graph with bundled vertices from a .dot . . . 90
5.8 Loading an undirected graph with bundled vertices from a .dot . 93
1 thename ‘my_vertexes’ is chosen to indicate this function returns a container of
my_vertex

3
6 Building graphs with bundled edges and vertices 95
6.1 Creating the bundled edge class . . . . . . . . . . . . . . . . . . . 96
6.2 Create an empty directed graph with bundled edges and vertices 98
6.3 Create an empty undirected graph with bundled edges and vertices 99
6.4 Add a bundled edge . . . . . . . . . . . . . . . . . . . . . . . . . 100
6.5 Getting the bundled edges my_edges . . . . . . . . . . . . . . . . 102
6.6 Creating a Markov-chain with bundled edges and vertices . . . . 103
6.6.1 Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
6.6.2 Function to create such a graph . . . . . . . . . . . . . . . 104
6.6.3 Creating such a graph . . . . . . . . . . . . . . . . . . . . 106
6.6.4 The .dot file produced . . . . . . . . . . . . . . . . . . . . 106
6.6.5 The .svg file produced . . . . . . . . . . . . . . . . . . . . 108
6.7 Creating K3 with bundled edges and vertices . . . . . . . . . . . 109
6.7.1 Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
6.7.2 Function to create such a graph . . . . . . . . . . . . . . . 111
6.7.3 Creating such a graph . . . . . . . . . . . . . . . . . . . . 112
6.7.4 The .dot file produced . . . . . . . . . . . . . . . . . . . . 112
6.7.5 The .svg file produced . . . . . . . . . . . . . . . . . . . . 114

7 Working on graphs with bundled edges and vertices 115


7.1 Has a my_bundled_edge . . . . . . . . . . . . . . . . . . . . . . 115
7.2 Find a my_bundled_edge . . . . . . . . . . . . . . . . . . . . . . 116
7.3 Get an edge its my_bundled_edge . . . . . . . . . . . . . . . . . 118
7.4 Set an edge its my_bundled_edge . . . . . . . . . . . . . . . . . 119
7.5 Storing a graph with bundled edges and vertices as a .dot . . . . 121
7.6 Load a directed graph with bundled edges and vertices from a
.dot file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
7.7 Load an undirected graph with bundled edges and vertices from
a .dot file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126

8 Building graphs with a graph name 129


8.1 Create an empty directed graph with a graph name property . . 129
8.2 Create an empty undirected graph with a graph name property . 130
8.3 Get a graph its name property . . . . . . . . . . . . . . . . . . . 132
8.4 Set a graph its name property . . . . . . . . . . . . . . . . . . . . 133
8.5 Create a directed graph with a graph name property . . . . . . . 133
8.5.1 Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
8.5.2 Function to create such a graph . . . . . . . . . . . . . . . 134
8.5.3 Creating such a graph . . . . . . . . . . . . . . . . . . . . 134
8.5.4 The .dot file produced . . . . . . . . . . . . . . . . . . . . 135
8.5.5 The .svg file produced . . . . . . . . . . . . . . . . . . . . 136
8.6 Create an undirected graph with a graph name property . . . . . 136
8.6.1 Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
8.6.2 Function to create such a graph . . . . . . . . . . . . . . . 136
8.6.3 Creating such a graph . . . . . . . . . . . . . . . . . . . . 137
8.6.4 The .dot file produced . . . . . . . . . . . . . . . . . . . . 138

4
8.6.5 The .svg file produced . . . . . . . . . . . . . . . . . . . . 138

9 Working on graphs with a graph name 138


9.1 Storing a graph with a graph name property as a .dot file . . . . 138
9.2 Loading a directed graph with a graph name property from a .dot
file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
9.3 Loading an undirected graph with a graph name property from
a .dot file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141

10 Other graph functions 143


10.1 Encode a std::string to a Graphviz-friendly format . . . . . . . . 143
10.2 Decode a std::string from a Graphviz-friendly format . . . . . . . 143
10.3 Check if a std::string is Graphviz-friendly . . . . . . . . . . . . . 143

11 Misc functions 144


11.1 Getting a data type as a std::string . . . . . . . . . . . . . . . . . 144
11.2 Convert a .dot to .svg . . . . . . . . . . . . . . . . . . . . . . . . 145
11.3 Check if a file exists . . . . . . . . . . . . . . . . . . . . . . . . . 147

12 Errors 147
12.1 Formed reference to void . . . . . . . . . . . . . . . . . . . . . . . 147
12.2 No matching function for call to ‘clear_out_edges’ . . . . . . . . 148
12.3 No matching function for call to ‘clear_in_edges’ . . . . . . . . . 148
12.4 Undefined reference to boost::detail::graph::read_graphviz_new . 148
12.5 Property not found: node_id . . . . . . . . . . . . . . . . . . . . 148
12.6 Stream zeroes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149

13 Appendix 151
13.1 List of all edge, graph and vertex properties . . . . . . . . . . . . 151
13.2 Graphviz attributes . . . . . . . . . . . . . . . . . . . . . . . . . . 151

1 Introduction
This is ’Boost.Graph Cookbook 1: Basics’ (formerly: ’A well-connected C++14
Boost.Graph tutorial’), version 3.0.

1.1 Why this tutorial


I needed this tutorial already in 2006, when I started experimenting with Boost.Graph.
More specifically, I needed a tutorial that:
• Orders concepts chronologically
• Increases complexity gradually

• Shows complete pieces of code

5
What I had were the book [8] and the Boost.Graph website, both did not satisfy
these requirements.

1.2 Tutorial style


Readable for beginners This tutorial is aimed at the beginner programmer.
This tutorial is intended to take the reader to the level of understanding the book
[8] and the Boost.Graph website require. It is about basic graph manipulation,
not the more advanced graph algorithms.

High verbosity This tutorial is intended to be as verbose, such that a begin-


ner should be able to follow every step, from reading the tutorial from beginning
to end chronologically. Especially in the earlier chapters, the rationale behind

d
the code presented is given, including references to the literature. Chapters
marked with ’ ’ are optional, less verbose and bring no new information to the
storyline.

Repetitiveness This tutorial is intended to be as repetitive, such that a be-


ginner can spot the patterns in the code snippets their increasing complexity.
Extending code from this tutorial should be as easy as extending the patterns.

Index In the index, I did first put all my long-named functions there literally,
but this resulted in a very sloppy layout. Instead, the function ’do_something’
can be found as ’Do something’ in the index. On the other hand, STL and Boost
functions like ’std::do_something’ and ’boost::do_something’ can be found as
such in the index.

1.3 Coding style


Concept For every concept, I will show
• a function that achieves a goal, for example ‘create_empty_undirected_graph’
• a test case of that function, that demonstrates how to use the function,
for example ‘create_empty_undirected_graph_test’

C++14 All coding snippets are taken from compiled and tested C++14 code.
I chose to use C++14 because it was available to me on all local and remote
computers. Next to this, it makes code even shorter then just C++11.

Coding standard I use the coding style from the Core C++ Guidelines. At
the time of this writing, the Core C++ Guidelines were still in early develop-
ment, so I can only hope the conventions I then chose to follow are still Good
Ideas.

6
No comments in code It is important to add comments to code. In this
tutorial, however, I have chosen not to put comments in code, as I already
describe the function in the tutorial its text. This way, it prevents me from
saying the same things twice.

Trade-off between generic code and readability It is good to write


generic code. In this tutorial, however, I have chosen my functions to have
no templated arguments for conciseness and readability. For example, a vertex
name is std::string, the type for if a vertex is selected is a boolean, and the
custom vertex type is of type ‘my_custom_vertex’. I think these choices are
reasonable and that the resulting increase in readability is worth it.

Long function names I enjoy to show concepts by putting those in (long-


named) functions. These functions sometimes border the trivial, by, for ex-
ample, only calling a single Boost.Graph function. On the other hand, these
functions have more English-sounding names, resulting in demonstration code
that is readable. Additionally, they explicitly mention their return type (in a
simpler way), which may be considered informative.

Long function names and readability Due to my long function names and
the limitation of ≈50 characters per line, sometimes the code does get to look
a bit awkward. I am sorry for this.

Use of auto I prefer to use the keyword auto over doubling the lines of code
for using statements. Often the ‘do’ functions return an explicit data type, these
can be used for reference. Sometime I deduce the return type using decltype
and a function with the same return type. When C++17 gets accessible, I
will use ‘decltype(auto)’. If you really want to know a type, you can use the
‘get_type_name’ function (chapter 11.1).

Explicit use of namespaces On the other hand, I am explicit in the


namespaces of functions and classes I use, so to distinguish between types like
‘std::array’ and ‘boost::array’. Some functions (for example, ‘get’) reside in
the namespace of the graph to work on. In this tutorial, this is in the global
namespace. Thus, I will write ‘get’, instead of ‘boost::get’, as the latter does
not compile.

Use of STL algorithms I try to use STL algorithms wherever I can. Also you
should prefer algorithm calls over hand-written for-loops ([9] chapter 18.12.1,
[7] item 43). Sometimes using these algorithms becomes a burden on the lines
of code. This is because in C++11, a lambda function argument (use by the
algorithm) must have its data type specified. It may take multiple lines of ‘using’
statements being able to do so. In C++14 one can use ‘auto’ there as well. So,
only if it shortens the number of lines significantly, I use raw for-loops, even
though you shouldn’t.

7
Re-use of functions The functions I develop in this tutorial are re-used from
that moment on. This improves to readability of the code and decreases the
number of lines.

Tested to compile All functions in this tutorial are tested to compile using
Travis CI in both debug and release mode.

Tested to work All functions in this tutorial are tested, using the Boost.Test
library. Travis CI calls these tests after each push to the repository.

Availability The code, as well as this tutorial, can be downloaded from the
GitHub at www.github.com/richelbilderbeek/BoostGraphTutorial.

1.4 License
This tutorial is licensed under Creative Commons license 4.0. All C++ code is
licensed under GPL 3.0.

Figure 1: Creative Commons license 4.0

1.5 Feedback
This tutorial is not intended to be perfect yet. For that, I need help and feed-
back from the community. All referenced feedback is welcome, as well as any
constructive feedback.
I have tried hard to strictly follow the style as described above. If you find I
deviated from these decisions somewhere, I would be grateful if you’d let know.
Next to this, there are some sections that need to be coded or have its code
improved.

1.6 Acknowledgements
These are users that improved this tutorial and/or the code behind this tutorial,
in chronological order:
• m-dudley, http://stackoverflow.com/users/111327/m-dudley
• E. Kawashima
• mat69, https://www.reddit.com/user/mat69
• danielhj, https://www.reddit.com/user/danieljh
• sehe, http://stackoverflow.com/users/85371/sehe

8
• cv_and_me, http://stackoverflow.com/users/2417774/cv-and-he
• mywtfmp3

1.7 Outline
The chapters of this tutorial are also like a well-connected graph. To allow for
quicker learners to skim chapters, or for beginners looking to find the patterns.
The distinction between the chapter is in the type of edges and vertices.
They can have:

• no properties: see chapter 2


• have a bundled property: see chapter 4
Pivotal chapters are chapters like ‘Finding the first vertex with ...’, as this opens
up the door to finding a vertex and manipulating it.
All chapters have a rather similar structure in themselves, as depicted in

d
figure 2.
There are also some bonus chapters, that I have labeled with a ’ ’. These
chapters are added I needed these functions myself and adding them would not
hurt. Just feel free to skip them, as there will be less theory explained.

2 Building graphs without properties


Boost.Graph is about creating graphs. In this chapter we create the simplest of
graphs, in which edges and nodes have no properties (e.g. having a name).
Still, there are two types of graphs that can be constructed: undirected and
directed graphs. The difference between directed and undirected graphs is in
the edges: in an undirected graph, an edge connects two vertices without any
directionality, as displayed in figure 3. In a directed graph, an edge goes from
a certain vertex, its source, to another (which may actually be the same), its
target. A directed graph is shown in figure 4.

Figure 3: Example of an undirected graph

9
10
Figure 2: The relations between sub-chapters
A B C

Figure 4: Example of a directed graph

In this chapter, we will build two directed and two undirected graphs:
• An empty (directed) graph, which is the default type: see chapter 2.1
• An empty (undirected) graph: see chapter 2.2
• A two-state Markov chain, a directed graph with two vertices and four
edges, chapter 2.14
• K2 , an undirected graph with two vertices and one edge, chapter 2.15
Creating an empty graph may sound trivial, it is not, thanks to the versatility
of the Boost.Graph library.
In the process of creating graphs, some basic (sometimes bordering trivial)
functions are encountered:
• Counting the number of vertices: see chapter 2.3
• Counting the number of edges: see chapter 2.4
• Adding a vertex: see chapter 2.5
• Getting all vertices: see chapter 2.7
• Getting all vertex descriptors: see chapter 2.8
• Adding an edge: see chapter 2.9
• Getting all edges: see chapter 2.11
• Getting all edge descriptors: see chapter 2.13
These functions are mostly there for completion and showing which data types
are used.
The chapter also introduces some important concepts:

11
• Vertex descriptors: see chapter 2.6
• Edge insertion result: see chapter 2.10
• Edge descriptors: see chapter 2.12
After this chapter you may want to:

• Building graphs with named vertices: see chapter ??


• Building graphs with bundled vertices: see chapter 4
• Building graphs with custom vertices: see chapter ??

• Building graphs with a graph name: see chapter 8

2.1 Creating an empty (directed) graph


Let’s create an empty graph!
Algorithm 1 shows the function to create an empty graph.

Algorithm 1 Creating an empty (directed) graph

#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>

b o o s t : : a d j a c e n c y _ l i s t <>
create_empty_directed_graph ( ) n o e x c e p t
{
return { } ;
}

The code consists out of an #include and a function definition. The #in-
clude tells the compiler to read the header file ‘adjacency_list.hpp’. A header
file (often with a ‘.h’ or ‘.hpp’ extension) contains class and functions decla-
rations and/or definitions. The header file ‘adjacency_list.hpp’ contains the
boost::adjacency_list class definition. Without including this file, you will get
compile errors like ‘definition of boost::adjacency_list unknown’2 . The function
‘create_empty_directed_graph’ has:
• a return type: The return type is ‘boost::adjacency_list<>’, that is a
‘boost::adjacency_list’ with all template arguments set at their defaults

• a noexcept specification: the function should not throw3 , so it is preferred


to mark it noexcept ([10] chapter 13.7).
2 Inpractice, these compiler error messages will be longer, bordering the unreadable
3 if
the function would throw because it cannot allocate this little piece of memory, you are
already in big trouble

12
• a function body: all the function body does is implicitly create its re-
turn type by using the ‘{}’. An alternative syntax would be ‘return
boost::adjacency_list<>()’, which is needlessly longer
Algorithm 2 demonstrates the ‘create_empty_directed_graph’ function. This
demonstration is embedded within a Boost.Test unit test case. It includes a
Boost.Test header to allow to use the Boost.Test framework. Additionally, a
header file is included with the same name as the function4 . This allows use to
be able to use the function. The test case creates an empty graph and stores it.
Instead of specifying the data type explicitly, ‘auto’ is used (this is preferred,
[10] chapter 31.6), which lets the compiler figure out the type itself.

Algorithm 2 Demonstration of ‘create_empty_directed_graph’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_empty_directed_graph . h"

BOOST_AUTO_TEST_CASE( test_create_empty_directed_graph )
{
const auto g = create_empty_directed_graph ( ) ;
}

Congratulations, you’ve just created a boost::adjacency_list with its default


template arguments. The boost::adjacency_list is the most commonly used
graph type, the other is the boost::adjacency_matrix. We do not do anything
with it yet, but still, you’ve just created a graph, in which:
• The out edges and vertices are stored in a std::vector
• The edges have a direction
• The vertices, edges and graph have no properties

• The edges are stored in a std::list


It stores its edges, out edges and vertices in a two different STL5 containers.
std::vector is the container you should use by default ([10] chapter 31.6, [11]
chapter 76), as it has constant time look-up and back insertion. The std::list
is used for storing the edges, as it is better suited at inserting elements at any
position.
I use const to store the empty graph as we do not modify it. Correct use of
const is called const-correct. Prefer to be const-correct ([9] chapter 7.9.3, [10]
chapter 12.7, [7] item 3, [3] chapter 3, [11] item 15, [2] FAQ 14.05, [1] item 8,
[4] 9.1.6).
4I do not think it is important to have creative names
5 Standard Template Library, the standard library

13
2.2 Creating an empty undirected graph
Let’s create another empty graph! This time, we even make it undirected!
Algorithm 3 shows how to create an undirected graph.

Algorithm 3 Creating an empty undirected graph

#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : undirectedS
>
create_empty_undirected_graph ( ) n o e x c e p t
{
return { } ;
}

This algorithm differs from the ‘create_empty_directed_graph’ function


(algorithm 1) in that there are three template arguments that need to be spec-
ified in the creation of the boost::adjacency_list:
• the first ‘boost::vecS’: select (that is what the ‘S’ means) that out edges
are stored in a std::vector. This is the default way.
• the second ‘boost::vecS’: select that the graph vertices are stored in a
std::vector. This is the default way.

• ‘boost::undirectedS’: select that the graph is undirected. This is all we


needed to change. By default, this argument is boost::directed
Algorithm 4 demonstrates the ‘create_empty_undirected_graph’ function.

Algorithm 4 Demonstration of ‘create_empty_undirected_graph’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_empty_undirected_graph . h"

BOOST_AUTO_TEST_CASE( test_create_empty_undirected_graph )
{
const auto g = create_empty_undirected_graph ( ) ;
}

Congratulations, with algorithm 4, you’ve just created an undirected graph


in which:

14
• The out edges and vertices are stored in a std::vector
• The graph is undirected
• Vertices, edges and graph have no properties
• Edges are stored in a std::list

2.3 Counting the number of vertices


Let’s count all zero vertices of an empty graph!

Algorithm 5 Count the number of vertices

#include <c a s s e r t >


#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>

template <typename graph>


int g e t _ n _ v e r t i c e s ( const graph& g ) n o e x c e p t
{
const int n{
static_cast<int >( b o o s t : : num_vertices ( g ) )
};
a s s e r t ( static_cast<unsigned long >(n )
== b o o s t : : num_vertices ( g )
);
return n ;
}

The function ‘get_n_vertices’ takes the result of boost::num_vertices, con-


verts it to int and checks if there was conversion error. We do so, as one should
prefer using signed data types over unsigned ones in an interface ([4] chapter
9.2.2). To do so, in the function body its first statement, the unsigned long
produced by boost::num_vertices get converted to an int using a static_cast.
Using an unsigned integer over a (signed) integer for the sake of gaining that
one more bit ([9] chapter 4.4) should be avoided. The integer ‘n’ is initialized
using list-initialization, which is preferred over the other initialization syntaxes
([10] chapter 17.7.6).
The assert checks if the conversion back to unsigned long re-creates the
original value, to check if no information has been lost. If information is lost,
the program crashes. Use assert extensively ([9] chapter 24.5.18, [10] chapter
30.5, [11] chapter 68, [6] chapter 8.2, [5] hour 24, [4] chapter 2.6).
The function ‘get_n_vertices’ is demonstrated in algorithm 6, to measure
the number of vertices of both the directed and undirected graph we are already
able to create.

15
Algorithm 6 Demonstration of the ‘get_n_vertices’ function

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_empty_directed_graph . h"
#include " create_empty_undirected_graph . h"
#include " g e t _ n _ v e r t i c e s . h"

BOOST_AUTO_TEST_CASE( t e s t _ g e t _ n _ v e r t i c e s )
{
const auto g = create_empty_directed_graph ( ) ;
BOOST_CHECK( g e t _ n _ v e r t i c e s ( g ) == 0 ) ;

const auto h = create_empty_undirected_graph ( ) ;


BOOST_CHECK( g e t _ n _ v e r t i c e s ( h ) == 0 ) ;
}

Note that the type of graph does not matter here. One can count the number
of vertices of every graph, as all graphs have vertices. Boost.Graph is very good
at detecting operations that are not allowed, during compile time.

2.4 Counting the number of edges


Let’s count all zero edges of an empty graph!
This is very similar to the previous chapter, only it uses boost::num_edges
instead:

Algorithm 7 Count the number of edges

#include <c a s s e r t >


#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>

template <typename graph>


int get_n_edges ( const graph& g ) n o e x c e p t
{
const int n{
static_cast<int >( b o o s t : : num_edges ( g ) )
};
a s s e r t ( static_cast<unsigned long >(n )
== b o o s t : : num_edges ( g )
);
return n ;
}

This code is similar to the ‘get_n_vertices’ function (algorithm 5, see ratio-


nale there) except ‘boost::num_edges’ is used, instead of ‘boost::num_vertices’,

16
which also returns an unsigned long.
The function ‘get_n_edges’ is demonstrated in algorithm 8, to measure the
number of edges of an empty directed and undirected graph.

Algorithm 8 Demonstration of the ‘get_n_edges’ function

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_empty_directed_graph . h"
#include " create_empty_undirected_graph . h"
#include " get_n_edges . h"

BOOST_AUTO_TEST_CASE( test_get_n_edges )
{
const auto g = create_empty_directed_graph ( ) ;
BOOST_CHECK( get_n_edges ( g ) == 0 ) ;

const auto h = create_empty_undirected_graph ( ) ;


BOOST_CHECK( get_n_edges ( h ) == 0 ) ;
}

2.5 Adding a vertex


Empty graphs are nice, now its time to add a vertex!
To add a vertex to a graph, the boost::add_vertex function is used as shows
in algorithm 9:

Algorithm 9 Adding a vertex to a graph

#include <t y p e _ t r a i t s >


#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>

template <typename graph>


typename b o o s t : : g r a p h _ t r a i t s <graph > : : v e r t e x _ d e s c r i p t o r
add_vertex ( graph& g ) n o e x c e p t
{
s t a t i c _ a s s e r t ( ! s t d : : i s _ c o n s t <graph > : : valu e ,
" graph ␣ cannot ␣ be ␣ c o n s t "
);
const auto vd = b o o s t : : add_vertex ( g ) ;
return vd ;
}

The static_assert at the top of the function checks during compiling if the
function is called with a non-const graph. One can freely omit this static_assert:
you will get a compiler error anyways, be it a less helpful one.

17
Note that boost::add_vertex (in the ‘add_vertex’ function) returns a vertex
descriptor, which is ignored for now. Vertex descriptors are looked at in more
details at the chapter 2.6, as we need these to add an edge. To allow for this
already, ‘add_vertex’ also returns a vertex descriptor.
Algorithm 10 shows how to add a vertex to a directed and undirected graph.

Algorithm 10 Demonstration of the ‘add_vertex’ function

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " add_vertex . h"
#include " create_empty_directed_graph . h"
#include " create_empty_undirected_graph . h"

BOOST_AUTO_TEST_CASE( test_add_vertex )
{
auto g = create_empty_undirected_graph ( ) ;
add_vertex ( g ) ;
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 1 ) ;

auto h = create_empty_directed_graph ( ) ;
add_vertex ( h ) ;
BOOST_CHECK( b o o s t : : num_vertices ( h ) == 1 ) ;
}

This demonstration code creates two empty graphs, adds one vertex to each
and then asserts that the number of vertices in each graph is one. This works
for both types of graphs, as all graphs have vertices.

2.6 Vertex descriptors


A vertex descriptor is a handle to a vertex within a graph.
Vertex descriptors can be obtained by dereferencing a vertex iterator (see
chapter 2.8). To do so, we first obtain some vertex iterators in chapter 2.7).
Vertex descriptors are used to:
• add an edge between two vertices, see chapter 2.9
• obtain properties of vertex a vertex, for example the vertex its out de-
grees (chapter 3.1), the vertex its name (chapter ??), or a custom vertex
property (chapter ??)
In this tutorial, vertex descriptors have named prefixed with ‘vd_’, for example
‘vd_1’.

18
2.7 Get the vertex iterators
You cannot get the vertices. This may sound unexpected, as it must be possible
to work on the vertices of a graph. Working on the vertices of a graph is done
through these steps:
• Obtain a vertex iterator pair from the graph
• Dereferencing a vertex iterator to obtain a vertex descriptor

‘vertices’ (not ‘boost::vertices’ ) is used to obtain a vertex iterator pair, as shown


in algorithm 11. The first vertex iterator points to the first vertex (its descriptor,
to be precise), the second points to beyond the last vertex (its descriptor, to be
precise). In this tutorial, vertex iterator pairs have named prefixed with ‘vip_’,
for example ‘vip_1’.

Algorithm 11 Get the vertex iterators of a graph

#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>

template <typename graph>


std : : pair<
typename graph : : v e r t e x _ i t e r a t o r ,
typename graph : : v e r t e x _ i t e r a t o r
>
g e t _ v e r t e x _ i t e r a t o r s ( const graph& g ) n o e x c e p t
{
return v e r t i c e s ( g ) ;
}

This is a somewhat trivial function, as it forwards the function call to ‘ver-


tices’ (not ‘boost::vertices’ ).
These vertex iterators can be dereferenced to obtain the vertex descriptors.
Note that ‘get_vertex_iterators’ will not be used often in isolation: usually one
obtains the vertex descriptors immediately. Just for your reference, algorithm 12
demonstrates of the ‘get_vertices’ function, by showing that the vertex iterators
of an empty graph point to the same location.

19
Algorithm 12 Demonstration of ‘get_vertex_iterators’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_empty_directed_graph . h"
#include " create_empty_undirected_graph . h"
#include " g e t _ v e r t e x _ i t e r a t o r s . h"

BOOST_AUTO_TEST_CASE( t e s t _ g e t _ v e r t e x _ i t e r a t o r s )
{
const auto g = create_empty_undirected_graph ( ) ;
const auto vip_g = g e t _ v e r t e x _ i t e r a t o r s ( g ) ;
BOOST_CHECK( vip_g . f i r s t == vip_g . s e c o n d ) ;

const auto h = create_empty_directed_graph ( ) ;


const auto vip_h = g e t _ v e r t e x _ i t e r a t o r s ( h ) ;
BOOST_CHECK( vip_h . f i r s t == vip_h . s e c o n d ) ;
}

2.8 Get all vertex descriptors


Vertex descriptors are the way to manipulate those vertices. Let’s go get the
all!
Vertex descriptors are obtained from dereferencing vertex iterators. Algo-
rithm 13 shows how to obtain all vertex descriptors from a graph.

Algorithm 13 Get all vertex descriptors of a graph

#include <v e c t o r >


#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>
#include <b o o s t / graph / g r a p h _ t r a i t s . hpp>

template <typename graph>


std : : vector<
typename b o o s t : : g r a p h _ t r a i t s <graph > : : v e r t e x _ d e s c r i p t o r
>
g e t _ v e r t e x _ d e s c r i p t o r s ( const graph& g ) n o e x c e p t
{
using vd = typename graph : : v e r t e x _ d e s c r i p t o r ;

s t d : : v e c t o r <vd> vds ( b o o s t : : num_vertices ( g ) ) ;


const auto v i s = v e r t i c e s ( g ) ;
s t d : : copy ( v i s . f i r s t , v i s . second , s t d : : b e g i n ( vds ) ) ;
return vds ;
}

20
This is the first more complex piece of code. In the first lines, some ‘using’
statements allow for shorter type names6 .
The std::vector to serve as a return value is created at the needed size, which
is the number of vertices.
The function ‘vertices’ (not boost::vertices!) returns a vertex iterator pair.
These iterators are used by std::copy to iterator over. std::copy is an STL
algorithm to copy a half-open range. Prefer algorithm calls over hand-written
for-loops ([9] chapter 18.12.1, [7] item 43).
In this case, we copy all vertex descriptors in the range produced by ‘vertices’
to the std::vector.
This function will not be used in practice: one iterates over the vertices
directly instead, saving the cost of creating a std::vector. This function is only
shown as an illustration.
Algorithm 14 demonstrates that an empty graph has no vertex descriptors:

Algorithm 14 Demonstration of ‘get_vertex_descriptors’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_empty_directed_graph . h"
#include " create_empty_undirected_graph . h"
#include " g e t _ v e r t e x _ d e s c r i p t o r s . h"

BOOST_AUTO_TEST_CASE( t e s t _ g e t _ v e r t e x _ d e s c r i p t o r s )
{
const auto g = create_empty_undirected_graph ( ) ;
const auto vds_g = g e t _ v e r t e x _ d e s c r i p t o r s ( g ) ;
BOOST_CHECK( vds_g . empty ( ) ) ;

const auto h = create_empty_directed_graph ( ) ;


const auto vds_h = g e t _ v e r t e x _ d e s c r i p t o r s ( h ) ;
BOOST_CHECK( vds_h . empty ( ) ) ;
}

Because all graphs have vertices and thus vertex descriptors, the type of
graph is unimportant for this code to compile.

2.9 Add an edge


To add an edge to a graph, two vertex descriptors are needed. A vertex descrip-
tor is a handle to the vertex within a graph (vertex descriptors are looked at in
more details in chapter 2.6). Algorithm 15 adds two vertices to a graph, and
connects these two using boost::add_edge:
6 which may be necessary just to create a tutorial with code snippets that are readable

21
Algorithm 15 Adding (two vertices and) an edge to a graph

#include <c a s s e r t >


#include <t y p e _ t r a i t s >
#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>

template <typename graph>


typename b o o s t : : g r a p h _ t r a i t s <graph > : : e d g e _ d e s c r i p t o r
add_edge ( graph& g ) n o e x c e p t
{
s t a t i c _ a s s e r t ( ! s t d : : i s _ c o n s t <graph > : : valu e ,
" graph ␣ cannot ␣ be ␣ c o n s t "
);
const auto vd_a = b o o s t : : add_vertex ( g ) ;
const auto vd_b = b o o s t : : add_vertex ( g ) ;
const auto a e r = b o o s t : : add_edge (
vd_a , vd_b , g
);
a s s e r t ( aer . second ) ;
return a e r . f i r s t ;
}

Algorithm 15 shows how to add an isolated edge to a graph (instead of


allowing for graphs with higher connectivities). First, two vertices are created,
using the function ‘boost::add_vertex’. ‘boost::add_vertex’ returns a vertex
descriptor (which I prefix with ‘vd’), both of which are stored. The vertex
descriptors are used to add an edge to the graph, using ‘boost::add_edge’.
‘boost::add_edge’ returns a std::pair, consisting of an edge descriptor and a
boolean success indicator. The success of adding the edge is checked by an
assert statement. Here we assert that this insertion was successful. Insertion
can fail if an edge is already present and duplicates are not allowed.
A demonstration of add_edge is shown in algorithm 16, in which an edge
is added to both a directed and undirected graph, after which the number of
edges and vertices is checked.

22
Algorithm 16 Demonstration of ‘add_edge’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " add_edge . h"
#include " create_empty_directed_graph . h"
#include " create_empty_undirected_graph . h"

BOOST_AUTO_TEST_CASE( test_add_edge )
{
auto g = create_empty_undirected_graph ( ) ;
add_edge ( g ) ;
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 2 ) ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 1 ) ;

auto h = create_empty_directed_graph ( ) ;
add_edge ( h ) ;
BOOST_CHECK( b o o s t : : num_vertices ( h ) == 2 ) ;
BOOST_CHECK( b o o s t : : num_edges ( h ) == 1 ) ;
}

The graph type is unimportant: as all graph types have vertices and edges,
edges can be added without possible compile problems.

2.10 boost::add_edge result


When using the function ‘boost::add_edge’, a ‘std::pair<edge_descriptor,bool>’
is returned. It contains both the edge descriptor (see chapter 2.12) and a
boolean, which indicates insertion success.
In this tutorial, boost::add_edge results have named prefixed with ‘aer_’,
for example ‘aer_1’.

2.11 Getting the edge iterators


You cannot get the edges directly. Instead, working on the edges of a graph is
done through these steps:
• Obtain an edge iterator pair from the graph
• Dereference an edge iterator to obtain an edge descriptor

‘edges’ (not boost::edges!) is used to obtain an edge iterator pair. The first edge
iterator points to the first edge (its descriptor, to be precise), the second points
to beyond the last edge (its descriptor, to be precise). In this tutorial, edge
iterator pairs have named prefixed with ‘eip_’, for example ‘eip_1’. Algorithm
17 shows how to obtain these:

23
Algorithm 17 Get the edge iterators of a graph

#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>

template <typename graph>


std : : pair<
typename graph : : e d g e _ i t e r a t o r ,
typename graph : : e d g e _ i t e r a t o r
>
g e t _ e d g e _ i t e r a t o r s ( const graph& g ) n o e x c e p t
{
return e d g e s ( g ) ;
}

This is a somewhat trivial function, as all it does is forward to function call


to ‘edges’ (not boost::edges!) These edge iterators can be dereferenced to obtain
the edge descriptors. Note that this function will not be used often in isolation:
usually one obtains the edge descriptors immediately.
Algorithm 18 demonstrates ‘get_edge_iterators’ by showing that both it-
erators of the edge iterator pair point to the same location, when the graph is
empty.

Algorithm 18 Demonstration of ‘get_edge_iterators’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_empty_directed_graph . h"
#include " create_empty_undirected_graph . h"
#include " g e t _ e d g e _ i t e r a t o r s . h"

BOOST_AUTO_TEST_CASE( t e s t _ g e t _ e d g e _ i t e r a t o r s )
{
const auto g = create_empty_undirected_graph ( ) ;
const auto eip_g = g e t _ e d g e _ i t e r a t o r s ( g ) ;
BOOST_CHECK( eip_g . f i r s t == eip_g . s e c o n d ) ;

auto h = create_empty_directed_graph ( ) ;
const auto eip_h = g e t _ e d g e _ i t e r a t o r s ( h ) ;
BOOST_CHECK( eip_h . f i r s t == eip_h . s e c o n d ) ;
}

2.12 Edge descriptors


An edge descriptor is a handle to an edge within a graph. They are similar to
vertex descriptors (chapter 2.6).

24
Edge descriptors are used to obtain the name, or other properties, of an edge
In this tutorial, edge descriptors have named prefixed with ‘ed_’, for example
‘ed_1’.

2.13 Get all edge descriptors


Obtaining all edge descriptors is similar to obtaining all vertex descriptors (al-
gorithm 13), as shown in algorithm 19:

Algorithm 19 Get all edge descriptors of a graph

#include <v e c t o r >


#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>
#include " b o o s t / graph / g r a p h _ t r a i t s . hpp"

template <typename graph>


std : : vector<
typename b o o s t : : g r a p h _ t r a i t s <graph > : : e d g e _ d e s c r i p t o r
> g e t _ e d g e _ d e s c r i p t o r s ( const graph& g ) n o e x c e p t
{
using b o o s t : : g r a p h _ t r a i t s ;
using ed = typename g r a p h _ t r a i t s <graph > : :
edge_descriptor ;
s t d : : v e c t o r <ed> v ( b o o s t : : num_edges ( g ) ) ;
const auto e i p = e d g e s ( g ) ;
s t d : : copy ( e i p . f i r s t , e i p . second , s t d : : b e g i n ( v ) ) ;
return v ;
}

The only difference is that instead of the function ‘vertices’ (not boost::vertices!),
‘edges’ (not boost::edges!) is used.
Algorithm 20 demonstrates the ‘get_edge_descriptor’, by showing that empty
graphs do not have any edge descriptors.

25
Algorithm 20 Demonstration of get_edge_descriptors

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_empty_directed_graph . h"
#include " create_empty_undirected_graph . h"
#include " g e t _ e d g e _ d e s c r i p t o r s . h"

BOOST_AUTO_TEST_CASE( t e s t _ g e t _ e d g e _ d e s c r i p t o r s )
{
const auto g = create_empty_directed_graph ( ) ;
const auto eds_g = g e t _ e d g e _ d e s c r i p t o r s ( g ) ;
BOOST_CHECK( eds_g . empty ( ) ) ;

const auto h = create_empty_undirected_graph ( ) ;


const auto eds_h = g e t _ e d g e _ d e s c r i p t o r s ( h ) ;
BOOST_CHECK( eds_h . empty ( ) ) ;
}

2.14 Creating a directed graph


Finally, we are going to create a directed non-empty graph!

2.14.1 Graph
This directed graph is a two-state Markov chain, with two vertices and four
edges, as depicted in figure 5:

A B

Figure 5: The two-state Markov chain

Note that directed graphs can have edges that start and end in the same
vertex. These are called self-loops.

26
2.14.2 Function to create such a graph
To create this two-state Markov chain, the following code can be used:

Algorithm 21 Creating the two-state Markov chain as depicted in figure 5

#include <c a s s e r t >


#include " create_empty_directed_graph . h"

b o o s t : : a d j a c e n c y _ l i s t <>
create_markov_chain ( ) n o e x c e p t
{
auto g = create_empty_directed_graph ( ) ;
const auto vd_a = b o o s t : : add_vertex ( g ) ;
const auto vd_b = b o o s t : : add_vertex ( g ) ;
b o o s t : : add_edge ( vd_a , vd_a , g ) ;
b o o s t : : add_edge ( vd_a , vd_b , g ) ;
b o o s t : : add_edge ( vd_b , vd_a , g ) ;
b o o s t : : add_edge ( vd_b , vd_b , g ) ;
return g ;
}

Instead of typing the complete type, we call the ‘create_empty_directed_graph’


function, and let auto figure out the type. The vertex descriptors (see chapter
2.6) created by two boost::add_vertex calls are stored to add an edge to the
graph. Then boost::add_edge is called four times. Every time, its return type
(see chapter 2.10) is checked for a successful insertion.
Note that the graph lacks all properties: nodes do not have names, nor do
edges.

2.14.3 Creating such a graph


Algorithm 22 demonstrates the ‘create_markov_chain_graph’ function and
checks if it has the correct amount of edges and vertices:

27
Algorithm 22 Demonstration of the ‘create_markov_chain’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_markov_chain . h"

BOOST_AUTO_TEST_CASE( test_create_markov_chain )
{
const auto g = create_markov_chain ( ) ;
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 2 ) ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 4 ) ;
}

2.14.4 The .dot file produced


Running a bit ahead, this graph can be converted to a .dot file using the
‘save_graph_to_dot’ function (algorithm 55). The .dot file created is displayed
in algorithm 23:

Algorithm 23 .dot file created from the ‘create_markov_chain_graph’ func-


tion (algorithm 21), converted from graph to .dot file using algorithm 55
digraph G {
0;
1;
0->0 ;
0->1 ;
1->0 ;
1->1 ;
}

From the .dot file one can already see that the graph is directed, because:
• The first word, ‘digraph’, denotes a directed graph (where ‘graph’ would
have indicated an undirected graph)

• The edges are written as ‘->’ (where undirected connections would be


written as ‘–’)

2.14.5 The .svg file produced


The .svg file of this graph is shown in figure 6:

28
Figure 6: .svg file created from the ‘create_markov_chain’ function (algorithm
21) its .dot file and converted from .dot file to .svg using algorithm 136

This figure shows that the graph in directed, as the edges have arrow heads.
The vertices display the node index, which is the default behavior.

2.15 Creating K2 , a fully connected undirected graph with


two vertices
Finally, we are going to create an undirected non-empty graph!

2.15.1 Graph
To create a fully connected undirected graph with two vertices (also called K2 ),
one needs two vertices and one (undirected) edge, as depicted in figure 7.

Figure 7: K2 : a fully connected undirected graph with two vertices

2.15.2 Function to create such a graph


To create K2 , the following code can be used:

29
Algorithm 24 Creating K2 as depicted in figure 7

#include " create_empty_undirected_graph . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : undirectedS
>
create_k2_graph ( ) n o e x c e p t
{
auto g = create_empty_undirected_graph ( ) ;
const auto vd_a = b o o s t : : add_vertex ( g ) ;
const auto vd_b = b o o s t : : add_vertex ( g ) ;
b o o s t : : add_edge ( vd_a , vd_b , g ) ;
return g ;
}

This code is very similar to the ‘add_edge’ function (algorithm 15). Instead
of typing the graph its type, we call the ‘create_empty_undirected_graph’
function and let auto figure it out. The vertex descriptors (see chapter 2.6)
created by two boost::add_vertex calls are stored to add an edge to the graph.
From boost::add_edge its return type (see chapter 2.10), it is only checked that
insertion has been successful.
Note that the graph lacks all properties: nodes do not have names, nor do
edges.

2.15.3 Creating such a graph


Algorithm 25 demonstrates how to ‘create_k2_graph’ and checks if it has the
correct amount of edges and vertices:

Algorithm 25 Demonstration of ‘create_k2_graph’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_k2_graph . h"

BOOST_AUTO_TEST_CASE( test_create_k2_graph )
{
const auto g = create_k2_graph ( ) ;
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 2 ) ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 1 ) ;
}

30
2.15.4 The .dot file produced
Running a bit ahead, this graph can be converted to the .dot file as shown in
algorithm 26:

Algorithm 26 .dot file created from the ‘create_k2_graph’ function (algorithm


24), converted from graph to .dot file using algorithm 55
graph G {
0;
1;
0--1 ;
}

From the .dot file one can already see that the graph is undirected, because:
• The first word, ‘graph’, denotes an undirected graph (where ‘digraph’
would have indicated a directional graph)
• The edge between 0 and 1 is written as ‘–’ (where directed connections
would be written as ‘->’, ‘<-’ or ‘<>’)

2.15.5 The .svg file produced


Continuing to running a bit ahead, this .dot file can be converted to the .svg as
shown in figure 8:

Figure 8: .svg file created from the ‘create_k2_graph’ function (algorithm 24)
its .dot file, converted from .dot file to .svg using algorithm 136

Also this figure shows that the graph in undirected, otherwise the edge would
have one or two arrow heads. The vertices display the node index, which is the
default behavior.

31
2.16 d Creating K , a fully connected undirected graph
3
with three vertices
This is an extension of the previous chapter

2.16.1 Graph
To create a fully connected undirected graph with two vertices (also called K2 ),
one needs two vertices and one (undirected) edge, as depicted in figure 9.

Figure 9: K3 : a fully connected graph with three edges and vertices

2.16.2 Function to create such a graph


To create K3 , the following code can be used:

32
Algorithm 27 Creating K3 as depicted in figure 9

#include <c a s s e r t >


#include " create_empty_undirected_graph . h"
#include " create_k3_graph . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : undirectedS
>
create_k3_graph ( ) n o e x c e p t
{
auto g = create_empty_undirected_graph ( ) ;
const auto vd_a = b o o s t : : add_vertex ( g ) ;
const auto vd_b = b o o s t : : add_vertex ( g ) ;
const auto vd_c = b o o s t : : add_vertex ( g ) ;
b o o s t : : add_edge ( vd_a , vd_b , g ) ;
b o o s t : : add_edge ( vd_b , vd_c , g ) ;
b o o s t : : add_edge ( vd_c , vd_a , g ) ;
return g ;
}

2.16.3 Creating such a graph


Algorithm 28 demonstrates how to ‘create_k2_graph’ and checks if it has the
correct amount of edges and vertices:

Algorithm 28 Demonstration of ‘create_k3_graph’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_k3_graph . h"

BOOST_AUTO_TEST_CASE( test_create_k3_graph )
{
const auto g = create_k3_graph ( ) ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 3 ) ;
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 3 ) ;
}

2.16.4 The .dot file produced


This graph can be converted to the .dot file as shown in algorithm 29:

33
Algorithm 29 .dot file created from the ‘create_k3_graph’ function (algorithm
27), converted from graph to .dot file using algorithm 55
graph G {
0;
1;
2;
0--1 ;
1--2 ;
2--0 ;
}

2.16.5 The .svg file produced


Continuing to running a bit ahead, this .dot file can be converted to the .svg as
shown in figure 10:

Figure 10: .svg file created from the ‘create_k3_graph’ function (algorithm 27)
its .dot file, converted from .dot file to .svg using algorithm 136

2.17 d Creating a path graph


A path graph is a linear graph without any branches

34
2.17.1 Graph
Here I show a path graph with four vertices (see figure 11):

A B C D

Figure 11: A path graph with four vertices

2.17.2 Function to create such a graph


To create a path graph, the following code can be used:

Algorithm 30 Creating a path graph as depicted in figure 11

#include " create_empty_undirected_graph . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : undirectedS
>
create_path_graph ( const s i z e _ t n _ v e r t i c e s ) n o e x c e p t
{
auto g = create_empty_undirected_graph ( ) ;
i f ( n _ v e r t i c e s == 0 ) return g ;
auto vd_1 = b o o s t : : add_vertex ( g ) ;
i f ( n _ v e r t i c e s == 1 ) return g ;
f o r ( s i z e _ t i =1; i != n _ v e r t i c e s ; ++i )
{
auto vd_2 = b o o s t : : add_vertex ( g ) ;
b o o s t : : add_edge ( vd_1 , vd_2 , g ) ;
vd_1 = vd_2 ;
}
return g ;
}

2.17.3 Creating such a graph


Algorithm 31 demonstrates how to ‘create_k2_graph’ and checks if it has the
correct amount of edges and vertices:

35
Algorithm 31 Demonstration of ‘create_path_graph’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_path_graph . h"

BOOST_AUTO_TEST_CASE( test_create_path_graph )
{
const auto g = create_path_graph ( 4 ) ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 3 ) ;
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 4 ) ;
}

2.17.4 The .dot file produced


This graph can be converted to the .dot file as shown in algorithm 32:

Algorithm 32 .dot file created from the ‘create_path_graph’ function (algo-


rithm 30), converted from graph to .dot file using algorithm 55
graph G {
0;
1;
2;
3;
0--1 ;
1--2 ;
2--3 ;
}

2.17.5 The .svg file produced


The .dot file can be converted to the .svg as shown in figure 12:

36
Figure 12: .svg file created from the ‘create_path_graph’ function (algorithm
30) its .dot file, converted from .dot file to .svg using algorithm 136

2.18 d Creating a Peterson graph


A Petersen graph is the first graph with interesting properties.

2.18.1 Graph
To create a Petersen graph, one needs five vertices and five undirected edges, as
depicted in figure 13.

37
Figure 13: A Petersen graph (from https://en.wikipedia.org/wiki/
Petersen_graph)

2.18.2 Function to create such a graph


To create a Petersen graph, the following code can be used:

38
Algorithm 33 Creating Petersen graph as depicted in figure 13

#include <c a s s e r t >


#include <v e c t o r >
#include " create_empty_undirected_graph . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : undirectedS
>
create_petersen_graph ( ) noexcept
{
using vd = d e c l t y p e ( create_empty_undirected_graph ( ) ) : :
vertex_descriptor ;

auto g = create_empty_undirected_graph ( ) ;

s t d : : v e c t o r <vd> v ; // Outer
f o r ( int i =0; i ! = 5 ; ++i ) {
v . push_back ( b o o s t : : add_vertex ( g ) ) ;
}
s t d : : v e c t o r <vd> w ; // I n n e r
f o r ( int i =0; i ! = 5 ; ++i ) {
w . push_back ( b o o s t : : add_vertex ( g ) ) ;
}
// Outer r i n g
f o r ( int i =0; i ! = 5 ; ++i ) {
b o o s t : : add_edge ( v [ i ] , v [ ( i + 1 ) % 5 ] , g ) ;
}
// Spoke
f o r ( int i =0; i ! = 5 ; ++i ) {
b o o s t : : add_edge ( v [ i ] , w [ i ] , g ) ;
}
// I n n e r pentagram
f o r ( int i =0; i ! = 5 ; ++i ) {
b o o s t : : add_edge (w [ i ] , w [ ( i + 2 ) % 5 ] , g ) ;
}
return g ;
}

2.18.3 Creating such a graph


Algorithm 34 demonstrates how to use ‘create_petersen_graph’ and checks if
it has the correct amount of edges and vertices:

39
Algorithm 34 Demonstration of ‘create_k3_graph’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " c r e a t e _ p e t e r s e n _ g r a p h . h"

BOOST_AUTO_TEST_CASE( t e s t _ c r e a t e _ p e t e r s e n _ g r a p h )
{
const auto g = c r e a t e _ p e t e r s e n _ g r a p h ( ) ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 1 5 ) ;
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 1 0 ) ;
}

2.18.4 The .dot file produced


This graph can be converted to the .dot file as shown in algorithm 35:

40
Algorithm 35 .dot file created from the ‘create_petersen_graph’ function (al-
gorithm 33), converted from graph to .dot file using algorithm 55
graph G {
0;
1;
2;
3;
4;
5;
6;
7;
8;
9;
0--1 ;
1--2 ;
2--3 ;
3--4 ;
4--0 ;
0--5 ;
1--6 ;
2--7 ;
3--8 ;
4--9 ;
5--7 ;
6--8 ;
7--9 ;
8--5 ;
9--6 ;
}

2.18.5 The .svg file produced


This .dot file can be converted to the .svg as shown in figure 14:

41
Figure 14: .svg file created from the ‘create_petersen_graph’ function (algo-
rithm 33) its .dot file, converted from .dot file to .svg using algorithm 136

3 Working on graphs without properties


Now that we can build a graph, there are some things we can do.
• Getting the vertices’ out degrees: see chapter 3.1

42
• Create a direct-neighbour subgraph from a vertex descriptor
• Create all direct-neighbour subgraphs from a graphs
• Saving a graph without properties to .dot file: see chapter 3.11
• Loading an undirected graph without properties from .dot file: see chapter
3.13
• Loading a directed graph without properties from .dot file: see chapter
3.12

3.1 Getting the vertices’ out degree


Let’s measure the out degree of all vertices in a graph!
The out degree of a vertex is the number of edges that originate at it.
The number of connections is called the ‘degree’ of the vertex. There are
three types of degrees:

• in degree: the number of incoming connections, using ‘in_degree’ (not


‘boost::in_degree’)
• out degree: the number of outgoing connections, using ‘out_degree’ (not
‘boost::out_degree’)

• degree: sum of the in degree and out degree, using ‘degree’ (not ‘boost::degree’)
Algorithm 36 shows how to obtain these:

43
Algorithm 36 Get the vertices’ out degrees

#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>


#include <v e c t o r >

template <typename graph>


s t d : : v e c t o r <int> get_vertex_out_degrees (
const graph& g
) noexcept
{
using vd = typename graph : : v e r t e x _ d e s c r i p t o r ;

s t d : : v e c t o r <int> v ( b o o s t : : num_vertices ( g ) ) ;
const auto v i p = v e r t i c e s ( g ) ;
s t d : : t r a n s f o r m ( v i p . f i r s t , v i p . second , s t d : : b e g i n ( v ) ,
[&g ] ( const vd& d ) {
return out_degree ( d , g ) ;
}
);
return v ;
}

The structure of this algorithm is similar to ‘get_vertex_descriptors’ (algo-


rithm 13), except that the out degrees from the vertex descriptors are stored.
The out degree of a vertex iterator is obtained from the function ‘out_degree’
(not boost::out_degree!).
Albeit that the K2 graph and the two-state Markov chain are rather sim-
ple, we can use it to demonstrate ‘get_vertex_out_degrees’ on, as shown in
algorithm 37.

44
Algorithm 37 Demonstration of the ‘get_vertex_out_degrees’ function

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_k2_graph . h"
#include " create_markov_chain . h"
#include " get_vertex_out_degrees . h"

BOOST_AUTO_TEST_CASE( te s t _ ge t _ ve r t e x_ o u t_ d e g re e s )
{
const auto g = create_k2_graph ( ) ;
const s t d : : v e c t o r <int> expected_out_degrees_g { 1 , 1 } ;
const s t d : : v e c t o r <int> vertex_out_degrees_g {
get_vertex_out_degrees ( g )
};
BOOST_CHECK( expected_out_degrees_g
== vertex_out_degrees_g
);

const auto h = create_markov_chain ( ) ;


const s t d : : v e c t o r <int> expected_out_degrees_h { 2 , 2 } ;
const s t d : : v e c t o r <int> vertex_out_degrees_h {
get_vertex_out_degrees ( h )
};
BOOST_CHECK( expected_out_degrees_h
== vertex_out_degrees_h
);
}

It is expected that K2 has one out-degree for every vertex, where the two-
state Markov chain is expected to have two out-degrees per vertex.

3.2 d Is there an edge between two vertices?


If you have two vertex descriptors, you can check if these are connected by an
edge:

45
Algorithm 38 Check if there exists an edge between two vertices

#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>


#include <b o o s t / graph / g r a p h _ t r a i t s . hpp>

template <typename graph>


bool has_edge_between_vertices (
const typename b o o s t : : g r a p h _ t r a i t s <graph > : :
v e r t e x _ d e s c r i p t o r& vd_1 ,
const typename b o o s t : : g r a p h _ t r a i t s <graph > : :
v e r t e x _ d e s c r i p t o r& vd_2 ,
const graph& g
) noexcept
{
return edge ( vd_1 , vd_2 , g ) . s e c o n d ;
}

This code uses the function ‘edge’ (not boost::edge: it returns a pair consist-
ing of an edge descriptor and a boolean indicating if it is a valid edge descriptor.
The boolean will be true if there exists an edge between the two vertices and
false if not.
The demo shows that there is an edge between the two vertices of a K2 graph,
but there are no self-loops (edges that original and end at the same vertex).

Algorithm 39 Demonstration of the ‘has_edge_between_vertices’ function

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_k2_graph . h"
#include " has_edge_between_vertices . h"

BOOST_AUTO_TEST_CASE( test_has_edge_between_vertices )
{
const auto g = create_k2_graph ( ) ;
const auto vd_1 = ∗ v e r t i c e s ( g ) . f i r s t ;
const auto vd_2 = ∗(++ v e r t i c e s ( g ) . f i r s t ) ;
BOOST_CHECK( has_edge_between_vertices ( vd_1 , vd_2 , g ) ) ;
BOOST_CHECK( ! has_edge_between_vertices ( vd_1 , vd_1 , g ) ) ;
}

3.3 d Get the edge between two vertices


If you have two vertex descriptors, you can use these to find the edge between
them.

46
Algorithm 40 Get the edge between two vertices

#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>

template <typename graph>


typename b o o s t : : g r a p h _ t r a i t s <graph > : : e d g e _ d e s c r i p t o r
get_edge_between_vertices (
const typename b o o s t : : g r a p h _ t r a i t s <graph > : :
v e r t e x _ d e s c r i p t o r& vd_from ,
const typename b o o s t : : g r a p h _ t r a i t s <graph > : :
v e r t e x _ d e s c r i p t o r& vd_to ,
const graph& g
)
{
const auto e r = edge ( vd_from , vd_to , g ) ;
i f ( ! er . second )
{
s t d : : s t r i n g s t r e a m msg ;
msg << __func__ << " : ␣ "
<< "no␣ edge ␣ between ␣ t h e s e ␣ v e r t i c e s "
;
throw s t d : : invalid_argument ( msg . s t r ( ) ) ;
}
return e r . f i r s t ;
}

This code does assume that there is an edge between the two vertices.
The demo shows how to get the edge between two vertices, deleting it, and
checking for success.

47
Algorithm 41 Demonstration of the ‘get_edge_between_vertices’ function

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_k2_graph . h"
#include " get_edge_between_vertices . h"
#include " has_edge_between_vertices . h"

BOOST_AUTO_TEST_CASE( t e s t _ g e t _ e d g e _ b e t w e e n _ v e r t i c e s )
{
auto g = create_k2_graph ( ) ;
const auto vd_1 = ∗ v e r t i c e s ( g ) . f i r s t ;
const auto vd_2 = ∗(++ v e r t i c e s ( g ) . f i r s t ) ;
BOOST_CHECK( has_edge_between_vertices ( vd_1 , vd_2 , g ) ) ;
const auto ed = get_edge_between_vertices ( vd_1 , vd_2 , g
);
b o o s t : : remove_edge ( ed , g ) ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 0 ) ;
}

3.4 dd Create a direct-neighbour subgraph from a vertex


descriptor
Suppose you have a vertex of interest its vertex descriptor. Let’s say you want
to get a subgraph of that vertex and its direct neighbours only. This means
that all vertices of that subgraph are adjacent vertices and that the edges go
either from focal vertex to its neighbours, or from adjacent vertex to adjacent
neighbour.
Here is the ‘create_direct_neighbour_subgraph’ code:

48
Algorithm 42 Get the direct-neighbour subgraph from a vertex descriptor

#include <map>
#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>

template <typename graph , typename v e r t e x _ d e s c r i p t o r >


graph c r e a t e _ d i r e c t _ n e i g h b o u r _ s u b g r a p h (
const v e r t e x _ d e s c r i p t o r& vd ,
const graph& g
)
{
graph h ;

s t d : : map<v e r t e x _ d e s c r i p t o r , v e r t e x _ d e s c r i p t o r > m;
{
const auto vd_h = b o o s t : : add_vertex ( h ) ;
m. i n s e r t ( s t d : : make_pair ( vd , vd_h ) ) ;
}
//Copy v e r t i c e s
{
const auto v d s i = b o o s t : : a d j a c e n t _ v e r t i c e s ( vd , g ) ;
f o r ( auto i = v d s i . f i r s t ; i != v d s i . s e c o n d ; ++i )
{
i f (m. f i n d ( ∗ i ) == m. end ( ) )
{
const auto vd_h = b o o s t : : add_vertex ( h ) ;
m. i n s e r t ( s t d : : make_pair ( ∗ i , vd_h ) ) ;
}
}
}
//Copy e d g e s
{
const auto e i p = e d g e s ( g ) ;
const auto j = e i p . s e c o n d ;
f o r ( auto i = e i p . f i r s t ; i != j ; ++i )
{
const auto vd_from = s o u r c e ( ∗ i , g ) ;
const auto vd_to = t a r g e t ( ∗ i , g ) ;
i f (m. f i n d ( vd_from ) == s t d : : end (m) ) continue ;
i f (m. f i n d ( vd_to ) == s t d : : end (m) ) continue ;
b o o s t : : add_edge (m[ vd_from ] ,m[ vd_to ] , h ) ;
}
}
return h ;
}

49
This demonstration code shows that the direct-neighbour graph of each ver-
tex of a K2 graphs is ... a K2 graph!

Algorithm 43 Demo of the ‘create_direct_neighbour_subgraph’ function

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " c r e a t e _ d i r e c t _ n e i g h b o u r _ s u b g r a p h . h"
#include " create_k2_graph . h"

BOOST_AUTO_TEST_CASE(
test_create_direct_neighbour_subgraph )
{
const auto g = create_k2_graph ( ) ;
const auto v i p = v e r t i c e s ( g ) ;
const auto j = v i p . s e c o n d ;
f o r ( auto i=v i p . f i r s t ; i != j ; ++i ) {
const auto h = c r e a t e _ d i r e c t _ n e i g h b o u r _ s u b g r a p h (
∗i , g
);
BOOST_CHECK( b o o s t : : num_vertices ( h ) == 2 ) ;
BOOST_CHECK( b o o s t : : num_edges ( h ) == 1 ) ;
}
}

Note that this algorithm works on both undirected and directional graphs.
If the graph is directional, only the out edges will be copied. To also copy the
vertices connected with inward edges, use 3.5

3.5 dd Create a direct-neighbour subgraph from a vertex


descriptor including inward edges
Too bad, this algorithm does not work yet.

50
Algorithm 44 Get the direct-neighbour subgraph from a vertex descriptor

#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>


#include <unordered_map>
#include <v e c t o r >

template <typename graph>


graph c r e a t e _ d i r e c t _ n e i g h b o u r _ s u b g r a p h _ i n c l u d i n g _ i n _ e d g e s
(
const typename graph : : v e r t e x _ d e s c r i p t o r& vd , const
graph& g )
{
using v e r t e x _ d e s c r i p t o r = typename graph : :
vertex_descriptor ;
using e d g e _ d e s c r i p t o r = typename graph : :
edge_descriptor ;
using v p a i r = s t d : : p a i r <v e r t e x _ d e s c r i p t o r ,
v e r t e x _ d e s c r i p t o r >;

s t d : : v e c t o r <v p a i r > conn_edges ;


s t d : : unordered_map<v e r t e x _ d e s c r i p t o r ,
v e r t e x _ d e s c r i p t o r > m;

v e r t e x _ d e s c r i p t o r vd_h = 0 ;
m. i n s e r t ( s t d : : make_pair ( vd , vd_h++)) ;

f o r ( const e d g e _ d e s c r i p t o r ed : b o o s t : :
make_iterator_range ( e d g e s ( g ) ) ) {
const auto vd_from = s o u r c e ( ed , g ) ;
const auto vd_to = t a r g e t ( ed , g ) ;
i f ( vd == vd_from ) {
conn_edges . emplace_back ( vd_from , vd_to ) ;
m. i n s e r t ( s t d : : make_pair ( vd_to , vd_h++)) ;
}
i f ( vd == vd_to ) {
conn_edges . emplace_back ( vd_from , vd_to ) ;
m. i n s e r t ( s t d : : make_pair ( vd_from , vd_h++)) ;
}
}

f o r ( v p a i r& vp : conn_edges ) {
vp . f i r s t = m[ vp . f i r s t ] ;
vp . s e c o n d = m[ vp . s e c o n d ] ;
}

return graph ( conn_edges . b e g i n ( ) , conn_edges . end ( ) , m.


size () ) ;
}
51
3.6 dd Creating all direct-neighbour subgraphs from a
graph without properties
Using the previous function, it is easy to create all direct-neighbour subgraphs
from a graph without properties:

Algorithm 45 Create all direct-neighbour subgraphs from a graph without


properties

#include <v e c t o r >


#include " c r e a t e _ d i r e c t _ n e i g h b o u r _ s u b g r a p h . h"

template <typename graph>


s t d : : v e c t o r <graph> c r e a t e _ a l l _ d i r e c t _ n e i g h b o u r _ s u b g r a p h s (
const graph& g
) noexcept
{
using vd = typename graph : : v e r t e x _ d e s c r i p t o r ;

s t d : : v e c t o r <graph> v ( b o o s t : : num_vertices ( g ) ) ;
const auto v i p = v e r t i c e s ( g ) ;
std : : transform (
v i p . f i r s t , v i p . second ,
std : : begin (v) ,
[&g ] ( const vd& d )
{
return c r e a t e _ d i r e c t _ n e i g h b o u r _ s u b g r a p h (
d, g
);
}
);
return v ;
}

This demonstration code shows that all two direct-neighbour graphs of a K2


graphs are ... K2 graphs!

52
Algorithm 46 Demo of the ‘create_all_direct_neighbour_subgraphs’ func-
tion
#include <b o o s t / t e s t / u n i t _ t e s t . hpp>
#include " c r e a t e _ a l l _ d i r e c t _ n e i g h b o u r _ s u b g r a p h s . h"
#include " create_k2_graph . h"

BOOST_AUTO_TEST_CASE(
test_create_all_direct_neighbour_subgraphs )
{
const auto v
= create_all_direct_neighbour_subgraphs (
create_k2_graph ( ) ) ;
BOOST_CHECK( v . s i z e ( ) == 2 ) ;
f o r ( const auto g : v )
{
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 2 ) ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 1 ) ;
}
}

3.7 d Are two graphs isomorphic?


You may want to check if two graphs are isomorphic. That is: if they have the
same shape.

Algorithm 47 Check if two graphs are isomorphic

#include <b o o s t / graph / isomorphism . hpp>

template <typename graph1 , typename graph2>


bool i s _ i s o m o r p h i c (
const graph1 g ,
const graph2 h
) noexcept
{
return b o o s t : : isomorphism ( g , h ) ;
}

This demonstration code shows that a K3 graph is not equivalent to a 3-


vertices path graph:

53
Algorithm 48 Demo of the ‘is_isomorphic’ function

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_path_graph . h"
#include " create_k3_graph . h"
#include " i s _ i s o m o r p h i c . h"

BOOST_AUTO_TEST_CASE( t e s t _ i s _ i s o m o r p h i c )
{
const auto g = create_path_graph ( 3 ) ;
const auto h = create_k3_graph ( ) ;
BOOST_CHECK( i s _ i s o m o r p h i c ( g , g ) ) ;
BOOST_CHECK( ! i s _ i s o m o r p h i c ( g , h ) ) ;
}

3.8 dd Count the number of connected components in


an directed graph
A directed graph may consist out of two components, that are connected within
each, but unconnected between them. Take for example, a graph of two isolated
edges, with four vertices.

Figure 15: Example of a directed graph with two components

This algorithm counts the number of connected components:

54
Algorithm 49 Count the number of connected components

#include <v e c t o r >


#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>
#include <b o o s t / graph / strong_components . hpp>

template <typename graph>


int count_directed_graph_connected_components (
const graph& g
) noexcept
{
s t d : : v e c t o r <int> c ( b o o s t : : num_vertices ( g ) ) ;
const int n = b o o s t : : strong_components ( g ,
b o o s t : : make_iterator_property_map (
std : : begin ( c ) ,
g e t ( b o o s t : : vertex_index , g )
)
);
return n ;
}

The complexity of this algorithm is O(|V | + |E|).


This demonstration code shows that two solitary edges are correctly counted
as being two components:

55
Algorithm 50 Demo of the ‘count_directed_graph_connected_components’
function
#include <b o o s t / t e s t / u n i t _ t e s t . hpp>
#include " create_empty_directed_graph . h"
#include " add_edge . h"
#include " count_directed_graph_connected_components . h"

BOOST_AUTO_TEST_CASE(
test_count_directed_graph_connected_components )
{
auto g = create_empty_directed_graph ( ) ;
BOOST_CHECK( count_directed_graph_connected_components ( g
) == 0 ) ;
const auto vd_a = b o o s t : : add_vertex ( g ) ;
const auto vd_b = b o o s t : : add_vertex ( g ) ;
const auto vd_c = b o o s t : : add_vertex ( g ) ;
b o o s t : : add_edge ( vd_a , vd_b , g ) ;
b o o s t : : add_edge ( vd_b , vd_c , g ) ;
b o o s t : : add_edge ( vd_c , vd_a , g ) ;
BOOST_CHECK( count_directed_graph_connected_components ( g
) == 1 ) ;
const auto vd_d = b o o s t : : add_vertex ( g ) ;
const auto vd_e = b o o s t : : add_vertex ( g ) ;
const auto vd_f = b o o s t : : add_vertex ( g ) ;
b o o s t : : add_edge ( vd_d , vd_e , g ) ;
b o o s t : : add_edge ( vd_e , vd_f , g ) ;
b o o s t : : add_edge ( vd_f , vd_d , g ) ;
BOOST_CHECK( count_directed_graph_connected_components ( g
) == 2 ) ;
}

3.9 dd Count the number of connected components in


an undirected graph
An undirected graph may consist out of two components, that are connect within
each, but unconnected between them. Take for example, a graph of two isolated
edges, with four vertices.

56
Figure 16: Example of an undirected graph with two components

This algorithm counts the number of connected components:

Algorithm 51 Count the number of connected components

#include <v e c t o r >


#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>
#include <b o o s t / graph / isomorphism . hpp>
#include <b o o s t / graph / connected_components . hpp>

template <typename graph>


int count_undirected_graph_connected_components (
const graph& g
) noexcept
{
s t d : : v e c t o r <int> c ( b o o s t : : num_vertices ( g ) ) ;
return b o o s t : : connected_components ( g ,
b o o s t : : make_iterator_property_map (
std : : begin ( c ) ,
g e t ( b o o s t : : vertex_index , g )
)
);
}

The complexity of this algorithm is O(|V | + |E|).


This demonstration code shows that two solitary edges are correctly counted
as being two components:

57
Algorithm 52 Demo of the ‘count_undirected_graph_connected_components’
function
#include <b o o s t / t e s t / u n i t _ t e s t . hpp>
#include " create_empty_undirected_graph . h"
#include " add_edge . h"
#include " count_undirected_graph_connected_components . h"

BOOST_AUTO_TEST_CASE(
test_count_undirected_graph_connected_components )
{
auto g = create_empty_undirected_graph ( ) ;
BOOST_CHECK( count_undirected_graph_connected_components
( g ) == 0 ) ;
add_edge ( g ) ;
BOOST_CHECK( count_undirected_graph_connected_components
( g ) == 1 ) ;
add_edge ( g ) ;
BOOST_CHECK( count_undirected_graph_connected_components
( g ) == 2 ) ;
}

3.10 dd Count the number of levels in an undirected


graph
Graphs can have a hierarchical structure. From a starting vertex, the number
of levels can be counted. A graph of one vertex has zero levels. A graph with
one edge has one level. A linear graph of three vertices and two edges has one
or two levels, depending on the starting vertex.

Figure 17: Example of an undirected graph with two components

This algorithm counts the number of levels in an undirected graph, starting


at a certain vertex.
It does so, by collecting the neighbours of the traversed vertices. Each sweep,
all neighbours of traversed neighbours are added to a set of known vertices. As
long as vertices can be added, the algorithm continues. If no vertices can be
added, the number of level equals the number of sweeps.

58
Algorithm 53 Count the number of levels in an undirected graph

#include <s e t >


#include <v e c t o r >
#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>

// C o l l e c t a l l n e i g h b o u r s
// I f t h e r e a r e no new n e i g h b o u r s , t h e l e v e l i s found

template <typename graph>


int c o u n t _ u n d i r e c t e d _ g r a p h _ l e v e l s (
typename b o o s t : : g r a p h _ t r a i t s <graph > : : v e r t e x _ d e s c r i p t o r
vd ,
const graph& g
) noexcept
{
int l e v e l = 0 ;
// This d o e s not work :
// s t d : : s e t <b o o s t : : g r a p h _ t r a i t s <graph > : :
vertex_descriptor > s ;
s t d : : s e t <int> s ;
s . i n s e r t ( vd ) ;

while ( 1 )
{
//How many nodes a r e known now
const auto s z _ b e f o r e = s . s i z e ( ) ;

const auto t = s ;

f o r ( const auto v : t )
{
const auto n e i g h b o u r s = b o o s t : : a d j a c e n t _ v e r t i c e s ( v ,
g) ;
f o r ( auto n = n e i g h b o u r s . f i r s t ; n != n e i g h b o u r s .
s e c o n d ; ++n )
{
s . i n s e r t (∗n) ;
}
}

// Have new nodes been d i s c o v e r e d ?


i f ( s . s i z e ( ) == s z _ b e f o r e ) break ;

//Found new nodes , t h u s an e x t r a l e v e l


++l e v e l ;
}
return l e v e l ;
} 59
This demonstration code shows the number of levels from a certain vertex,
while adding edges to form a linear graph. The vertex, when still without edges,
has zero levels. After adding one edge, the graph has one level, etc.

Algorithm 54 Demo of the ‘count_undirected_graph_levels’ function

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_empty_undirected_graph . h"
#include " add_edge . h"
#include " c o u n t _ u n d i r e c t e d _ g r a p h _ l e v e l s . h"

BOOST_AUTO_TEST_CASE( t e s t _ c o u n t _ u n d i r e c t e d _ g r a p h _ l e v e l s )
{
auto g = create_empty_undirected_graph ( ) ;
const auto vd_a = b o o s t : : add_vertex ( g ) ;
const auto vd_b = b o o s t : : add_vertex ( g ) ;
const auto vd_c = b o o s t : : add_vertex ( g ) ;
const auto vd_d = b o o s t : : add_vertex ( g ) ;
BOOST_CHECK( c o u n t _ u n d i r e c t e d _ g r a p h _ l e v e l s ( vd_a , g ) ==
0) ;
b o o s t : : add_edge ( vd_a , vd_b , g ) ;
BOOST_CHECK( c o u n t _ u n d i r e c t e d _ g r a p h _ l e v e l s ( vd_a , g ) ==
1) ;
b o o s t : : add_edge ( vd_b , vd_c , g ) ;
BOOST_CHECK( c o u n t _ u n d i r e c t e d _ g r a p h _ l e v e l s ( vd_a , g ) ==
2) ;
b o o s t : : add_edge ( vd_c , vd_d , g ) ;
BOOST_CHECK( c o u n t _ u n d i r e c t e d _ g r a p h _ l e v e l s ( vd_a , g ) ==
3) ;
}

3.11 Saving a graph to a .dot file


Graph are easily saved to a file, thanks to Graphviz. Graphviz (short for Graph
Visualization Software) is a package of open-source tools for drawing graphs. It
uses the DOT language for describing graphs, and these are commonly stored
in (plain-text) .dot files (I show .dot file of every non-empty graph created, e.g.
chapters 2.14.4 and 2.15.4)

60
Algorithm 55 Saving a graph to a .dot file

#include <f s t r e a m >


#include <b o o s t / graph / g r a p h v i z . hpp>

template <typename graph>


void save_graph_to_dot (
const graph& g ,
const s t d : : s t r i n g& f i l e n a m e
) noexcept
{
std : : ofstream f ( filename ) ;
boost : : write_graphviz ( f , g ) ;
}

All the code does is create an std::ofstream (an output-to-file stream) and
use boost::write_graphviz to write the DOT description of our graph to that
stream. Instead of ‘std::ofstream’, one could use std::cout (a related output
stream) to display the DOT language on screen directly.
Algorithm 56 shows how to use the ‘save_graph_to_dot’ function:

Algorithm 56 Demonstration of the ‘save_graph_to_dot’ function

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_k2_graph . h"
#include " create_markov_chain . h"
#include " save_graph_to_dot . h"

BOOST_AUTO_TEST_CASE( test_save_graph_to_dot )
{
const auto g = create_k2_graph ( ) ;
save_graph_to_dot ( g , " create_k2_graph . dot " ) ;

const auto h = create_markov_chain ( ) ;


save_graph_to_dot ( h , " create_markov_chain . dot " ) ;
}

When using the ‘save_graph_to_dot’ function (algorithm 55), only the


structure of the graph is saved: all other properties like names are not stored.
Algorithm ?? shows how to do so.

3.12 Loading a directed graph from a .dot


When loading a graph from file, one needs to specify a type of graph. In this
example, an directed graph is loaded, as shown in algorithm 57:

61
Algorithm 57 Loading a directed graph from a .dot file

#include <f s t r e a m >


#include <b o o s t / graph / g r a p h v i z . hpp>
#include " create_empty_directed_graph . h"
#include " i s _ r e g u l a r _ f i l e . h"

b o o s t : : a d j a c e n c y _ l i s t <>
load_directed_graph_from_dot (
const s t d : : s t r i n g& d o t _ f i l e n a m e
)
{
i f ( ! i s _ r e g u l a r _ f i l e ( dot_filename ) )
{
s t d : : s t r i n g s t r e a m msg ;
msg << __func__ << " : ␣ f i l e ␣ ’ "
<< d o t _ f i l e n a m e << " ’ ␣ not ␣ found "
;
throw s t d : : invalid_argument ( msg . s t r ( ) ) ;
}
std : : i f s t r e a m f ( dot_filename . c_str ( ) ) ;
auto g = create_empty_directed_graph ( ) ;
b o o s t : : d y n a m i c _ p r o p e r t i e s dp (
boost : : ignore_other_properties
);
b o o s t : : read_graphviz ( f , g , dp ) ;
return g ;
}

In this algorithm, first it is checked if the file to load exists, using the
‘is_regular_file’ function (algorithm 137), after which an std::ifstream is opened.
Then an empty directed graph is created, which saves us writing down the tem-
plate arguments explicitly. Then, a boost::dynamic_properties is created with
the ‘boost::ignore_other_properties’ in its constructor (using a default con-
structor here results in the run-time error ‘property not found: node_id’, see
chapter 12.5). From this and the empty graph, ‘boost::read_graphviz’ is called
to build up the graph.
Algorithm 58 shows how to use the ‘load_directed_graph_from_dot’ func-
tion:

62
Algorithm 58 Demonstration of the ‘load_directed_graph_from_dot’ func-
tion
#include <b o o s t / t e s t / u n i t _ t e s t . hpp>
#include " create_markov_chain . h"
#include " load_directed_graph_from_dot . h"
#include " save_graph_to_dot . h"

BOOST_AUTO_TEST_CASE( test_load_directed_graph_from_dot )
{
using b o o s t : : num_edges ;
using b o o s t : : num_vertices ;

const auto g = create_markov_chain ( ) ;


const s t d : : s t r i n g f i l e n a m e {
" create_markov_chain . dot "
};
save_graph_to_dot ( g , f i l e n a m e ) ;
const auto h = load_directed_graph_from_dot ( f i l e n a m e ) ;
BOOST_CHECK( num_edges ( g ) == num_edges ( h ) ) ;
BOOST_CHECK( num_vertices ( g ) == num_vertices ( h ) ) ;
}

This demonstration shows how the Markov chain is created using the ‘cre-
ate_markov_chain_graph’ function (algorithm 21), saved and then loaded.
The loaded graph is then checked to be a two-state Markov chain.

3.13 Loading an undirected graph from a .dot file


Loading an undirected graph from a .dot file is very similar to loading a directed
graph from a .dot file, as shown in chapter 3.12. Algorithm 59 show how to do
so:

63
Algorithm 59 Loading an undirected graph from a .dot file

#include <f s t r e a m >


#include <b o o s t / graph / g r a p h v i z . hpp>
#include " create_empty_undirected_graph . h"
#include " i s _ r e g u l a r _ f i l e . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : undirectedS
>
load_undirected_graph_from_dot (
const s t d : : s t r i n g& d o t _ f i l e n a m e
)
{
i f ( ! i s _ r e g u l a r _ f i l e ( dot_filename ) )
{
s t d : : s t r i n g s t r e a m msg ;
msg << __func__ << " : ␣ f i l e ␣ ’ "
<< d o t _ f i l e n a m e << " ’ ␣ not ␣ found "
;
throw s t d : : invalid_argument ( msg . s t r ( ) ) ;
}
std : : i f s t r e a m f ( dot_filename . c_str ( ) ) ;
auto g = create_empty_undirected_graph ( ) ;
boost : : dynamic_properties p(
boost : : ignore_other_properties
);
b o o s t : : read_graphviz ( f , g , p ) ;
return g ;
}

The only difference with loading a directed graph, is that the initial empty
graph is undirected instead. Chapter 3.12 describes the rationale of this func-
tion.
Algorithm 60 shows how to use the ‘load_undirected_graph_from_dot’
function:

64
Algorithm 60 Demonstration of the ‘load_undirected_graph_from_dot’
function
#include <b o o s t / t e s t / u n i t _ t e s t . hpp>
#include " create_k2_graph . h"
#include " load_undirected_graph_from_dot . h"
#include " save_graph_to_dot . h"

BOOST_AUTO_TEST_CASE( test_load_undirected_graph_from_dot )
{
using b o o s t : : num_edges ;
using b o o s t : : num_vertices ;

const auto g = create_k2_graph ( ) ;


const s t d : : s t r i n g f i l e n a m e { " create_k2_graph . dot " } ;
save_graph_to_dot ( g , f i l e n a m e ) ;
const auto h
= load_undirected_graph_from_dot ( f i l e n a m e ) ;
BOOST_CHECK( num_edges ( g ) == num_edges ( h ) ) ;
BOOST_CHECK( num_vertices ( g ) == num_vertices ( h ) ) ;
}

This demonstration shows how the K2 graph is created using the ‘cre-
ate_k2_graph’ function (algorithm 24), saved and then loaded. The loaded
graph is checked to be a K2 graph.

4 Building graphs with bundled vertices


Up until now, the graphs created have had edges and vertices without any
properties. In this chapter, graphs will be created, in which the vertices can have
a bundled ‘my_bundled_vertex’ type7 . The following graphs will be created:
• An empty directed graph that allows for bundled vertices: see chapter 62
• An empty undirected graph that allows for bundled vertices: see chapter
4.2
• A two-state Markov chain with bundled vertices: see chapter 4.6
• K2 with bundled vertices: see chapter 4.7
In the process, some basic (sometimes bordering trivial) functions are shown:
• Create the vertex class, called ‘my_bundled_vertex’: see chapter 4.1
• Adding a ‘my_bundled_vertex’: see chapter 4.4
7I do not intend to be original in naming my data types

65
• Getting the vertices ‘my_bundled_vertex’-es: see chapter 4.5
These functions are mostly there for completion and showing which data types
are used.

4.1 Creating the bundled vertex class


Before creating an empty graph with bundled vertices, that bundled vertex class
must be created. In this tutorial, it is called ‘my_bundled_vertex’. ‘my_bundled_vertex’
is a class that is nonsensical, but it can be replaced by any other class type.
Here I will show the header file of ‘my_bundled_vertex’, as the implemen-
tation of it is not important:

Algorithm 61 Declaration of my_bundled_vertex

#include <s t r i n g >


#include <i o s f w d >
#include <b o o s t / property_map / dynamic_property_map . hpp>

struct my_bundled_vertex
{
e x p l i c i t my_bundled_vertex (
const s t d : : s t r i n g& name = " " ,
const s t d : : s t r i n g& d e s c r i p t i o n = " " ,
const double x = 0 . 0 ,
const double y = 0 . 0
) noexcept ;
s t d : : s t r i n g m_name ;
std : : s t r i n g m_description ;
double m_x;
double m_y;
};

s t d : : ostream& operator<<(s t d : : ostream& os , const


my_bundled_vertex& e ) n o e x c e p t ;
bool operator==(const my_bundled_vertex& l h s , const
my_bundled_vertex& r h s ) n o e x c e p t ;
bool operator !=( const my_bundled_vertex& l h s , const
my_bundled_vertex& r h s ) n o e x c e p t ;

‘my_bundled_vertex’ is a class that has multiple properties:


• It has four public member variables: the double ‘m_x’ (‘m_’ stands for
member), the double ‘m_y’, the std::string m_name and the std::string
m_description. These variables must be public
• It has a default constructor

66
• It is copyable
• It is comparable for equality (it has operator==), which is needed for
searching
‘my_bundled_vertex’ does not have to have the stream operators defined for
file I/O, as this goes via the public member variables.

4.2 Create the empty directed graph with bundled ver-


tices

Algorithm 62 Creating an empty directed graph with bundled vertices

#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>


#include " my_bundled_vertex . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : directedS ,
my_bundled_vertex
>
create_empty_directed_bundled_vertices_graph ( ) n o e x c e p t
{
return { } ;
}

This graph:
• has its out edges stored in a std::vector (due to the first boost::vecS)

• has its vertices stored in a std::vector (due to the second boost::vecS)


• is directed (due to the boost::directedS)
• The vertices have one property: they have a bundled type, that is of data
type ‘my_bundled_vertex’

• The edges and graph have no properties


• Edges are stored in a std::list
The boost::adjacency_list has a new, fourth template argument ‘my_bundled_vertex’.
This can be read as: “vertices have the bundled property ‘my_bundled_vertex’”.
Or simply: “vertices have a bundled type called my_bundled_vertex”.

67
4.3 Create the empty undirected graph with bundled ver-
tices

Algorithm 63 Creating an empty undirected graph with bundled vertices

#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>


#include " my_bundled_vertex . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : undirectedS ,
my_bundled_vertex
>
create_empty_undirected_bundled_vertices_graph ( ) n o e x c e p t
{
return { } ;
}

This code is very similar to the code described in chapter 4.2, except that the di-
rectness (the third template argument) is undirected (due to the boost::undirectedS).

4.4 Add a bundled vertex


Adding a bundled vertex is very similar to adding a named vertex (chapter ??).

Algorithm 64 Add a bundled vertex

#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>


#include " my_bundled_vertex . h"

template <typename graph , typename bundled_vertex>


typename b o o s t : : g r a p h _ t r a i t s <graph > : : v e r t e x _ d e s c r i p t o r
add_bundled_vertex ( const bundled_vertex& v , graph& g )
noexcept
{
s t a t i c _ a s s e r t ( ! s t d : : i s _ c o n s t <graph > : : valu e ,
" graph ␣ cannot ␣ be ␣ c o n s t "
);
return b o o s t : : add_vertex ( v , g ) ;
}

When having added a new (abstract) vertex to the graph, the vertex de-
scriptor is used to set the ‘my_bundled_vertex’ in the graph.

68
4.5 Getting the bundled vertices’ my_vertexes8
When the vertices of a graph have any bundled ‘my_bundled_vertex’, one can
extract these as such:

Algorithm 65 Get the bundled vertices’ my_vertexes

#include <v e c t o r >


#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>
#include <b o o s t / graph / g r a p h _ t r a i t s . hpp>
#include <b o o s t / graph / p r o p e r t i e s . hpp>
#include " my_bundled_vertex . h"

template <typename graph>


s t d : : v e c t o r <my_bundled_vertex> get_my_bundled_vertexes (
const graph& g
) noexcept
{
using vd = typename graph : : v e r t e x _ d e s c r i p t o r ;

s t d : : v e c t o r <my_bundled_vertex> v ( b o o s t : : num_vertices ( g )
);
const auto v i p = v e r t i c e s ( g ) ;
s t d : : t r a n s f o r m ( v i p . f i r s t , v i p . second , s t d : : b e g i n ( v ) ,
[&g ] ( const vd& d ) { return g [ d ] ; }
);
return v ;
}

The ‘my_bundled_vertex’ bundled in each vertex is obtained from a vertex


descriptor and then put into a std::vector.
The order of the ‘my_bundled_vertex’ objects may be different after saving
and loading.
When trying to get the vertices’ my_bundled_vertex from a graph without
these, you will get the error ‘formed reference to void’ (see chapter 12.1).

4.6 Creating a two-state Markov chain with bundled ver-


tices
4.6.1 Graph
Figure 18 shows the graph that will be reproduced:
8 the name ‘my_vertexes’ is chosen to indicate this function returns a container of

my_vertex

69
Sunny, Yellow, 1.0, 2.0 Not rainy, Not grey, 3.0, 4.0

Figure 18: A two-state Markov chain where the vertices have bundled properties
and the edges have no properties. The vertices’ properties are nonsensical

4.6.2 Function to create such a graph


Here is the code creating a two-state Markov chain with bundled vertices:

70
Algorithm 66 Creating the two-state Markov chain as depicted in figure 18

#include " add_bundled_vertex . h"


#include " create_empty_directed_bundled_vertices_graph . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : directedS ,
my_bundled_vertex
>
create_bundled_vertices_markov_chain ( ) n o e x c e p t
{
auto g
= create_empty_directed_bundled_vertices_graph ( ) ;
const my_bundled_vertex a ( "Sunny" ,
" Yellow " , 1 . 0 , 2 . 0
);
const my_bundled_vertex b ( "Not␣ r a i n y " ,
"Not␣ g r e y " , 3 . 0 , 4 . 0
);
const auto vd_a = add_bundled_vertex ( a , g ) ;
const auto vd_b = add_bundled_vertex ( b , g ) ;
b o o s t : : add_edge ( vd_a , vd_a , g ) ;
b o o s t : : add_edge ( vd_a , vd_b , g ) ;
b o o s t : : add_edge ( vd_b , vd_a , g ) ;
b o o s t : : add_edge ( vd_b , vd_b , g ) ;
return g ;
}

4.6.3 Creating such a graph


Here is the demo:

71
Algorithm 67 Demo of the ‘create_bundled_vertices_markov_chain’ func-
tion (algorithm 66)

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_bundled_vertices_markov_chain . h"
#include " get_my_bundled_vertexes . h"
#include " get_my_bundled_vertex . h"

BOOST_AUTO_TEST_CASE(
test_create_bundled_vertices_markov_chain )
{
const auto g
= create_bundled_vertices_markov_chain ( ) ;
const s t d : : v e c t o r <my_bundled_vertex> e x p e c t e d {
my_bundled_vertex ( "Sunny" , " Yellow " , 1 . 0 , 2 . 0 ) ,
my_bundled_vertex ( "Not␣ r a i n y " , "Not␣ g r e y " , 3 . 0 , 4 . 0 )
};
const auto found = get_my_bundled_vertexes ( g ) ;
BOOST_CHECK( e x p e c t e d == found ) ;
}

4.6.4 The .dot file produced

Algorithm 68 .dot file created from the ‘cre-


ate_bundled_vertices_markov_chain’ function (algorithm 66), converted
from graph to .dot file using algorithm 81
digraph G {
0[label="Sunny",comment="Yellow",width=1,height=2];
1[label="Not$$$SPACE$$$rainy",comment="Not$$$SPACE$$$grey",width=3,height=4];
0->0 ;
0->1 ;
1->0 ;
1->1 ;
}

72
73
4.6.5 The .svg file produced

Figure 19: .svg file created from the ‘create_bundled_vertices_markov_chain’


function (algorithm 66) its .dot file, converted from .dot file to .svg using algo-
rithm 136

74
4.7 Creating K2 with bundled vertices
4.7.1 Graph
We reproduce the K2 with named vertices of chapter ?? , but with our bundled
vertices instead, as show in figure 20:

Me,Myself,1.0,2.0 My computer,Not me,3.0,4.0

Figure 20: K2 : a fully connected graph with two bundled vertices

75
4.7.2 Function to create such a graph

Algorithm 69 Creating K2 as depicted in figure ??

#include " create_empty_undirected_bundled_vertices_graph .


h"
#include " add_bundled_vertex . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : undirectedS ,
my_bundled_vertex
>
create_bundled_vertices_k2_graph ( ) n o e x c e p t
{
auto g = create_empty_undirected_bundled_vertices_graph
() ;

const my_bundled_vertex a (
"Me" , " M y s e l f " , 1 . 0 , 2 . 0
);
const my_bundled_vertex b (
"My␣ computer " , "Not␣me" , 3 . 0 , 4 . 0
);
const auto vd_a = add_bundled_vertex ( a , g ) ;
const auto vd_b = add_bundled_vertex ( b , g ) ;
b o o s t : : add_edge ( vd_a , vd_b , g ) ;
return g ;
}

Most of the code is a slight modification of the ‘create_named_vertices_k2_graph’


function (algorithm ??). In the end, (references to) the my_bundled_vertices
are obtained and set with two bundled my_bundled_vertex objects.

4.7.3 Creating such a graph


Demo:

76
Algorithm 70 Demo of the ‘create_bundled_vertices_k2_graph’ function (al-
gorithm 69)

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_bundled_vertices_k2_graph . h"
#include " has_bundled_vertex_with_my_vertex . h"

BOOST_AUTO_TEST_CASE(
test_create_bundled_vertices_k2_graph )
{
const auto g = create_bundled_vertices_k2_graph ( ) ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 1 ) ;
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 2 ) ;
BOOST_CHECK( has_bundled_vertex_with_my_vertex (
my_bundled_vertex ( "Me" , " M y s e l f " , 1 . 0 , 2 . 0 ) , g )
);
BOOST_CHECK( has_bundled_vertex_with_my_vertex (
my_bundled_vertex ( "My␣ computer " , "Not␣me" , 3 . 0 , 4 . 0 ) , g )
);
}

4.7.4 The .dot file produced

Algorithm 71 .dot file created from the ‘create_bundled_vertices_k2_graph’


function (algorithm 69), converted from graph to .dot file using algorithm 55
graph G {
0[label="Me",comment="Myself",width=1,height=2];
1[label="My$$$SPACE$$$computer",comment="Not$$$SPACE$$$me",width=3,height=4];
0--1 ;
}

77
78
4.7.5 The .svg file produced

Figure 21: .svg file created from the ‘create_bundled_vertices_k2_graph’ func-


tion (algorithm 69) its .dot file, converted from .dot file to .svg using algorithm
136

79
5 Working on graphs with bundled vertices
When using graphs with bundled vertices, their state gives a way to find a vertex
and working with it. This chapter shows some basic operations on graphs with
bundled vertices.
• Check if there exists a vertex with a certain ‘my_bundled_vertex’: chap-
ter 5.1
• Find a vertex with a certain ‘my_bundled_vertex’: chapter 5.2

• Get a vertex its ‘my_bundled_vertex’ from its vertex descriptor: chapter


5.3
• Set a vertex its ‘my_bundled_vertex’ using its vertex descriptor: chapter
5.4
• Setting all vertices their ‘my_bundled_vertex’-es: chapter 5.5

• Storing an directed/undirected graph with bundled vertices as a .dot file:


chapter 5.6
• Loading a directed graph with bundled vertices from a .dot file: chapter
5.7

• Loading an undirected directed graph with bundled vertices from a .dot


file: chapter 5.8

5.1 Has a bundled vertex with a my_bundled_vertex


Before modifying our vertices, let’s first determine if we can find a vertex by
its bundled type (‘my_bundled_vertex’) in a graph. After obtain the vertex
iterators, we can dereference each these to obtain the vertex descriptors and
then compare each vertex its ‘my_bundled_vertex’ with the one desired.

80
Algorithm 72 Find if there is vertex with a certain my_bundled_vertex

#include <s t r i n g >


#include <b o o s t / graph / p r o p e r t i e s . hpp>
#include " my_bundled_vertex . h"

template <typename graph>


bool has_bundled_vertex_with_my_vertex (
const my_bundled_vertex& v ,
const graph& g
) noexcept
{
using vd = typename graph : : v e r t e x _ d e s c r i p t o r ;

const auto v i p = v e r t i c e s ( g ) ;
return s t d : : f i n d _ i f ( v i p . f i r s t , v i p . second ,
[&v , &g ] ( const vd& d )
{
return g [ d ] == v ;
}
) != v i p . s e c o n d ;
}

This function can be demonstrated as in algorithm 73, where a certain


my_bundled_vertex cannot be found in an empty graph. After adding the
desired my_bundled_vertex, it is found.

81
Algorithm 73 Demonstration of the ‘has_bundled_vertex_with_my_vertex’
function
#include <b o o s t / t e s t / u n i t _ t e s t . hpp>
#include " add_bundled_vertex . h"
#include " create_empty_undirected_bundled_vertices_graph .
h"
#include " has_bundled_vertex_with_my_vertex . h"
#include " my_bundled_vertex . h"

BOOST_AUTO_TEST_CASE(
test_has_bundled_vertex_with_my_vertex )
{
auto g = create_empty_undirected_bundled_vertices_graph
() ;
BOOST_CHECK( ! has_bundled_vertex_with_my_vertex (
my_bundled_vertex ( " F e l i x " ) , g ) ) ;
add_bundled_vertex ( my_bundled_vertex ( " F e l i x " ) , g ) ;
BOOST_CHECK( has_bundled_vertex_with_my_vertex (
my_bundled_vertex ( " F e l i x " ) , g ) ) ;
}

Note that this function only finds if there is at least one bundled vertex with
that my_bundled_vertex: it does not tell how many bundled vertices with that
my_bundled_vertex exist in the graph.

5.2 Find a bundled vertex with a certain my_bundled_vertex


Where STL functions work with iterators, here we obtain a vertex descrip-
tor (see chapter 2.6) to obtain a handle to the desired vertex. Algorithm 74
shows how to obtain a vertex descriptor to the first vertex found with a specific
‘my_bundled_vertex’ value.

82
Algorithm 74 Find the first vertex with a certain my_bundled_vertex

#include <c a s s e r t >


#include <b o o s t / graph / g r a p h _ t r a i t s . hpp>
#include <b o o s t / graph / p r o p e r t i e s . hpp>
#include " has_bundled_vertex_with_my_vertex . h"
#include " my_bundled_vertex . h"

template <typename graph , typename bundled_vertex_t>


typename b o o s t : : g r a p h _ t r a i t s <graph > : : v e r t e x _ d e s c r i p t o r
find_first_bundled_vertex_with_my_vertex (
const bundled_vertex_t& v ,
const graph& g
)
{
using vd = typename graph : : v e r t e x _ d e s c r i p t o r ;
const auto v i p = v e r t i c e s ( g ) ;
const auto i = s t d : : f i n d _ i f (
v i p . f i r s t , v i p . second ,
[&v , &g ] ( const vd d ) { return g [ d ] == v ; }
);
i f ( i == v i p . s e c o n d )
{
s t d : : s t r i n g s t r e a m msg ;
msg << __func__ << " : ␣ "
<< " c o u l d ␣ not ␣ f i n d ␣ my_bundled_vertex ␣ ’ "
<< v << " ’ "
;
throw s t d : : invalid_argument ( msg . s t r ( ) ) ;
}
return ∗ i ;
}

With the vertex descriptor obtained, one can read and modify the vertex
and the edges surrounding it. Algorithm 75 shows some examples of how to do
so.

83
Algorithm 75 Demonstration of the ‘find_first_bundled_vertex_with_my_vertex’
function
#include <b o o s t / t e s t / u n i t _ t e s t . hpp>
#include " create_bundled_vertices_k2_graph . h"
#include " find_first_bundled_vertex_with_my_vertex . h"

BOOST_AUTO_TEST_CASE(
test_find_first_bundled_vertex_with_my_vertex )
{
const auto g = create_bundled_vertices_k2_graph ( ) ;
const auto vd =
find_first_bundled_vertex_with_my_vertex (
my_bundled_vertex ( "Me" , " M y s e l f " , 1 . 0 , 2 . 0 ) ,
g
);
BOOST_CHECK( out_degree ( vd , g ) == 1 ) ;
BOOST_CHECK( i n _ d e g r e e ( vd , g ) == 1 ) ;
}

5.3 Get a bundled vertex its ‘my_bundled_vertex’


To obtain the ‘my_bundled_vertex’ from a vertex descriptor is simple:

Algorithm 76 Get a bundled vertex its my_vertex from its vertex descriptor

#include <b o o s t / graph / g r a p h _ t r a i t s . hpp>


#include <b o o s t / graph / p r o p e r t i e s . hpp>
#include " my_bundled_vertex . h"

template <typename graph>


my_bundled_vertex get_my_bundled_vertex (
const typename b o o s t : : g r a p h _ t r a i t s <graph > : :
v e r t e x _ d e s c r i p t o r& vd ,
const graph& g
) noexcept
{
return g [ vd ] ;
}

One can just use the graph as a property map and let it be looked-up.
To use ‘get_bundled_vertex_my_vertex’, one first needs to obtain a vertex
descriptor. Algorithm 77 shows a simple example.

84
Algorithm 77 Demonstration if the ‘get_bundled_vertex_my_vertex’ func-
tion
#include <b o o s t / t e s t / u n i t _ t e s t . hpp>
#include " add_bundled_vertex . h"
#include " create_empty_undirected_bundled_vertices_graph .
h"
#include " find_first_bundled_vertex_with_my_vertex . h"
#include " get_my_bundled_vertex . h"

BOOST_AUTO_TEST_CASE( test_get_my_bundled_vertex )
{
auto g
= create_empty_undirected_bundled_vertices_graph ( ) ;
const my_bundled_vertex v{ "Dex" } ;
add_bundled_vertex ( v , g ) ;
const auto vd
= find_first_bundled_vertex_with_my_vertex ( v , g ) ;
BOOST_CHECK( get_my_bundled_vertex ( vd , g ) == v ) ;
}

5.4 Set a bundled vertex its my_vertex


If you know how to get the ‘my_bundled_vertex’ from a vertex descriptor,
setting it is just as easy, as shown in algorithm 78.

Algorithm 78 Set a bundled vertex its my_vertex from its vertex descriptor

#include <b o o s t / graph / g r a p h _ t r a i t s . hpp>


#include <b o o s t / graph / p r o p e r t i e s . hpp>
#include " my_bundled_vertex . h"

template <typename graph>


void set_my_bundled_vertex (
const my_bundled_vertex& v ,
const typename b o o s t : : g r a p h _ t r a i t s <graph > : :
v e r t e x _ d e s c r i p t o r& vd ,
graph& g
) noexcept
{
s t a t i c _ a s s e r t ( ! s t d : : i s _ c o n s t <graph > : : valu e , " graph ␣
cannot ␣ be ␣ c o n s t " ) ;
g [ vd ] = v ;
}

85
To use ‘set_bundled_vertex_my_vertex’, one first needs to obtain a vertex
descriptor. Algorithm 79 shows a simple example.

Algorithm 79 Demonstration if the ‘set_bundled_vertex_my_vertex’ func-


tion
#include <b o o s t / t e s t / u n i t _ t e s t . hpp>
#include " add_bundled_vertex . h"
#include " create_empty_undirected_bundled_vertices_graph .
h"
#include " find_first_bundled_vertex_with_my_vertex . h"
#include " get_my_bundled_vertex . h"
#include " set_my_bundled_vertex . h"

BOOST_AUTO_TEST_CASE( test_set_my_bundled_vertex )
{
auto g = create_empty_undirected_bundled_vertices_graph
() ;
const my_bundled_vertex old_name{ "Dex" } ;
add_bundled_vertex ( old_name , g ) ;
const auto vd =
find_first_bundled_vertex_with_my_vertex ( old_name , g )
;
BOOST_CHECK( get_my_bundled_vertex ( vd , g ) == old_name ) ;
const my_bundled_vertex new_name{ " Diggy " } ;
set_my_bundled_vertex ( new_name , vd , g ) ;
BOOST_CHECK( get_my_bundled_vertex ( vd , g ) == new_name ) ;
}

5.5 Setting all bundled vertices’ my_vertex objects


When the vertices of a graph are ‘my_bundled_vertex’ objects, one can set
these as such:

86
Algorithm 80 Setting the bundled vertices’ ‘my_bundled_vertex’-es

#include <s t r i n g >


#include <v e c t o r >
#include <b o o s t / graph / g r a p h _ t r a i t s . hpp>
#include <b o o s t / graph / p r o p e r t i e s . hpp>
#include " my_bundled_vertex . h"

template <typename graph>


void set_my_bundled_vertexes (
graph& g ,
const s t d : : v e c t o r <my_bundled_vertex>& my_vertexes
) noexcept
{
s t a t i c _ a s s e r t ( ! s t d : : i s _ c o n s t <graph > : : valu e ,
" graph ␣ cannot ␣ be ␣ c o n s t "
);

auto my_vertexes_begin = s t d : : b e g i n ( my_vertexes ) ;


// c o n s t a u t o my_vertexes_end = s t d : : end ( my_vertexes ) ;
const auto v i p = v e r t i c e s ( g ) ;
const auto j = v i p . s e c o n d ;
for (
auto i = v i p . f i r s t ;
i != j ; ++i ,
++my_vertexes_begin
) {
// a s s e r t ( my_vertexes_begin != my_vertexes_end ) ;
g [ ∗ i ] = ∗ my_vertexes_begin ;
}
}

5.6 Storing a graph with bundled vertices as a .dot


If you used the ‘create_bundled_vertices_k2_graph’ function (algorithm 69) to
produce a K2 graph with vertices associated with ‘my_bundled_vertex’ objects,
you can store these with algorithm 81:

87
Algorithm 81 Storing a graph with bundled vertices as a .dot file

#include <f s t r e a m >


#include <b o o s t / graph / g r a p h v i z . hpp>
#include " make_bundled_vertices_writer . h"

template <typename graph>


void save_bundled_vertices_graph_to_dot (
const graph& g ,
const s t d : : s t r i n g& f i l e n a m e
)
{
std : : ofstream f ( filename ) ;
boost : : write_graphviz ( f , g ,
make_bundled_vertices_writer ( g )
);
}

This code looks small, because we call the ‘make_bundled_vertices_writer’


function, which is shown in algorithm 82:

Algorithm 82 The ‘make_bundled_vertices_writer’ function

template <typename graph>


i n l i n e b u n d l e d _ v e r t i c e s _ w r i t e r <graph>
make_bundled_vertices_writer (
const graph& g
)
{
return b u n d l e d _ v e r t i c e s _ w r i t e r <
graph
>(g ) ;
}

Also this function is forwarding the real work to the ‘bundled_vertices_writer’,


shown in algorithm 83:

88
Algorithm 83 The ‘bundled_vertices_writer’ function

#include <ostream>
#include " graphviz_encode . h"
#include " i s _ g r a p h v i z _ f r i e n d l y . h"

template <
typename graph
>
class bundled_vertices_writer {
public :
bundled_vertices_writer (
graph g
) : m_g{ g }
{

}
template <c l a s s v e r t e x _ d e s c r i p t o r >
void operator ( ) (
s t d : : ostream& out ,
const v e r t e x _ d e s c r i p t o r& vd
) const n o e x c e p t {
out
<< " [ l a b e l =\""
<< graphviz_encode (
m_g[ vd ] . m_name
)
<< " \ " , comment=\""
<< graphviz_encode (
m_g[ vd ] . m _ d e s c r i p t i o n
)
<< " \ " , width="
<< m_g[ vd ] . m_x
<< " , h e i g h t="
<< m_g[ vd ] . m_y
<< " ] "
;
}
private :
graph m_g;
};

Here, some interesting things are happening: the writer needs the bundled
property maps to work with and thus copies the whole graph to its internals.
I have chosen to map the ‘my_bundled_vertex’ member variables to Graphviz

89
attributes (see chapter 13.2 for most Graphviz attributes) as shown in table 1:

my_bundled_vertex variable C++ data type Graphviz data type Graphviz attribute
m_name std::string string label
m_description std::string string comment
m_x double double width
m_y double double height

Table 1: Mapping of my_bundled_vertex member variable and Graphviz at-


tributes

Important in this mapping is that the C++ and the Graphviz data types
match. I also chose attributes that matched as closely as possible.
The writer also encodes the std::string of the name and description to a
Graphviz-friendly format. When loading the .dot file again, this will have to be
undone again.

5.7 Loading a directed graph with bundled vertices from


a .dot
When loading a graph from file, one needs to specify a type of graph. In
this example, an directed graph with bundled vertices is loaded, as shown in
algorithm 84:

90
Algorithm 84 Loading a directed graph with bundled vertices from a .dot file

#include <f s t r e a m >


#include <b o o s t / graph / g r a p h v i z . hpp>
#include " create_empty_directed_bundled_vertices_graph . h"
#include " graphviz_decode . h"
#include " i s _ r e g u l a r _ f i l e . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : directedS ,
my_bundled_vertex
>
load_directed_bundled_vertices_graph_from_dot (
const s t d : : s t r i n g& d o t _ f i l e n a m e
)
{
i f ( ! i s _ r e g u l a r _ f i l e ( dot_filename ) )
{
s t d : : s t r i n g s t r e a m msg ;
msg << __func__ << " : ␣ f i l e ␣ ’ "
<< d o t _ f i l e n a m e << " ’ ␣ not ␣ found "
;
throw s t d : : invalid_argument ( msg . s t r ( ) ) ;
}
std : : i f s t r e a m f ( dot_filename . c_str ( ) ) ;
auto g = create_empty_directed_bundled_vertices_graph ( )
;

b o o s t : : d y n a m i c _ p r o p e r t i e s dp ( b o o s t : :
ignore_other_properties ) ;
dp . p r o p e r t y ( " l a b e l " , g e t (&my_bundled_vertex : : m_name, g ) )
;
dp . p r o p e r t y ( "comment" , g e t (&my_bundled_vertex : :
m_description , g ) ) ;
dp . p r o p e r t y ( " width " , g e t (&my_bundled_vertex : : m_x, g ) ) ;
dp . p r o p e r t y ( " h e i g h t " , g e t (&my_bundled_vertex : : m_y, g ) ) ;
b o o s t : : read_graphviz ( f , g , dp ) ;

// Decode v e r t i c e s
const auto v i p = v e r t i c e s ( g ) ;
const auto j = v i p . s e c o n d ;
f o r ( auto i = v i p . f i r s t ; i != j ; ++i )
{
g [ ∗ i ] . m_name = graphviz_decode ( g [ ∗ i ] . m_name) ;
g [ ∗ i ] . m _ d e s c r i p t i o n = graphviz_decode ( g [ ∗ i ] .
m_description ) ;
} 91

return g ;
}
In this algorithm, first it is checked if the file to load exists. Then an empty
directed graph is created, to save typing the typename explicitly.
Then a boost::dynamic_properties is created with its default constructor,
after which we set it to follow the same mapping as in the previous chapter.
From this and the empty graph, ‘boost::read_graphviz’ is called to build up the
graph.
At the moment the graph is created, all ‘my_bundled_vertex’ their names
and description are in a Graphviz-friendly format. By obtaining all vertex iter-
ators and vertex descriptors, the encoding is made undone.
Algorithm 85 shows how to use the ‘load_directed_bundled_vertices_graph_from_dot’
function:

Algorithm 85 Demonstration of the ‘load_directed_bundled_vertices_graph_from_dot’


function
#include <b o o s t / t e s t / u n i t _ t e s t . hpp>
#include " create_bundled_vertices_markov_chain . h"
#include " load_directed_bundled_vertices_graph_from_dot . h
"
#include " save_bundled_vertices_graph_to_dot . h"
#include " get_my_bundled_vertexes . h"

BOOST_AUTO_TEST_CASE(
test_load_directed_bundled_vertices_graph_from_dot )
{
using b o o s t : : num_edges ;
using b o o s t : : num_vertices ;

const auto g
= create_bundled_vertices_markov_chain ( ) ;
const s t d : : s t r i n g f i l e n a m e {
" create_bundled_vertices_markov_chain . dot "
};
save_bundled_vertices_graph_to_dot ( g , f i l e n a m e ) ;
const auto h
= load_directed_bundled_vertices_graph_from_dot (
filename ) ;
BOOST_CHECK( num_edges ( g ) == num_edges ( h ) ) ;
BOOST_CHECK( num_vertices ( g ) == num_vertices ( h ) ) ;
BOOST_CHECK( get_my_bundled_vertexes ( g ) ==
get_my_bundled_vertexes ( h ) ) ;
}

This demonstration shows how the Markov chain is created using the ‘cre-
ate_bundled_vertices_markov_chain’ function (algorithm 66), saved and then

92
loaded. The loaded graph is checked to be the same as the original.

5.8 Loading an undirected graph with bundled vertices


from a .dot
When loading a graph from file, one needs to specify a type of graph. In this
example, an undirected graph with bundled vertices is loaded, as shown in
algorithm 86:

93
Algorithm 86 Loading an undirected graph with bundled vertices from a .dot
file
#include <f s t r e a m >
#include <b o o s t / graph / g r a p h v i z . hpp>
#include " create_empty_undirected_bundled_vertices_graph .
h"
#include " graphviz_decode . h"
#include " i s _ r e g u l a r _ f i l e . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : undirectedS ,
my_bundled_vertex
>
load_undirected_bundled_vertices_graph_from_dot (
const s t d : : s t r i n g& d o t _ f i l e n a m e
)
{
i f ( ! i s _ r e g u l a r _ f i l e ( dot_filename ) )
{
s t d : : s t r i n g s t r e a m msg ;
msg << __func__ << " : ␣ f i l e ␣ ’ "
<< d o t _ f i l e n a m e << " ’ ␣ not ␣ found "
;
throw s t d : : invalid_argument ( msg . s t r ( ) ) ;
}
std : : i f s t r e a m f ( dot_filename . c_str ( ) ) ;
auto g = create_empty_undirected_bundled_vertices_graph
() ;

b o o s t : : d y n a m i c _ p r o p e r t i e s dp ( b o o s t : :
ignore_other_properties ) ;
dp . p r o p e r t y ( " l a b e l " , g e t (&my_bundled_vertex : : m_name, g ) )
;
dp . p r o p e r t y ( "comment" , g e t (&my_bundled_vertex : :
m_description , g ) ) ;
dp . p r o p e r t y ( " width " , g e t (&my_bundled_vertex : : m_x, g ) ) ;
dp . p r o p e r t y ( " h e i g h t " , g e t (&my_bundled_vertex : : m_y, g ) ) ;
b o o s t : : read_graphviz ( f , g , dp ) ;

// Decode v e r t i c e s
const auto v i p = v e r t i c e s ( g ) ;
const auto j = v i p . s e c o n d ;
f o r ( auto i = v i p . f i r s t ; i != j ; ++i )
{
g [ ∗ i ] . m_name = graphviz_decode ( g [ ∗ i ] . m_name) ;
g [ ∗ i ] . m _ d e s c r i p t i o n = graphviz_decode
94 (g [∗ i ] .
m_description ) ;
}

return g ;
}
The only difference with loading a directed graph, is that the initial empty
graph is undirected instead. Chapter 5.7 describes the rationale of this function.
Algorithm 87 shows how to use the ‘load_undirected_bundled_vertices_graph_from_dot’
function:

Algorithm 87 Demonstration of the ‘load_undirected_bundled_vertices_graph_from_dot’


function
#include <b o o s t / t e s t / u n i t _ t e s t . hpp>
#include " create_bundled_vertices_k2_graph . h"
#include " load_undirected_bundled_vertices_graph_from_dot
. h"
#include " save_bundled_vertices_graph_to_dot . h"
#include " get_my_bundled_vertexes . h"

BOOST_AUTO_TEST_CASE(
test_load_undirected_bundled_vertices_graph_from_dot )
{
using b o o s t : : num_edges ;
using b o o s t : : num_vertices ;

const auto g
= create_bundled_vertices_k2_graph ( ) ;
const s t d : : s t r i n g f i l e n a m e {
" create_bundled_vertices_k2_graph . dot "
};
save_bundled_vertices_graph_to_dot ( g , f i l e n a m e ) ;
const auto h
= load_undirected_bundled_vertices_graph_from_dot (
filename ) ;
BOOST_CHECK( get_my_bundled_vertexes ( g )
== get_my_bundled_vertexes ( h )
);
}

This demonstration shows how K2 with bundled vertices is created using the
‘create_bundled_vertices_k2_graph’ function (algorithm 69), saved and then
loaded. The loaded graph is checked to be the same as the original.

6 Building graphs with bundled edges and ver-


tices
Up until now, the graphs created have had only bundled vertices. In this chapter,
graphs will be created, in which both the edges and vertices have a bundled

95
‘my_bundled_edge’ and ‘my_bundled_edge’ type9 .
• An empty directed graph that allows for bundled edges and vertices: see
chapter 6.2
• An empty undirected graph that allows for bundled edges and vertices:
see chapter 6.3
• A two-state Markov chain with bundled edges and vertices: see chapter
6.6
• K3 with bundled edges and vertices: see chapter 6.7

In the process, some basic (sometimes bordering trivial) functions are shown:
• Creating the ‘my_bundled_edge’ class: see chapter 6.1
• Adding a bundled ‘my_bundled_edge’: see chapter 6.4
These functions are mostly there for completion and showing which data types
are used.

6.1 Creating the bundled edge class


In this example, I create a ‘my_bundled_edge’ class. Here I will show the
header file of it, as the implementation of it is not important yet.
9I do not intend to be original in naming my data types

96
Algorithm 88 Declaration of my_bundled_edge

#include <s t r i n g >


#include <i o s f w d >

c l a s s my_bundled_edge
{
public :
e x p l i c i t my_bundled_edge (
const s t d : : s t r i n g& name = " " ,
const s t d : : s t r i n g& d e s c r i p t i o n = " " ,
const double width = 1 . 0 ,
const double h e i g h t = 1 . 0
) noexcept ;
s t d : : s t r i n g m_name ;
std : : s t r i n g m_description ;
double m_width ;
double m_height ;
};

s t d : : ostream& operator<<(s t d : : ostream& os , const


my_bundled_edge& e ) n o e x c e p t ;
bool operator==(const my_bundled_edge& l h s , const
my_bundled_edge& r h s ) n o e x c e p t ;
bool operator !=( const my_bundled_edge& l h s , const
my_bundled_edge& r h s ) n o e x c e p t ;

my_bundled_edge is a class that has multiple properties: two doubles


‘m_width’ (‘m_’ stands for member) and ‘m_height’, and two std::strings
m_name and m_description.‘my_bundled_edge’ is copyable, but cannot triv-
ially be converted to a ‘std::string.’ ‘my_bundled_edge’ is comparable for
equality (that is, operator== is defined).
‘my_bundled_edge’ does not have to have the stream operators defined for
file I/O, as this goes via the public member variables.

97
6.2 Create an empty directed graph with bundled edges
and vertices

Algorithm 89 Creating an empty directed graph with bundled edges and ver-
tices
#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>
#include "my_bundled_edge . h"
#include " my_bundled_vertex . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : directedS ,
my_bundled_vertex ,
my_bundled_edge
>
create_empty_directed_bundled_edges_and_vertices_graph ( )
noexcept
{
return { } ;
}

This code is very similar to the code described in chapter ??, except that there
is a new, fifth template argument:
b o o s t : : p r o p e r t y <b o o s t : : edge_bundled_type_t , my_edge>
This can be read as: “edges have the property ‘boost::edge_bundled_type_t’,
which is of data type ‘my_bundled_edge’”. Or simply: “edges have a bundled
type called my_bundled_edge”.
Demo:

98
Algorithm 90 Demonstration of the ‘cre-
ate_empty_directed_bundled_edges_and_vertices_graph’ function

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include "
create_empty_directed_bundled_edges_and_vertices_graph
. h"

BOOST_AUTO_TEST_CASE(
test_create_empty_directed_bundled_edges_and_vertices_graph
)
{
const auto g =
create_empty_directed_bundled_edges_and_vertices_graph
() ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 0 ) ;
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 0 ) ;
}

6.3 Create an empty undirected graph with bundled edges


and vertices

Algorithm 91 Creating an empty undirected graph with bundled edges and


vertices
#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>
#include "my_bundled_edge . h"
#include " my_bundled_vertex . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : undirectedS ,
my_bundled_vertex ,
my_bundled_edge
>
create_empty_undirected_bundled_edges_and_vertices_graph
( ) noexcept
{
return { } ;
}

This code is very similar to the code described in chapter 6.2, except that the di-
rectness (the third template argument) is undirected (due to the boost::undirectedS).

99
Demo:

Algorithm 92 Demonstration of the ‘cre-


ate_empty_undirected_bundled_edges_and_vertices_graph’ function

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include "
create_empty_undirected_bundled_edges_and_vertices_graph
. h"

BOOST_AUTO_TEST_CASE(
test_create_empty_undirected_bundled_edges_and_vertices_graph
)
{
const auto g
=
create_empty_undirected_bundled_edges_and_vertices_graph
() ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 0 ) ;
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 0 ) ;
}

6.4 Add a bundled edge


Adding a bundled edge is very similar to adding a named edge (chapter ??).

100
Algorithm 93 Add a bundled edge

#include <c a s s e r t >


#include <sstream >
#include <s t d e x c e p t >
#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>
#include "my_bundled_edge . h"
#include " has_edge_between_vertices . h"

template <typename graph , typename bundled_edge>


typename b o o s t : : g r a p h _ t r a i t s <graph > : : e d g e _ d e s c r i p t o r
add_bundled_edge (
const typename b o o s t : : g r a p h _ t r a i t s <graph > : :
v e r t e x _ d e s c r i p t o r& vd_from ,
const typename b o o s t : : g r a p h _ t r a i t s <graph > : :
v e r t e x _ d e s c r i p t o r& vd_to ,
const bundled_edge& edge ,
graph& g
)
{
s t a t i c _ a s s e r t ( ! s t d : : i s _ c o n s t <graph > : : valu e , " graph ␣
cannot ␣ be ␣ c o n s t " ) ;
i f ( has_edge_between_vertices ( vd_from , vd_to , g ) )
{
s t d : : s t r i n g s t r e a m msg ;
msg << __func__ << " : ␣ a l r e a d y ␣an␣ edge ␣ t h e r e " ;
throw s t d : : invalid_argument ( msg . s t r ( ) ) ;
}
const auto a e r = b o o s t : : add_edge ( vd_from , vd_to , g ) ;
a s s e r t ( aer . second ) ;
g [ a e r . f i r s t ] = edge ;
return a e r . f i r s t ;
}

When having added a new (abstract) edge to the graph, the edge descriptor
is used to set the my_edge in the graph.
Here is the demo:

101
Algorithm 94 Demo of ‘add_bundled_edge’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " add_bundled_edge . h"
#include " add_bundled_vertex . h"
#include "
create_empty_directed_bundled_edges_and_vertices_graph
. h"

BOOST_AUTO_TEST_CASE( test_add_bundled_edge )
{
auto g =
create_empty_directed_bundled_edges_and_vertices_graph
() ;
const auto vd_from = add_bundled_vertex (
my_bundled_vertex ( "From" ) , g ) ;
const auto vd_to = add_bundled_vertex ( my_bundled_vertex
( "To" ) , g ) ;
add_bundled_edge ( vd_from , vd_to , my_bundled_edge ( "X" ) ,
g) ;
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 2 ) ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 1 ) ;
}

6.5 Getting the bundled edges my_edges


When the edges of a graph are ‘my_bundled_edge’ objects, one can extract
these all as such:

102
Algorithm 95 Get the edges’ my_bundled_edges

#include <v e c t o r >


#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>
#include "my_bundled_edge . h"

template <typename graph>


s t d : : v e c t o r <my_bundled_edge> get_my_bundled_edges (
const graph& g
) noexcept
{
using ed = typename b o o s t : : g r a p h _ t r a i t s <graph > : :
edge_descriptor ;
s t d : : v e c t o r <my_bundled_edge> v ( b o o s t : : num_edges ( g ) ) ;
const auto e i p = e d g e s ( g ) ;
s t d : : t r a n s f o r m ( e i p . f i r s t , e i p . second , s t d : : b e g i n ( v ) ,
[&g ] ( const ed e ) { return g [ e ] ; }
);
return v ;
}

The ‘my_bundled_edge’ object associated with the edges are obtained from
the graph its property_map and then put into a std::vector.
Note: the order of the my_bundled_edge objects may be different after
saving and loading.
When trying to get the edges’ my_bundled_edge objects from a graph with-
out bundled edges objects associated, you will get the error ‘formed reference
to void’ (see chapter 12.1).

6.6 Creating a Markov-chain with bundled edges and ver-


tices
6.6.1 Graph
Figure 22 shows the graph that will be reproduced:

103
Green cols,Stay cool,6,7

Red,Heat,1,2

Orange,Lose heat,3,4

Stable,Right, 1.0, 2.0 Not unstable,Not left, 3.0, 4.0

Yellow cold,Heat,4,5

Figure 22: A two-state Markov chain where the edges and vertices have bundled
properties. The edges’ and vertices’ properties are nonsensical

6.6.2 Function to create such a graph


Here is the code creating a two-state Markov chain with bundled edges and
vertices:

104
Algorithm 96 Creating the two-state Markov chain as depicted in figure 22

#include <c a s s e r t >


#include "
create_empty_directed_bundled_edges_and_vertices_graph
. h"
#include " add_bundled_edge . h"
#include " add_bundled_vertex . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : directedS ,
my_bundled_vertex ,
my_bundled_edge
>
create_bundled_edges_and_vertices_markov_chain ( )
{
auto g
=
create_empty_directed_bundled_edges_and_vertices_graph
() ;
const auto va = my_bundled_vertex ( " S t a b l e " , " Right "
,1.0 ,2.0) ;
const auto vb = my_bundled_vertex ( "Not␣ u n s t a b l e " , "Not␣
left " ,3.0 ,4.0) ;
const auto vd_a = add_bundled_vertex ( va , g ) ;
const auto vd_b = add_bundled_vertex ( vb , g ) ;
const auto e_aa = my_bundled_edge ( "Red" , " Heat " , 1 . 0 , 2 . 0 )
;
const auto e_ab = my_bundled_edge ( " Orange " , " Lose ␣ h e a t "
,3.0 ,4.0) ;
const auto e_ba = my_bundled_edge ( " Yellow ␣ c o l d " , " Heat "
,5.0 ,6.0) ;
const auto e_bb = my_bundled_edge ( " Green ␣ c o l d " , " Stay ␣
cool " ,7.0 ,8.0) ;
add_bundled_edge ( vd_a , vd_a , e_aa , g ) ;
add_bundled_edge ( vd_a , vd_b , e_ab , g ) ;
add_bundled_edge ( vd_b , vd_a , e_ba , g ) ;
add_bundled_edge ( vd_b , vd_b , e_bb , g ) ;
return g ;
}

105
6.6.3 Creating such a graph
Here is the demo:

Algorithm 97 Demo of the ‘create_bundled_edges_and_vertices_markov_chain’


function (algorithm 96)

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_bundled_edges_and_vertices_markov_chain .
h"
#include " get_my_bundled_edges . h"
#include " my_bundled_vertex . h"

BOOST_AUTO_TEST_CASE(
test_create_bundled_edges_and_vertices_markov_chain )
{
const auto g =
create_bundled_edges_and_vertices_markov_chain ( ) ;
const s t d : : v e c t o r <my_bundled_edge> edge_my_edges{
get_my_bundled_edges ( g )
};
const s t d : : v e c t o r <my_bundled_edge> expected_my_edges {
my_bundled_edge ( "Red" , " Heat " , 1 . 0 , 2 . 0 ) ,
my_bundled_edge ( " Orange " , " Lose ␣ h e a t " , 3 . 0 , 4 . 0 ) ,
my_bundled_edge ( " Yellow ␣ c o l d " , " Heat " , 5 . 0 , 6 . 0 ) ,
my_bundled_edge ( " Green ␣ c o l d " , " Stay ␣ c o o l " , 7 . 0 , 8 . 0 )
};
BOOST_CHECK( edge_my_edges == expected_my_edges ) ;
}

6.6.4 The .dot file produced

Algorithm 98 .dot file created from the ‘cre-


ate_bundled_edges_and_vertices_markov_chain’ function (algorithm
96), converted from graph to .dot file using algorithm 55
digraph G {
0[label="Stable",comment="Right",width=1,height=2];
1[label="Not$$$SPACE$$$unstable",comment="Not$$$SPACE$$$left",width=3,height=4];
0->0 [label="Red",comment="Heat",width=1,height=2];
0->1 [label="Orange",comment="Lose$$$SPACE$$$heat",width=3,height=4];
1->0 [label="Yellow$$$SPACE$$$cold",comment="Heat",width=5,height=6];
1->1 [label="Green$$$SPACE$$$cold",comment="Stay$$$SPACE$$$cool",width=7,height=8];
}

106
107
6.6.5 The .svg file produced

108

Figure 23: .svg file created from the ‘cre-


6.7 Creating K3 with bundled edges and vertices
Instead of using edges with a name, or other properties, here we use a bundled
edge class called ‘my_bundled_edge’.

6.7.1 Graph
We reproduce the K3 with named edges and vertices of chapter ?? , but with
our bundled edges and vertices instead:

Red,Not green,1,2

Stable temperature,Here,5,6 Oxygen,Air,1,2

Orange,Orange,5,6 Light red,Not dark,3,4


Helium,From tube,3,4

Figure 24: K3 : a fully connected graph with three named edges and vertices

109
110
6.7.2 Function to create such a graph

Algorithm 99 Creating K3 as depicted in figure ??

#include "
create_empty_undirected_bundled_edges_and_vertices_graph
. h"
#include " add_bundled_edge . h"
#include " add_bundled_vertex . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : undirectedS ,
my_bundled_vertex ,
my_bundled_edge
>
create_bundled_edges_and_vertices_k3_graph ( )
{
auto g
=
create_empty_undirected_bundled_edges_and_vertices_graph
() ;
const auto vd_a = add_bundled_vertex (
my_bundled_vertex ( "Red" , "Not␣ g r e e n " , 1 . 0 , 2 . 0 ) ,
g
);
const auto vd_b = add_bundled_vertex (
my_bundled_vertex ( " L i g h t ␣ r e d " , "Not␣ dark " , 3 . 0 , 4 . 0 ) ,
g
);
const auto vd_c = add_bundled_vertex (
my_bundled_vertex ( " Orange " , " Orangy " , 5 . 0 , 6 . 0 ) ,
g
);
add_bundled_edge ( vd_a , vd_b ,
my_bundled_edge ( "Oxygen" , " Air " , 1 . 0 , 2 . 0 ) ,
g
);
add_bundled_edge ( vd_b , vd_c ,
my_bundled_edge ( " Helium " , "From␣ tube " , 3 . 0 , 4 . 0 ) ,
g
);
add_bundled_edge ( vd_c , vd_a ,
my_bundled_edge ( " S t a b l e ␣ t e m p e r a t u r e " , " Here " , 5 . 0 , 6 . 0 ) ,
g
);
return g ; 111
}
Most of the code is a slight modification of algorithm ??. In the end, the
my_edges and my_vertices are obtained as the graph its property_map and
set with the ‘my_bundled_edge’ and ‘my_bundled_vertex’ objects.

6.7.3 Creating such a graph


Here is the demo:

Algorithm 100 Demo of the ‘create_bundled_edges_and_vertices_k3_graph’


function (algorithm 99)

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_bundled_edges_and_vertices_k3_graph . h"

BOOST_AUTO_TEST_CASE(
test_create_bundled_edges_and_vertices_k3_graph )
{
auto g
= create_bundled_edges_and_vertices_k3_graph ( ) ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 3 ) ;
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 3 ) ;
}

6.7.4 The .dot file produced

Algorithm 101 .dot file created from the ‘cre-


ate_bundled_edges_and_vertices_markov_chain’ function (algorithm
99), converted from graph to .dot file using algorithm 55
graph G {
0[label="Red",comment="Not$$$SPACE$$$green",width=1,height=2];
1[label="Light$$$SPACE$$$red",comment="Not$$$SPACE$$$dark",width=3,height=4];
2[label="Orange",comment="Orangy",width=5,height=6];
0--1 [label="Oxygen",comment="Air",width=1,height=2];
1--2 [label="Helium",comment="From$$$SPACE$$$tube",width=3,height=4];
2--0 [label="Stable$$$SPACE$$$temperature",comment="Here",width=5,height=6];
}

112
113
6.7.5 The .svg file produced

Figure 25: .svg file created from the ‘cre-


ate_bundled_edges_and_vertices_k3_graph’ function (algorithm ??) its
.dot file, converted from .dot file to .svg using algorithm 136
114
7 Working on graphs with bundled edges and
vertices
7.1 Has a my_bundled_edge
Before modifying our edges, let’s first determine if we can find an edge by its bun-
dled type (‘my_bundled_edge’) in a graph. After obtaining a my_bundled_edge
map, we obtain the edge iterators, dereference these to obtain the edge descrip-
tors and then compare each edge its my_bundled_edge with the one desired.

Algorithm 102 Find if there is a bundled edge with a certain


my_bundled_edge

#include <b o o s t / graph / p r o p e r t i e s . hpp>


#include "my_bundled_edge . h"

template <typename graph>


bool has_bundled_edge_with_my_edge (
const my_bundled_edge& e ,
const graph& g
) noexcept
{
using ed = typename b o o s t : : g r a p h _ t r a i t s <graph > : :
edge_descriptor ;
const auto e i p = e d g e s ( g ) ;
return s t d : : f i n d _ i f ( e i p . f i r s t , e i p . second ,
[& e , &g ] ( const ed& d )
{
return g [ d ] == e ;
}
) != e i p . s e c o n d ;
}

This function can be demonstrated as in algorithm 103, where a certain


‘my_bundled_edge’ cannot be found in an empty graph. After adding the
desired my_bundled_edge, it is found.

115
Algorithm 103 Demonstration of the ‘has_bundled_edge_with_my_edge’
function
#include <b o o s t / t e s t / u n i t _ t e s t . hpp>
#include " create_bundled_edges_and_vertices_k3_graph . h"
#include "has_bundled_edge_with_my_edge . h"

BOOST_AUTO_TEST_CASE( test_has_bundled_edge_with_my_edge )
{
auto g
= create_bundled_edges_and_vertices_k3_graph ( ) ;
BOOST_CHECK(
has_bundled_edge_with_my_edge (
my_bundled_edge ( "Oxygen" , " Air " , 1 . 0 , 2 . 0 ) , g
)
);
}

Note that this function only finds if there is at least one edge with that
my_bundled_edge: it does not tell how many edges with that my_bundled_edge
exist in the graph.

7.2 Find a my_bundled_edge


Where STL functions work with iterators, here we obtain an edge descrip-
tor (see chapter 2.12) to obtain a handle to the desired edge. Algorithm 104
shows how to obtain an edge descriptor to the first edge found with a specific
my_bundled_edge value.

116
Algorithm 104 Find the first bundled edge with a certain my_bundled_edge

#include <c a s s e r t >


#include <b o o s t / graph / g r a p h _ t r a i t s . hpp>
#include "has_bundled_edge_with_my_edge . h"
#include "has_custom_edge_with_my_edge . h"
#include "my_bundled_edge . h"

template <typename graph>


typename b o o s t : : g r a p h _ t r a i t s <graph > : : e d g e _ d e s c r i p t o r
find_first_bundled_edge_with_my_edge (
const my_bundled_edge& e ,
const graph& g
)
{
using ed = typename b o o s t : : g r a p h _ t r a i t s <graph > : :
edge_descriptor ;
const auto e i p = e d g e s ( g ) ;
const auto i = s t d : : f i n d _ i f (
e i p . f i r s t , e i p . second ,
[& e , &g ] ( const ed d ) { return g [ d ] == e ; }
);
i f ( i == e i p . s e c o n d )
{
s t d : : s t r i n g s t r e a m msg ;
msg << __func__ << " : ␣ "
<< " c o u l d ␣ not ␣ f i n d ␣my_bundled_edge␣ ’ "
<< e << " ’ "
;
throw s t d : : invalid_argument ( msg . s t r ( ) ) ;
}
return ∗ i ;
}

With the edge descriptor obtained, one can read and modify the edge and
the vertices surrounding it. Algorithm 105 shows some examples of how to do
so.

117
Algorithm 105 Demonstration of the ‘find_first_bundled_edge_with_my_edge’
function
#include <b o o s t / t e s t / u n i t _ t e s t . hpp>
#include " create_bundled_edges_and_vertices_k3_graph . h"
#include " find_first_bundled_edge_with_my_edge . h"

BOOST_AUTO_TEST_CASE(
test_find_first_bundled_edge_with_my_edge )
{
const auto g
= create_bundled_edges_and_vertices_k3_graph ( ) ;
const auto ed
= find_first_bundled_edge_with_my_edge (
my_bundled_edge ( "Oxygen" , " Air " , 1 . 0 , 2 . 0 ) ,
g
);
BOOST_CHECK( b o o s t : : s o u r c e ( ed , g )
!= b o o s t : : t a r g e t ( ed , g )
);
}

7.3 Get an edge its my_bundled_edge


To obtain the my_bundled_edge from an edge descriptor, one needs to pull out
the my_bundled_edges map and then look up the my_edge of interest.

Algorithm 106 Get a vertex its my_bundled_vertex from its vertex descriptor

#include <b o o s t / graph / g r a p h _ t r a i t s . hpp>


#include "my_bundled_edge . h"

template <typename graph>


my_bundled_edge get_my_bundled_edge (
const typename b o o s t : : g r a p h _ t r a i t s <graph > : :
e d g e _ d e s c r i p t o r& ed ,
const graph& g
) noexcept
{
return g [ ed ] ;
}

To use ‘get_my_bundled_edge’, one first needs to obtain an edge descriptor.


Algorithm 107 shows a simple example.

118
Algorithm 107 Demonstration if the ‘get_my_bundled_edge’ function

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " add_bundled_edge . h"
#include " add_bundled_vertex . h"
#include "
create_empty_undirected_bundled_edges_and_vertices_graph
. h"
#include " find_first_bundled_edge_with_my_edge . h"
#include "get_my_bundled_edge . h"

BOOST_AUTO_TEST_CASE( test_get_my_bundled_edge )
{
auto g
=
create_empty_undirected_bundled_edges_and_vertices_graph
() ;
const my_bundled_edge edge { "Dex" } ;
const auto vd_a = add_bundled_vertex (
my_bundled_vertex ( "A" ) , g
);
const auto vd_b = add_bundled_vertex (
my_bundled_vertex ( "B" ) , g
);
add_bundled_edge ( vd_a , vd_b , edge , g ) ;
const auto ed
= find_first_bundled_edge_with_my_edge ( edge , g ) ;
BOOST_CHECK( get_my_bundled_edge ( ed , g ) == edge ) ;
}

7.4 Set an edge its my_bundled_edge


If you know how to get the my_bundled_edge from an edge descriptor, setting
it is just as easy, as shown in algorithm 108.

119
Algorithm 108 Set a bundled edge its my_bundled_edge from its edge de-
scriptor

#include <b o o s t / graph / p r o p e r t i e s . hpp>


#include "my_bundled_edge . h"

template <typename graph>


void set_my_bundled_edge (
const my_bundled_edge& name ,
const typename b o o s t : : g r a p h _ t r a i t s <graph > : :
e d g e _ d e s c r i p t o r& ed ,
graph& g
) noexcept
{
s t a t i c _ a s s e r t ( ! s t d : : i s _ c o n s t <graph > : : valu e ,
" graph ␣ cannot ␣ be ␣ c o n s t "
);
g [ ed ] = name ;
}

To use ‘set_bundled_edge_my_edge’, one first needs to obtain an edge


descriptor. Algorithm 109 shows a simple example.

120
Algorithm 109 Demonstration if the ‘set_bundled_edge_my_edge’ function

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " add_bundled_edge . h"
#include " add_bundled_vertex . h"
#include "
create_empty_undirected_bundled_edges_and_vertices_graph
. h"
#include " find_first_bundled_edge_with_my_edge . h"
#include "get_my_bundled_edge . h"
#include " set_my_bundled_edge . h"

BOOST_AUTO_TEST_CASE( test_set_my_bundled_edge )

{
auto g
=
create_empty_undirected_bundled_edges_and_vertices_graph
() ;
const auto vd_a = add_bundled_vertex ( my_bundled_vertex {
"A" } , g ) ;
const auto vd_b = add_bundled_vertex ( my_bundled_vertex {
"B" } , g ) ;
const my_bundled_edge old_edge { "Dex" } ;
add_bundled_edge ( vd_a , vd_b , old_edge , g ) ;
const auto vd
= find_first_bundled_edge_with_my_edge ( old_edge , g ) ;
BOOST_CHECK( get_my_bundled_edge ( vd , g )
== old_edge
);
const my_bundled_edge new_edge{ " Diggy " } ;
set_my_bundled_edge ( new_edge , vd , g ) ;
BOOST_CHECK( get_my_bundled_edge ( vd , g )
== new_edge
);
}

7.5 Storing a graph with bundled edges and vertices as a


.dot
If you used the ‘create_bundled_edges_and_vertices_k3_graph’ function (al-
gorithm 99) to produce a K3 graph with edges and vertices associated with
my_bundled_edge and my_bundled_vertex objects, you can store these my_bundled_edges
and my_bundled_vertex-es additionally with algorithm 110:

121
Algorithm 110 Storing a graph with bundled edges and vertices as a .dot file

#include <f s t r e a m >


#include <b o o s t / graph / g r a p h v i z . hpp>
#include " make_bundled_vertices_writer . h"
#include " make_bundled_edges_writer . h"

template <typename graph>


void save_bundled_edges_and_vertices_graph_to_dot (
const graph& g ,
const s t d : : s t r i n g& f i l e n a m e
)
{
std : : ofstream f ( filename ) ;
boost : : write_graphviz (
f,
g,
make_bundled_vertices_writer ( g ) ,
make_bundled_edges_writer ( g )
);
}

7.6 Load a directed graph with bundled edges and vertices


from a .dot file
When loading a graph from file, one needs to specify a type of graph. In this
example, an directed graph with bundled edges and vertices is loaded, as shown
in algorithm 111:

122
Algorithm 111 Loading a directed graph with bundled edges and vertices from
a .dot file
#include <f s t r e a m >
#include <b o o s t / graph / g r a p h v i z . hpp>
#include "
create_empty_directed_bundled_edges_and_vertices_graph
. h"
#include " i s _ r e g u l a r _ f i l e . h"
#include " graphviz_decode . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : directedS ,
my_bundled_vertex ,
my_bundled_edge
>
load_directed_bundled_edges_and_vertices_graph_from_dot (
const s t d : : s t r i n g& d o t _ f i l e n a m e
)
{
i f ( ! i s _ r e g u l a r _ f i l e ( dot_filename ) )
{
s t d : : s t r i n g s t r e a m msg ;
msg << __func__ << " : ␣ f i l e ␣ ’ "
<< d o t _ f i l e n a m e << " ’ ␣ not ␣ found "
;
throw s t d : : invalid_argument ( msg . s t r ( ) ) ;
}
std : : i f s t r e a m f ( dot_filename . c_str ( ) ) ;
auto g =
create_empty_directed_bundled_edges_and_vertices_graph
() ;

b o o s t : : d y n a m i c _ p r o p e r t i e s dp ( b o o s t : :
ignore_other_properties ) ;
dp . p r o p e r t y ( " l a b e l " , g e t (&my_bundled_vertex : : m_name, g ) )
;
dp . p r o p e r t y ( "comment" , g e t (&my_bundled_vertex : :
m_description , g ) ) ;
dp . p r o p e r t y ( " width " , g e t (&my_bundled_vertex : : m_x, g ) ) ;
dp . p r o p e r t y ( " h e i g h t " , g e t (&my_bundled_vertex : : m_y, g ) ) ;
dp . p r o p e r t y ( " edge_id " , g e t (&my_bundled_edge : : m_name, g ) )
;
dp . p r o p e r t y ( " l a b e l " , g e t (&my_bundled_edge : : m_name, g ) ) ;
dp . p r o p e r t y ( "comment" , g e t (&my_bundled_edge : :
m_description , g ) ) ;
123
dp . p r o p e r t y ( " width " , g e t (&my_bundled_edge : : m_width , g ) )
;
dp . p r o p e r t y ( " h e i g h t " , g e t (&my_bundled_edge : : m_height , g
));
b o o s t : : read_graphviz ( f , g , dp ) ;

// Decode v e r t i c e s
{
In this algorithm, first it is checked if the file to load exists. Then an empty
directed graph is created. Next to this, a boost::dynamic_properties is created
with its default constructor, after which we direct the boost::dynamic_properties
to find a ‘node_id’ and ‘label’ in the vertex name map, ‘edge_id’ and ‘label’ to
the edge name map. From this and the empty graph, ‘boost::read_graphviz’ is
called to build up the graph.
Algorithm 112 shows how to use the ‘load_directed_bundled_edges_and_vertices_graph_from_dot’
function:

124
Algorithm 112 Demonstration of the ‘load_directed_bundled_edges_and_vertices_graph_from_dot’functi

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_bundled_edges_and_vertices_markov_chain .
h"
#include " get_sorted_bundled_vertex_my_vertexes . h"
#include "
load_directed_bundled_edges_and_vertices_graph_from_dot
. h"
#include " save_bundled_edges_and_vertices_graph_to_dot . h"

BOOST_AUTO_TEST_CASE(
test_load_directed_bundled_edges_and_vertices_graph_from_dot
)
{
using b o o s t : : num_edges ;
using b o o s t : : num_vertices ;

const auto g
= create_bundled_edges_and_vertices_markov_chain ( ) ;
const s t d : : s t r i n g f i l e n a m e {
" create_bundled_edges_and_vertices_markov_chain . dot "
};
save_bundled_edges_and_vertices_graph_to_dot ( g ,
filename ) ;
const auto h
=
load_directed_bundled_edges_and_vertices_graph_from_dot
(
filename
);
BOOST_CHECK( num_edges ( g ) == num_edges ( h ) ) ;
BOOST_CHECK( num_vertices ( g ) == num_vertices ( h ) ) ;
BOOST_CHECK( get_sorted_bundled_vertex_my_vertexes ( g )
== get_sorted_bundled_vertex_my_vertexes ( h )
);
}

This demonstration shows how the Markov chain is created using the ‘cre-
ate_bundled_edges_and_vertices_markov_chain’ function (algorithm 96), saved
and then loaded.

125
7.7 Load an undirected graph with bundled edges and ver-
tices from a .dot file
When loading a graph from file, one needs to specify a type of graph. In this
example, an undirected graph with bundled edges and vertices is loaded, as
shown in algorithm 113:

126
Algorithm 113 Loading an undirected graph with bundled edges and vertices
from a .dot file
#include <f s t r e a m >
#include <b o o s t / graph / g r a p h v i z . hpp>
#include "
create_empty_undirected_bundled_edges_and_vertices_graph
. h"
#include " i s _ r e g u l a r _ f i l e . h"
#include " graphviz_decode . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : undirectedS ,
my_bundled_vertex ,
my_bundled_edge
>
load_undirected_bundled_edges_and_vertices_graph_from_dot
(
const s t d : : s t r i n g& d o t _ f i l e n a m e
)
{
i f ( ! i s _ r e g u l a r _ f i l e ( dot_filename ) )
{
s t d : : s t r i n g s t r e a m msg ;
msg << __func__ << " : ␣ f i l e ␣ ’ "
<< d o t _ f i l e n a m e << " ’ ␣ not ␣ found "
;
throw s t d : : invalid_argument ( msg . s t r ( ) ) ;
}
std : : i f s t r e a m f ( dot_filename . c_str ( ) ) ;
auto g =
create_empty_undirected_bundled_edges_and_vertices_graph
() ;

b o o s t : : d y n a m i c _ p r o p e r t i e s dp ( b o o s t : :
ignore_other_properties ) ;
dp . p r o p e r t y ( " l a b e l " , g e t (&my_bundled_vertex : : m_name, g ) )
;
dp . p r o p e r t y ( "comment" , g e t (&my_bundled_vertex : :
m_description , g ) ) ;
dp . p r o p e r t y ( " width " , g e t (&my_bundled_vertex : : m_x, g ) ) ;
dp . p r o p e r t y ( " h e i g h t " , g e t (&my_bundled_vertex : : m_y, g ) ) ;
dp . p r o p e r t y ( " edge_id " , g e t (&my_bundled_edge : : m_name, g ) )
;
dp . p r o p e r t y ( " l a b e l " , g e t (&my_bundled_edge : : m_name, g ) ) ;
dp . p r o p e r t y ( "comment" , g e t (&my_bundled_edge : :
m_description , g ) ) ; 127
dp . p r o p e r t y ( " width " , g e t (&my_bundled_edge : : m_width , g ) )
;
dp . p r o p e r t y ( " h e i g h t " , g e t (&my_bundled_edge : : m_height , g
));
b o o s t : : read_graphviz ( f , g , dp ) ;

// Decode v e r t i c e s
The only difference with loading a directed graph, is that the initial empty
graph is undirected instead. Chapter 7.6 describes the rationale of this function.
Algorithm 114 shows how to use the ‘load_undirected_bundled_vertices_graph_from_dot’
function:

Algorithm 114 Demonstration of the ‘load_undirected_bundled_edges_and_vertices_graph_from_dot’fun

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_bundled_edges_and_vertices_k3_graph . h"
#include " get_sorted_bundled_vertex_my_vertexes . h"
#include "
load_undirected_bundled_edges_and_vertices_graph_from_dot
. h"
#include " save_bundled_edges_and_vertices_graph_to_dot . h"

BOOST_AUTO_TEST_CASE(
test_load_undirected_bundled_edges_and_vertices_graph_from_dot
)
{
using b o o s t : : num_edges ;
using b o o s t : : num_vertices ;

const auto g
= create_bundled_edges_and_vertices_k3_graph ( ) ;
const s t d : : s t r i n g f i l e n a m e {
" create_bundled_edges_and_vertices_k3_graph . dot "
};
save_bundled_edges_and_vertices_graph_to_dot ( g ,
filename ) ;
const auto h
=
load_undirected_bundled_edges_and_vertices_graph_from_dot
(
filename
);
BOOST_CHECK( num_edges ( g ) == num_edges ( h ) ) ;
BOOST_CHECK( num_vertices ( g ) == num_vertices ( h ) ) ;
BOOST_CHECK( get_sorted_bundled_vertex_my_vertexes ( g )
== get_sorted_bundled_vertex_my_vertexes ( h )
);
}

This demonstration shows how K2 with bundled vertices is created using the
‘create_bundled_vertices_k2_graph’ function (algorithm ??), saved and then
loaded. The loaded graph is checked to be a graph similar to the original.

128
8 Building graphs with a graph name
Up until now, the graphs created have had no properties themselves. Sure, the
edges and vertices have had properties, but the graph itself has had none. Until
now.
In this chapter, graphs will be created with a graph name of type std::string
• An empty directed graph with a graph name: see chapter
• An empty undirected graph with a graph name: see chapter

• A two-state Markov chain with a graph name: see chapter


• K3 with a graph name: see chapter
In the process, some basic (sometimes bordering trivial) functions are shown:
• Getting a graph its name: see chapter

• Setting a graph its name: see chapter

8.1 Create an empty directed graph with a graph name


property
Algorithm 115 shows the function to create an empty directed graph with a
graph name.

Algorithm 115 Creating an empty directed graph with a graph name

#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : directedS ,
b o o s t : : no_property ,
b o o s t : : no_property ,
boost : : property<
b o o s t : : graph_name_t , s t d : : s t r i n g
>
>
create_empty_directed_graph_with_graph_name ( ) n o e x c e p t
{
return { } ;
}

This boost::adjacency_list is of the following type:

129
• the first ‘boost::vecS’: select (that is what the ‘S’ means) that out edges
are stored in a std::vector. This is the default way.
• the second ‘boost::vecS’: select that the graph vertices are stored in a
std::vector. This is the default way.

• ‘boost::directedS’: select that the graph is directed. This is the default


selectedness
• the first ‘boost::no_property’: the vertices have no properties. This is the
default (non-)property
• the second ‘boost::no_property’: the vertices have no properties. This is
the default (non-)property
• ‘boost::property<boost::graph_name_t, std::string>’: the graph itself
has a single property: its boost::graph_name has type std::string
Algorithm 116 demonstrates the ‘create_empty_directed_graph_with_graph_name’
function.

Algorithm 116 Demonstration of ‘create_empty_directed_graph_with_graph_name’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_empty_directed_graph_with_graph_name . h"

BOOST_AUTO_TEST_CASE(
test_create_empty_directed_graph_with_graph_name )
{
auto g
= create_empty_directed_graph_with_graph_name ( ) ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 0 ) ;
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 0 ) ;
}

8.2 Create an empty undirected graph with a graph name


property
Algorithm 117 shows the function to create an empty undirected graph with a
graph name.

130
Algorithm 117 Creating an empty undirected graph with a graph name

#include <b o o s t / graph / a d j a c e n c y _ l i s t . hpp>

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : undirectedS ,
b o o s t : : no_property ,
b o o s t : : no_property ,
boost : : property<
b o o s t : : graph_name_t , s t d : : s t r i n g
>
>
create_empty_undirected_graph_with_graph_name ( ) n o e x c e p t
{
return { } ;
}

This code is very similar to the code described in chapter 115, except that the
directness (the third template argument) is undirected (due to the boost::undirectedS).
Algorithm 118 demonstrates the ‘create_empty_undirected_graph_with_graph_name’
function.

Algorithm 118 Demonstration of ‘create_empty_undirected_graph_with_graph_name’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_empty_undirected_graph_with_graph_name . h
"

BOOST_AUTO_TEST_CASE(
test_create_empty_undirected_graph_with_graph_name )
{
auto g = create_empty_undirected_graph_with_graph_name
() ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 0 ) ;
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 0 ) ;
}

131
8.3 Get a graph its name property

Algorithm 119 Get a graph its name

#include <s t r i n g >


#include <b o o s t / graph / p r o p e r t i e s . hpp>

template <typename graph>


s t d : : s t r i n g get_graph_name (
const graph& g
) noexcept
{
return g e t _ p r o p e r t y (
g , b o o s t : : graph_name
);
}

Algorithm 120 demonstrates the ‘get_graph_name’ function.

Algorithm 120 Demonstration of ‘get_graph_name’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_empty_directed_graph_with_graph_name . h"
#include "get_graph_name . h"
#include " set_graph_name . h"

BOOST_AUTO_TEST_CASE( test_get_graph_name )
{
auto g = create_empty_directed_graph_with_graph_name ( ) ;
const s t d : : s t r i n g name{ "Dex" } ;
set_graph_name ( name , g ) ;
BOOST_CHECK( get_graph_name ( g ) == name ) ;
}

132
8.4 Set a graph its name property

Algorithm 121 Set a graph its name

#include <c a s s e r t >


#include <s t r i n g >
#include <b o o s t / graph / p r o p e r t i e s . hpp>

template <typename graph>


void set_graph_name (
const s t d : : s t r i n g& name ,
graph& g
) noexcept
{
s t a t i c _ a s s e r t ( ! s t d : : i s _ c o n s t <graph > : : valu e ,
" graph ␣ cannot ␣ be ␣ c o n s t "
);
g e t _ p r o p e r t y ( g , b o o s t : : graph_name ) = name ;
}

Algorithm 122 demonstrates the ‘set_graph_name’ function.

Algorithm 122 Demonstration of ‘set_graph_name’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_empty_directed_graph_with_graph_name . h"
#include "get_graph_name . h"
#include " set_graph_name . h"

BOOST_AUTO_TEST_CASE( test_set_graph_name )
{
auto g = create_empty_directed_graph_with_graph_name ( ) ;
const s t d : : s t r i n g name{ "Dex" } ;
set_graph_name ( name , g ) ;
BOOST_CHECK( get_graph_name ( g ) == name ) ;
}

8.5 Create a directed graph with a graph name property


8.5.1 Graph
See figure 5.

133
8.5.2 Function to create such a graph
Algorithm 123 shows the function to create an empty directed graph with a
graph name.

Algorithm 123 Creating a two-state Markov chain with a graph name

#include <c a s s e r t >


#include " create_empty_directed_graph_with_graph_name . h"
#include " set_graph_name . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : directedS ,
b o o s t : : no_property ,
b o o s t : : no_property ,
b o o s t : : p r o p e r t y <b o o s t : : graph_name_t , s t d : : s t r i n g >
>
create_markov_chain_with_graph_name ( ) n o e x c e p t
{
auto g = create_empty_directed_graph_with_graph_name ( ) ;
const auto vd_a = b o o s t : : add_vertex ( g ) ;
const auto vd_b = b o o s t : : add_vertex ( g ) ;
b o o s t : : add_edge ( vd_a , vd_a , g ) ;
b o o s t : : add_edge ( vd_a , vd_b , g ) ;
b o o s t : : add_edge ( vd_b , vd_a , g ) ;
b o o s t : : add_edge ( vd_b , vd_b , g ) ;

set_graph_name ( "Two−s t a t e ␣Markov␣ c h a i n " , g ) ;


return g ;
}

8.5.3 Creating such a graph


Algorithm 124 demonstrates the ‘create_markov_chain_with_graph_name’
function.

134
Algorithm 124 Demonstration of ‘create_markov_chain_with_graph_name’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_markov_chain_with_graph_name . h"
#include "get_graph_name . h"

BOOST_AUTO_TEST_CASE(
test_create_markov_chain_with_graph_name )
{
const auto g = create_markov_chain_with_graph_name ( ) ;
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 2 ) ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 4 ) ;
BOOST_CHECK( get_graph_name ( g ) == "Two−s t a t e ␣Markov␣
chain " ) ;
}

8.5.4 The .dot file produced

Algorithm 125 .dot file created from the ‘cre-


ate_markov_chain_with_graph_name’ function (algorithm 123), converted
from graph to .dot file using algorithm 55
digraph G {
name="Two-state Markov chain";
0;
1;
0->0 ;
0->1 ;
1->0 ;
1->1 ;
}

135
8.5.5 The .svg file produced

Figure 26: .svg file created from the ‘cre-


ate_markov_chain_with_graph_name’ function (algorithm 123) its .dot
file, converted from .dot file to .svg using algorithm 136

8.6 Create an undirected graph with a graph name prop-


erty
8.6.1 Graph
See figure 7.

8.6.2 Function to create such a graph


Algorithm 126 shows the function to create K2 graph with a graph name.

136
Algorithm 126 Creating a K2 graph with a graph name

#include " create_empty_undirected_graph_with_graph_name . h


"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : undirectedS ,
b o o s t : : no_property ,
b o o s t : : no_property ,
b o o s t : : p r o p e r t y <b o o s t : : graph_name_t , s t d : : s t r i n g >
>
create_k2_graph_with_graph_name ( ) n o e x c e p t
{
auto g = create_empty_undirected_graph_with_graph_name
() ;
const auto vd_a = b o o s t : : add_vertex ( g ) ;
const auto vd_b = b o o s t : : add_vertex ( g ) ;
b o o s t : : add_edge ( vd_a , vd_b , g ) ;
g e t _ p r o p e r t y ( g , b o o s t : : graph_name ) = "K2" ;

return g ;
}

8.6.3 Creating such a graph


Algorithm 127 demonstrates the ‘create_k2_graph_with_graph_name’ func-
tion.

Algorithm 127 Demonstration of ‘create_k2_graph_with_graph_name’

#include <b o o s t / t e s t / u n i t _ t e s t . hpp>


#include " create_k2_graph_with_graph_name . h"
#include "get_graph_name . h"

BOOST_AUTO_TEST_CASE( test_create_k2_graph_with_graph_name
)
{
const auto g = create_k2_graph_with_graph_name ( ) ;
BOOST_CHECK( b o o s t : : num_vertices ( g ) == 2 ) ;
BOOST_CHECK( b o o s t : : num_edges ( g ) == 1 ) ;
BOOST_CHECK( get_graph_name ( g ) == "K2" ) ;
}

137
8.6.4 The .dot file produced

Algorithm 128 .dot file created from the ‘cre-


ate_k2_graph_with_graph_name’ function (algorithm 126), converted
from graph to .dot file using algorithm 55
graph G {
name="K2";
0;
1;
0--1 ;
}

8.6.5 The .svg file produced

Figure 27: .svg file created from the ‘create_k2_graph_with_graph_name’


function (algorithm 126) its .dot file, converted from .dot file to .svg using
algorithm 136

9 Working on graphs with a graph name


9.1 Storing a graph with a graph name property as a .dot
file
This works:

138
Algorithm 129 Storing a graph with a graph name as a .dot file

#include <s t r i n g >


#include <f s t r e a m >
#include <b o o s t / graph / g r a p h v i z . hpp>
#include <b o o s t / graph / p r o p e r t i e s . hpp>

#include "get_graph_name . h"

template <typename graph>


void save_graph_with_graph_name_to_dot (
const graph& g ,
const s t d : : s t r i n g& f i l e n a m e
)
{
std : : ofstream f ( filename ) ;
boost : : write_graphviz (
f,
g,
boost : : default_writer () ,
boost : : default_writer () ,
// Unsure i f t h i s r e s u l t s i n a graph
// t h a t can be l o a d e d c o r r e c t l y
// from a . d o t f i l e
[&g ] ( s t d : : ostream& o s ) {
o s << "name=\""
<< get_graph_name ( g )
<< " \ " ; \ n" ;
}
);
}

9.2 Loading a directed graph with a graph name property


from a .dot file
This will result in a directed graph with a name:

139
Algorithm 130 Loading a directed graph with a graph name from a .dot file

#include <f s t r e a m >


#include <b o o s t / graph / g r a p h v i z . hpp>
#include " i s _ r e g u l a r _ f i l e . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : directedS ,
b o o s t : : no_property ,
b o o s t : : no_property ,
boost : : property<
b o o s t : : graph_name_t , s t d : : s t r i n g
>
>
load_directed_graph_with_graph_name_from_dot (
const s t d : : s t r i n g& d o t _ f i l e n a m e
)
{
using graph = b o o s t : : a d j a c e n c y _ l i s t <
b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : directedS ,
b o o s t : : no_property ,
b o o s t : : no_property ,
boost : : property<
b o o s t : : graph_name_t , s t d : : s t r i n g
>
>;

i f ( ! i s _ r e g u l a r _ f i l e ( dot_filename ) )
{
s t d : : s t r i n g s t r e a m msg ;
msg << __func__ << " : ␣ f i l e ␣ ’ "
<< d o t _ f i l e n a m e << " ’ ␣ not ␣ found "
;
throw s t d : : invalid_argument ( msg . s t r ( ) ) ;
}

graph g ;

b o o s t : : ref_property_map<graph ∗ , s t d : : s t r i n g >
graph_name{
g e t _ p r o p e r t y ( g , b o o s t : : graph_name )
};
b o o s t : : d y n a m i c _ p r o p e r t i e s dp{
boost : : ignore_other_properties
}; 140
dp . p r o p e r t y ( "name" , graph_name ) ;

std : : i f s t r e a m f ( dot_filename . c_str ( ) ) ;


b o o s t : : read_graphviz ( f , g , dp ) ;
return g ;
}
9.3 Loading an undirected graph with a graph name prop-
erty from a .dot file
This will result in an undirected graph with a name:

141
Algorithm 131 Loading an undirected graph with a graph name from a .dot
file
#include <f s t r e a m >
#include <s t r i n g >
#include <b o o s t / graph / g r a p h v i z . hpp>
#include " create_empty_undirected_graph_with_graph_name . h
"
#include " i s _ r e g u l a r _ f i l e . h"

boost : : adjacency_list <


b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : undirectedS ,
b o o s t : : no_property ,
b o o s t : : no_property ,
boost : : property<
b o o s t : : graph_name_t , s t d : : s t r i n g
>
>
load_undirected_graph_with_graph_name_from_dot (
const s t d : : s t r i n g& d o t _ f i l e n a m e
)
{
using graph = b o o s t : : a d j a c e n c y _ l i s t <
b o o s t : : vecS ,
b o o s t : : vecS ,
boost : : undirectedS ,
b o o s t : : no_property ,
b o o s t : : no_property ,
boost : : property<
b o o s t : : graph_name_t , s t d : : s t r i n g
>
>;
i f ( ! i s _ r e g u l a r _ f i l e ( dot_filename ) )
{
s t d : : s t r i n g s t r e a m msg ;
msg << __func__ << " : ␣ f i l e ␣ ’ "
<< d o t _ f i l e n a m e << " ’ ␣ not ␣ found "
;
throw s t d : : invalid_argument ( msg . s t r ( ) ) ;
}
graph g ;

b o o s t : : ref_property_map<graph ∗ , s t d : : s t r i n g >
graph_name{
g e t _ p r o p e r t y ( g , b o o s t : : graph_name )
};
b o o s t : : d y n a m i c _ p r o p e r t i e s 142
dp{
boost : : ignore_other_properties
};
dp . p r o p e r t y ( "name" , graph_name ) ;

std : : i f s t r e a m f ( dot_filename . c_str ( ) ) ;


b o o s t : : read_graphviz ( f , g , dp ) ;
return g ;
10 Other graph functions
Some functions that did not fit in.

10.1 Encode a std::string to a Graphviz-friendly format


You may want to use a label with spaces, comma’s and/or quotes. Saving
and loading these, will result in problem. This function replaces these special
characters by a rare combination of ordinary characters.

Algorithm 132 Encode a std::string to a Graphviz-friendly format

#include <b o o s t / a l g o r i t h m / s t r i n g / r e p l a c e . hpp>

s t d : : s t r i n g graphviz_encode ( s t d : : s t r i n g s ) n o e x c e p t
{
b o o s t : : a l g o r i t h m : : r e p l a c e _ a l l ( s , " , " , "$$$COMMA$$$" ) ;
b o o s t : : a l g o r i t h m : : r e p l a c e _ a l l ( s , " ␣ " , "$$$SPACE$$$" ) ;
b o o s t : : a l g o r i t h m : : r e p l a c e _ a l l ( s , " \" " , "$$$QUOTE$$$" ) ;
return s ;
}

10.2 Decode a std::string from a Graphviz-friendly format


This function undoes the ‘graphviz_encode’ function (algorithm 132) and thus
converts a Graphviz-friendly std::string to the original human-friendly std::string.

Algorithm 133 Decode a std::string from a Graphviz-friendly format to a


human-friendly format

#include <b o o s t / a l g o r i t h m / s t r i n g / r e p l a c e . hpp>

s t d : : s t r i n g graphviz_decode ( s t d : : s t r i n g s ) n o e x c e p t
{
b o o s t : : a l g o r i t h m : : r e p l a c e _ a l l ( s , "$$$COMMA$$$" , " , " ) ;
b o o s t : : a l g o r i t h m : : r e p l a c e _ a l l ( s , "$$$SPACE$$$" , " ␣ " ) ;
b o o s t : : a l g o r i t h m : : r e p l a c e _ a l l ( s , "$$$QUOTE$$$" , " \" " ) ;
return s ;
}

10.3 Check if a std::string is Graphviz-friendly


There are pieces where I check if a std::string is Graphviz-friendly. This is done
only where it matters. If it is tested not to matter, ‘is_graphviz_friendly’ is
absent.

143
Algorithm 134 Check if a std::string is Graphviz-friendly

#include " graphviz_encode . h"

bool i s _ g r a p h v i z _ f r i e n d l y ( const s t d : : s t r i n g& s ) n o e x c e p t


{
return graphviz_encode ( s ) == s ;
}

11 Misc functions
These are some function I needed for creating this tutorial. Although they are
not important for working with graphs, I used these heavily. These functions
may be compiler-dependent, platform-dependent and/or there may be superior
alternatives. I just add them for completeness.

11.1 Getting a data type as a std::string


This function will only work under GCC. I found this code at: http://stackoverflow.
com/questions/1055452/c-get-name-of-type-in-template . Thanks to ‘m-
dudley’ (Stack Overflow user page at http://stackoverflow.com/users/111327/
m-dudley ).

144
Algorithm 135 Getting a data type its name as a std::string

#include <c s t d l i b >


#include <s t r i n g >
#include <t y p e i n f o >
#include <c x x a b i . h>

template<typename T>
s t d : : s t r i n g get_type_name ( ) n o e x c e p t
{
s t d : : s t r i n g tname = typeid (T) . name ( ) ;
int s t a t u s = −1;
char ∗ const demangled_name{
a b i : : __cxa_demangle (
tname . c _ s t r ( ) , NULL, NULL, &s t a t u s
)
};
i f ( s t a t u s == 0 ) {
tname = demangled_name ;
s t d : : f r e e ( demangled_name ) ;
}
return tname ;
}

11.2 Convert a .dot to .svg


All illustrations in this tutorial are created by converting .dot to a .svg (‘Scalable
Vector Graphic’) file. This function assumes the program ‘dot’ is installed, which
is part of Graphviz.

145
Algorithm 136 Convert a .dot file to a .svg

#include <c a s s e r t >


#include <s t r i n g >
#include <i o s t r e a m >
#include <sstream >
#include <s t d e x c e p t >
#include " has_dot . h"
#include " i s _ r e g u l a r _ f i l e . h"
#include " i s _ v a l i d _ d o t _ f i l e . h"

void convert_dot_to_svg (
const s t d : : s t r i n g& dot_filename ,
const s t d : : s t r i n g& s v g _ f i l e n a m e
)
{
i f ( ! has_dot ( ) )
{
s t d : : s t r i n g s t r e a m msg ;
msg << __func__ << " : ␣ ’ dot ’ ␣ cannot ␣ be ␣ found . ␣ "
<< " type ␣ ’ sudo ␣ apt−g e t ␣ i n s t a l l ␣ g r a p h v i z ’ ␣ i n ␣ t h e ␣
command␣ l i n e "
;
throw s t d : : r u n t i m e _ e r r o r ( msg . s t r ( ) ) ;
}
i f ( ! is_valid_dot_file ( dot_filename ) )
{
s t d : : s t r i n g s t r e a m msg ;
msg << __func__ << " : ␣ f i l e ␣ ’ " << d o t _ f i l e n a m e
<< " ’ ␣ i s ␣ not ␣ a ␣ v a l i d ␣DOT␣ l a n g u a g e "
;
throw s t d : : invalid_argument ( msg . s t r ( ) ) ;
}
s t d : : s t r i n g s t r e a m cmd ;
cmd << " dot ␣−Tsvg ␣ " << d o t _ f i l e n a m e << " ␣−o ␣ " <<
svg_filename ;
const int e r r o r {
s t d : : system (cmd . s t r ( ) . c _ s t r ( ) )
};
if ( error )
{
s t d : : c e r r << __func__ << " : ␣ warning : ␣command␣ ’ "
<< cmd . s t r ( ) << " ’ ␣ r e s u l t i n g ␣ i n ␣ e r r o r ␣ "
<< e r r o r ;
}
i f ( ! i s _ r e g u l a r _ f i l e ( svg_filename ) )
{
s t d : : s t r i n g s t r e a m msg ;
msg << __func__ << " : ␣ f a146 i l e d ␣ t o ␣ c r e a t e ␣SVG␣ output ␣
f i l e ␣ ’"
<< s v g _ f i l e n a m e << " ’ "
;
throw s t d : : r u n t i m e _ e r r o r ( msg . s t r ( ) ) ;
}
}
‘convert_dot_to_svg’ makes a system call to the program ‘dot’ to convert
the .dot file to an .svg file.

11.3 Check if a file exists


Not the most smart way perhaps, but it does only use the STL.

Algorithm 137 Check if a file exists

#include <f s t r e a m >

bool i s _ r e g u l a r _ f i l e ( const s t d : : s t r i n g& f i l e n a m e )


noexcept
{
std : : fstream f ;
f . open ( f i l e n a m e . c _s t r ( ) , s t d : : i o s : : i n ) ;
return f . is_open ( ) ;
}

12 Errors
Some common errors.

12.1 Formed reference to void


This compile-time error occurs when you create a graph without a certain prop-
erty, then subsequently reading that property, as in algorithm 138:

Algorithm 138 Creating the error ‘formed reference to void’

#include " create_k2_graph . h"


#include " get_vertex_names . h"

void formed_reference_to_void ( ) n o e x c e p t
{
get_vertex_names ( create_k2_graph ( ) ) ;
}

In algorithm 138 a graph is created with vertices of no properties. Then the


names of these vertices, which do not exists, are tried to be read. If you want
to read the names of the vertices, supply a graph that has this property.

147
12.2 No matching function for call to ‘clear_out_edges’
This compile-time error occurs when you want to clear the outward edges from
a vertex in an undirected graph.

Algorithm 139 Creating the error ‘no matching function for call to
clear_out_edges’

#include " create_k2_graph . h"

void no_matching_function_for_call_to_clear_out_edges ( )
noexcept
{
auto g = create_k2_graph ( ) ;
const auto vd = ∗ v e r t i c e s ( g ) . f i r s t ;
b o o s t : : c l e a r _ i n _ e d g e s ( vd , g ) ;
}

In algorithm 139an undirected graph is created, a vertex descriptor is ob-


tained, then itsout edges are tried to be cleared.Either use a directed graph
(which has out edges), or use the ‘boost::clear_vertex’ function instead.

12.3 No matching function for call to ‘clear_in_edges’


See chapter 12.2.

12.4 Undefined reference to boost::detail::graph::read_graphviz_new


You will have to link against the Boost.Graph and Boost.Regex libraries. In Qt
Creator, this is achieved by adding these lines to your Qt Creator project file:
LIBS += −l b o o s t _ g r a p h −l b o o s t _ r e g e x

12.5 Property not found: node_id


When loading a graph from file (as in chapter 3.13) you will be using boost::read_graphviz.
boost::read_graphviz needs a third argument, of type boost::dynamic_properties.
When a graph does not have properties, do not use a default constructed version,
but initialize with ‘boost::ignore_other_properties’ as a constructor argument
instead. Algorithm 140 shows how to trigger this run-time error.

148
Algorithm 140 Creating the error ‘Property not found: node_id’

#include <c a s s e r t >


#include <f s t r e a m >
#include " i s _ r e g u l a r _ f i l e . h"
#include " create_empty_undirected_graph . h"
#include " create_k2_graph . h"
#include " save_graph_to_dot . h"

void property_not_found_node_id ( ) n o e x c e p t
{
const s t d : : s t r i n g d o t _ f i l e n a m e { "
property_not_found_node_id . dot " } ;
// C r e a t e a f i l e
{
const auto g = create_k2_graph ( ) ;
save_graph_to_dot ( g , d o t _ f i l e n a m e ) ;
a s s e r t ( i s _ r e g u l a r _ f i l e ( dot_filename ) ) ;
}

// Try t o re ad t h a t f i l e
std : : i f s t r e a m f ( dot_filename . c_str ( ) ) ;
auto g = create_empty_undirected_graph ( ) ;

// Line b e l o w s h o u l d have been


// b o o s t : : d y n a m i c _ p r o p e r t i e s dp ( b o o s t : :
ignore_other_properties ) ;
b o o s t : : d y n a m i c _ p r o p e r t i e s dp ; // Error

try {
b o o s t : : read_graphviz ( f , g , dp ) ;
}
catch ( s t d : : e x c e p t i o n &) {
return ; // S h o u l d g e t h e r e
}
a s s e r t ( ! " Should ␣ not ␣ g e t ␣ h e r e " ) ;
}

12.6 Stream zeroes


When loading a graph from a .dot file, in operator>‌>, I encountered reading
zeroes, where I expected an XML formatted string:
s t d : : i s t r e a m& r i b i : : cmap : : o p e r a t o r >>(s t d : : i s t r e a m& i s , my_class& a n y _ c l a s s ) n o e x
{
std : : s t r i n g s ;

149
i s >> s ; // s has an XML format
a s s e r t ( s != " 0 " ) ;
a n y _ c l a s s = my_class ( s ) ;
return i s ;
}
This was because I misconfigured the reader. I did (heavily simplified code):
graph load_from_dot ( c o n s t s t d : : s t r i n g& d o t _ f i l e n a m e )
{
std : : i f s t r e a m f ( dot_filename . c_str ( ) ) ;
graph g ;
b o o s t : : d y n a m i c _ p r o p e r t i e s dp ;
dp . p r o p e r t y ( " node_id " , g e t ( b o o s t : : vertex_custom_type , g ) ) ;
dp . p r o p e r t y ( " l a b e l " , g e t ( b o o s t : : vertex_custom_type , g ) ) ;
b o o s t : : read_graphviz ( f , g , dp ) ;
return g ;
}
Where it should have been:
graph load_from_dot ( c o n s t s t d : : s t r i n g& d o t _ f i l e n a m e )
{
std : : i f s t r e a m f ( dot_filename . c_str ( ) ) ;
graph g ;
b o o s t : : d y n a m i c _ p r o p e r t i e s dp ( b o o s t : : i g n o r e _ o t h e r _ p r o p e r t i e s ) ;
dp . p r o p e r t y ( " l a b e l " , g e t ( b o o s t : : vertex_custom_type , g ) ) ;
b o o s t : : read_graphviz ( f , g , dp ) ;
return g ;
}
The explanation is that by setting the boost::dynamic_property ‘node_id’
to ‘boost::vertex_custom_type’, operator>‌> will receive the node indices.
An alternative, but less clean solution, is to let operator>‌> ignore the node
indices:
s t d : : i s t r e a m& r i b i : : cmap : : o p e r a t o r >>(s t d : : i s t r e a m& i s , my_class& a n y _ c l a s s ) n o e x
{
std : : s t r i n g s ;
i s >> s ; // s has an XML format
i f ( ! is_xml ( s ) ) { // I g n o r e node i n d e x
a n y _ c l a s s _ c l a s s = my_class ( ) ;
}
else {
a n y _ c l a s s _ c l a s s = my_class ( s ) ;
}
return i s ;
}

150
13 Appendix
13.1 List of all edge, graph and vertex properties
The following list is obtained from the file ‘boost/graph/properties.hpp’.
Edge Graph Vertex
edge_all graph_all vertex_all
edge_bundle graph_bundle vertex_bundle
edge_capacity graph_name vertex_centrality
edge_centrality graph_visitor vertex_color
edge_color vertex_current_degree
edge_discover_time vertex_degree
edge_finished vertex_discover_time
edge_flow vertex_distance
edge_global vertex_distance2
edge_index vertex_finish_time
edge_local vertex_global
edge_local_index vertex_in_degree
edge_name vertex_index
edge_owner vertex_index1
edge_residual_capacity vertex_index2
edge_reverse vertex_local
edge_underlying vertex_local_index
edge_update vertex_lowpoint
edge_weight vertex_name
edge_weight2 vertex_out_degree
vertex_owner
vertex_potential
vertex_predecessor
vertex_priority
vertex_rank
vertex_root
vertex_underlying
vertex_update

13.2 Graphviz attributes


List created from www.graphviz.org/content/attrs, where only the attributes
that are supported by all formats are listed:

151
Edge Graph Vertex
arrowhead _background color
arrowsize bgcolor colorscheme
arrowtail center comment
color charset distortion
colorscheme color fillcolor
comment colorscheme fixedsize
decorate comment fontcolor
dir concentrate fontname
fillcolor fillcolor fontsize
fontcolor fontcolor gradientangle
fontname fontname height
fontsize fontpath image
gradientangle fontsize imagescale
headclip forcelabels label
headlabel gradientangle labelloc
headport imagepath layer
label label margin
labelangle labeljust nojustify
labeldistance labelloc orientation
labelfloat landscape penwidth
labelfontcolor layerlistsep peripheries
labelfontname layers pos
labelfontsize layerselect regular
layer layersep samplepoints
nojustify layout shape
penwidth margin shapefile
pos nodesep sides
style nojustify skew
tailclip orientation sortv
taillabel outputorder style
tailport pack width
weight packmode xlabel
xlabel pad z
page
pagedir
penwidth
quantum
ratio
rotate
size
sortv
splines
style
viewport

152
References
[1] Eckel Bruce. Thinking in c++, volume 1. 2002.
[2] Marshall P Cline, Greg Lomow, and Mike Girou. C++ FAQs. Pearson
Education, 1998.
[3] Jarrod Hollingworth, Bob Swart, and Jamie Allsop. C++ Builder 5 Devel-
oper’s Guide with Cdrom. Sams, 2000.
[4] John Lakos. Large-scale C++ software design, volume 10. Addison-Wesley
Reading, 1996.
[5] Jesse Liberty. Sams teach yourself C++ in 24 hours. Sams Publishing,
2001.
[6] Steve McConnell. Code complete. Pearson Education, 2004.

[7] Scott Meyers. Effective C++: 55 specific ways to improve your programs
and designs. Pearson Education, 2005.
[8] Jeremy G Siek, Lie-Quan Lee, and Andrew Lumsdaine. Boost Graph Li-
brary: User Guide and Reference Manual, The. Pearson Education, 2001.
[9] Bjarne Stroustrup. The C++ Programming Language (3rd edition). 1997.

[10] Bjarne Stroustrup. The C++ Programming Language (4th edition). 2013.
[11] Herb Sutter and Andrei Alexandrescu. C++ coding standards: 101 rules,
guidelines, and best practices. Pearson Education, 2004.

153
Index
#include, 12 boost::vertices does not exist, 19, 21,
K2 , create, 29 25
K3 , create, 32 boost::write_graphviz, 61
bundled_vertices_writer, 89
Add a vertex, 17
Add an edge, 21 const, 13
Add bundled edge, 101 const-correctness, 13
Add bundled vertex, 68 Convert dot to svg, 146
Add vertex, 17 Count connected components, 55, 57
add_edge, 22 Count undirected graph levels, 59
aer_, 23 Counting the number of edges, 16
All edge properties, 151 Counting the number of vertices, 15
All graph properties, 151 Create K2 , 29
All vertex properties, 151 Create K2 graph, 30
assert, 15, 22 Create K3 , 32
auto, 13 Create K3 graph, 33
Create .dot from graph, 60
boost::add_edge, 21, 22, 27, 30 Create .dot from graph with bundled
boost::add_edge result, 23 edges and vertices, 121
boost::add_vertex, 17, 27, 30 Create all direct-neighbour subgraphs,
boost::adjacency_list, 13 52
boost::adjacency_matrix, 13 Create an empty directed graph, 12
boost::degree does not exist, 43 Create an empty graph, 14
boost::directedS, 14, 67, 130 Create bundled edges and vertices K3
boost::dynamic_properties, 62, 92, 124, graph, 111
148 Create bundled edges and vertices Markov
boost::edge does not exist, 46 chain, 105
boost::edge_bundled_type_t, 98 Create bundled vertices K2 graph, 76
boost::edges does not exist, 23–25 Create bundled vertices Markov chain,
boost::get does not exist, 7 71
boost::graph_name, 130 Create direct-neighbour subgraph, 49
boost::graph_name_t, 130 Create direct-neighbour subgraph_including_in_edges,
boost::ignore_other_properties, 62, 148 51
boost::in_degree does not exist, 43 Create directed graph, 26
boost::no_property, 130 Create directed graph from .dot, 61
boost::num_edges, 16 Create empty directed bundled edges
boost::num_vertices, 15 and vertices graph, 98
boost::out_degree does not exist, 43, Create empty directed bundled vertices
44 graph, 67
boost::property, 98, 130 Create empty directed graph, 12
boost::read_graphviz, 62, 92, 124, 148 Create empty directed graph with graph
boost::undirectedS, 14, 68, 99, 131 name, 129
boost::vecS, 14, 67, 130

154
Create empty undirected bundled edges Get bundled vertex my_vertexes, 69
and vertices graph, 99 Get edge between vertices, 47
Create empty undirected bundled ver- Get edge descriptors, 25
tices graph, 68 Get edge iterators, 24
Create empty undirected graph, 14 Get edge my_bundled_edges, 103
Create empty undirected graph with Get graph name, 132
graph name, 131 Get my_bundled_edge, 118
Create K2 graph with graph name, 137 Get n edges, 16
Create Markov chain, 27 Get n vertices, 15
Create Markov chain with graph name, Get type name, 145
134 Get vertex descriptors, 20
Create path graph, 34, 35 Get vertex iterators, 19
Create Petersen graph, 37, 39 Get vertex out degrees, 44
Create undirected graph from .dot, 63 Get vertices, 19
Create undirected graph with bundled Graph properties, 151
edges and vertices from .dot, Graphviz, 60
126 graphviz decode, 143
graphviz encode, 143
Declaration, my_bundled_edge, 97
Declaration, my_bundled_vertex, 66 Has bundled edge with my_bundled_edge,
decltype(auto), 7 115
directed graph, 9 Has bundled vertex with my_vertex,
Directed graph, create, 26 81
Has edge between vertices, 46
ed_, 25 header file, 12
edge, 46
Edge descriptor, 24 idegree, 43
Edge descriptors, get, 25 in_degree, 43
Edge iterator, 23 Is isomorphic, 53
Edge iterator pair, 23 Is regular file, 147
Edge properties, 151 is_graphviz_friendly, 144
Edge, add, 21
link, 148
edges, 23, 25
Load directed bundled edges and ver-
Edges, counting, 16
tices graph from dot, 123
eip_, 23
Load directed bundled vertices graph
Empty directed graph, create, 12
from dot, 91
Empty graph, create, 14
Load directed custom edges and ver-
Find first bundled edge with my_bundled_edge, tices graph from dot, 140
117 Load directed graph from .dot, 61
Find first bundled vertex with my_vertex,Load directed graph from dot, 62
83 Load undirected bundled edges and ver-
Formed reference to void, 147 tices graph from dot, 127
Load undirected bundled vertices graph
get, 7 from dot, 94
Get bundled vertex my_bundled_vertex,Load undirected custom edges and ver-
84 tices graph from dot, 142

155
Load undirected graph from .dot, 63 Set bundled edge my_bundled_edge,
Load undirected graph from_dot, 64 120
Load undirected graph with bundled Set bundled vertex my_bundled_vertexes,
edges and vertices from .dot, 87
126 Set graph name, 133
Set vertex my_vertex, 85
m_, 66, 97 static_assert, 17
make_bundled_vertices_writer, 88 static_cast, 15
member, 66, 97 std::copy, 21
my_bundled_edge, 97 std::cout, 61
my_bundled_edge declaration, 97 std::ifstream, 62
my_bundled_edge.h, 97 std::list, 13
my_bundled_vertex, 66, 67 std::ofstream, 61
my_bundled_vertex.h, 66 std::pair, 22
my_edge, 98 std::vector, 13
my_vertex declaration, 66 STL, 13

No matching function for call to clear_out_edges,


test case, 6
148
node_id, 148 Undefined reference to read_graphviz_new,
noexcept, 12 148
noexcept specification, 12 undirected graph, 9
Number of edges, get, 16 unsigned long, 15
Number of vertices, get, 15
vd, 22
out_degree, 43, 44 vd_, 18
Vertex descriptor, 18, 21
Path graph, create, 34 Vertex descriptors, get, 20
Petersen graph, create, 37 Vertex iterator, 19
Property not found, 148 Vertex iterator pair, 19
Property not found: node_id, 148, 149 Vertex iterators, get, 19
Vertex properties, 151
read_graphviz_new, 148 Vertex, add, 17
read_graphviz_new, undefined refer- vertices, 19, 21
ence, 148 Vertices, counting, 15
vip_, 19
S, 14, 130
Save bundled edges and vertices graph
to dot, 122
Save bundled vertices graph to dot, 88
Save graph as .dot, 60
Save graph to dot, 61
Save graph with bundled edges and ver-
tices as .dot, 121
Save graph with graph name to dot,
139

156

You might also like