Math for Causal Inference

Day 46. Graph Basics & Directed Acyclic Graphs

The vocabulary of causal graphs (nodes, arrows, paths, parents, ancestors, descendants), acyclicity and topological orders, and what an arrow, and a missing arrow, claims about the world.

Video coming soon
Learning outcomes
  • ●Read off parents, children, ancestors and descendants from a DAG.
  • ●Decide whether a directed graph is acyclic and find a topological order.
  • ●Use powers of the adjacency matrix to count directed paths.
  • ●Translate an economic or health story into a causal DAG and list the assumptions it encodes.
2-HOUR SESSION PLAN
Theory 25′Warm-up (1–5) 20′Proofs (6–10) 35′Applied (11–15) 25′Python & Lab 15′
Colab notebook (.ipynb) Jump to the simulator

Theory

Why graphs?

Phase 3 asked whether treatment is as good as random given XX (unconfoundedness). It never said which XX. Causal graphs answer that question by drawing the assumptions about how variables cause each other, then reading off which comparisons are valid. Phase 4 builds that machinery.

Directed graphs

A directed graph G=(V,E)G = (V, E) has a set of nodes VV (variables) and a set of directed edges EE, written A→BA \to B.

  • If A→BA \to B, then AA is a parent of BB and BB is a child of AA. We write pa⁡(B)\operatorname{pa}(B) for the parents of BB.
  • A path is a sequence of distinct nodes, each adjacent to the next, ignoring arrow directions: A→B←CA \to B \leftarrow C is a path from AA to CC.
  • A directed (causal) path follows the arrows: A→B→CA \to B \to C.
  • AA is an ancestor of BB if there is a directed path from AA to BB; then BB is a descendant of AA. By convention every node is its own ancestor and descendant.
  • A cycle is a directed path from a node back to itself: A→B→C→AA \to B \to C \to A.

DAGs

A directed acyclic graph (DAG) has no directed cycles. Equivalent characterisation:

G is acyclic  ⟺  its nodes can be ordered V1,…,Vp so that every edge points forward (Vi→Vj⇒i<j).G \text{ is acyclic} \iff \text{its nodes can be ordered } V_1, \dots, V_p \text{ so that every edge points forward } (V_i \to V_j \Rightarrow i < j).

Such an ordering is a topological order. In a causal DAG it is a possible time order: causes before effects.

Causal DAGs

In a causal DAG, an arrow A→BA \to B means "AA is a direct cause of BB relative to the variables in the graph". Two rules:

  1. Missing arrows are the strong assumptions. Omitting A→BA \to B claims that AA has no direct effect on BB. Drawing an arrow only allows an effect; it may be zero.
  2. Common causes must be included. If any variable (observed or not) causes two variables in the graph, it must appear, perhaps as an unobserved node UU.

Example (returns to schooling): ability AA affects schooling SS and wages WW; family background FF affects AA and SS; schooling affects wages directly and through occupation OO:

F→A,F→S,A→S,A→W,S→O,S→W,O→W.F \to A, \quad F \to S, \quad A \to S, \quad A \to W, \quad S \to O, \quad S \to W, \quad O \to W.

The adjacency matrix

Number the nodes 1,…,p1, \dots, p. The adjacency matrix AA has Aij=1A_{ij} = 1 if i→ji \to j, else 0. Then

(Ak)ij=number of directed paths (walks) of length k from i to j.(A^k)_{ij} = \text{number of directed paths (walks) of length } k \text{ from } i \text{ to } j.

A graph is acyclic exactly when AA is nilpotent: Ap=0A^p = 0. In a topological order, AA is strictly upper triangular.

Time and feedback

Real systems have feedback (health ↔ income). A DAG handles it by indexing time: Healtht→Incomet+1→Healtht+2\text{Health}_{t} \to \text{Income}_{t+1} \to \text{Health}_{t+2} is acyclic even though the two variables affect each other.

Part 1 · Warm-up

Use this graph for Exercises 1–3: A→BA \to B, A→CA \to C, B→CB \to C, B→DB \to D, C→DC \to D, E→DE \to D.

Exercise 1 · Parents and children

List the parents and children of each node.

Show solution

Step 1. Read each arrow X→YX \to Y as "X is a parent of Y".

Step 2. Parents: pa⁡(A)=∅\operatorname{pa}(A) = \varnothing, pa⁡(B)={A}\operatorname{pa}(B) = \{A\}, pa⁡(C)={A,B}\operatorname{pa}(C) = \{A, B\}, pa⁡(D)={B,C,E}\operatorname{pa}(D) = \{B, C, E\}, pa⁡(E)=∅\operatorname{pa}(E) = \varnothing.

Step 3. Children: ch⁡(A)={B,C}\operatorname{ch}(A) = \{B, C\}, ch⁡(B)={C,D}\operatorname{ch}(B) = \{C, D\}, ch⁡(C)={D}\operatorname{ch}(C) = \{D\}, ch⁡(D)=∅\operatorname{ch}(D) = \varnothing, ch⁡(E)={D}\operatorname{ch}(E) = \{D\}.

Exercise 2 · Ancestors and descendants

Find the ancestors of DD and the descendants of BB.

Show solution

Step 1. Ancestors of DD: its parents B,C,EB, C, E, their parents AA (of BB and CC), and DD itself.

Step 2. So an⁡(D)={A,B,C,D,E}\operatorname{an}(D) = \{A, B, C, D, E\}.

Step 3. Descendants of BB: B→CB \to C, B→DB \to D, C→DC \to D.

Answer: an⁡(D)={A,B,C,D,E}\operatorname{an}(D) = \{A, B, C, D, E\} and de⁡(B)={B,C,D}\operatorname{de}(B) = \{B, C, D\}.

Exercise 3 · A topological order

Give two different topological orders.

Show solution

Step 1. Sources (no parents): AA and EE. Either can go first.

Step 2. After AA: BB (its only parent is placed), then CC (parents A,BA, B placed).

Step 3. DD needs B,C,EB, C, E placed, so it is last.

Answer: A,B,C,E,DA, B, C, E, D and E,A,B,C,DE, A, B, C, D (also A,E,B,C,DA, E, B, C, D, and others).

Exercise 4 · Counting paths with matrices

For A→BA \to B, A→CA \to C, B→CB \to C, B→DB \to D, C→DC \to D (order A,B,C,DA, B, C, D), compute A2A^2 and A3A^3 and count the directed paths from AA to DD.

Show solution

Step 1. The adjacency matrix is

A=(0110001100010000).\mathbf A = \begin{pmatrix} 0 & 1 & 1 & 0 \\ 0 & 0 & 1 & 1 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 0 & 0 \end{pmatrix}.

Step 2. Row AA of A2\mathbf A^2: (A2)AD=∑kAAkAkD=AABABD+AACACD=1+1=2(\mathbf A^2)_{AD} = \sum_k \mathbf A_{Ak}\mathbf A_{kD} = \mathbf A_{AB}\mathbf A_{BD} + \mathbf A_{AC}\mathbf A_{CD} = 1 + 1 = 2 (paths A→B→DA \to B \to D and A→C→DA \to C \to D).

Step 3. Also (A2)AC=AABABC=1(\mathbf A^2)_{AC} = \mathbf A_{AB}\mathbf A_{BC} = 1 and (A2)BD=ABCACD=1(\mathbf A^2)_{BD} = \mathbf A_{BC}\mathbf A_{CD} = 1; every other entry is 0.

Step 4. (A3)AD=∑k(A2)AkAkD=(A2)ACACD=1(\mathbf A^3)_{AD} = \sum_k (\mathbf A^2)_{Ak}\mathbf A_{kD} = (\mathbf A^2)_{AC}\mathbf A_{CD} = 1 (path A→B→C→DA \to B \to C \to D). All other entries of A3\mathbf A^3 are 0, and A4=0\mathbf A^4 = 0.

Answer: 2+1=32 + 1 = 3 directed paths from AA to DD.

Exercise 5 · Spot the cycle

Is the graph X→YX \to Y, Y→ZY \to Z, Z→WZ \to W, W→YW \to Y a DAG? If not, give the cycle and fix it by adding time indices.

Show solution

Step 1. Follow the arrows from YY: Y→Z→W→YY \to Z \to W \to Y. That is a directed cycle.

Step 2. So the graph is not a DAG and has no topological order.

Step 3. With time indices the loop unrolls: Yt→Zt→Wt→Yt+1→Zt+1→…Y_t \to Z_t \to W_t \to Y_{t+1} \to Z_{t+1} \to \dots, with X→YtX \to Y_t at each period.

Answer: not a DAG; the time-indexed graph is.

Part 2 · Proofs

Exercise 6 · Every DAG has a source

Prove that every finite DAG has at least one node with no parents.

Show solution

Step 1. Suppose not: every node has a parent.

Step 2. Start at any node V0V_0 and move to a parent V1V_1, then to a parent of V1V_1, and so on. This walk never stops, since every node has a parent.

Step 3. With pp nodes, after pp steps some node must repeat: Vi=VjV_i = V_j with i<ji < j.

Step 4. Reversed, the walk Vj→Vj−1→⋯→ViV_j \to V_{j-1} \to \dots \to V_i is a directed path from ViV_i back to itself: a cycle.

Step 5. That contradicts acyclicity, so a node with no parents exists. ■\blacksquare

Exercise 7 · DAGs have topological orders

Prove by induction on the number of nodes that every DAG has a topological order.

Show solution

Step 1. Base case: one node, no edges; the single node is an order.

Step 2. Induction step: let GG have pp nodes. By Exercise 6 it has a source SS.

Step 3. Delete SS and its edges. The remaining graph has p−1p - 1 nodes and is still acyclic (deleting edges cannot create cycles).

Step 4. By the induction hypothesis it has a topological order V1,…,Vp−1V_1, \dots, V_{p-1}.

Step 5. Put SS first: S,V1,…,Vp−1S, V_1, \dots, V_{p-1}. Edges out of SS point forward because SS is first; no edge points into SS; all other edges point forward by the hypothesis. ■\blacksquare

Exercise 8 · Orders imply acyclicity

Prove the converse: if a topological order exists, the graph has no directed cycle.

Show solution

Step 1. Let π(V)\pi(V) be the position of VV in the order. Every edge V→WV \to W has π(V)<π(W)\pi(V) < \pi(W).

Step 2. Along a directed path V0→V1→⋯→VkV_0 \to V_1 \to \dots \to V_k, positions strictly increase: π(V0)<π(V1)<⋯<π(Vk)\pi(V_0) < \pi(V_1) < \dots < \pi(V_k).

Step 3. A cycle would need Vk=V0V_k = V_0, so π(V0)<π(V0)\pi(V_0) < \pi(V_0): impossible. ■\blacksquare

Exercise 9 · Matrix powers count paths

Prove by induction that (Ak)ij(\mathbf A^k)_{ij} equals the number of directed walks of length kk from ii to jj.

Show solution

Step 1. Base case k=1k = 1: Aij=1\mathbf A_{ij} = 1 exactly when the one-edge walk i→ji \to j exists.

Step 2. Assume the claim for kk. A walk of length k+1k + 1 from ii to jj is a walk of length kk from ii to some node mm, followed by the edge m→jm \to j.

Step 3. Summing over the last intermediate node mm:

#{walks of length k+1}=∑m(Ak)im Amj=(Ak+1)ij.\#\{\text{walks of length } k + 1\} = \sum_m (\mathbf A^k)_{im}\,\mathbf A_{mj} = (\mathbf A^{k+1})_{ij}.

Step 4. In a DAG every walk is a path (a repeated node would create a cycle), so the entries count directed paths. ■\blacksquare

Exercise 10 · Acyclic means nilpotent

Prove that a graph with pp nodes is acyclic if and only if Ap=0\mathbf A^p = 0.

Show solution

Step 1. (⇒) In a DAG a directed path visits distinct nodes, so it has at most p−1p - 1 edges.

Step 2. Hence there are no walks of length pp, and by Exercise 9 every entry of Ap\mathbf A^p is 0.

Step 3. (⇐) If there is a cycle through node ii of length c≤pc \le p, then going around it repeatedly gives walks from ii to ii of every length that is a multiple of cc.

Step 4. Going around and then stopping partway gives walks of length exactly pp from ii to some node, so Ap≠0\mathbf A^p \ne 0. ■\blacksquare

Part 3 · Applied

Exercise 11 · Returns to schooling

Use the schooling DAG from the theory: F→AF \to A, F→SF \to S, A→SA \to S, A→WA \to W, S→OS \to O, S→WS \to W, O→WO \to W (family background, ability, schooling, occupation, wage). (a) List all directed paths from SS to WW. (b) List all other paths from SS to WW. (c) Which variables are descendants of schooling?

Show solution

Step 1. (a) Directed paths: S→WS \to W and S→O→WS \to O \to W. These carry the causal effect of schooling.

Step 2. (b) Paths that start with an arrow into SS: S←A→WS \leftarrow A \to W and S←F→A→WS \leftarrow F \to A \to W.

Step 3. Both run through ability, a common cause of schooling and wages; they generate correlation that is not causal (Day 52 calls them back-door paths).

Step 4. (c) Descendants of SS: SS, OO, WW.

Answer: occupation is a descendant (a mediator), so controlling for it would remove part of the effect of schooling (Day 53).

Exercise 12 · Assumptions hidden in missing arrows

A cardiology team draws: age →\to obesity, age →\to heart disease, obesity →\to diabetes, diabetes →\to heart disease, smoking →\to heart disease. List three missing arrows and the substantive claim each makes. Which is the least plausible?

Show solution

Step 1. No arrow obesity →\to heart disease: obesity affects heart disease only through diabetes.

Step 2. No arrow age →\to diabetes: age affects diabetes only through obesity.

Step 3. No arrow between age and smoking, and no common cause of them: smoking is unrelated to age (and to income, education...).

Step 4. The obesity claim is the least plausible: obesity raises blood pressure and cholesterol, which affect heart disease without diabetes.

Answer: every missing arrow is a testable or debatable claim; arguing about the graph means arguing about these claims.

Exercise 13 · Insurance and health spending

An analyst writes: health insurance →\to health spending →\to health →\to insurance (sicker people buy coverage). Explain the problem and redraw the graph for annual panel data.

Show solution

Step 1. Insurance →\to spending →\to health →\to insurance is a directed cycle, so it is not a DAG and the causal question "effect of insurance" is ill-posed in this graph.

Step 2. In reality the arrows act at different times: this year's health affects next year's insurance choice.

Step 3. Time-indexed DAG:

Healtht−1→Inst→Spendt→Healtht→Inst+1,Healtht−1→Healtht.\text{Health}_{t-1} \to \text{Ins}_t \to \text{Spend}_t \to \text{Health}_t \to \text{Ins}_{t+1}, \quad \text{Health}_{t-1} \to \text{Health}_t.

Answer: the unrolled graph is acyclic, and it shows that Healtht−1\text{Health}_{t-1} is a common cause of insurance and later health, which must be accounted for.

Exercise 14 · Paths from the minimum wage to poverty

A labour economist draws: minimum wage WW →\to employment EE, W→W \to hours HH, W→W \to earnings RR, E→RE \to R, H→RH \to R, R→R \to poverty PP, E→PE \to P. Count the directed paths from WW to PP by length using the adjacency matrix, and list them.

Show solution

Step 1. Order the nodes W,E,H,R,PW, E, H, R, P. Arrows out of each: W:E,H,RW: E, H, R; E:R,PE: R, P; H:RH: R; R:PR: P.

Step 2. Length 2: (A2)WP=∑kAWkAkP=AWEAEP+AWRARP=2(\mathbf A^2)_{WP} = \sum_k \mathbf A_{Wk}\mathbf A_{kP} = \mathbf A_{WE}\mathbf A_{EP} + \mathbf A_{WR}\mathbf A_{RP} = 2: paths W→E→PW \to E \to P and W→R→PW \to R \to P.

Step 3. Length 3: (A2)WR=AWEAER+AWHAHR=2(\mathbf A^2)_{WR} = \mathbf A_{WE}\mathbf A_{ER} + \mathbf A_{WH}\mathbf A_{HR} = 2, so (A3)WP=(A2)WR ARP=2(\mathbf A^3)_{WP} = (\mathbf A^2)_{WR}\,\mathbf A_{RP} = 2: paths W→E→R→PW \to E \to R \to P and W→H→R→PW \to H \to R \to P.

Step 4. Length 4: (A4)WP=0(\mathbf A^4)_{WP} = 0, since no path from WW has four edges.

Answer: 4 causal channels. The total effect of the minimum wage on poverty adds them up; a positive hourly wage effect can be offset by negative employment and hours effects.

Exercise 15 · Pre-treatment variables

In a job-training evaluation the DAG is: age →\to training TT, age →\to earnings YY, prior earnings P→TP \to T, P→YP \to Y, T→T \to certificate C→YC \to Y, T→YT \to Y, T→T \to job-search effort JJ, Y→Y \to savings SS. Which variables are descendants of TT, and which are not?

Show solution

Step 1. Follow arrows out of TT: T→CT \to C, T→JT \to J, T→YT \to Y, and then C→YC \to Y, Y→SY \to S.

Step 2. Descendants: {T,C,J,Y,S}\{T, C, J, Y, S\}.

Step 3. Non-descendants: age and PP.

Answer: age and prior earnings are pre-treatment variables, the natural candidates for adjustment. Certificate, job-search effort and savings are affected by training; Day 53 shows why adjusting for them is a mistake.

Verify in Python

import numpy as np
import networkx as nx

G = nx.DiGraph([("A", "B"), ("A", "C"), ("B", "C"), ("B", "D"), ("C", "D"), ("E", "D")])
print("acyclic:", nx.is_directed_acyclic_graph(G))
print("parents of D:", sorted(G.predecessors("D")), " ancestors of D:", sorted(nx.ancestors(G, "D")))
print("descendants of B:", sorted(nx.descendants(G, "B")))
print("all topological orders:", ["".join(o) for o in nx.all_topological_sorts(G)])

# Exercise 4: counting paths with matrix powers
H = nx.DiGraph([("A", "B"), ("A", "C"), ("B", "C"), ("B", "D"), ("C", "D")])
nodes = ["A", "B", "C", "D"]
M = nx.to_numpy_array(H, nodelist=nodes, dtype=int)
for k in (1, 2, 3, 4):
    print(f"A^{k}[A,D] =", np.linalg.matrix_power(M, k)[0, 3])

# Exercise 14: minimum wage -> poverty
W = nx.DiGraph([("W", "E"), ("W", "H"), ("W", "R"), ("E", "R"), ("H", "R"), ("R", "P"), ("E", "P")])
print([" -> ".join(p) for p in nx.all_simple_paths(W, "W", "P")])
M = nx.to_numpy_array(W, nodelist=list("WEHRP"), dtype=int)
print("paths by length:", [np.linalg.matrix_power(M, k)[0, 4] for k in (1, 2, 3, 4)])
print("nilpotent (A^5 = 0):", not np.linalg.matrix_power(M, 5).any())

# Exercise 5: a cycle
C = nx.DiGraph([("X", "Y"), ("Y", "Z"), ("Z", "W"), ("W", "Y")])
print("cycle:", nx.find_cycle(C))

Key takeaways

  • A causal DAG is a set of claims: each arrow allows a direct effect, each missing arrow rules one out, and every common cause must be drawn.
  • Acyclic ⇔ topological order exists ⇔ the adjacency matrix is nilpotent. Feedback is handled by indexing time.
  • Directed paths carry causal effects; other paths (through common causes) carry non-causal association. The next days make this precise.

Simulation Lab: Build a Causal DAG

Open full screen →

Click to add arrows to a returns-to-schooling graph; see parents, ancestors, cycles, topological orders and path counts.

FamilyAbilitySchoolingOccupationWageRegion
Acyclic. Topological order: Family → Region → Ability → Schooling → Occupation → Wage
parents of Schooling
Family, Ability
children of Schooling
Occupation, Wage
ancestors
Family, Ability
descendants
Occupation, Wage
ADJACENCY MATRIX (row → column)
FASOWR
F011000
A001010
S000110
O000010
W000000
R000000
Directed paths Schooling → Wage: 2 (Schooling → Occupation → Wage; Schooling → Wage)

Click one node, then another, to add or remove the arrow between them (click the same node twice to cancel). The panel reports parents, children, ancestors and descendants of the last node clicked, checks acyclicity and counts the causal paths from schooling to wages.

Day 45Day 47