Combinatorics with SageMath: Graphs¶

Nadia Lafrenière¶

Dartmouth College (🇺🇸) $\xrightarrow{🚌}$ Concordia University (🇨🇦)¶

EAUMP-ICTP School on Enumerative Combinatorics¶

Arusha, Tanzania, July 27, 2023¶

Graphs¶

A graph is given by a set of vertices and a set of edges connecting the vertices. Just that!

Graphs are very useful to represent connections between people, networks, etc. A lot of theory exists on them!

Motivation¶

Can you draw these pictures without ever crossing your path?

In [2]:
A = graphs.CompleteGraph(5)
B = A.copy(); B.delete_edge([0,1])
graphics_array([A.plot(vertex_labels=False), B.plot(vertex_labels=False)])
Out[2]:
In [3]:
B.plot(layout='planar')
Out[3]:

When we ask this question in graph theory, we mean 'Can we draw a picture equivalent to this one, in the sense that the same vertices are connected?'

Can you draw this graph without ever lifting your pen?

In [4]:
A = graphs.WheelGraph(5)
A.delete_edge([0,1])
A.plot(vertex_labels=False)
Out[4]:

These problems look like children problems because the graphs are small, but we could ask the same question for much much larger graphs.

In [5]:
graphics_array([graphs.HararyGraph(8,16).plot(vertex_labels=False),graphs.CompleteBipartiteGraph(8,6).plot(vertex_labels=False)])
Out[5]:

Motivation¶

How many colours do you need to draw a map of Africa so that no two adjacent countries have the same colour ?

We already know that we needed at least 4 colours, since Uganda, Rwanda, Tanzania and the DRC are all adjacent. The four color theorem tells us that any map can be colored with only 4 colors so that no two countries are adjacent. SageMath can confirm that.

In [6]:
# This number is called the chromatic number of a graph
G = graphs.AfricaMap()  # already in SageMath
G.chromatic_number()
Out[6]:
4

More interestingly, SageMath can tell us how to use for what country.

In [7]:
c = G.coloring()
In [8]:
for i in range(4):
    s = ''
    for country in c[i]:
        s += str(country)
        s += ", "
    print(s)
Liberia, Mali, Guinea-Bissau, Libya, Central Africa, Benin, Gabon, Angola, Tanzania, South Africa, Ethiopia, Ghana, Morocco, Gambia, Cape Verde, Seychelles, Mauritius, São Tomé and Príncipe, Madagascar, Comoros, 
Sierra Leone, Ivory Coast, Senegal, Algeria, Chad, South Sudan, Republic of the Congo, Equatorial Guinea, Egypt, Zambia, Rwanda, Swaziland, Botswana, Eritrea, Somalia, Togo, Lesotho, 
Guinea, Burkina Faso, Mauritania, Tunisia, Sudan, Nigeria, Democratic Republic of the Congo, Namibia, Kenya, Malawi, Zimbabwe, Djibouti, 
Niger, Cameroon, Uganda, Burundi, Mozambique, 

Then we can export that list to some online tools that can plot for us the map.

Notice that G.coloring() does not always return the same coloring, so the list above might not match the picture below.

Constructing graphs in SageMath¶

Recall that a graph is a set of vertices and a set of edges between these vertices.

This is the data that SageMath takes to construct graphs, even though they can be constructed in many ways.

Find how to construct a graph in SageMath.

In [9]:
Graph?

The documentation says that a graph is created with some data, that can be any of the following.

  1. "Graph()" -- build a graph on 0 vertices.
  2. "Graph(5)" -- return an edgeless graph on the 5 vertices 0,...,4.
  3. "Graph([list_of_vertices, list_of_edges])" -- returns a graph with given vertices/edges.
  4. "Graph(list_of_edges)" -- return a graph with a given list of edges (see documentation of "add_edges()").
  5. "Graph({1: [2, 3, 4], 3: [4]})" -- return a graph by associating to each vertex the list of its neighbors.
  6. "Graph({1: {2: 'a', 3:'b'} ,3:{2:'c'}})" -- return a graph by associating a list of neighbors to each vertex and providing its edge label.
  7. "Graph(a_symmetric_matrix)" -- return a graph with given (weighted) adjacency matrix (see documentation of "adjacency_matrix()").
  8. "Graph(a_nonsymmetric_matrix)" -- return a graph with given incidence matrix (see documentation of "incidence_matrix()").

[...]

SageMath also knows a lot of common graphs. These are accessed by typing graphs.[tab]

In [10]:
# In class

What is your favorite graph?

Create the following graph, in class¶

In [11]:
# In class
In [13]:
# A graph I like
G = graphs.PetersenGraph(); c = G.coloring(hex_colors=True); G.plot(vertex_colors=c, vertex_labels=False)
Out[13]:

Some homework problems that my students could use SageMath for.¶

Prove or disprove: All hypercubes are bipartite.

What is the number of non-loop edges in the De Bruijn digraph Dn (for n ≥ 2)? Prove your answer

Are the following graphs planar? Prove your answer. (a) The complete bipartite graph $K_{4,2}$ (b) The hypercube $H_3$ (c) The Petersen graph

Prove or disprove: All hypercubes are bipartite.

Won't give a proof, but might either give a counterexample, or convince one to prove it.

In [14]:
for n in range(1, 10):
    print(n, graphs.CubeGraph(n).is_bipartite())
1 True
2 True
3 True
4 True
5 True
6 True
7 True
8 True
9 True

Theorem: All hypergraphs are bipartite.

(The proof can be done easily, by writing the coordinates as tuples over 0 and 1 and taking their sum. All the neighbors of an odd-sum vertex have an even sum.)

What is the number of non-loop edges in the De Bruijn digraph Dn (for n ≥ 2)? Prove your answer

Again, won't give a proof, but we could count it for all small values of $n$,

In [15]:
for n in range(1, 10):
    G = digraphs.DeBruijn(2, n)
    print(n, len(G.edges()) - len(G.loop_edges()))
1 2
2 6
3 14
4 30
5 62
6 126
7 254
8 510
9 1022
/tmp/ipykernel_12449/2879207802.py:3: DeprecationWarning: parameter 'sort' will be set to False by default in the future
See https://github.com/sagemath/sage/issues/27408 for details.
  print(n, len(G.edges()) - len(G.loop_edges()))

Conjecture: the number of non-loop edges in a DeBruijn graph for $n$ is $2^{n+1}-2$.

It is not hard to prove, but we would need to know what a DeBruijn graph is, and to understand it.

In [16]:
digraphs.DeBruijn(2,3).plot(vertex_size=800)
Out[16]:

A De Bruijn graph has for vertices all the binary sequence of a given length, and there is an arrow connecting two sequences if taking the tail removing the first letter and replacing the last letter by anything, we can get the tip of the arrow.

It has $2^n$ vertices, $2^{n+1}$ edges, and only two of them are loops (000...0 -> 000...0and 111...1 -> 111...1).

Are the following graphs planar? Prove your answer. (a) The complete bipartite graph $K_{4,2}$ (b) The hypercube $H_3$ (c) The Petersen graph

In [17]:
G = graphs.CompleteBipartiteGraph(4,2)
graphics_array([G.plot(vertex_labels=False), G.plot(layout='planar', vertex_labels=False)])
Out[17]:
In [18]:
G = graphs.CubeGraph(3)
graphics_array([G.plot(vertex_labels=True, vertex_size=800), G.plot(layout='planar', vertex_labels=False)])
Out[18]:
In [19]:
G = graphs.PetersenGraph()
G.is_planar()
Out[19]:
False

The cube and the complete bipartite graph $K_{4,2}$ are planar, the Petersen graph is not.

Takeaways¶

  • SageMath would be a good help for my student's homeworks (at least for some problems)
  • SageMath does not always give the most natural or clever visual representation. But, it has a lot of parameters to customize the presentation.
  • Also, other tools in Python, for example, are much better for visualization.

A few classical problems in graph theory¶

Given a graph, what is...

  • ... the distance between two given vertices?
  • ... the minimum number of edges that one needs to remove to disconnect the graph (this is the edge-connectivity)?
  • ... the largest set of vertices that have no edge in between (the largest independent set)?
  • ... the minimum number of colours needed to colour the vertices, so that two adjacent vertices have different colours; this is the chromatic number?
  • ... a shortest path between two given vertices?
  • ... the size of the largest clique: a clique is a complete subgraph?

SageMath knows all of them!

In class. Generate a random graph with 15 vertices, in which each edge appears with probability 0.3

Then solve all the problems above.

In [20]:
# In-class work
G = graphs.RandomGNP(15, 0.3); G  # parameters are # of vertices and probability of an edge to be in the graph
Out[20]:

Display¶

For each of the problems above, we can illustrate this directly on the graph. We will explore the drawing options together, and solve each of the problems above.

Given a graph, what is...

  • ... the distance between two given vertices?
  • ... the minimum number of edges that one needs to remove to disconnect the graph (this is the edge-connectivity)?
  • ... the largest set of vertices that have no edge in between (the largest independent set)?
  • ... the minimum number of colours needed to colour the vertices, so that two adjacent vertices have different colours; this is the chromatic number?
  • ... a shortest path between two given vertices?
  • ... the size of the largest clique: a clique is a complete subgraph?
In [34]:
# In class

A quiz!¶

The chromatic number of a graph is the minimum number of colours needed to colour all vertices such that no two adjacent vertices (so vertices that share an edge) have the same colour.

What is the chromatic number of the following graphs?

For 1 point:¶

In [44]:
G.plot(vertex_labels=False)
Out[44]:
In [45]:
c = G.coloring(hex_colors=True); G.plot(vertex_colors=c, vertex_labels=False)
Out[45]:

For complete graphs, so graphs for which all possible exist, the chromatic number is the number of vertices.

For 1 point:¶

In [47]:
G.plot(vertex_labels=false)
Out[47]:
In [48]:
c = G.coloring(hex_colors=True); G.plot(vertex_colors=c, vertex_labels=False)
Out[48]:

This is a bipartite graph (because there is no edge from the top set to the top set, or between two vertices of the bottom set). All vertices of the top can be coloured the same, just like all the vertices in the bottom.

For 1 point:¶

In [50]:
G.plot(vertex_labels=False)
Out[50]:
In [51]:
c = G.coloring(hex_colors=True); G.plot(vertex_colors=c, vertex_labels=False)
Out[51]:

Cycles of odd length need to be colored with 3 different colors.

For 1 point:¶

In [53]:
G.plot(vertex_labels=False)
Out[53]:
In [54]:
c = G.coloring(hex_colors=True); G.plot(vertex_colors=c, vertex_labels=False)
Out[54]:

Cycles of even length are bipartite graphs, so they can be colored with two colors.

For 2 points:¶

In [56]:
G.plot(vertex_labels=False)
Out[56]:

For 1 point if you accept the hint:¶

Hint: This is called the Mycielski graph of order 4.

In [57]:
c = G.coloring(hex_colors=True); G.plot(vertex_colors=c, vertex_labels=False)
Out[57]:

Mycielski's do not contain any triangle, but they have arbitrary large chromatic numbers.

In [58]:
graphics_array([graphs.MycielskiGraph(i).plot(vertex_labels=False, vertex_colors=graphs.MycielskiGraph(i).coloring(hex_colors=True)) for i in range(1,5)])
Out[58]:

For 2 points:¶

In [60]:
G.plot(vertex_labels=False)
Out[60]:
In [61]:
c = G.coloring(hex_colors=True); G.plot(vertex_colors=c, vertex_labels=False)
Out[61]:

This is the hypercube of dimension 4, and hypercubes are bipartite.

Planarity questions¶

Are the following graphs planar? A graph is planar if it can be drawn without edge crossings.

For 1 point:¶

In [63]:
G.plot(vertex_labels=False)
Out[63]:
In [64]:
G.plot(vertex_labels=False, layout='planar')
Out[64]:

The complete graph on four vertices is also the skeleton of the tetrahedron, and can be drawn in a planar way.

For 1 point:¶

In [66]:
G.plot(vertex_labels=False)
Out[66]:

The complete graph on five vertices is the smallest graph that is not planar.

For 1 point:¶

In [68]:
G.plot(vertex_labels=False, layout ='circular')
Out[68]:
In [69]:
# Hint!
G.plot(layout ='circular', vertex_size=600)
Out[69]:

This is the Cube Graph! The cube graph is planar.

For 1 point:¶

In [71]:
G.plot(vertex_labels=False)
Out[71]:

The hypercube of dimension 4 is not planar...

Counting the points... Do we have a winner?¶