2-Connected Graphs and Ear Decompositions
The question
Six routers and nine cables: two triangles, and , joined by the three cables –, – and –. This graph is called the prism.
Whichever single router fails, the other five can still reach each other. You can check that by deleting each router in turn. But that is six separate experiments, and it does not tell you why the network is robust, or how to design another one that is. This module gives two better answers. The first is local: between any two routers there are two routes that share no router in between. The second is a recipe: the network can be built from a cycle by repeatedly adding a path between two routers already present. Both turn out to be equivalent to "no single failure disconnects".
The naive approach, and where it wastes work
from itertools import combinations
from collections import deque
def network(edges):
g = {}
for u, v in edges:
g.setdefault(u, set()).add(v)
g.setdefault(v, set()).add(u)
return g
def connected(g, removed=()):
gone = set(removed)
left = [v for v in g if v not in gone]
if len(left) <= 1:
return True
seen, queue = {left[0]}, deque([left[0]])
while queue:
u = queue.popleft()
for w in g[u]:
if w not in gone and w not in seen:
seen.add(w)
queue.append(w)
return len(seen) == len(left)
def two_connected(g):
"""By brute force: at least 3 vertices, connected, and no single deletion disconnects."""
return len(g) >= 3 and connected(g) and all(connected(g, [v]) for v in g)
prism = network([(0, 1), (1, 2), (2, 0), (3, 4), (4, 5), (5, 3), (0, 3), (1, 4), (2, 5)])
assert two_connected(prism)
The brute-force test deletes each of the vertices and searches what is left: searches, each over the whole graph. It answers "yes" or "no" but leaves no evidence behind, and it says nothing about how to build such a network. Each deletion re-explores almost the same graph.
Definitions
A graph is 2-connected if it has at least 3 vertices, is connected, and has no cut vertex. (This is from module 14. The complete graph has no cut vertex but only two vertices, and , so it is not 2-connected.)
Two -paths are internally disjoint if they share no vertex other than and . In the prism, and are internally disjoint -paths.
Whitney's theorem
Whitney's theorem (1932)
Let have at least 3 vertices. is 2-connected if and only if every two vertices of are joined by two internally disjoint -paths.
Proof. If. Suppose every pair has two internally disjoint paths. Deleting one vertex cannot separate two other vertices and , because lies on at most one of their two paths. So is connected for every , and is connected, with at least 3 vertices.
Only if. Let be 2-connected. We prove by induction on the distance that every two vertices have two internally disjoint -paths.
Base, . The edge is one path. is still connected: otherwise is a cut edge, and since has at least 3 vertices, one of has another neighbor and is a cut vertex. So has a -path, which is the second.
Step, . Let be the vertex before on a shortest -path, so . By induction there are internally disjoint -paths and . Since is 2-connected, has a -path .
- If lies on or , say on , then up to , and followed by the edge , are internally disjoint -paths.
- Otherwise let be the last vertex of that lies on . ( starts at , so such a vertex exists.) Say is on . Then from to followed by from to is one path, and followed by is the other. They are internally disjoint: the part of after meets neither nor , because was the last such vertex; and and are internally disjoint by induction.
Proof moves used here.
- Induction on the distance between and , so the step can use the two paths to the vertex one before .
- Extremal choice. is the last vertex of on . That is what guarantees the tail of avoids both paths.
- Case split. The case where is already on or is handled first, so the main case can assume it is not.
The expansion lemma
Expansion lemma. If is 2-connected and is obtained by adding a new vertex adjacent to at least two vertices of , then is 2-connected.
Proof. has at least 4 vertices and is connected. Delete one vertex. Deleting leaves , which is connected. Deleting some of leaves , connected because is 2-connected, together with , which still has a neighbor in because it had at least two. So no vertex of is a cut vertex.
Cycles through any two vertices
Two internally disjoint -paths together form a cycle through and , and a cycle through and splits at them into two such paths. So Whitney's theorem can be restated:
Corollary. A graph with at least 3 vertices is 2-connected if and only if every two of its vertices lie on a common cycle.
In the prism, and lie on the cycle :
def internally_disjoint(p, q):
return p[0] == q[0] and p[-1] == q[-1] and not set(p[1:-1]) & set(q[1:-1])
def is_path(g, p):
return len(set(p)) == len(p) and all(b in g[a] for a, b in zip(p, p[1:]))
p, q = [0, 3, 4], [0, 1, 4]
assert is_path(prism, p) and is_path(prism, q) and internally_disjoint(p, q)
Predict: does Whitney's theorem hold for ?
No, and that is why the theorem says "at least 3 vertices". has no cut vertex, yet its two vertices are joined by only one path. With the definition used here, is not 2-connected, so the theorem is not contradicted; the hypothesis keeps it out.
Ear decompositions, traced on the prism
An ear of a subgraph is a path in whose two endpoints are distinct vertices of , whose other vertices (if any) are not in , and whose edges are not in . A single edge of outside between two vertices of counts. An ear decomposition of is a sequence: a cycle, then ears added one at a time, until every edge of is used.
Here is one for the prism. Start with the triangle ; add the ear ; then the ear ; then the single-edge ear –:
def valid_ears(g, cycle, ears):
"""Check an ear decomposition (a stand-in checker, not a way to find one)."""
if len(cycle) < 3 or not is_path(g, cycle) or cycle[0] not in g[cycle[-1]]:
return False
built = set(cycle)
used = {frozenset(e) for e in zip(cycle, cycle[1:] + cycle[:1])}
for ear in ears:
ends, inside = (ear[0], ear[-1]), ear[1:-1]
new = {frozenset(e) for e in zip(ear, ear[1:])}
if ends[0] == ends[1] or not set(ends) <= built or set(inside) & built or not is_path(g, ear):
return False
if new & used:
return False
used |= new
built |= set(inside)
return built == set(g) and used == {frozenset((u, w)) for u in g for w in g[u]}
assert valid_ears(prism, [0, 1, 2], [[0, 3, 4, 1], [2, 5, 4], [3, 5]])
assert not valid_ears(prism, [0, 1, 2], [[0, 1], [0, 3, 4, 1], [2, 5, 4], [3, 5]]) # 0-1 is reused
Whitney's ear theorem
A graph is 2-connected if and only if it has an ear decomposition. Moreover, every cycle of a 2-connected graph can be the starting cycle.
Proof. If. A cycle is 2-connected. Adding an ear to a 2-connected keeps it 2-connected: the new graph has at least 3 vertices and is connected. Delete a vertex . If is in , then is connected, and the ear, minus if is an endpoint, still hangs from the other endpoint, which is in because the endpoints are distinct. If is inside the ear, is untouched and each remaining piece of the ear is attached to an endpoint. Either way the rest is connected.
Only if. Let be 2-connected and any cycle of it (one exists: by the corollary, any two vertices lie on a cycle). Among the subgraphs that can be built from by adding ears, take a maximal one, . Suppose .
- If some edge of outside joins two vertices of , that edge is an ear, contradicting maximality.
- Otherwise some vertex is missing from . Since is connected, there is an edge with and . Since is 2-connected, is connected, so it has a path from to a vertex of (which is nonempty, as contains a cycle). Let be the first vertex of on that path. Then , , then the path up to , is an ear of : its ends are in , and its inner vertices are not. Again maximality is contradicted.
So , and has an ear decomposition starting from .
Proof moves used here.
- Extremal choice: a maximal subgraph built by ears, so that "it cannot grow" becomes a hypothesis to contradict.
- Case split on whether a missing edge or a missing vertex is what stops from being .
- Where the hypothesis is used: connected is exactly what lets the ear return to at a vertex other than .
When an ear closes on itself
The word distinct in "two distinct endpoints" matters. Take two copies of that share one vertex. You can start from a triangle in one copy and add ears until that copy is used up. To reach the other copy, any path from the first must leave and return through the shared vertex, so it is a closed ear: both ends are the same vertex. That graph has a cut vertex, so it is not 2-connected, and indeed it has no ear decomposition with open ears.
left = list(combinations(range(4), 2))
shared = network(left + [(a + 3, b + 3) for a, b in left]) # both copies contain vertex 3
assert not two_connected(shared) and not connected(shared, [3])
What a certificate costs
An ear decomposition is a certificate of 2-connectedness: checking one, as valid_ears does,
takes one pass over the edges. A cut vertex is a certificate of the opposite: delete it and
search once. The brute-force test instead runs searches. Hopcroft and Tarjan (1973) found
all cut vertices of a graph in one depth-first search, in time.
A problem that looks different
A depot ships to three warehouses through a network of hubs. A hub can fail, and the company wants routes from the depot to the three warehouses that share no hub at all, so that one failure costs at most one delivery. When can it be done, and what short evidence shows it cannot? Nothing in the question mentions cycles or ears. It is a question about routes that avoid each other, and module 16 answers it.
Practise
The lab runs in your browser. Your code grows an ear decomposition one ear per frame and refuses to be fooled by an ear that closes on itself. It then finds two disjoint routes where the obvious first choice blocks the second. Half of the lab is proofs. You assemble a proof that a small change to a 2-connected graph keeps it 2-connected, find the broken step in a near-copy of Whitney's proof and build the graph that breaks it, and finish with a problem that names no technique, where you write the proof yourself.
Recap
- You can now: prove Whitney's theorem by induction on distance; prove the expansion lemma; restate 2-connectivity with cycles; define ears and ear decompositions; and prove that a graph is 2-connected exactly when it has one, from any starting cycle.
- Invariant: in Whitney's proof, the tail of after its last vertex on meets neither path; in the ear theorem, every stage of the construction is 2-connected.
- Complexity achieved: an ear decomposition is checked in ; finding cut vertices takes one depth-first search, , against searches by brute force.
- Failure mode: allowing an ear whose two ends coincide, and forgetting the hypothesis of at least 3 vertices ().
- In real software: NetworkX's
is_biconnectedandarticulation_pointsfind cut vertices with a depth-first search (the Hopcroft–Tarjan approach). - Retrieval: module 14 asked how many vertices must fail before a graph splits. In those terms, what is a 2-connected graph? (One with : no single vertex failure splits it.)
Check yourself
After the lab, the tutor will ask you to defend your work out loud:
- In the step of Whitney's proof, why is the case " lies on or " handled separately?
- In the proof of the ear theorem, where is 2-connectedness used, and what goes wrong in a graph with a cut vertex?
- Two copies of sharing one vertex: which ears can you add after the first copy, and why is none of them open?
Topic list modeled on the public syllabus of UIUC Math 412 (Graph Theory), which follows D. B. West, Introduction to Graph Theory, 2nd ed., Chapters 1–7. All lessons, proofs, examples, code and exercises here are original. This course is independent and not affiliated with or endorsed by the University of Illinois.