Paper I · Lean source

PathGraphKrylov.lean

Declared contract recorded Coverage and evidence

The cited release explicitly reports completion of its registered formal contract, under its exact hypotheses.

This viewer reads the retained source; it does not run Lean or assign new claim mappings.

Local imports (1)

KomorebiVerification/PathGraphKrylov.lean238 lines

Original source pathformal/current/KomorebiVerification/PathGraphKrylov.lean
Skip declarations and read code

Skip source text

1 import KomorebiVerification.MathlibImports
2 
3 /-!
4 # Endpoint Krylov bases for path graphs
5 
6 For the path with vertices `0, ..., n`, let `A` be its adjacency operator and
7 let `e₀` be the endpoint vector.  This file proves that the walk matrix whose
8 `k`th column is `A ^ k e₀` is upper triangular with diagonal equal to one.
9 Consequently its determinant is one over every commutative ring, the first
10 `n + 1` Krylov vectors span, and `e₀` is a cyclic vector for `A`.
11 
12 Writing the number of vertices as `n + 1` makes the endpoint available without
13 an extra nonemptiness hypothesis; thus the result covers every nonempty finite
14 path, including the one-vertex path.
15 -/
16 
17 set_option autoImplicit false
18 
19 namespace Komorebi.PathGraphKrylov
20 
21 universe u
22 
23 variable (R : Type u) [CommSemiring R]
24 variable (n : ℕ)
25 
26 /-- The contribution from the neighbor immediately to the left, when it exists. -/
27 def leftTerm (x : Fin (n + 1) → R) (i : Fin (n + 1)) : R :=
28   if _h : i = 0 then
29     0
30   else
31     x ⟨i.val - 1, lt_of_le_of_lt (Nat.sub_le i.val 1) i.isLt⟩
32 
33 /-- The contribution from the neighbor immediately to the right, when it exists. -/
34 def rightTerm (x : Fin (n + 1) → R) (i : Fin (n + 1)) : R :=
35   if h : i.val < n then x ⟨i.val + 1, Nat.succ_lt_succ h⟩ else 0
36 
37 /-- The shift which reads the neighbor immediately to the left. -/
38 def leftStep : Module.End R (Fin (n + 1) → R) :=
39   LinearMap.pi fun i ↦
40     if _h : i = 0 then
41       0
42     else
43       LinearMap.proj ⟨i.val - 1, lt_of_le_of_lt (Nat.sub_le i.val 1) i.isLt⟩
44 
45 /-- The shift which reads the neighbor immediately to the right. -/
46 def rightStep : Module.End R (Fin (n + 1) → R) :=
47   LinearMap.pi fun i ↦
48     if h : i.val < n then LinearMap.proj ⟨i.val + 1, Nat.succ_lt_succ h⟩ else 0
49 
50 /-- The adjacency operator of the path `0 - 1 - ... - n`. -/
51 def pathStep : Module.End R (Fin (n + 1) → R) :=
52   leftStep R n + rightStep R n
53 
54 @[simp]
55 theorem pathStep_apply (x : Fin (n + 1) → R) (i : Fin (n + 1)) :
56     pathStep R n x i = leftTerm R n x i + rightTerm R n x i :=
57   by
58     by_cases hLeft : i = 0
59     · subst i
60       by_cases hn : 0 < n <;>
61         simp [pathStep, leftStep, rightStep, leftTerm, rightTerm, hn]
62     · by_cases hRight : i.val < n <;>
63         simp [pathStep, leftStep, rightStep, leftTerm, rightTerm, hLeft, hRight]
64 
65 /-- The standard basis vector at the left endpoint. -/
66 def endpoint : Fin (n + 1) → R :=
67   fun i ↦ if i.val = 0 then 1 else 0
68 
69 /-- The recursively presented Krylov sequence `e₀, A e₀, A² e₀, ...`. -/
70 def krylov : ℕ → Fin (n + 1) → R
71   | 0 => endpoint R n
72   | k + 1 => pathStep R n (krylov k)
73 
74 @[simp]
75 theorem krylov_zero : krylov R n 0 = endpoint R n :=
76   rfl
77 
78 @[simp]
79 theorem krylov_succ (k : ℕ) :
80     krylov R n (k + 1) = pathStep R n (krylov R n k) :=
81   rfl
82 
83 /-- The recursive Krylov sequence really is given by powers of the adjacency operator. -/
84 theorem krylov_eq_pow (k : ℕ) :
85     krylov R n k = ((pathStep R n) ^ k) (endpoint R n) := by
86   induction k with
87   | zero => simp
88   | succ k ih =>
89       rw [krylov_succ, pow_succ', Module.End.mul_apply, ih]
90 
91 /-- A walk of length `k` from `0` cannot reach a vertex strictly beyond `k`. -/
92 theorem krylov_apply_eq_zero_of_lt (k : ℕ) (i : Fin (n + 1))
93     (hki : k < i.val) : krylov R n k i = 0 := by
94   induction k generalizing i with
95   | zero =>
96       simp only [krylov_zero, endpoint]
97       simp [Nat.ne_of_gt hki]
98   | succ k ih =>
99       rw [krylov_succ, pathStep_apply]
100       have hi : 0 < i.val := by omega
101       have hi0 : i ≠ 0 := Fin.ne_of_val_ne (by simpa using Nat.ne_of_gt hi)
102       let iLeft : Fin (n + 1) :=
103         ⟨i.val - 1, lt_of_le_of_lt (Nat.sub_le i.val 1) i.isLt⟩
104       have hLeft : k < iLeft.val := by
105         dsimp [iLeft]
106         omega
107       have hzLeft : krylov R n k iLeft = 0 := ih iLeft hLeft
108       by_cases hRight : i.val < n
109       · let iRight : Fin (n + 1) := ⟨i.val + 1, Nat.succ_lt_succ hRight⟩
110         have hRight' : k < iRight.val := by
111           dsimp [iRight]
112           omega
113         have hzRight : krylov R n k iRight = 0 := ih iRight hRight'
114         simp only [leftTerm, rightTerm, hi0, hRight, dite_true, dite_false,
115           iLeft, iRight, hzLeft, hzRight, add_zero]
116       · simp only [leftTerm, rightTerm, hi0, hRight, dite_false,
117           iLeft, hzLeft, add_zero]
118 
119 /-- There is exactly one length-`k` walk from `0` to vertex `k`. -/
120 theorem krylov_diagonal (k : ℕ) (hk : k < n + 1) :
121     krylov R n k ⟨k, hk⟩ = 1 := by
122   induction k with
123   | zero => simp [krylov_zero, endpoint]
124   | succ k ih =>
125       rw [krylov_succ, pathStep_apply]
126       have hk' : k < n + 1 := by omega
127       have hne : (⟨k + 1, hk⟩ : Fin (n + 1)) ≠ 0 :=
128         Fin.ne_of_val_ne (by simp)
129       by_cases hRight : k + 1 < n
130       · let iRight : Fin (n + 1) :=
131           ⟨(k + 1) + 1, Nat.succ_lt_succ hRight⟩
132         have hlt : k < iRight.val := by
133           dsimp [iRight]
134           omega
135         have hzRight : krylov R n k iRight = 0 :=
136           krylov_apply_eq_zero_of_lt R n k iRight hlt
137         simp only [leftTerm, rightTerm, hne, hRight, dite_true, dite_false,
138           Nat.add_sub_cancel, ih hk', iRight, hzRight, add_zero]
139       · simp only [leftTerm, rightTerm, hne, hRight, dite_false,
140           Nat.add_sub_cancel, ih hk', add_zero]
141 
142 /-- The matrix of the path adjacency operator in the standard coordinate basis. -/
143 noncomputable def pathAdjacency : Matrix (Fin (n + 1)) (Fin (n + 1)) R :=
144   LinearMap.toMatrix (Pi.basisFun R (Fin (n + 1)))
145     (Pi.basisFun R (Fin (n + 1))) (pathStep R n)
146 
147 /-- Matrix multiplication by `pathAdjacency` is exactly `pathStep`. -/
148 theorem pathAdjacency_mulVec (x : Fin (n + 1) → R) :
149     (pathAdjacency R n).mulVec x = pathStep R n x := by
150   have h := LinearMap.congr_fun
151     (Matrix.toLin_toMatrix (Pi.basisFun R (Fin (n + 1)))
152       (Pi.basisFun R (Fin (n + 1))) (pathStep R n)) x
153   simpa only [pathAdjacency, Matrix.toLin_eq_toLin', Matrix.toLin'_apply] using h
154 
155 /-- Matrix powers of the adjacency matrix give the same Krylov vectors. -/
156 theorem pathAdjacency_pow_mulVec_endpoint (k : ℕ) :
157     ((pathAdjacency R n) ^ k).mulVec (endpoint R n) = krylov R n k := by
158   induction k with
159   | zero => simp [krylov_zero]
160   | succ k ih =>
161       rw [pow_succ', ← Matrix.mulVec_mulVec, ih, pathAdjacency_mulVec,
162         ← krylov_succ]
163 
164 /-- The walk matrix: column `k` is `A ^ k e₀`. -/
165 noncomputable def walkMatrix : Matrix (Fin (n + 1)) (Fin (n + 1)) R :=
166   fun i k ↦ ((pathAdjacency R n) ^ k.val).mulVec (endpoint R n) i
167 
168 theorem walkMatrix_apply (i k : Fin (n + 1)) :
169     walkMatrix R n i k = krylov R n k.val i := by
170   rw [walkMatrix, pathAdjacency_pow_mulVec_endpoint]
171 
172 /-- Entries below the diagonal of the walk matrix vanish. -/
173 theorem walkMatrix_apply_eq_zero_of_lt (i k : Fin (n + 1)) (hki : k < i) :
174     walkMatrix R n i k = 0 := by
175   rw [walkMatrix_apply]
176   exact krylov_apply_eq_zero_of_lt R n k.val i hki
177 
178 /-- Every diagonal entry of the walk matrix is one. -/
179 @[simp]
180 theorem walkMatrix_diagonal (i : Fin (n + 1)) :
181     walkMatrix R n i i = 1 := by
182   rw [walkMatrix_apply]
183   exact krylov_diagonal R n i.val i.isLt
184 
185 /-- The endpoint walk matrix is upper triangular. -/
186 theorem walkMatrix_isUpperTriangular :
187     (walkMatrix R n).IsUpperTriangular := by
188   intro i k hki
189   exact walkMatrix_apply_eq_zero_of_lt R n i k hki
190 
191 section CommRing
192 
193 variable {R : Type u} [CommRing R]
194 
195 /-- The endpoint walk matrix is unitriangular, hence has determinant one. -/
196 @[simp]
197 theorem walkMatrix_det : (walkMatrix R n).det = 1 := by
198   rw [Matrix.det_of_isUpperTriangular (walkMatrix_isUpperTriangular R n)]
199   simp
200 
201 /-- The finite endpoint Krylov family spans the whole coordinate module. -/
202 theorem krylov_span_eq_top :
203     Submodule.span R (Set.range fun k : Fin (n + 1) ↦ krylov R n k.val) = ⊤ := by
204   have hdet : IsUnit (walkMatrix R n).det := by
205     rw [walkMatrix_det]
206     exact isUnit_one
207   have hrange : LinearMap.range (Matrix.toLin' (walkMatrix R n)) = ⊤ := by
208     rw [← Matrix.toLin_eq_toLin']
209     exact Matrix.range_toLin_eq_top (Pi.basisFun R (Fin (n + 1)))
210       (walkMatrix R n) hdet
211   rw [Matrix.range_toLin'] at hrange
212   have hcol : (walkMatrix R n).col =
213       (fun k : Fin (n + 1) ↦ krylov R n k.val) := by
214     funext k i
215     exact walkMatrix_apply R n i k
216   rwa [hcol] at hrange
217 
218 /-- A vector is cyclic for an operator when the span of all of its iterates is the top module. -/
219 def IsCyclic (T : Module.End R (Fin (n + 1) → R))
220     (x : Fin (n + 1) → R) : Prop :=
221   Submodule.span R (Set.range fun k : ℕ ↦ (T ^ k) x) = ⊤
222 
223 /-- The left endpoint is cyclic for the path adjacency operator. -/
224 theorem endpoint_isCyclic :
225     IsCyclic (R := R) n (pathStep R n) (endpoint R n) := by
226   rw [IsCyclic]
227   apply le_antisymm le_top
228   rw [← krylov_span_eq_top (R := R) n]
229   apply Submodule.span_mono
230   rintro _ ⟨k, rfl⟩
231   refine ⟨k.val, ?_⟩
232   exact (krylov_eq_pow R n k.val).symm
233 
234 end CommRing
235 
236 end Komorebi.PathGraphKrylov
237 
238 #print axioms Komorebi.PathGraphKrylov.endpoint_isCyclic

Back to source controls

Original file and source record

This copy matches the recorded source file. Its publication here does not change the work’s review status.

SHA-256: 8c2390db3155899b3ab9c6d80da3037a815fa0d06d67ff1bb93c6a6e2dcb7f4f

Original source on GitHub

Back to Paper I: Typed Operator Systems, Seed Rank, and Exact Packet Coordinates