5.4 The Lindström–Gessel–Viennot lemma
5.4.1 Definitions
We consider the infinite simple digraph with vertex set \(\mathbb {Z}^{2}\) (so the vertices are pairs of integers) and arcs
and
The arcs of the first form are called east-steps or right-steps; the arcs of the second form are called north-steps or up-steps.
The vertices of this digraph will be called lattice points or grid points or simply points.
The entire digraph will be denoted by \(\mathbb {Z}^{2}\) and called the integer lattice or integer grid.
Any path is uniquely determined by its starting point and its step sequence.
5.4.2 Helpers for lattice path infrastructure
Let \(p_1, p_2\) be two lattice paths and \(A\) a starting point. Then the endpoint of the concatenation \(p_1 \cdot p_2\) starting from \(A\) equals the endpoint of \(p_2\) starting from the endpoint of \(p_1\):
By induction on \(p_1\): applying the steps of \(p_1 \cdot p_2\) starting from \(A\) is the same as first applying the steps of \(p_1\) (reaching the endpoint of \(p_1\)) and then applying the steps of \(p_2\).
If a path \(p\) goes from \(A\) to \(B\), then for any \(n\), the first \(n\) steps of \(p\) form a path from \(A\) to the intermediate vertex \(M\), and the remaining steps form a path from \(M\) to \(B\).
Follows from the fact that \(p\) equals its first \(n\) steps concatenated with its remaining steps, together with Lemma 5.121.
If path \(h\) goes from \(A\) to \(v\) and path \(t\) goes from \(v\) to \(B\), then \(h \cdot t\) goes from \(A\) to \(B\).
By Lemma 5.121: \(\operatorname {endpoint}(h \cdot t, A) = \operatorname {endpoint}(t, \operatorname {endpoint}(h, A)) = \operatorname {endpoint}(t, v) = B\).
For any lattice path \(p\) starting at \(A\), the coordinate sum of the endpoint satisfies
where \(\ell (p)\) is the number of steps in \(p\).
By induction on \(p\): each step increases the coordinate sum by exactly \(1\).
The x-coordinate of the endpoint of a path \(p\) starting at \(A\) satisfies
By induction: each east-step increments the x-coordinate by \(1\), and each north-step leaves it unchanged.
For any two lattice points \(A, B\), the set of lattice paths from \(A\) to \(B\) is finite.
If \(B\) is not componentwise \(\ge A\), the set is empty. Otherwise, every path from \(A\) to \(B\) has a bounded number of steps (exactly \(\operatorname {cs}(B) - \operatorname {cs}(A)\)), and there are finitely many lists of bounded length over the two-element set \(\{ \text{east}, \text{north}\} \).
If a path \(p\) goes from \(A\) to \(B\), then \(\operatorname {x}(A) \le \operatorname {x}(B)\) and \(\operatorname {y}(A) \le \operatorname {y}(B)\).
By induction on the path: each east-step increments the x-coordinate and each north-step increments the y-coordinate.
5.4.3 Counting paths from \((a,b)\) to \((c,d)\)
Let \((a,b), (c,d) \in \mathbb {Z}^2\).
Observation 1: Each path from \((a,b)\) to \((c,d)\) has exactly \(c+d-a-b\) steps.
Observation 2: Each path from \((a,b)\) to \((c,d)\) has exactly \(c-a\) east-steps.
Observation 1: We define the coordinate sum of a point \((x,y) \in \mathbb {Z}^{2}\) to be \(x+y\), denoted \(\operatorname {cs}(x,y)\). The coordinate sum increases by exactly \(1\) along each arc. If the path visits vertices \(v_0, v_1, \ldots , v_n\) with \(v_0 = (a,b)\) and \(v_n = (c,d)\), then by the telescope principle,
Observation 2: The x-coordinate of a point increases by exactly \(1\) along each east-step and stays unchanged along each north-step. By telescoping on the x-coordinate:
Let \(\left( a,b\right) \in \mathbb {Z}^{2}\) and \(\left( c,d\right) \in \mathbb {Z}^{2}\) be two points. Then,
Observation 1 immediately shows that no path from \((a,b)\) to \((c,d)\) exists when \(c+d {\lt} a+b\) (it would need a negative number of steps), so the count is \(0\).
Otherwise, \(c + d \ge a + b\), so \(c+d-a-b \in \mathbb {N}\). Observations 1 and 2 show that every path from \((a,b)\) to \((c,d)\) has exactly \(c + d - a - b\) steps, of which exactly \(c - a\) are east-steps.
Observation 3: Let \(p\) be a path that starts at the point \((a,b)\) and has exactly \(c+d-a-b\) steps. Assume that exactly \(c-a\) of these steps are east-steps. Then, this path \(p\) ends at \((c,d)\).
(This follows by applying Observations 1 and 2 to the endpoint of \(p\) and comparing.)
Combining Observations 1, 2 and 3, the paths from \((a,b)\) to \((c,d)\) are precisely the paths that start at \((a,b)\) and have exactly \(c+d-a-b\) steps and exactly \(c-a\) east-steps. Such a path is uniquely determined by which \(c-a\) of its \(c+d-a-b\) steps are east-steps. By the bijection principle,
5.4.4 Path tuples, nipats and ipats
Let \(k\in \mathbb {N}\).
(a) A \(k\)-vertex means a \(k\)-tuple of lattice points.
(b) If \(\mathbf{A}=\left( A_{1},A_{2},\ldots ,A_{k}\right) \) is a \(k\)-vertex, and if \(\sigma \in S_{k}\) is a permutation, then \(\sigma \left( \mathbf{A}\right) \) shall denote the \(k\)-vertex \(\left( A_{\sigma \left( 1\right) },A_{\sigma \left( 2\right) },\ldots ,A_{\sigma \left( k\right) }\right) \).
(c) If \(\mathbf{A}=\left( A_{1},A_{2},\ldots ,A_{k}\right) \) and \(\mathbf{B}=\left( B_{1},B_{2},\ldots ,B_{k}\right) \) are two \(k\)-vertices, then a path tuple from \(\mathbf{A}\) to \(\mathbf{B}\) means a \(k\)-tuple \(\left( p_{1},p_{2},\ldots ,p_{k}\right) \), where each \(p_{i}\) is a path from \(A_{i}\) to \(B_{i}\).
(d) A path tuple \(\left( p_{1},p_{2},\ldots ,p_{k}\right) \) is said to be non-intersecting if no two of the paths \(p_{1},p_{2},\ldots ,p_{k}\) have any vertex in common. We abbreviate “non-intersecting path tuple” as nipat.
(e) A path tuple \(\left( p_{1},p_{2},\ldots ,p_{k}\right) \) is said to be intersecting if it is not non-intersecting (i.e., if two of its paths have a vertex in common). We abbreviate “intersecting path tuple” as ipat.
- paths : Fin k → LatticePath
The i-th path in the tuple
- valid (i : Fin k) : (self.paths i).isPathFromTo (A i) (B i)
Each path goes from A_i to B_i
- pt.isNonIntersecting = ∀ (i j : Fin k), i ≠ j → Disjoint (pt.verticesOf i) (pt.verticesOf j)
5.4.5 Helpers for path tuple finiteness
For any two \(k\)-vertices \(\mathbf{A}\), \(\mathbf{B}\), the set of path tuples from \(\mathbf{A}\) to \(\mathbf{B}\) is finite.
The set of path tuples embeds injectively into the product \(\prod _{i=1}^k \{ \text{paths from } A_i \text{ to } B_i\} \), which is finite by Lemma 5.126.
For any two \(k\)-vertices \(\mathbf{A}\), \(\mathbf{B}\), the set of nipats from \(\mathbf{A}\) to \(\mathbf{B}\) is finite.
Subset of the finite set of all path tuples (Lemma 5.131).
For any two \(k\)-vertices \(\mathbf{A}\), \(\mathbf{B}\), the set of ipats from \(\mathbf{A}\) to \(\mathbf{B}\) is finite.
Subset of the finite set of all path tuples (Lemma 5.131).
5.4.6 Crowded vertices and the minimum crowded path index
Let \(\mathbf{p} = (p_1, \ldots , p_k)\) be a path tuple.
(a) A vertex \(v\) is crowded in \(\mathbf{p}\) if \(v\) lies on at least two distinct paths \(p_i, p_j\) with \(i \ne j\).
(b) The crowded path indices of \(\mathbf{p}\) is the set of indices \(i\) such that \(p_i\) contains a vertex shared with some other path \(p_j\).
(c) For an ipat \(\mathbf{p}\), the minimum crowded path index is the smallest \(i\) in the crowded path indices.
(d) The crowded vertices on path \(i\) is the set of vertices on \(p_i\) that also appear on some other path.
- pt.crowdedPathIndices = {i : Fin k | ∃ (j : Fin k), i ≠ j ∧ ¬Disjoint (pt.verticesOf i) (pt.verticesOf j)}
- pt.minCrowdedPathIndex hip = pt.crowdedPathIndices.min' ⋯
- pt.crowdedVerticesOnPath i = {v : LGV1.LatticePoint | v ∈ pt.verticesOf i ∧ ∃ (j : Fin k), i ≠ j ∧ v ∈ pt.verticesOf j}
A path tuple is intersecting if and only if it has at least one crowded vertex. Equivalently, a path tuple is intersecting if and only if its set of crowded path indices is nonempty.
Immediate from the definitions: the negation of “all pairs of paths are disjoint” is equivalent to the existence of a shared vertex.
5.4.7 The LGV lemma for two paths
Signed path tuple infrastructure
Given four lattice points \(A, A', B, B'\):
(a) A signed path tuple is a pair of paths \((p_0, p_1)\) together with a sign flag indicating whether the destinations are \((B, B')\) (sign \(+1\)) or \((B', B)\) (sign \(-1\)).
(b) The path count matrix is the \(2 \times 2\) integer matrix with entries \(\# \mathrm{paths}(A_i \to B_j)\).
(c) The number of nipats from \((A, A')\) to \((B, B')\).
- path0 : LatticePath
The first path
- path1 : LatticePath
The second path
- toBB' : Bool
Whether this is to (B,B') (true) or (B',B) (false)
Path 0 goes from A to its destination
Path 1 goes from A' to its destination
- LGV1.pathMatrix2 A A' B B' = !![↑(LGV1.numPaths A B), ↑(LGV1.numPaths A B'); ↑(LGV1.numPaths A' B), ↑(LGV1.numPaths A' B')]
- LGV1.numNipats2 A A' B B' = (LGV1.nipatsFromTo ![A, A'] ![B, B']).ncard
The sets of signed path tuples (all, non-intersecting, and intersecting) are finite.
The signed path tuples inject into the product of two finite path sets times a two-element set. All three subsets are finite as subsets of this finite set.
First intersection point
Given an intersecting signed path tuple \((p_0, p_1)\), the first intersection index is the smallest index \(i\) such that the \(i\)-th vertex of \(p_0\) belongs to the vertices of \(p_1\). This index is strictly less than the number of vertices of \(p_0\).
- LGV1.firstIntersectionIdx spt _h = List.findIdx (fun (v : LGV1.LatticePoint) => decide (v ∈ spt.path1.vertices A')) (spt.path0.vertices A)
The existence of a shared vertex guarantees that a valid index is found before the end of the vertex list.
The first intersection point \(v\) of an intersecting signed path tuple \((p_0, p_1)\) satisfies:
\(v\) lies on \(p_0\) (at the first intersection index).
\(v\) lies on \(p_1\).
\(v\) is first: no vertex of \(p_0\) at an earlier index belongs to \(p_1\).
- LGV1.firstIntersection spt h = (spt.path0.vertices A)[LGV1.firstIntersectionIdx spt h]
Property (1) is by definition. Property (2) follows from the search semantics: the predicate tested is membership in \(p_1\)’s vertices. Property (3) follows from the minimality of the search: all earlier indices fail the predicate.
Splitting a path at a vertex \(v\) (by taking the first steps up to the index of \(v\) and the remaining steps after) produces a head ending at \(v\) and a tail starting at \(v\).
- One or more equations did not get rendered due to their size.
By Lemma 5.122, taking \(n\) steps gives a path from \(A\) to the intermediate point, and dropping \(n\) steps gives a path from that point to \(B\). The key fact is that the vertex at the split position equals \(v\), so the intermediate point is \(v\).
After applying the ipat involution (exchanging tails at the first intersection point \(v\)), the first intersection point of the resulting path tuple is still \(v\).
This is the key technical lemma for proving the involution is involutive. It relies on:
The prefix of \(p_0\) up to the split index is unchanged.
\(v\) is at the same index in the new path.
No earlier vertex of \(p_0\) lies in \(p_1\)’s vertices (by minimality).
Vertices at distinct positions on a lattice path are distinct (because the coordinate sum strictly increases).
The new path \(q_0 = \mathrm{head}(p_0) \cdot \mathrm{tail}(p_1)\) shares the same prefix as \(p_0\) up to the split index. The value \(v\) at this index is preserved. For \(j\) less than the split index, the \(j\)-th vertex of \(q_0\) equals the \(j\)-th vertex of \(p_0\), which is not among the new \(p_1\)’s vertices (the head of old \(p_1\) is a subset of old \(p_1\)’s vertices, and the tail of old \(p_0\) cannot contain an earlier vertex because coordinate sums strictly increase). Thus the search on \(q_0\) returns the same index.
The sign-reversing involution on intersecting path tuples for \(k = 2\).
Given an intersecting path tuple \((p, p')\) in the set \(\mathcal{X}\) of ipats from \((A, A')\) to \((B, B')\) or to \((B', B)\):
Since \((p, p') \in \mathcal{X}\), the paths \(p\) and \(p'\) have a vertex in common. Let \(v\) be the first one. (The first one on \(p\) or the first one on \(p'\)? These are the same, since our digraph is acyclic.) We call this vertex \(v\) the first intersection of \((p, p')\).
Split each path at \(v\) into a head (before \(v\)) and a tail (after \(v\)).
Exchange the tails: \(q = (\text{head of } p) \cup (\text{tail of } p')\) and \(q' = (\text{head of } p') \cup (\text{tail of } p)\).
Define \(f(p, p') = (q, q')\).
Then \(f\) is a sign-reversing involution on \(\mathcal{X}\) with no fixed points.
- One or more equations did not get rendered due to their size.
- LGV1.firstIntersection spt h = (spt.path0.vertices A)[LGV1.firstIntersectionIdx spt h]
- One or more equations did not get rendered due to their size.
If \((p, p')\) is an ipat from \((A, A')\) to \((B, B')\), then \(f(p, p') = (q, q')\) is an ipat from \((A, A')\) to \((B', B)\) (exchanging tails swaps the endpoints), and vice versa. Thus \(f\) is well-defined and sign-reversing.
To show \(f \circ f = \operatorname {id}\): after exchanging tails, the heads are unchanged, so \(v\) is still the first intersection point (Lemma 5.141). Exchanging tails again undoes the swap.
Since \(f\) is sign-reversing, it has no fixed points.
For any four lattice points \(A, A', B, B'\),
where \(\mathcal{X}\) is the set of intersecting path tuples and the sign is \(+1\) for path tuples to \((B, B')\) and \(-1\) for path tuples to \((B', B)\).
The sum over all signed path tuples decomposes as:
and the sum over nipats gives:
The first identity follows from the product rule: the product of path counts equals the count of path tuples.
The second identity is immediate from the definitions: among the nipats, those going to \((B,B')\) contribute \(+1\) each and those going to \((B',B)\) contribute \(-1\) each.
Let \(\left( A,A^{\prime }\right) \) and \(\left( B,B^{\prime }\right) \) be two \(2\)-vertices (i.e., let \(A,A^{\prime },B,B^{\prime }\) be four lattice points). Then,
We have
(by the product rule). By Lemma 5.144, the right hand side equals \(\sum _{(p,p') \in \mathcal{A}} \operatorname {sign}(p,p')\).
By Lemma 4.10, using the sign-reversing involution of Lemma 5.142 (which uses Lemma 5.143), we obtain
The right hand side equals
by Lemma 5.144.
5.4.8 The baby Jordan curve theorem
Let \(A\), \(B\), \(A^{\prime }\) and \(B^{\prime }\) be four lattice points satisfying
(That is, \(A'\) is weakly northwest of \(A\), and \(B'\) is weakly northwest of \(B\).)
Let \(p\) be any path from \(A\) to \(B^{\prime }\). Let \(p^{\prime }\) be any path from \(A^{\prime }\) to \(B\). Then, \(p\) and \(p^{\prime }\) have a vertex in common.
In particular, there are no nipats from \((A, A')\) to \((B', B)\).
The proof is by strong induction on \(\ell (p) + \ell (p')\), the sum of path lengths.
Case 3 (\(A' = A\)): Then \(A\) is a common vertex of both paths and we are done.
Case 1 (\(\operatorname {y}(A') {\gt} \operatorname {y}(A)\)): Let \(P\) be the second vertex of \(p\). Every vertex of the subpath \(r\) from \(P\) to \(B'\) is a vertex of \(p\), so \(r\) and \(p'\) have no vertex in common. Also \(\ell (r) + \ell (p') {\lt} \ell (p) + \ell (p')\). If \(\operatorname {y}(A') \ge \operatorname {y}(P)\), then we could apply the induction hypothesis to \(r\) and \(p'\), contradicting \(r \cap p' = \emptyset \). Hence \(\operatorname {y}(A') {\lt} \operatorname {y}(P)\), so \(\operatorname {y}(A') \le \operatorname {y}(P) - 1\). If the arc from \(A\) to \(P\) were an east-step, we would have \(\operatorname {y}(P) = \operatorname {y}(A)\), contradicting \(\operatorname {y}(A) \le \operatorname {y}(A') {\lt} \operatorname {y}(P)\). So the arc is a north-step, giving \(\operatorname {y}(P) = \operatorname {y}(A) + 1\), hence \(\operatorname {y}(A') \le \operatorname {y}(A)\), contradicting \(\operatorname {y}(A') {\gt} \operatorname {y}(A)\).
Case 2 (\(\operatorname {x}(A') {\lt} \operatorname {x}(A)\)): Symmetric to Case 1, looking at the first step of \(p'\) and using reflection across the line \(x = y\).
The consequence that there are no nipats from \((A, A')\) to \((B', B)\) follows immediately: if any pair of paths (one from \(A\) to \(B'\), one from \(A'\) to \(B\)) must intersect, then there can be no nipats from \((A, A')\) to \((B', B)\).
5.4.9 Log-concavity of binomial coefficients
Let \(n,k\in \mathbb {N}\). Then, \(\binom {n}{k}^{2}\geq \binom {n}{k-1}\cdot \binom {n}{k+1}\).
Combinatorial proof (from the source text, using LGV): Define four lattice points \(A=\left( 1,0\right) \) and \(A^{\prime }=\left( 0,1\right) \) and \(B=\left( k+1,n-k\right) \) and \(B^{\prime }=\left( k,n-k+1\right) \). Then, Proposition 5.145 yields
(Here, the second term is \(0\) by Proposition 5.146.) However, Proposition 5.129 yields
so the determinant is \(\binom {n}{k}^{2}-\binom {n}{k-1}\cdot \binom {n}{k+1}\geq 0\).
Lean formalization (algebraic proof): The Lean proof avoids the LGV machinery and proceeds purely algebraically, using the recurrences
These allow rewriting both sides after multiplying by \(k(k+1) {\gt} 0\). The inequality reduces to \((n-k+1)(k+1) \ge (n-k) \cdot k\), which holds because the difference is \(n + 1 \ge 0\). This proof is complete.
5.4.10 The LGV lemma for \(k\) paths
Definitions for general \(k\)
Let \(k \in \mathbb {N}\) and let \(\mathbf{A}, \mathbf{B}\) be two \(k\)-vertices.
(a) The path count matrix \(M\) is the \(k \times k\) integer matrix with entries \(M_{i,j} = \# \mathrm{paths}(A_i \to B_j)\).
(b) For \(\sigma \in S_k\), the number of nipats from \(\mathbf{A}\) to \(\sigma (\mathbf{B})\).
(c) For \(\sigma \in S_k\), the number of ipats from \(\mathbf{A}\) to \(\sigma (\mathbf{B})\).
- LGV1.pathMatrixK A B = Matrix.of fun (i j : Fin k) => ↑(LGV1.numPaths (A i) (B j))
- LGV1.numNipatsK A B σ = (LGV1.nipatsFromTo A (B.permute σ)).ncard
- LGV1.numIpatsK A B σ = (LGV1.ipatsFromTo A (B.permute σ)).ncard
Bridge between LGV1 and LGV2
The lattice step types in LGV1 and LGV2 are equivalent: the two representations of lattice steps are isomorphic, and this equivalence preserves the step application function. Lattice paths can be converted between representations, preserving endpoints and vertices.
- One or more equations did not get rendered due to their size.
- LGV1.latticePathToLatticePath' path = List.map (⇑LGV1.latticeStepEquiv) path
- LGV1.latticePath'ToLatticePath path = List.map (⇑LGV1.latticeStepEquiv.symm) path
Both types are two-element enumerations with the same constructors. The equivalence and endpoint preservation follow by case analysis.
The ipat count (defined via one representation of path tuples) equals the cardinality of the ipat set (defined via the other representation). This is the key bridge that allows the proof to invoke the sign-reversing involution from the weighted LGV formalization.
The proof constructs an equivalence between the two representations of intersecting path tuples, converting between list-of-steps and list-of-vertices representations, then verifies that the intersection property is preserved at each step.
Product rule and partition lemmas
Let \(k \in \mathbb {N}\) and let \(\mathbf{A}, \mathbf{B}\) be two \(k\)-vertices. Then:
(a) (Product rule) For any \(\sigma \in S_k\),
(b) (Partition) Each path tuple is either a nipat or an ipat, so
(c) (Determinant expansion)
(a) A path tuple from \(\mathbf{A}\) to \(\sigma (\mathbf{B})\) is just a tuple of independent choices (one path per index), so by the product rule the count is the product.
(b) Every path tuple is intersecting or not (classical logic); the sets are disjoint and their union is the set of all path tuples.
(c) This is the Leibniz formula \(\det (M) = \sum _\sigma (-1)^\sigma \prod _i M_{i,\sigma (i)}\).
The ipat cancellation lemma for general \(k\):
This is proved by a sign-reversing involution on pairs \((\sigma , \mathbf{p})\) where \(\mathbf{p}\) is an ipat from \(\mathbf{A}\) to \(\sigma (\mathbf{B})\). The involution:
A point \(u\) is crowded if it is contained in at least two of the paths \(p_1, p_2, \ldots , p_k\).
Pick the smallest \(i \in [k]\) such that \(p_i\) contains a crowded point.
Let \(v\) be the first crowded point on \(p_i\).
Let \(j {\gt} i\) be the largest index such that \(v \in p_j\).
Exchange the tails of \(p_i\) and \(p_j\) at \(v\).
Replace \(\sigma \) by \(\sigma \cdot t_{i,j}\) (composing with the transposition swapping \(i\) and \(j\)), which flips the sign (by Proposition 3.110 (b) and (d)).
The map \(f : (\sigma , \mathbf{p}) \mapsto (\sigma ', \mathbf{q})\) is an involution because the heads of \(p_i\) and \(p_j\) are unchanged, so the same \(v\), \(i\), \(j\) are selected again.
Let \(k\in \mathbb {N}\). Let \(\mathbf{A}=\left( A_{1},A_{2},\ldots ,A_{k}\right) \) and \(\mathbf{B}=\left( B_{1},B_{2},\ldots ,B_{k}\right) \) be two \(k\)-vertices. Then,
Define \(\mathcal{A}:=\left\{ \left( \sigma ,\mathbf{p}\right) \ \mid \ \sigma \in S_{k}\text{, and}\ \mathbf{p}\text{ is a path tuple from }\mathbf{A}\text{ to }\sigma \left( \mathbf{B}\right) \right\} \) and \(\mathcal{X}:=\left\{ \left( \sigma ,\mathbf{p}\right) \in \mathcal{A}\ \mid \ \mathbf{p}\text{ is intersecting}\right\} \). Set \(\operatorname {sign}\left( \sigma ,\mathbf{p}\right) :=\left( -1\right) ^{\sigma }\).
By Lemma 4.10 applied to the sign-reversing involution of Lemma 5.152,
The left hand side equals
(by Lemma 5.151(a) and the definition of the determinant), and the right hand side equals