Skip to content

Commit bd8664d

Browse files
Ruben-VandeVeldeParcly-TaxelChrisHughes24
committed
feat: port LinearAlgebra.StdBasis (#3264)
Co-authored-by: Jeremy Tan Jie Rui <reddeloostw@gmail.com> Co-authored-by: Chris Hughes <chrishughes24@gmail.com>
1 parent 5432803 commit bd8664d

File tree

2 files changed

+333
-0
lines changed

2 files changed

+333
-0
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,7 @@ import Mathlib.LinearAlgebra.Ray
12331233
import Mathlib.LinearAlgebra.SModEq
12341234
import Mathlib.LinearAlgebra.SesquilinearForm
12351235
import Mathlib.LinearAlgebra.Span
1236+
import Mathlib.LinearAlgebra.StdBasis
12361237
import Mathlib.LinearAlgebra.TensorProduct
12371238
import Mathlib.Logic.Basic
12381239
import Mathlib.Logic.Denumerable
Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
/-
2+
Copyright (c) 2017 Johannes Hölzl. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Johannes Hölzl
5+
6+
! This file was ported from Lean 3 source module linear_algebra.std_basis
7+
! leanprover-community/mathlib commit f2edd790f6c6e1d660515f76768f63cb717434d7
8+
! Please do not edit these lines, except to modify the commit id
9+
! if you have ported upstream changes.
10+
-/
11+
import Mathlib.Data.Matrix.Basis
12+
import Mathlib.LinearAlgebra.Basis
13+
import Mathlib.LinearAlgebra.Pi
14+
15+
/-!
16+
# The standard basis
17+
18+
This file defines the standard basis `Pi.basis (s : ∀ j, Basis (ι j) R (M j))`,
19+
which is the `Σ j, ι j`-indexed basis of `Π j, M j`. The basis vectors are given by
20+
`Pi.basis s ⟨j, i⟩ j' = LinearMap.stdBasis R M j' (s j) i = if j = j' then s i else 0`.
21+
22+
The standard basis on `R^η`, i.e. `η → R` is called `Pi.basisFun`.
23+
24+
To give a concrete example, `LinearMap.stdBasis R (λ (i : Fin 3), R) i 1`
25+
gives the `i`th unit basis vector in `R³`, and `Pi.basisFun R (Fin 3)` proves
26+
this is a basis over `Fin 3 → R`.
27+
28+
## Main definitions
29+
30+
- `LinearMap.stdBasis R M`: if `x` is a basis vector of `M i`, then
31+
`LinearMap.stdBasis R M i x` is the `i`th standard basis vector of `Π i, M i`.
32+
- `Pi.basis s`: given a basis `s i` for each `M i`, the standard basis on `Π i, M i`
33+
- `Pi.basisFun R η`: the standard basis on `R^η`, i.e. `η → R`, given by
34+
`Pi.basisFun R η i j = if i = j then 1 else 0`.
35+
- `Matrix.stdBasis R n m`: the standard basis on `Matrix n m R`, given by
36+
`Matrix.stdBasis R n m (i, j) i' j' = if (i, j) = (i', j') then 1 else 0`.
37+
38+
-/
39+
40+
41+
open Function Submodule
42+
43+
open BigOperators
44+
45+
namespace LinearMap
46+
47+
variable (R : Type _) {ι : Type _} [Semiring R] (φ : ι → Type _) [∀ i, AddCommMonoid (φ i)]
48+
[∀ i, Module R (φ i)] [DecidableEq ι]
49+
50+
/-- The standard basis of the product of `φ`. -/
51+
def stdBasis : ∀ i : ι, φ i →ₗ[R] ∀ i, φ i :=
52+
single
53+
#align linear_map.std_basis LinearMap.stdBasis
54+
55+
theorem stdBasis_apply (i : ι) (b : φ i) : stdBasis R φ i b = update (0 : (a : ι) → φ a) i b :=
56+
rfl
57+
#align linear_map.std_basis_apply LinearMap.stdBasis_apply
58+
59+
@[simp]
60+
theorem stdBasis_apply' (i i' : ι) : (stdBasis R (fun _x : ι => R) i) 1 i' = ite (i = i') 1 0 := by
61+
rw [LinearMap.stdBasis_apply, Function.update_apply, Pi.zero_apply]
62+
congr 1; rw [eq_iff_iff, eq_comm]
63+
#align linear_map.std_basis_apply' LinearMap.stdBasis_apply'
64+
65+
theorem coe_stdBasis (i : ι) : ⇑(stdBasis R φ i) = Pi.single i :=
66+
rfl
67+
#align linear_map.coe_std_basis LinearMap.coe_stdBasis
68+
69+
@[simp]
70+
theorem stdBasis_same (i : ι) (b : φ i) : stdBasis R φ i b i = b :=
71+
Pi.single_eq_same i b
72+
#align linear_map.std_basis_same LinearMap.stdBasis_same
73+
74+
theorem stdBasis_ne (i j : ι) (h : j ≠ i) (b : φ i) : stdBasis R φ i b j = 0 :=
75+
Pi.single_eq_of_ne h b
76+
#align linear_map.std_basis_ne LinearMap.stdBasis_ne
77+
78+
theorem stdBasis_eq_pi_diag (i : ι) : stdBasis R φ i = pi (diag i) := by
79+
ext (x j)
80+
-- Porting note: made types explicit
81+
convert (update_apply (R := R) (φ := φ) (ι := ι) 0 x i j _).symm
82+
rfl
83+
#align linear_map.std_basis_eq_pi_diag LinearMap.stdBasis_eq_pi_diag
84+
85+
theorem ker_stdBasis (i : ι) : ker (stdBasis R φ i) = ⊥ :=
86+
ker_eq_bot_of_injective <| Pi.single_injective _ _
87+
#align linear_map.ker_std_basis LinearMap.ker_stdBasis
88+
89+
theorem proj_comp_stdBasis (i j : ι) : (proj i).comp (stdBasis R φ j) = diag j i := by
90+
rw [stdBasis_eq_pi_diag, proj_pi]
91+
#align linear_map.proj_comp_std_basis LinearMap.proj_comp_stdBasis
92+
93+
theorem proj_stdBasis_same (i : ι) : (proj i).comp (stdBasis R φ i) = id :=
94+
LinearMap.ext <| stdBasis_same R φ i
95+
#align linear_map.proj_std_basis_same LinearMap.proj_stdBasis_same
96+
97+
theorem proj_stdBasis_ne (i j : ι) (h : i ≠ j) : (proj i).comp (stdBasis R φ j) = 0 :=
98+
LinearMap.ext <| stdBasis_ne R φ _ _ h
99+
#align linear_map.proj_std_basis_ne LinearMap.proj_stdBasis_ne
100+
101+
theorem supᵢ_range_stdBasis_le_infᵢ_ker_proj (I J : Set ι) (h : Disjoint I J) :
102+
(⨆ i ∈ I, range (stdBasis R φ i)) ≤ ⨅ i ∈ J, ker (proj i : (∀ i, φ i) →ₗ[R] φ i) := by
103+
refine' supᵢ_le fun i => supᵢ_le fun hi => range_le_iff_comap.2 _
104+
simp only [←ker_comp, eq_top_iff, SetLike.le_def, mem_ker, comap_infᵢ, mem_infᵢ]
105+
rintro b - j hj
106+
rw [proj_stdBasis_ne R φ j i, zero_apply]
107+
rintro rfl
108+
exact h.le_bot ⟨hi, hj⟩
109+
#align linear_map.supr_range_std_basis_le_infi_ker_proj LinearMap.supᵢ_range_stdBasis_le_infᵢ_ker_proj
110+
111+
theorem infᵢ_ker_proj_le_supᵢ_range_stdBasis {I : Finset ι} {J : Set ι} (hu : Set.univ ⊆ ↑I ∪ J) :
112+
(⨅ i ∈ J, ker (proj i : (∀ i, φ i) →ₗ[R] φ i)) ≤ ⨆ i ∈ I, range (stdBasis R φ i) :=
113+
SetLike.le_def.2
114+
(by
115+
intro b hb
116+
simp only [mem_infᵢ, mem_ker, proj_apply] at hb
117+
rw [←
118+
show (∑ i in I, stdBasis R φ i (b i)) = b by
119+
ext i
120+
rw [Finset.sum_apply, ← stdBasis_same R φ i (b i)]
121+
refine Finset.sum_eq_single i (fun j _ ne => stdBasis_ne _ _ _ _ ne.symm _) ?_
122+
intro hiI
123+
rw [stdBasis_same]
124+
exact hb _ ((hu trivial).resolve_left hiI)]
125+
exact sum_mem_bsupᵢ fun i _ => mem_range_self (stdBasis R φ i) (b i))
126+
#align linear_map.infi_ker_proj_le_supr_range_std_basis LinearMap.infᵢ_ker_proj_le_supᵢ_range_stdBasis
127+
128+
theorem supᵢ_range_stdBasis_eq_infᵢ_ker_proj {I J : Set ι} (hd : Disjoint I J)
129+
(hu : Set.univ ⊆ I ∪ J) (hI : Set.Finite I) :
130+
(⨆ i ∈ I, range (stdBasis R φ i)) = ⨅ i ∈ J, ker (proj i : (∀ i, φ i) →ₗ[R] φ i) := by
131+
refine' le_antisymm (supᵢ_range_stdBasis_le_infᵢ_ker_proj _ _ _ _ hd) _
132+
have : Set.univ ⊆ ↑hI.toFinset ∪ J := by rwa [hI.coe_toFinset]
133+
refine' le_trans (infᵢ_ker_proj_le_supᵢ_range_stdBasis R φ this) (supᵢ_mono fun i => _)
134+
rw [Set.Finite.mem_toFinset]
135+
#align linear_map.supr_range_std_basis_eq_infi_ker_proj LinearMap.supᵢ_range_stdBasis_eq_infᵢ_ker_proj
136+
137+
theorem supᵢ_range_stdBasis [Finite ι] : (⨆ i, range (stdBasis R φ i)) = ⊤ := by
138+
cases nonempty_fintype ι
139+
convert top_unique (infᵢ_emptyset.ge.trans <| infᵢ_ker_proj_le_supᵢ_range_stdBasis R φ _)
140+
· rename_i i
141+
exact ((@supᵢ_pos _ _ _ fun _ => range <| stdBasis R φ i) <| Finset.mem_univ i).symm
142+
· rw [Finset.coe_univ, Set.union_empty]
143+
#align linear_map.supr_range_std_basis LinearMap.supᵢ_range_stdBasis
144+
145+
theorem disjoint_stdBasis_stdBasis (I J : Set ι) (h : Disjoint I J) :
146+
Disjoint (⨆ i ∈ I, range (stdBasis R φ i)) (⨆ i ∈ J, range (stdBasis R φ i)) := by
147+
refine'
148+
Disjoint.mono (supᵢ_range_stdBasis_le_infᵢ_ker_proj _ _ _ _ <| disjoint_compl_right)
149+
(supᵢ_range_stdBasis_le_infᵢ_ker_proj _ _ _ _ <| disjoint_compl_right) _
150+
simp only [disjoint_iff_inf_le, SetLike.le_def, mem_infᵢ, mem_inf, mem_ker, mem_bot, proj_apply,
151+
funext_iff]
152+
rintro b ⟨hI, hJ⟩ i
153+
classical
154+
by_cases hiI : i ∈ I
155+
· by_cases hiJ : i ∈ J
156+
· exact (h.le_bot ⟨hiI, hiJ⟩).elim
157+
· exact hJ i hiJ
158+
· exact hI i hiI
159+
#align linear_map.disjoint_std_basis_std_basis LinearMap.disjoint_stdBasis_stdBasis
160+
161+
theorem stdBasis_eq_single {a : R} :
162+
(fun i : ι => (stdBasis R (fun _ : ι => R) i) a) = fun i : ι => ↑(Finsupp.single i a) :=
163+
funext fun i => (Finsupp.single_eq_pi_single i a).symm
164+
#align linear_map.std_basis_eq_single LinearMap.stdBasis_eq_single
165+
166+
end LinearMap
167+
168+
namespace Pi
169+
170+
open LinearMap
171+
172+
open Set
173+
174+
variable {R : Type _}
175+
176+
section Module
177+
178+
variable {η : Type _} {ιs : η → Type _} {Ms : η → Type _}
179+
180+
theorem linearIndependent_stdBasis [Ring R] [∀ i, AddCommGroup (Ms i)] [∀ i, Module R (Ms i)]
181+
[DecidableEq η] (v : ∀ j, ιs j → Ms j) (hs : ∀ i, LinearIndependent R (v i)) :
182+
LinearIndependent R fun ji : Σj, ιs j => stdBasis R Ms ji.1 (v ji.1 ji.2) := by
183+
have hs' : ∀ j : η, LinearIndependent R fun i : ιs j => stdBasis R Ms j (v j i) := by
184+
intro j
185+
exact (hs j).map' _ (ker_stdBasis _ _ _)
186+
apply linearIndependent_unionᵢ_finite hs'
187+
· intro j J _ hiJ
188+
simp only
189+
have h₀ :
190+
∀ j, span R (range fun i : ιs j => stdBasis R Ms j (v j i)) ≤
191+
LinearMap.range (stdBasis R Ms j) := by
192+
intro j
193+
rw [span_le, LinearMap.range_coe]
194+
apply range_comp_subset_range
195+
have h₁ :
196+
span R (range fun i : ιs j => stdBasis R Ms j (v j i)) ≤
197+
⨆ i ∈ ({j} : Set _), LinearMap.range (stdBasis R Ms i) := by
198+
rw [@supᵢ_singleton _ _ _ fun i => LinearMap.range (stdBasis R (Ms) i)]
199+
apply h₀
200+
have h₂ :
201+
(⨆ j ∈ J, span R (range fun i : ιs j => stdBasis R Ms j (v j i))) ≤
202+
⨆ j ∈ J, LinearMap.range (stdBasis R (fun j : η => Ms j) j) :=
203+
supᵢ₂_mono fun i _ => h₀ i
204+
have h₃ : Disjoint (fun i : η => i ∈ ({j} : Set _)) J := by
205+
convert Set.disjoint_singleton_left.2 hiJ using 0
206+
exact (disjoint_stdBasis_stdBasis _ _ _ _ h₃).mono h₁ h₂
207+
#align pi.linear_independent_std_basis Pi.linearIndependent_stdBasis
208+
209+
variable [Semiring R] [∀ i, AddCommMonoid (Ms i)] [∀ i, Module R (Ms i)]
210+
211+
variable [Fintype η]
212+
213+
section
214+
215+
open LinearEquiv
216+
217+
/-- `Pi.basis (s : ∀ j, Basis (ιs j) R (Ms j))` is the `Σ j, ιs j`-indexed basis on `Π j, Ms j`
218+
given by `s j` on each component.
219+
220+
For the standard basis over `R` on the finite-dimensional space `η → R` see `Pi.basisFun`.
221+
-/
222+
protected noncomputable def basis (s : ∀ j, Basis (ιs j) R (Ms j)) :
223+
Basis (Σj, ιs j) R (∀ j, Ms j) :=
224+
Basis.ofRepr
225+
((LinearEquiv.piCongrRight fun j => (s j).repr) ≪≫ₗ
226+
(Finsupp.sigmaFinsuppLEquivPiFinsupp R).symm)
227+
-- Porting note: was
228+
-- -- The `AddCommMonoid (Π j, Ms j)` instance was hard to find.
229+
-- -- Defining this in tactic mode seems to shake up instance search enough
230+
-- -- that it works by itself.
231+
-- refine Basis.ofRepr (?_ ≪≫ₗ (Finsupp.sigmaFinsuppLEquivPiFinsupp R).symm)
232+
-- exact LinearEquiv.piCongrRight fun j => (s j).repr
233+
#align pi.basis Pi.basis
234+
235+
@[simp]
236+
theorem basis_repr_stdBasis [DecidableEq η] (s : ∀ j, Basis (ιs j) R (Ms j)) (j i) :
237+
(Pi.basis s).repr (stdBasis R _ j (s j i)) = Finsupp.single ⟨j, i⟩ 1 := by
238+
ext ⟨j', i'⟩
239+
by_cases hj : j = j'
240+
· subst hj
241+
-- Porting note: needed to add more lemmas
242+
simp only [Pi.basis, LinearEquiv.trans_apply, Basis.repr_self, stdBasis_same,
243+
LinearEquiv.piCongrRight, Finsupp.sigmaFinsuppLEquivPiFinsupp_symm_apply,
244+
Basis.repr_symm_apply, LinearEquiv.coe_mk, ne_eq, Sigma.mk.inj_iff, heq_eq_eq, true_and]
245+
symm
246+
-- Porting note: `Sigma.mk.inj` not found in the following, replaced by `Sigma.mk.inj_iff.mp`
247+
exact
248+
Finsupp.single_apply_left
249+
(fun i i' (h : (⟨j, i⟩ : Σj, ιs j) = ⟨j, i'⟩) => eq_of_heq (Sigma.mk.inj_iff.mp h).2) _ _ _
250+
simp only [Pi.basis, LinearEquiv.trans_apply, Finsupp.sigmaFinsuppLEquivPiFinsupp_symm_apply,
251+
LinearEquiv.piCongrRight]
252+
dsimp
253+
rw [stdBasis_ne _ _ _ _ (Ne.symm hj), LinearEquiv.map_zero, Finsupp.zero_apply,
254+
Finsupp.single_eq_of_ne]
255+
rintro ⟨⟩
256+
contradiction
257+
#align pi.basis_repr_std_basis Pi.basis_repr_stdBasis
258+
259+
@[simp]
260+
theorem basis_apply [DecidableEq η] (s : ∀ j, Basis (ιs j) R (Ms j)) (ji) :
261+
Pi.basis s ji = stdBasis R _ ji.1 (s ji.1 ji.2) :=
262+
Basis.apply_eq_iff.mpr (by simp)
263+
#align pi.basis_apply Pi.basis_apply
264+
265+
@[simp]
266+
theorem basis_repr (s : ∀ j, Basis (ιs j) R (Ms j)) (x) (ji) :
267+
(Pi.basis s).repr x ji = (s ji.1).repr (x ji.1) ji.2 :=
268+
rfl
269+
#align pi.basis_repr Pi.basis_repr
270+
271+
end
272+
273+
section
274+
275+
variable (R η)
276+
277+
/-- The basis on `η → R` where the `i`th basis vector is `Function.update 0 i 1`. -/
278+
noncomputable def basisFun : Basis η R (∀ _ : η, R) :=
279+
Basis.ofEquivFun (LinearEquiv.refl _ _)
280+
#align pi.basis_fun Pi.basisFun
281+
282+
@[simp]
283+
theorem basisFun_apply [DecidableEq η] (i) : basisFun R η i = stdBasis R (fun _ : η => R) i 1 := by
284+
simp only [basisFun, Basis.coe_ofEquivFun, LinearEquiv.refl_symm, LinearEquiv.refl_apply,
285+
stdBasis_apply]
286+
#align pi.basis_fun_apply Pi.basisFun_apply
287+
288+
@[simp]
289+
theorem basisFun_repr (x : η → R) (i : η) : (Pi.basisFun R η).repr x i = x i := by simp [basisFun]
290+
#align pi.basis_fun_repr Pi.basisFun_repr
291+
292+
end
293+
294+
end Module
295+
296+
end Pi
297+
298+
namespace Matrix
299+
300+
variable (R : Type _) (m n : Type _) [Fintype m] [Fintype n] [Semiring R]
301+
302+
/-- The standard basis of `Matrix m n R`. -/
303+
noncomputable def stdBasis : Basis (m × n) R (Matrix m n R) :=
304+
Basis.reindex (Pi.basis fun _ : m => Pi.basisFun R n) (Equiv.sigmaEquivProd _ _)
305+
#align matrix.std_basis Matrix.stdBasis
306+
307+
variable {n m}
308+
309+
theorem stdBasis_eq_stdBasisMatrix (i : n) (j : m) [DecidableEq n] [DecidableEq m] :
310+
stdBasis R n m (i, j) = stdBasisMatrix i j (1 : R) := by
311+
-- Porting note: `simp` fails to apply `Pi.basis_apply`
312+
ext (a b)
313+
by_cases hi : i = a <;> by_cases hj : j = b
314+
· simp [stdBasis, hi, hj, Basis.coe_reindex, comp_apply, Equiv.sigmaEquivProd_symm_apply,
315+
StdBasisMatrix.apply_same]
316+
erw [Pi.basis_apply]
317+
simp
318+
· simp only [stdBasis, hi, Basis.coe_reindex, comp_apply, Equiv.sigmaEquivProd_symm_apply,
319+
hj, and_false, not_false_iff, StdBasisMatrix.apply_of_ne]
320+
erw [Pi.basis_apply]
321+
simp [hj]
322+
· simp only [stdBasis, hj, Basis.coe_reindex, comp_apply, Equiv.sigmaEquivProd_symm_apply,
323+
hi, and_true, not_false_iff, StdBasisMatrix.apply_of_ne]
324+
erw [Pi.basis_apply]
325+
simp [hi, hj, Ne.symm hi, LinearMap.stdBasis_ne]
326+
· simp only [stdBasis, Basis.coe_reindex, comp_apply, Equiv.sigmaEquivProd_symm_apply,
327+
hi, hj, and_self, not_false_iff, StdBasisMatrix.apply_of_ne]
328+
erw [Pi.basis_apply]
329+
simp [hi, hj, Ne.symm hj, Ne.symm hi, LinearMap.stdBasis_ne]
330+
#align matrix.std_basis_eq_std_basis_matrix Matrix.stdBasis_eq_stdBasisMatrix
331+
332+
end Matrix

0 commit comments

Comments
 (0)