Skip to content

Commit c085fa8

Browse files
committed
feat(LinearAlgebra/Basis): flag defined by a basis (#6269)
Also add supporting lemmas and golf some proofs. Based on a file from the Sphere Eversion Project.
1 parent 465dada commit c085fa8

File tree

4 files changed

+223
-73
lines changed

4 files changed

+223
-73
lines changed

Mathlib.lean

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,6 +1358,7 @@ import Mathlib.Data.Erased
13581358
import Mathlib.Data.FP.Basic
13591359
import Mathlib.Data.Fin.Basic
13601360
import Mathlib.Data.Fin.Fin2
1361+
import Mathlib.Data.Fin.FlagRange
13611362
import Mathlib.Data.Fin.Interval
13621363
import Mathlib.Data.Fin.SuccPred
13631364
import Mathlib.Data.Fin.Tuple.Basic
@@ -2152,6 +2153,7 @@ import Mathlib.LinearAlgebra.AnnihilatingPolynomial
21522153
import Mathlib.LinearAlgebra.Basic
21532154
import Mathlib.LinearAlgebra.Basis
21542155
import Mathlib.LinearAlgebra.Basis.Bilinear
2156+
import Mathlib.LinearAlgebra.Basis.Flag
21552157
import Mathlib.LinearAlgebra.Basis.VectorSpace
21562158
import Mathlib.LinearAlgebra.BilinearForm
21572159
import Mathlib.LinearAlgebra.BilinearForm.TensorProduct

Mathlib/Data/Fin/FlagRange.lean

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/-
2+
Copyright (c) 2023 Yury Kudryashov. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Yury Kudryashov
5+
-/
6+
import Mathlib.Order.Cover
7+
import Mathlib.Order.Chain
8+
import Mathlib.Data.Fin.Basic
9+
10+
/-!
11+
# Range of `f : Fin (n + 1) → α` as a `Flag`
12+
13+
Let `f : Fin (n + 1) → α` be an `(n + 1)`-tuple `(f₀, …, fₙ)` such that
14+
- `f₀ = ⊥` and `fₙ = ⊤`;
15+
- `fₖ₊₁` weakly covers `fₖ` for all `0 ≤ k < n`;
16+
this means that `fₖ ≤ fₖ₊₁` and there is no `c` such that `fₖ<c<fₖ₊₁`.
17+
Then the range of `f` is a maximal chain.
18+
19+
We formulate this result in terms of `IsMaxChain` and `Flag`.
20+
-/
21+
22+
open Set
23+
24+
variable {α : Type _} [PartialOrder α] [BoundedOrder α] {n : ℕ} {f : Fin (n + 1) → α}
25+
26+
/-- Let `f : Fin (n + 1) → α` be an `(n + 1)`-tuple `(f₀, …, fₙ)` such that
27+
- `f₀ = ⊥` and `fₙ = ⊤`;
28+
- `fₖ₊₁` weakly covers `fₖ` for all `0 ≤ k < n`;
29+
this means that `fₖ ≤ fₖ₊₁` and there is no `c` such that `fₖ<c<fₖ₊₁`.
30+
Then the range of `f` is a maximal chain. -/
31+
theorem IsMaxChain.range_fin_of_covby (h0 : f 0 = ⊥) (hlast : f (.last n) = ⊤)
32+
(hcovby : ∀ k : Fin n, f k.castSucc ⩿ f k.succ) :
33+
IsMaxChain (· ≤ ·) (range f) := by
34+
have hmono : Monotone f := Fin.monotone_iff_le_succ.2 fun k ↦ (hcovby k).1
35+
refine ⟨hmono.isChain_range, fun t htc hbt ↦ hbt.antisymm fun x hx ↦ ?_⟩
36+
rw [mem_range]; by_contra' h
37+
suffices ∀ k, f k < x by simpa [hlast] using this (.last _)
38+
intro k
39+
induction k using Fin.induction with
40+
| zero => simpa [h0, bot_lt_iff_ne_bot] using (h 0).symm
41+
| succ k ihk =>
42+
rw [range_subset_iff] at hbt
43+
exact (htc.lt_of_le (hbt k.succ) hx (h _)).resolve_right ((hcovby k).2 ihk)
44+
45+
/-- Let `f : Fin (n + 1) → α` be an `(n + 1)`-tuple `(f₀, …, fₙ)` such that
46+
- `f₀ = ⊥` and `fₙ = ⊤`;
47+
- `fₖ₊₁` weakly covers `fₖ` for all `0 ≤ k < n`;
48+
this means that `fₖ ≤ fₖ₊₁` and there is no `c` such that `fₖ<c<fₖ₊₁`.
49+
Then the range of `f` is a `Flag α`. -/
50+
@[simps]
51+
def Flag.rangeFin (f : Fin (n + 1) → α) (h0 : f 0 = ⊥) (hlast : f (.last n) = ⊤)
52+
(hcovby : ∀ k : Fin n, f k.castSucc ⩿ f k.succ) : Flag α where
53+
carrier := range f
54+
Chain' := (IsMaxChain.range_fin_of_covby h0 hlast hcovby).1
55+
max_chain' := (IsMaxChain.range_fin_of_covby h0 hlast hcovby).2
56+
57+
@[simp] theorem Flag.mem_rangeFin {x h0 hlast hcovby} :
58+
x ∈ rangeFin f h0 hlast hcovby ↔ ∃ k, f k = x :=
59+
Iff.rfl
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/-
2+
Copyright (c) 2023 Yury Kudryashov. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Yury Kudryashov, Patrick Massot
5+
-/
6+
import Mathlib.LinearAlgebra.Basis
7+
import Mathlib.Data.Fin.FlagRange
8+
9+
/-!
10+
# Flag of submodules defined by a basis
11+
12+
In this file we define `Basis.flag b k`, where `b : Basis (Fin n) R M`, `k : Fin (n + 1)`,
13+
to be the subspace spanned by the first `k` vectors of the basis `b`.
14+
15+
We also prove some lemmas about this definition.
16+
-/
17+
18+
open Set Submodule
19+
20+
namespace Basis
21+
22+
section Semiring
23+
24+
variable {R M : Type _} [Semiring R] [AddCommMonoid M] [Module R M] {n : ℕ}
25+
26+
/-- The subspace spanned by the first `k` vectors of the basis `b`. -/
27+
def flag (b : Basis (Fin n) R M) (k : Fin (n + 1)) : Submodule R M :=
28+
.span R <| b '' {i | i.castSucc < k}
29+
30+
@[simp]
31+
theorem flag_zero (b : Basis (Fin n) R M) : b.flag 0 = ⊥ := by simp [flag]
32+
33+
@[simp]
34+
theorem flag_last (b : Basis (Fin n) R M) : b.flag (.last n) = ⊤ := by
35+
simp [flag, Fin.castSucc_lt_last]
36+
37+
theorem flag_le_iff (b : Basis (Fin n) R M) {k p} :
38+
b.flag k ≤ p ↔ ∀ i : Fin n, i.castSucc < k → b i ∈ p :=
39+
span_le.trans ball_image_iff
40+
41+
theorem flag_succ (b : Basis (Fin n) R M) (k : Fin n) :
42+
b.flag k.succ = (R ∙ b k) ⊔ b.flag k.castSucc := by
43+
simp only [flag, Fin.castSucc_lt_castSucc_iff]
44+
simp [Fin.castSucc_lt_iff_succ_le, le_iff_eq_or_lt, setOf_or, image_insert_eq, span_insert]
45+
46+
theorem self_mem_flag (b : Basis (Fin n) R M) {i : Fin n} {k : Fin (n + 1)} (h : i.castSucc < k) :
47+
b i ∈ b.flag k :=
48+
subset_span <| mem_image_of_mem _ h
49+
50+
@[simp]
51+
theorem self_mem_flag_iff [Nontrivial R] (b : Basis (Fin n) R M) {i : Fin n} {k : Fin (n + 1)} :
52+
b i ∈ b.flag k ↔ i.castSucc < k :=
53+
b.self_mem_span_image
54+
55+
@[mono]
56+
theorem flag_mono (b : Basis (Fin n) R M) : Monotone b.flag :=
57+
Fin.monotone_iff_le_succ.2 fun k ↦ by rw [flag_succ]; exact le_sup_right
58+
59+
theorem isChain_range_flag (b : Basis (Fin n) R M) : IsChain (· ≤ ·) (range b.flag) :=
60+
b.flag_mono.isChain_range
61+
62+
@[mono]
63+
theorem flag_strictMono [Nontrivial R] (b : Basis (Fin n) R M) : StrictMono b.flag :=
64+
Fin.strictMono_iff_lt_succ.2 fun _ ↦ by simp [flag_succ]
65+
66+
end Semiring
67+
68+
section CommRing
69+
70+
variable {R M : Type _} [CommRing R] [AddCommGroup M] [Module R M] {n : ℕ}
71+
72+
@[simp]
73+
theorem flag_le_ker_coord_iff [Nontrivial R] (b : Basis (Fin n) R M) {k : Fin (n + 1)} {l : Fin n} :
74+
b.flag k ≤ LinearMap.ker (b.coord l) ↔ k ≤ l.castSucc := by
75+
simp [flag_le_iff, Finsupp.single_apply_eq_zero, imp_false, imp_not_comm]
76+
77+
theorem flag_le_ker_coord (b : Basis (Fin n) R M) {k : Fin (n + 1)} {l : Fin n}
78+
(h : k ≤ l.castSucc) : b.flag k ≤ LinearMap.ker (b.coord l) := by
79+
nontriviality R
80+
exact b.flag_le_ker_coord_iff.2 h
81+
82+
end CommRing
83+
84+
section DivisionRing
85+
86+
variable {K V : Type _} [DivisionRing K] [AddCommGroup V] [Module K V] {n : ℕ}
87+
88+
theorem flag_covby (b : Basis (Fin n) K V) (i : Fin n) :
89+
b.flag i.castSucc ⋖ b.flag i.succ := by
90+
rw [flag_succ]
91+
apply covby_span_singleton_sup
92+
simp
93+
94+
theorem flag_wcovby (b : Basis (Fin n) K V) (i : Fin n) :
95+
b.flag i.castSucc ⩿ b.flag i.succ :=
96+
(b.flag_covby i).wcovby
97+
98+
/-- Range of `Basis.flag` as a `Flag`. -/
99+
@[simps!]
100+
def toFlag (b : Basis (Fin n) K V) : Flag (Submodule K V) :=
101+
.rangeFin b.flag b.flag_zero b.flag_last b.flag_wcovby
102+
103+
@[simp]
104+
theorem mem_toFlag (b : Basis (Fin n) K V) {p : Submodule K V} : p ∈ b.toFlag ↔ ∃ k, b.flag k = p :=
105+
Iff.rfl
106+
107+
theorem isMaxChain_range_flag (b : Basis (Fin n) K V) : IsMaxChain (· ≤ ·) (range b.flag) :=
108+
b.toFlag.maxChain
109+
110+
end DivisionRing

Mathlib/LinearAlgebra/Span.lean

Lines changed: 52 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -484,20 +484,7 @@ theorem mem_span_singleton_trans {x y z : M} (hxy : x ∈ R ∙ y) (hyz : y ∈
484484
exact Submodule.subset_span_trans hxy hyz
485485
#align submodule.mem_span_singleton_trans Submodule.mem_span_singleton_trans
486486

487-
theorem mem_span_insert {y} :
488-
x ∈ span R (insert y s) ↔ ∃ a : R, ∃ z ∈ span R s, x = a • y + z := by
489-
simp only [← union_singleton, span_union, mem_sup, mem_span_singleton, exists_prop,
490-
exists_exists_eq_and]
491-
rw [exists_comm]
492-
simp only [eq_comm, add_comm, exists_and_left]
493-
#align submodule.mem_span_insert Submodule.mem_span_insert
494-
495-
theorem mem_span_pair {x y z : M} :
496-
z ∈ span R ({x, y} : Set M) ↔ ∃ a b : R, a • x + b • y = z := by
497-
simp_rw [mem_span_insert, mem_span_singleton, exists_exists_eq_and, eq_comm]
498-
#align submodule.mem_span_pair Submodule.mem_span_pair
499-
500-
theorem span_insert (x) (s : Set M) : span R (insert x s) = span R ({x} : Set M) ⊔ span R s := by
487+
theorem span_insert (x) (s : Set M) : span R (insert x s) = (R ∙ x) ⊔ span R s := by
501488
rw [insert_eq, span_union]
502489
#align submodule.span_insert Submodule.span_insert
503490

@@ -509,6 +496,16 @@ theorem span_span : span R (span R s : Set M) = span R s :=
509496
span_eq _
510497
#align submodule.span_span Submodule.span_span
511498

499+
theorem mem_span_insert {y} :
500+
x ∈ span R (insert y s) ↔ ∃ a : R, ∃ z ∈ span R s, x = a • y + z := by
501+
simp [span_insert, mem_sup, mem_span_singleton, eq_comm (a := x)]
502+
#align submodule.mem_span_insert Submodule.mem_span_insert
503+
504+
theorem mem_span_pair {x y z : M} :
505+
z ∈ span R ({x, y} : Set M) ↔ ∃ a b : R, a • x + b • y = z := by
506+
simp_rw [mem_span_insert, mem_span_singleton, exists_exists_eq_and, eq_comm]
507+
#align submodule.mem_span_pair Submodule.mem_span_pair
508+
512509
variable (R S s)
513510

514511
/-- If `R` is "smaller" ring than `S` then the span by `R` is smaller than the span by `S`. -/
@@ -548,37 +545,25 @@ theorem span_singleton_eq_bot : (R ∙ x) = ⊥ ↔ x = 0 :=
548545
theorem span_zero : span R (0 : Set M) = ⊥ := by rw [← singleton_zero, span_singleton_eq_bot]
549546
#align submodule.span_zero Submodule.span_zero
550547

548+
@[simp]
549+
theorem span_singleton_le_iff_mem (m : M) (p : Submodule R M) : (R ∙ m) ≤ p ↔ m ∈ p := by
550+
rw [span_le, singleton_subset_iff, SetLike.mem_coe]
551+
#align submodule.span_singleton_le_iff_mem Submodule.span_singleton_le_iff_mem
552+
551553
theorem span_singleton_eq_span_singleton {R M : Type*} [Ring R] [AddCommGroup M] [Module R M]
552554
[NoZeroSMulDivisors R M] {x y : M} : ((R ∙ x) = R ∙ y) ↔ ∃ z : Rˣ, z • x = y := by
553-
by_cases hx : x = 0
554-
· rw [hx, span_zero_singleton, eq_comm, span_singleton_eq_bot]
555-
exact ⟨fun hy => ⟨1, by rw [hy, smul_zero]⟩, fun ⟨_, hz⟩ => by rw [← hz, smul_zero]⟩
556-
by_cases hy : y = 0
557-
· rw [hy, span_zero_singleton, span_singleton_eq_bot]
558-
exact ⟨fun hx => ⟨1, by rw [hx, smul_zero]⟩, fun ⟨z, hz⟩ => (smul_eq_zero_iff_eq z).mp hz⟩
559555
constructor
560-
· intro hxy
561-
cases'
562-
mem_span_singleton.mp
563-
(by
564-
rw [hxy]
565-
apply mem_span_singleton_self) with
566-
v hv
567-
cases'
568-
mem_span_singleton.mp
569-
(by
570-
rw [← hxy]
571-
apply mem_span_singleton_self) with
572-
i hi
573-
have vi : v * i = 1 := by
574-
rw [← one_smul R y, ← hi, smul_smul] at hv
575-
exact smul_left_injective R hy hv
576-
have iv : i * v = 1 := by
577-
rw [← one_smul R x, ← hv, smul_smul] at hi
578-
exact smul_left_injective R hx hi
579-
exact ⟨⟨v, i, vi, iv⟩, hv⟩
580-
· rintro ⟨v, rfl⟩
581-
rw [span_singleton_group_smul_eq]
556+
· simp only [le_antisymm_iff, span_singleton_le_iff_mem, mem_span_singleton]
557+
rintro ⟨⟨a, rfl⟩, b, hb⟩
558+
rcases eq_or_ne y 0 with rfl | hy; · simp
559+
refine ⟨⟨b, a, ?_, ?_⟩, hb⟩
560+
· apply smul_left_injective R hy
561+
simpa only [mul_smul, one_smul]
562+
· rw [← hb] at hy
563+
apply smul_left_injective R (smul_ne_zero_iff.1 hy).2
564+
simp only [mul_smul, one_smul, hb]
565+
· rintro ⟨u, rfl⟩
566+
exact (span_singleton_group_smul_eq _ _ _).symm
582567
#align submodule.span_singleton_eq_span_singleton Submodule.span_singleton_eq_span_singleton
583568

584569
@[simp]
@@ -664,11 +649,6 @@ theorem iSup_induction' {ι : Sort*} (p : ι → Submodule R M) {C : ∀ x, (x
664649
refine' ⟨_, hadd _ _ _ _ Cx Cy⟩
665650
#align submodule.supr_induction' Submodule.iSup_induction'
666651

667-
@[simp]
668-
theorem span_singleton_le_iff_mem (m : M) (p : Submodule R M) : (R ∙ m) ≤ p ↔ m ∈ p := by
669-
rw [span_le, singleton_subset_iff, SetLike.mem_coe]
670-
#align submodule.span_singleton_le_iff_mem Submodule.span_singleton_le_iff_mem
671-
672652
theorem singleton_span_isCompactElement (x : M) :
673653
CompleteLattice.IsCompactElement (span R {x} : Submodule R M) := by
674654
rw [CompleteLattice.isCompactElement_iff_le_of_directed_sSup_le]
@@ -717,27 +697,7 @@ theorem submodule_eq_sSup_le_nonzero_spans (p : Submodule R M) :
717697
rwa [span_singleton_le_iff_mem]
718698
#align submodule.submodule_eq_Sup_le_nonzero_spans Submodule.submodule_eq_sSup_le_nonzero_spans
719699

720-
theorem lt_sup_iff_not_mem {I : Submodule R M} {a : M} : (I < I ⊔ R ∙ a) ↔ a ∉ I := by
721-
constructor
722-
· intro h
723-
by_contra akey
724-
have h1 : (I ⊔ R ∙ a) ≤ I := by
725-
simp only [sup_le_iff]
726-
constructor
727-
· exact le_refl I
728-
· exact (span_singleton_le_iff_mem a I).mpr akey
729-
have h2 := gt_of_ge_of_gt h1 h
730-
exact lt_irrefl I h2
731-
· intro h
732-
apply SetLike.lt_iff_le_and_exists.mpr
733-
constructor
734-
simp only [le_sup_left]
735-
use a
736-
constructor
737-
swap
738-
· assumption
739-
· have : (R ∙ a) ≤ I ⊔ R ∙ a := le_sup_right
740-
exact this (mem_span_singleton_self a)
700+
theorem lt_sup_iff_not_mem {I : Submodule R M} {a : M} : (I < I ⊔ R ∙ a) ↔ a ∉ I := by simp
741701
#align submodule.lt_sup_iff_not_mem Submodule.lt_sup_iff_not_mem
742702

743703
theorem mem_iSup {ι : Sort*} (p : ι → Submodule R M) {m : M} :
@@ -881,6 +841,28 @@ theorem comap_map_eq_self {f : F} {p : Submodule R M} (h : LinearMap.ker f ≤ p
881841

882842
end AddCommGroup
883843

844+
section DivisionRing
845+
846+
variable [DivisionRing K] [AddCommGroup V] [Module K V]
847+
848+
/-- There is no vector subspace between `p` and `(K ∙ x) ⊔ p`, `Wcovby` version. -/
849+
theorem wcovby_span_singleton_sup (x : V) (p : Submodule K V) : Wcovby p ((K ∙ x) ⊔ p) := by
850+
refine ⟨le_sup_right, fun q hpq hqp ↦ hqp.not_le ?_⟩
851+
rcases SetLike.exists_of_lt hpq with ⟨y, hyq, hyp⟩
852+
obtain ⟨c, z, hz, rfl⟩ : ∃ c : K, ∃ z ∈ p, c • x + z = y := by
853+
simpa [mem_sup, mem_span_singleton] using hqp.le hyq
854+
rcases eq_or_ne c 0 with rfl | hc
855+
· simp [hz] at hyp
856+
· have : x ∈ q
857+
· rwa [q.add_mem_iff_left (hpq.le hz), q.smul_mem_iff hc] at hyq
858+
simp [hpq.le, this]
859+
860+
/-- There is no vector subspace between `p` and `(K ∙ x) ⊔ p`, `Covby` version. -/
861+
theorem covby_span_singleton_sup {x : V} {p : Submodule K V} (h : x ∉ p) : Covby p ((K ∙ x) ⊔ p) :=
862+
by simpa, (wcovby_span_singleton_sup _ _).2
863+
864+
end DivisionRing
865+
884866
end Submodule
885867

886868
namespace LinearMap
@@ -1010,13 +992,10 @@ variable [Field K] [AddCommGroup V] [Module K V]
1010992

1011993
theorem span_singleton_sup_ker_eq_top (f : V →ₗ[K] K) {x : V} (hx : f x ≠ 0) :
1012994
(K ∙ x) ⊔ ker f = ⊤ :=
1013-
eq_top_iff.2 fun y _ =>
995+
top_unique fun y _ =>
1014996
Submodule.mem_sup.2
1015997
⟨(f y * (f x)⁻¹) • x, Submodule.mem_span_singleton.2 ⟨f y * (f x)⁻¹, rfl⟩,
1016-
⟨y - (f y * (f x)⁻¹) • x, by
1017-
rw [LinearMap.mem_ker, f.map_sub, f.map_smul, smul_eq_mul, mul_assoc, inv_mul_cancel hx,
1018-
mul_one, sub_self],
1019-
by simp only [add_sub_cancel'_right]⟩⟩
998+
⟨y - (f y * (f x)⁻¹) • x, by simp [hx]⟩⟩
1020999
#align linear_map.span_singleton_sup_ker_eq_top LinearMap.span_singleton_sup_ker_eq_top
10211000

10221001
end Field

0 commit comments

Comments
 (0)