Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit a1dda1e

Browse files
CPutzmergify[bot]
authored andcommitted
feat(linear_algebra/matrix): linear maps are linearly equivalent to matrices (#1310)
* linear map to matrix (WIP) * WIP * feat (linear_algebra/matrix): lin_equiv_matrix * feat (linear_algebra.basic): linear_equiv.arrow_congr, std_basis_eq_single * change unnecessary vector_space assumption for equiv_fun_basis to module * add docstrings and refactor * add docstrings * move instance to pi_instances * add docstrings + name change * remove duplicate instance
1 parent 2e76f36 commit a1dda1e

File tree

4 files changed

+184
-33
lines changed

4 files changed

+184
-33
lines changed

src/field_theory/finite_card.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace finite_field
1414
theorem card (p : ℕ) [char_p α p] : ∃ (n : ℕ+), nat.prime p ∧ fintype.card α = p^(n : ℕ) :=
1515
have hp : nat.prime p, from char_p.char_is_prime α p,
1616
have V : vector_space (zmodp p hp) α, from {..zmod.to_module'},
17-
let ⟨n, h⟩ := @vector_space.card_fintype' _ _ _ _ _ _ V _ _ in
17+
let ⟨n, h⟩ := @vector_space.card_fintype _ _ _ _ _ _ V _ _ in
1818
have hn : n > 0, from or.resolve_left (nat.eq_zero_or_pos n)
1919
(assume h0 : n = 0,
2020
have fintype.card α = 1, by rw[←nat.pow_zero (fintype.card _), ←h0]; exact h,

src/linear_algebra/basic.lean

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,12 +1242,33 @@ of_linear ((a:α) • 1 : β →ₗ β) (((a⁻¹ : units α) : α) • 1 : β
12421242
(by rw [smul_comp, comp_smul, smul_smul, units.mul_inv, one_smul]; refl)
12431243
(by rw [smul_comp, comp_smul, smul_smul, units.inv_mul, one_smul]; refl)
12441244

1245-
def congr_right (f : γ ≃ₗ[α] δ) : (β →ₗ[α] γ) ≃ₗ (β →ₗ δ) :=
1246-
of_linear
1247-
f.to_linear_map.congr_right
1248-
f.symm.to_linear_map.congr_right
1249-
(linear_map.ext $ λ _, linear_map.ext $ λ _, f.6 _)
1250-
(linear_map.ext $ λ _, linear_map.ext $ λ _, f.5 _)
1245+
/-- A linear isomorphism between the domains and codomains of two spaces of linear maps gives a
1246+
linear isomorphism between the two function spaces. -/
1247+
def arrow_congr {α β₁ β₂ γ₁ γ₂ : Sort*} [comm_ring α]
1248+
[add_comm_group β₁] [add_comm_group β₂] [add_comm_group γ₁] [add_comm_group γ₂]
1249+
[module α β₁] [module α β₂] [module α γ₁] [module α γ₂]
1250+
(e₁ : β₁ ≃ₗ[α] β₂) (e₂ : γ₁ ≃ₗ[α] γ₂) :
1251+
(β₁ →ₗ[α] γ₁) ≃ₗ[α] (β₂ →ₗ[α] γ₂) :=
1252+
{ to_fun := λ f, e₂.to_linear_map.comp $ f.comp e₁.symm.to_linear_map,
1253+
inv_fun := λ f, e₂.symm.to_linear_map.comp $ f.comp e₁.to_linear_map,
1254+
left_inv := λ f, by { ext x, unfold_coes,
1255+
change e₂.inv_fun (e₂.to_fun $ f.to_fun $ e₁.inv_fun $ e₁.to_fun x) = _,
1256+
rw [e₁.left_inv, e₂.left_inv] },
1257+
right_inv := λ f, by { ext x, unfold_coes,
1258+
change e₂.to_fun (e₂.inv_fun $ f.to_fun $ e₁.to_fun $ e₁.inv_fun x) = _,
1259+
rw [e₁.right_inv, e₂.right_inv] },
1260+
add := λ f g, by { ext x, change e₂.to_fun ((f + g) (e₁.inv_fun x)) = _,
1261+
rw [linear_map.add_apply, e₂.add], refl },
1262+
smul := λ c f, by { ext x, change e₂.to_fun ((c • f) (e₁.inv_fun x)) = _,
1263+
rw [linear_map.smul_apply, e₂.smul], refl } }
1264+
1265+
/-- If γ and δ are linearly isomorphic then the two spaces of linear maps from β into γ and
1266+
β into δ are linearly isomorphic. -/
1267+
def congr_right (f : γ ≃ₗ[α] δ) : (β →ₗ[α] γ) ≃ₗ (β →ₗ δ) := arrow_congr (linear_equiv.refl β) f
1268+
1269+
/-- If β and γ are linearly isomorphic then the two spaces of linear maps from β and γ to themselves
1270+
are linearly isomorphic. -/
1271+
def conj (e : β ≃ₗ[α] γ) : (β →ₗ[α] β) ≃ₗ[α] (γ →ₗ[α] γ) := arrow_congr e e
12511272

12521273
end comm_ring
12531274

@@ -1528,6 +1549,16 @@ begin
15281549
{ exact hI i hiI }
15291550
end
15301551

1552+
lemma std_basis_eq_single [decidable_eq α] {a : α} :
1553+
(λ (i : ι), (std_basis α (λ _ : ι, α) i) a) = λ (i : ι), (finsupp.single i a) :=
1554+
begin
1555+
ext i j,
1556+
rw [std_basis_apply, finsupp.single_apply],
1557+
split_ifs,
1558+
{ rw [h, function.update_same] },
1559+
{ rw [function.update_noteq (ne.symm h)], refl },
1560+
end
1561+
15311562
end
15321563

15331564
end pi

src/linear_algebra/basis.lean

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,22 @@ begin
776776
exact (submodule.mem_bot α).1 (subtype.mem x),
777777
end
778778

779+
open fintype
780+
variables [fintype ι] (h : is_basis α v)
781+
782+
/-- A module over α with a finite basis is linearly equivalent to functions from its basis to α. -/
783+
def equiv_fun_basis : β ≃ₗ[α] (ι → α) :=
784+
linear_equiv.trans (module_equiv_finsupp h)
785+
{ to_fun := finsupp.to_fun,
786+
add := λ x y, by ext; exact finsupp.add_apply,
787+
smul := λ x y, by ext; exact finsupp.smul_apply,
788+
..finsupp.equiv_fun_on_fintype }
789+
790+
theorem module.card_fintype [fintype α] [fintype β] :
791+
card β = (card α) ^ (card ι) :=
792+
calc card β = card (ι → α) : card_congr (equiv_fun_basis h).to_equiv
793+
... = card α ^ card ι : card_fun
794+
779795
end module
780796

781797
section vector_space
@@ -1006,27 +1022,15 @@ begin
10061022
end
10071023

10081024
open fintype
1009-
variables (h : is_basis α v)
1010-
1011-
local attribute [instance] submodule.module
1012-
1013-
noncomputable def equiv_fun_basis [fintype ι] : β ≃ (ι → α) :=
1014-
calc β ≃ (ι →₀ α) : (module_equiv_finsupp h).to_equiv
1015-
... ≃ (ι → α) : finsupp.equiv_fun_on_fintype
1016-
1017-
theorem vector_space.card_fintype [fintype ι] [fintype α] [fintype β] :
1018-
card β = (card α) ^ (card ι) :=
1019-
calc card β = card (ι → α) : card_congr (equiv_fun_basis h)
1020-
... = card α ^ card ι : card_fun
10211025

1022-
theorem vector_space.card_fintype' [fintype α] [fintype β] :
1026+
theorem vector_space.card_fintype [fintype α] [fintype β] :
10231027
∃ n : ℕ, card β = (card α) ^ n :=
10241028
begin
10251029
apply exists.elim (exists_is_basis α β),
10261030
intros b hb,
10271031
haveI := classical.dec_pred (λ x, x ∈ b),
10281032
use card b,
1029-
exact vector_space.card_fintype hb,
1033+
exact module.card_fintype hb,
10301034
end
10311035

10321036
end vector_space

src/linear_algebra/matrix.lean

Lines changed: 128 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,52 @@
11
/-
22
Copyright (c) 2019 Johannes Hölzl. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
4-
Author: Johannes Hölzl
4+
Author: Johannes Hölzl, Casper Putz
55
6-
Linear structures on function with finit support `α →₀ β` and multivariate polynomials.
6+
The equivalence between matrices and linear maps.
77
-/
8+
89
import data.matrix.basic
910
import linear_algebra.dimension linear_algebra.tensor_product
11+
12+
/-!
13+
14+
# Linear maps and matrices
15+
16+
This file defines the maps to send matrices to a linear map,
17+
and to send linear maps between modules with a finite bases
18+
to matrices. This defines a linear equivalence between linear maps
19+
between finite-dimensional vector spaces and matrices indexed by
20+
the respective bases.
21+
22+
Some results are proved about the linear map corresponding to a
23+
diagonal matrix (range, ker and rank).
24+
25+
## Main definitions
26+
27+
to_lin, to_matrix, lin_equiv_matrix
28+
29+
## Tags
30+
31+
linear_map, matrix, linear_equiv, diagonal
32+
33+
-/
34+
1035
noncomputable theory
1136

12-
open lattice set linear_map submodule
37+
open set submodule
1338

14-
namespace matrix
1539
universes u v
16-
variables {l m n o : Type u} [fintype l] [fintype m] [fintype n] [fintype o]
40+
variables {l m n : Type u} [fintype l] [fintype m] [fintype n]
1741

18-
instance [decidable_eq m] [decidable_eq n] (α) [fintype α] : fintype (matrix m n α) :=
19-
by unfold matrix; apply_instance
42+
namespace matrix
2043

21-
section ring
2244
variables {α : Type v} [comm_ring α]
45+
instance [decidable_eq m] [decidable_eq n] (α) [fintype α] : fintype (matrix m n α) :=
46+
by unfold matrix; apply_instance
2347

48+
/-- Evaluation of matrices gives a linear map from matrix m n α to
49+
linear maps (n → α) →ₗ[α] (m → α). -/
2450
def eval : (matrix m n α) →ₗ[α] ((n → α) →ₗ[α] (m → α)) :=
2551
begin
2652
refine linear_map.mk₂ α mul_vec _ _ _ _,
@@ -43,6 +69,8 @@ begin
4369
refl }
4470
end
4571

72+
/-- Evaluation of matrices gives a map from matrix m n α to
73+
linear maps (n → α) →ₗ[α] (m → α). -/
4674
def to_lin : matrix m n α → (n → α) →ₗ[α] (m → α) := eval.to_fun
4775

4876
lemma to_lin_add (M N : matrix m n α) : (M + N).to_lin = M.to_lin + N.to_lin :=
@@ -72,8 +100,96 @@ begin
72100
rw [mul_assoc]
73101
end
74102

75-
section
76-
open linear_map
103+
end matrix
104+
105+
namespace linear_map
106+
107+
variables {α : Type v} [comm_ring α]
108+
109+
/-- The linear map from linear maps (n → α) →ₗ[α] (m → α) to matrix m n α. -/
110+
def to_matrixₗ [decidable_eq n] : ((n → α) →ₗ[α] (m → α)) →ₗ[α] matrix m n α :=
111+
begin
112+
refine linear_map.mk (λ f i j, f (λ n, ite (j = n) 1 0) i) _ _,
113+
{ assume f g, simp only [add_apply], refl },
114+
{ assume f g, simp only [smul_apply], refl }
115+
end
116+
117+
/-- The map from linear maps (n → α) →ₗ[α] (m → α) to matrix m n α. -/
118+
def to_matrix [decidable_eq n] : ((n → α) →ₗ[α] (m → α)) → matrix m n α := to_matrixₗ.to_fun
119+
120+
end linear_map
121+
122+
section lin_equiv_matrix
123+
124+
variables {α : Type v} [comm_ring α] [decidable_eq n]
125+
126+
open finsupp matrix linear_map
127+
128+
/-- to_lin is the left inverse of to_matrix. -/
129+
lemma to_matrix_to_lin [decidable_eq α] {f : (n → α) →ₗ[α] (m → α)} :
130+
to_lin (to_matrix f) = f :=
131+
begin
132+
ext : 1,
133+
-- Show that the two sides are equal by showing that they are equal on a basis
134+
convert linear_eq_on (set.range _) _ (is_basis.mem_span (@pi.is_basis_fun α _ n _ _ _) _),
135+
assume e he,
136+
rw [@std_basis_eq_single α _ _ _ _ 1] at he,
137+
cases (set.mem_range.mp he) with i h,
138+
ext j,
139+
change finset.univ.sum (λ k, (f.to_fun (single k 1).to_fun) j * (e k)) = _,
140+
rw [←h],
141+
conv_lhs { congr, skip, funext,
142+
rw [mul_comm, ←smul_eq_mul, ←pi.smul_apply, ←linear_map.smul, single_apply],
143+
rw [show f.to_fun (ite (i = k) (1:α) 0 • (single k 1).to_fun) = ite (i = k) (f.to_fun ((single k 1).to_fun)) 0,
144+
{ split_ifs, { rw [one_smul] }, { rw [zero_smul], exact linear_map.map_zero f } }] },
145+
convert finset.sum_eq_single i _ _,
146+
{ rw [if_pos rfl], refl },
147+
{ assume _ _ hbi, rw [if_neg $ ne.symm hbi], refl },
148+
{ assume hi, exact false.elim (hi $ finset.mem_univ i) }
149+
end
150+
151+
/-- to_lin is the right inverse of to_matrix. -/
152+
lemma to_lin_to_matrix {M : matrix m n α} : to_matrix (to_lin M) = M :=
153+
begin
154+
ext,
155+
change finset.univ.sum (λ y, M i y * ite (j = y) 1 0) = M i j,
156+
have h1 : (λ y, M i y * ite (j = y) 1 0) = (λ y, ite (j = y) (M i y) 0),
157+
{ ext, split_ifs, exact mul_one _, exact ring.mul_zero _ },
158+
have h2 : finset.univ.sum (λ y, ite (j = y) (M i y) 0) = (finset.singleton j).sum (λ y, ite (j = y) (M i y) 0),
159+
{ refine (finset.sum_subset _ _).symm,
160+
{ intros _ H, rwa finset.mem_singleton.1 H, exact finset.mem_univ _ },
161+
{ exact λ _ _ H, if_neg (mt (finset.mem_singleton.2 ∘ eq.symm) H) } },
162+
rw [h1, h2, finset.sum_singleton],
163+
exact if_pos rfl
164+
end
165+
166+
/-- Linear maps (n → α) →ₗ[α] (m → α) are linearly equivalent to matrix m n α. -/
167+
def lin_equiv_matrix' [decidable_eq α] : ((n → α) →ₗ[α] (m → α)) ≃ₗ[α] matrix m n α :=
168+
{ to_fun := to_matrix,
169+
inv_fun := to_lin,
170+
right_inv := λ _, to_lin_to_matrix,
171+
left_inv := λ _, to_matrix_to_lin,
172+
add := to_matrixₗ.add,
173+
smul := to_matrixₗ.smul }
174+
175+
/-- Given a basis of two modules β and γ over a commutative ring α, we get a linear equivalence
176+
between linear maps β →ₗ γ and matrices over α indexed by the bases. -/
177+
def lin_equiv_matrix {ι κ β γ : Type*} [decidable_eq α]
178+
[add_comm_group β] [decidable_eq β] [module α β]
179+
[add_comm_group γ] [decidable_eq γ] [module α γ]
180+
[fintype ι] [decidable_eq ι] [fintype κ] [decidable_eq κ]
181+
{v₁ : ι → β} {v₂ : κ → γ} (hv₁ : is_basis α v₁) (hv₂ : is_basis α v₂) :
182+
(β →ₗ[α] γ) ≃ₗ[α] matrix κ ι α :=
183+
linear_equiv.trans (linear_equiv.arrow_congr (equiv_fun_basis hv₁) (equiv_fun_basis hv₂)) lin_equiv_matrix'
184+
185+
end lin_equiv_matrix
186+
187+
namespace matrix
188+
189+
section ring
190+
191+
variables {α : Type v} [comm_ring α]
192+
open linear_map matrix
77193

78194
lemma proj_diagonal [decidable_eq m] (i : m) (w : m → α) :
79195
(proj i).comp (to_lin (diagonal w)) = (w i) • proj i :=
@@ -89,14 +205,14 @@ begin
89205
{ subst h },
90206
{ rw [std_basis_ne α (λ_:n, α) _ _ (ne.symm h), _root_.mul_zero, _root_.mul_zero] }
91207
end
92-
end
93208

94209
end ring
95210

96211
section vector_space
212+
97213
variables {α : Type u} [discrete_field α] -- maybe try to relax the universe constraint
98214

99-
open linear_map
215+
open linear_map matrix
100216

101217
lemma rank_vec_mul_vec [decidable_eq n] (w : m → α) (v : n → α) :
102218
rank (vec_mul_vec w v).to_lin ≤ 1 :=

0 commit comments

Comments
 (0)