-
Notifications
You must be signed in to change notification settings - Fork 251
/
Dual.lean
1902 lines (1535 loc) · 80.7 KB
/
Dual.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/-
Copyright (c) 2019 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin, Fabian Glöckle, Kyle Miller
-/
import Mathlib.LinearAlgebra.FiniteDimensional
import Mathlib.LinearAlgebra.FreeModule.Finite.Basic
import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition
import Mathlib.LinearAlgebra.Projection
import Mathlib.LinearAlgebra.SesquilinearForm
import Mathlib.RingTheory.TensorProduct.Basic
import Mathlib.RingTheory.Ideal.LocalRing
#align_import linear_algebra.dual from "leanprover-community/mathlib"@"b1c017582e9f18d8494e5c18602a8cb4a6f843ac"
/-!
# Dual vector spaces
The dual space of an $R$-module $M$ is the $R$-module of $R$-linear maps $M \to R$.
## Main definitions
* Duals and transposes:
* `Module.Dual R M` defines the dual space of the `R`-module `M`, as `M →ₗ[R] R`.
* `Module.dualPairing R M` is the canonical pairing between `Dual R M` and `M`.
* `Module.Dual.eval R M : M →ₗ[R] Dual R (Dual R)` is the canonical map to the double dual.
* `Module.Dual.transpose` is the linear map from `M →ₗ[R] M'` to `Dual R M' →ₗ[R] Dual R M`.
* `LinearMap.dualMap` is `Module.Dual.transpose` of a given linear map, for dot notation.
* `LinearEquiv.dualMap` is for the dual of an equivalence.
* Bases:
* `Basis.toDual` produces the map `M →ₗ[R] Dual R M` associated to a basis for an `R`-module `M`.
* `Basis.toDual_equiv` is the equivalence `M ≃ₗ[R] Dual R M` associated to a finite basis.
* `Basis.dualBasis` is a basis for `Dual R M` given a finite basis for `M`.
* `Module.dual_bases e ε` is the proposition that the families `e` of vectors and `ε` of dual
vectors have the characteristic properties of a basis and a dual.
* Submodules:
* `Submodule.dualRestrict W` is the transpose `Dual R M →ₗ[R] Dual R W` of the inclusion map.
* `Submodule.dualAnnihilator W` is the kernel of `W.dualRestrict`. That is, it is the submodule
of `dual R M` whose elements all annihilate `W`.
* `Submodule.dualRestrict_comap W'` is the dual annihilator of `W' : Submodule R (Dual R M)`,
pulled back along `Module.Dual.eval R M`.
* `Submodule.dualCopairing W` is the canonical pairing between `W.dualAnnihilator` and `M ⧸ W`.
It is nondegenerate for vector spaces (`subspace.dualCopairing_nondegenerate`).
* `Submodule.dualPairing W` is the canonical pairing between `Dual R M ⧸ W.dualAnnihilator`
and `W`. It is nondegenerate for vector spaces (`Subspace.dualPairing_nondegenerate`).
* Vector spaces:
* `Subspace.dualLift W` is an arbitrary section (using choice) of `Submodule.dualRestrict W`.
## Main results
* Bases:
* `Module.dualBasis.basis` and `Module.dualBasis.coe_basis`: if `e` and `ε` form a dual pair,
then `e` is a basis.
* `Module.dualBasis.coe_dualBasis`: if `e` and `ε` form a dual pair,
then `ε` is a basis.
* Annihilators:
* `Module.dualAnnihilator_gc R M` is the antitone Galois correspondence between
`Submodule.dualAnnihilator` and `Submodule.dualConnihilator`.
* `LinearMap.ker_dual_map_eq_dualAnnihilator_range` says that
`f.dual_map.ker = f.range.dualAnnihilator`
* `LinearMap.range_dual_map_eq_dualAnnihilator_ker_of_subtype_range_surjective` says that
`f.dual_map.range = f.ker.dualAnnihilator`; this is specialized to vector spaces in
`LinearMap.range_dual_map_eq_dualAnnihilator_ker`.
* `Submodule.dualQuotEquivDualAnnihilator` is the equivalence
`Dual R (M ⧸ W) ≃ₗ[R] W.dualAnnihilator`
* `Submodule.quotDualCoannihilatorToDual` is the nondegenerate pairing
`M ⧸ W.dualCoannihilator →ₗ[R] Dual R W`.
It is an perfect pairing when `R` is a field and `W` is finite-dimensional.
* Vector spaces:
* `Subspace.dualAnnihilator_dualConnihilator_eq` says that the double dual annihilator,
pulled back ground `Module.Dual.eval`, is the original submodule.
* `Subspace.dualAnnihilator_gci` says that `module.dualAnnihilator_gc R M` is an
antitone Galois coinsertion.
* `Subspace.quotAnnihilatorEquiv` is the equivalence
`Dual K V ⧸ W.dualAnnihilator ≃ₗ[K] Dual K W`.
* `LinearMap.dualPairing_nondegenerate` says that `Module.dualPairing` is nondegenerate.
* `Subspace.is_compl_dualAnnihilator` says that the dual annihilator carries complementary
subspaces to complementary subspaces.
* Finite-dimensional vector spaces:
* `Module.evalEquiv` is the equivalence `V ≃ₗ[K] Dual K (Dual K V)`
* `Module.mapEvalEquiv` is the order isomorphism between subspaces of `V` and
subspaces of `Dual K (Dual K V)`.
* `Subspace.orderIsoFiniteCodimDim` is the antitone order isomorphism between
finite-codimensional subspaces of `V` and finite-dimensional subspaces of `Dual K V`.
* `Subspace.orderIsoFiniteDimensional` is the antitone order isomorphism between
subspaces of a finite-dimensional vector space `V` and subspaces of its dual.
* `Subspace.quotDualEquivAnnihilator W` is the equivalence
`(Dual K V ⧸ W.dualLift.range) ≃ₗ[K] W.dualAnnihilator`, where `W.dualLift.range` is a copy
of `Dual K W` inside `Dual K V`.
* `Subspace.quotEquivAnnihilator W` is the equivalence `(V ⧸ W) ≃ₗ[K] W.dualAnnihilator`
* `Subspace.dualQuotDistrib W` is an equivalence
`Dual K (V₁ ⧸ W) ≃ₗ[K] Dual K V₁ ⧸ W.dualLift.range` from an arbitrary choice of
splitting of `V₁`.
-/
noncomputable section
namespace Module
-- Porting note: max u v universe issues so name and specific below
universe uR uA uM uM' uM''
variable (R : Type uR) (A : Type uA) (M : Type uM)
variable [CommSemiring R] [AddCommMonoid M] [Module R M]
/-- The dual space of an R-module M is the R-module of linear maps `M → R`. -/
abbrev Dual :=
M →ₗ[R] R
#align module.dual Module.Dual
/-- The canonical pairing of a vector space and its algebraic dual. -/
def dualPairing (R M) [CommSemiring R] [AddCommMonoid M] [Module R M] :
Module.Dual R M →ₗ[R] M →ₗ[R] R :=
LinearMap.id
#align module.dual_pairing Module.dualPairing
@[simp]
theorem dualPairing_apply (v x) : dualPairing R M v x = v x :=
rfl
#align module.dual_pairing_apply Module.dualPairing_apply
namespace Dual
instance : Inhabited (Dual R M) := ⟨0⟩
/-- Maps a module M to the dual of the dual of M. See `Module.erange_coe` and
`Module.evalEquiv`. -/
def eval : M →ₗ[R] Dual R (Dual R M) :=
LinearMap.flip LinearMap.id
#align module.dual.eval Module.Dual.eval
@[simp]
theorem eval_apply (v : M) (a : Dual R M) : eval R M v a = a v :=
rfl
#align module.dual.eval_apply Module.Dual.eval_apply
variable {R M} {M' : Type uM'}
variable [AddCommMonoid M'] [Module R M']
/-- The transposition of linear maps, as a linear map from `M →ₗ[R] M'` to
`Dual R M' →ₗ[R] Dual R M`. -/
def transpose : (M →ₗ[R] M') →ₗ[R] Dual R M' →ₗ[R] Dual R M :=
(LinearMap.llcomp R M M' R).flip
#align module.dual.transpose Module.Dual.transpose
-- Porting note: with reducible def need to specify some parameters to transpose explicitly
theorem transpose_apply (u : M →ₗ[R] M') (l : Dual R M') : transpose (R := R) u l = l.comp u :=
rfl
#align module.dual.transpose_apply Module.Dual.transpose_apply
variable {M'' : Type uM''} [AddCommMonoid M''] [Module R M'']
-- Porting note: with reducible def need to specify some parameters to transpose explicitly
theorem transpose_comp (u : M' →ₗ[R] M'') (v : M →ₗ[R] M') :
transpose (R := R) (u.comp v) = (transpose (R := R) v).comp (transpose (R := R) u) :=
rfl
#align module.dual.transpose_comp Module.Dual.transpose_comp
end Dual
section Prod
variable (M' : Type uM') [AddCommMonoid M'] [Module R M']
/-- Taking duals distributes over products. -/
@[simps!]
def dualProdDualEquivDual : (Module.Dual R M × Module.Dual R M') ≃ₗ[R] Module.Dual R (M × M') :=
LinearMap.coprodEquiv R
#align module.dual_prod_dual_equiv_dual Module.dualProdDualEquivDual
@[simp]
theorem dualProdDualEquivDual_apply (φ : Module.Dual R M) (ψ : Module.Dual R M') :
dualProdDualEquivDual R M M' (φ, ψ) = φ.coprod ψ :=
rfl
#align module.dual_prod_dual_equiv_dual_apply Module.dualProdDualEquivDual_apply
end Prod
end Module
section DualMap
open Module
universe u v v'
variable {R : Type u} [CommSemiring R] {M₁ : Type v} {M₂ : Type v'}
variable [AddCommMonoid M₁] [Module R M₁] [AddCommMonoid M₂] [Module R M₂]
/-- Given a linear map `f : M₁ →ₗ[R] M₂`, `f.dualMap` is the linear map between the dual of
`M₂` and `M₁` such that it maps the functional `φ` to `φ ∘ f`. -/
def LinearMap.dualMap (f : M₁ →ₗ[R] M₂) : Dual R M₂ →ₗ[R] Dual R M₁ :=
-- Porting note: with reducible def need to specify some parameters to transpose explicitly
Module.Dual.transpose (R := R) f
#align linear_map.dual_map LinearMap.dualMap
lemma LinearMap.dualMap_eq_lcomp (f : M₁ →ₗ[R] M₂) : f.dualMap = f.lcomp R := rfl
-- Porting note: with reducible def need to specify some parameters to transpose explicitly
theorem LinearMap.dualMap_def (f : M₁ →ₗ[R] M₂) : f.dualMap = Module.Dual.transpose (R := R) f :=
rfl
#align linear_map.dual_map_def LinearMap.dualMap_def
theorem LinearMap.dualMap_apply' (f : M₁ →ₗ[R] M₂) (g : Dual R M₂) : f.dualMap g = g.comp f :=
rfl
#align linear_map.dual_map_apply' LinearMap.dualMap_apply'
@[simp]
theorem LinearMap.dualMap_apply (f : M₁ →ₗ[R] M₂) (g : Dual R M₂) (x : M₁) :
f.dualMap g x = g (f x) :=
rfl
#align linear_map.dual_map_apply LinearMap.dualMap_apply
@[simp]
theorem LinearMap.dualMap_id : (LinearMap.id : M₁ →ₗ[R] M₁).dualMap = LinearMap.id := by
ext
rfl
#align linear_map.dual_map_id LinearMap.dualMap_id
theorem LinearMap.dualMap_comp_dualMap {M₃ : Type*} [AddCommGroup M₃] [Module R M₃]
(f : M₁ →ₗ[R] M₂) (g : M₂ →ₗ[R] M₃) : f.dualMap.comp g.dualMap = (g.comp f).dualMap :=
rfl
#align linear_map.dual_map_comp_dual_map LinearMap.dualMap_comp_dualMap
/-- If a linear map is surjective, then its dual is injective. -/
theorem LinearMap.dualMap_injective_of_surjective {f : M₁ →ₗ[R] M₂} (hf : Function.Surjective f) :
Function.Injective f.dualMap := by
intro φ ψ h
ext x
obtain ⟨y, rfl⟩ := hf x
exact congr_arg (fun g : Module.Dual R M₁ => g y) h
#align linear_map.dual_map_injective_of_surjective LinearMap.dualMap_injective_of_surjective
/-- The `Linear_equiv` version of `LinearMap.dualMap`. -/
def LinearEquiv.dualMap (f : M₁ ≃ₗ[R] M₂) : Dual R M₂ ≃ₗ[R] Dual R M₁ where
__ := f.toLinearMap.dualMap
invFun := f.symm.toLinearMap.dualMap
left_inv φ := LinearMap.ext fun x ↦ congr_arg φ (f.right_inv x)
right_inv φ := LinearMap.ext fun x ↦ congr_arg φ (f.left_inv x)
#align linear_equiv.dual_map LinearEquiv.dualMap
@[simp]
theorem LinearEquiv.dualMap_apply (f : M₁ ≃ₗ[R] M₂) (g : Dual R M₂) (x : M₁) :
f.dualMap g x = g (f x) :=
rfl
#align linear_equiv.dual_map_apply LinearEquiv.dualMap_apply
@[simp]
theorem LinearEquiv.dualMap_refl :
(LinearEquiv.refl R M₁).dualMap = LinearEquiv.refl R (Dual R M₁) := by
ext
rfl
#align linear_equiv.dual_map_refl LinearEquiv.dualMap_refl
@[simp]
theorem LinearEquiv.dualMap_symm {f : M₁ ≃ₗ[R] M₂} :
(LinearEquiv.dualMap f).symm = LinearEquiv.dualMap f.symm :=
rfl
#align linear_equiv.dual_map_symm LinearEquiv.dualMap_symm
theorem LinearEquiv.dualMap_trans {M₃ : Type*} [AddCommGroup M₃] [Module R M₃] (f : M₁ ≃ₗ[R] M₂)
(g : M₂ ≃ₗ[R] M₃) : g.dualMap.trans f.dualMap = (f.trans g).dualMap :=
rfl
#align linear_equiv.dual_map_trans LinearEquiv.dualMap_trans
@[simp]
lemma Dual.apply_one_mul_eq (f : Dual R R) (r : R) :
f 1 * r = f r := by
conv_rhs => rw [← mul_one r, ← smul_eq_mul]
rw [map_smul, smul_eq_mul, mul_comm]
@[simp]
lemma LinearMap.range_dualMap_dual_eq_span_singleton (f : Dual R M₁) :
range f.dualMap = R ∙ f := by
ext m
rw [Submodule.mem_span_singleton]
refine ⟨fun ⟨r, hr⟩ ↦ ⟨r 1, ?_⟩, fun ⟨r, hr⟩ ↦ ⟨r • LinearMap.id, ?_⟩⟩
· ext; simp [dualMap_apply', ← hr]
· ext; simp [dualMap_apply', ← hr]
end DualMap
namespace Basis
universe u v w
open Module Module.Dual Submodule LinearMap Cardinal Function
universe uR uM uK uV uι
variable {R : Type uR} {M : Type uM} {K : Type uK} {V : Type uV} {ι : Type uι}
section CommSemiring
variable [CommSemiring R] [AddCommMonoid M] [Module R M] [DecidableEq ι]
variable (b : Basis ι R M)
/-- The linear map from a vector space equipped with basis to its dual vector space,
taking basis elements to corresponding dual basis elements. -/
def toDual : M →ₗ[R] Module.Dual R M :=
b.constr ℕ fun v => b.constr ℕ fun w => if w = v then (1 : R) else 0
#align basis.to_dual Basis.toDual
theorem toDual_apply (i j : ι) : b.toDual (b i) (b j) = if i = j then 1 else 0 := by
erw [constr_basis b, constr_basis b]
simp only [eq_comm]
#align basis.to_dual_apply Basis.toDual_apply
@[simp]
theorem toDual_total_left (f : ι →₀ R) (i : ι) :
b.toDual (Finsupp.total ι M R b f) (b i) = f i := by
rw [Finsupp.total_apply, Finsupp.sum, _root_.map_sum, LinearMap.sum_apply]
simp_rw [LinearMap.map_smul, LinearMap.smul_apply, toDual_apply, smul_eq_mul, mul_boole,
Finset.sum_ite_eq']
split_ifs with h
· rfl
· rw [Finsupp.not_mem_support_iff.mp h]
#align basis.to_dual_total_left Basis.toDual_total_left
@[simp]
theorem toDual_total_right (f : ι →₀ R) (i : ι) :
b.toDual (b i) (Finsupp.total ι M R b f) = f i := by
rw [Finsupp.total_apply, Finsupp.sum, _root_.map_sum]
simp_rw [LinearMap.map_smul, toDual_apply, smul_eq_mul, mul_boole, Finset.sum_ite_eq]
split_ifs with h
· rfl
· rw [Finsupp.not_mem_support_iff.mp h]
#align basis.to_dual_total_right Basis.toDual_total_right
theorem toDual_apply_left (m : M) (i : ι) : b.toDual m (b i) = b.repr m i := by
rw [← b.toDual_total_left, b.total_repr]
#align basis.to_dual_apply_left Basis.toDual_apply_left
theorem toDual_apply_right (i : ι) (m : M) : b.toDual (b i) m = b.repr m i := by
rw [← b.toDual_total_right, b.total_repr]
#align basis.to_dual_apply_right Basis.toDual_apply_right
theorem coe_toDual_self (i : ι) : b.toDual (b i) = b.coord i := by
ext
apply toDual_apply_right
#align basis.coe_to_dual_self Basis.coe_toDual_self
/-- `h.toDual_flip v` is the linear map sending `w` to `h.toDual w v`. -/
def toDualFlip (m : M) : M →ₗ[R] R :=
b.toDual.flip m
#align basis.to_dual_flip Basis.toDualFlip
theorem toDualFlip_apply (m₁ m₂ : M) : b.toDualFlip m₁ m₂ = b.toDual m₂ m₁ :=
rfl
#align basis.to_dual_flip_apply Basis.toDualFlip_apply
theorem toDual_eq_repr (m : M) (i : ι) : b.toDual m (b i) = b.repr m i :=
b.toDual_apply_left m i
#align basis.to_dual_eq_repr Basis.toDual_eq_repr
theorem toDual_eq_equivFun [Finite ι] (m : M) (i : ι) : b.toDual m (b i) = b.equivFun m i := by
rw [b.equivFun_apply, toDual_eq_repr]
#align basis.to_dual_eq_equiv_fun Basis.toDual_eq_equivFun
theorem toDual_injective : Injective b.toDual := fun x y h ↦ b.ext_elem_iff.mpr fun i ↦ by
simp_rw [← toDual_eq_repr]; exact DFunLike.congr_fun h _
theorem toDual_inj (m : M) (a : b.toDual m = 0) : m = 0 :=
b.toDual_injective (by rwa [_root_.map_zero])
#align basis.to_dual_inj Basis.toDual_inj
-- Porting note (#11036): broken dot notation lean4#1910 LinearMap.ker
theorem toDual_ker : LinearMap.ker b.toDual = ⊥ :=
ker_eq_bot'.mpr b.toDual_inj
#align basis.to_dual_ker Basis.toDual_ker
-- Porting note (#11036): broken dot notation lean4#1910 LinearMap.range
theorem toDual_range [Finite ι] : LinearMap.range b.toDual = ⊤ := by
refine eq_top_iff'.2 fun f => ?_
let lin_comb : ι →₀ R := Finsupp.equivFunOnFinite.symm fun i => f (b i)
refine ⟨Finsupp.total ι M R b lin_comb, b.ext fun i => ?_⟩
rw [b.toDual_eq_repr _ i, repr_total b]
rfl
#align basis.to_dual_range Basis.toDual_range
end CommSemiring
section
variable [CommSemiring R] [AddCommMonoid M] [Module R M] [Fintype ι]
variable (b : Basis ι R M)
@[simp]
theorem sum_dual_apply_smul_coord (f : Module.Dual R M) :
(∑ x, f (b x) • b.coord x) = f := by
ext m
simp_rw [LinearMap.sum_apply, LinearMap.smul_apply, smul_eq_mul, mul_comm (f _), ← smul_eq_mul, ←
f.map_smul, ← _root_.map_sum, Basis.coord_apply, Basis.sum_repr]
#align basis.sum_dual_apply_smul_coord Basis.sum_dual_apply_smul_coord
end
section CommRing
variable [CommRing R] [AddCommGroup M] [Module R M] [DecidableEq ι]
variable (b : Basis ι R M)
section Finite
variable [Finite ι]
/-- A vector space is linearly equivalent to its dual space. -/
def toDualEquiv : M ≃ₗ[R] Dual R M :=
LinearEquiv.ofBijective b.toDual ⟨ker_eq_bot.mp b.toDual_ker, range_eq_top.mp b.toDual_range⟩
#align basis.to_dual_equiv Basis.toDualEquiv
-- `simps` times out when generating this
@[simp]
theorem toDualEquiv_apply (m : M) : b.toDualEquiv m = b.toDual m :=
rfl
#align basis.to_dual_equiv_apply Basis.toDualEquiv_apply
-- Not sure whether this is true for free modules over a commutative ring
/-- A vector space over a field is isomorphic to its dual if and only if it is finite-dimensional:
a consequence of the Erdős-Kaplansky theorem. -/
theorem linearEquiv_dual_iff_finiteDimensional [Field K] [AddCommGroup V] [Module K V] :
Nonempty (V ≃ₗ[K] Dual K V) ↔ FiniteDimensional K V := by
refine ⟨fun ⟨e⟩ ↦ ?_, fun h ↦ ⟨(Module.Free.chooseBasis K V).toDualEquiv⟩⟩
rw [FiniteDimensional, ← Module.rank_lt_alpeh0_iff]
by_contra!
apply (lift_rank_lt_rank_dual this).ne
have := e.lift_rank_eq
rwa [lift_umax.{uV,uK}, lift_id'.{uV,uK}] at this
/-- Maps a basis for `V` to a basis for the dual space. -/
def dualBasis : Basis ι R (Dual R M) :=
b.map b.toDualEquiv
#align basis.dual_basis Basis.dualBasis
-- We use `j = i` to match `Basis.repr_self`
theorem dualBasis_apply_self (i j : ι) : b.dualBasis i (b j) =
if j = i then 1 else 0 := by
convert b.toDual_apply i j using 2
rw [@eq_comm _ j i]
#align basis.dual_basis_apply_self Basis.dualBasis_apply_self
theorem total_dualBasis (f : ι →₀ R) (i : ι) :
Finsupp.total ι (Dual R M) R b.dualBasis f (b i) = f i := by
cases nonempty_fintype ι
rw [Finsupp.total_apply, Finsupp.sum_fintype, LinearMap.sum_apply]
· simp_rw [LinearMap.smul_apply, smul_eq_mul, dualBasis_apply_self, mul_boole,
Finset.sum_ite_eq, if_pos (Finset.mem_univ i)]
· intro
rw [zero_smul]
#align basis.total_dual_basis Basis.total_dualBasis
theorem dualBasis_repr (l : Dual R M) (i : ι) : b.dualBasis.repr l i = l (b i) := by
rw [← total_dualBasis b, Basis.total_repr b.dualBasis l]
#align basis.dual_basis_repr Basis.dualBasis_repr
theorem dualBasis_apply (i : ι) (m : M) : b.dualBasis i m = b.repr m i :=
b.toDual_apply_right i m
#align basis.dual_basis_apply Basis.dualBasis_apply
@[simp]
theorem coe_dualBasis : ⇑b.dualBasis = b.coord := by
ext i x
apply dualBasis_apply
#align basis.coe_dual_basis Basis.coe_dualBasis
@[simp]
theorem toDual_toDual : b.dualBasis.toDual.comp b.toDual = Dual.eval R M := by
refine b.ext fun i => b.dualBasis.ext fun j => ?_
rw [LinearMap.comp_apply, toDual_apply_left, coe_toDual_self, ← coe_dualBasis,
Dual.eval_apply, Basis.repr_self, Finsupp.single_apply, dualBasis_apply_self]
#align basis.to_dual_to_dual Basis.toDual_toDual
end Finite
theorem dualBasis_equivFun [Finite ι] (l : Dual R M) (i : ι) :
b.dualBasis.equivFun l i = l (b i) := by rw [Basis.equivFun_apply, dualBasis_repr]
#align basis.dual_basis_equiv_fun Basis.dualBasis_equivFun
theorem eval_ker {ι : Type*} (b : Basis ι R M) :
LinearMap.ker (Dual.eval R M) = ⊥ := by
rw [ker_eq_bot']
intro m hm
simp_rw [LinearMap.ext_iff, Dual.eval_apply, zero_apply] at hm
exact (Basis.forall_coord_eq_zero_iff _).mp fun i => hm (b.coord i)
#align basis.eval_ker Basis.eval_ker
-- Porting note (#11036): broken dot notation lean4#1910 LinearMap.range
theorem eval_range {ι : Type*} [Finite ι] (b : Basis ι R M) :
LinearMap.range (Dual.eval R M) = ⊤ := by
classical
cases nonempty_fintype ι
rw [← b.toDual_toDual, range_comp, b.toDual_range, Submodule.map_top, toDual_range _]
#align basis.eval_range Basis.eval_range
section
variable [Finite R M] [Free R M]
instance dual_free : Free R (Dual R M) :=
Free.of_basis (Free.chooseBasis R M).dualBasis
#align basis.dual_free Basis.dual_free
instance dual_finite : Finite R (Dual R M) :=
Finite.of_basis (Free.chooseBasis R M).dualBasis
#align basis.dual_finite Basis.dual_finite
end
end CommRing
/-- `simp` normal form version of `total_dualBasis` -/
@[simp]
theorem total_coord [CommRing R] [AddCommGroup M] [Module R M] [Finite ι] (b : Basis ι R M)
(f : ι →₀ R) (i : ι) : Finsupp.total ι (Dual R M) R b.coord f (b i) = f i := by
haveI := Classical.decEq ι
rw [← coe_dualBasis, total_dualBasis]
#align basis.total_coord Basis.total_coord
theorem dual_rank_eq [CommRing K] [AddCommGroup V] [Module K V] [Finite ι] (b : Basis ι K V) :
Cardinal.lift.{uK,uV} (Module.rank K V) = Module.rank K (Dual K V) := by
classical rw [← lift_umax.{uV,uK}, b.toDualEquiv.lift_rank_eq, lift_id'.{uV,uK}]
#align basis.dual_rank_eq Basis.dual_rank_eq
end Basis
namespace Module
universe uK uV
variable {K : Type uK} {V : Type uV}
variable [CommRing K] [AddCommGroup V] [Module K V] [Module.Free K V]
open Module Module.Dual Submodule LinearMap Cardinal Basis FiniteDimensional
section
variable (K) (V)
-- Porting note (#11036): broken dot notation lean4#1910 LinearMap.ker
theorem eval_ker : LinearMap.ker (eval K V) = ⊥ := by
classical exact (Module.Free.chooseBasis K V).eval_ker
#align module.eval_ker Module.eval_ker
theorem map_eval_injective : (Submodule.map (eval K V)).Injective := by
apply Submodule.map_injective_of_injective
rw [← LinearMap.ker_eq_bot]
exact eval_ker K V
#align module.map_eval_injective Module.map_eval_injective
theorem comap_eval_surjective : (Submodule.comap (eval K V)).Surjective := by
apply Submodule.comap_surjective_of_injective
rw [← LinearMap.ker_eq_bot]
exact eval_ker K V
#align module.comap_eval_surjective Module.comap_eval_surjective
end
section
variable (K)
theorem eval_apply_eq_zero_iff (v : V) : (eval K V) v = 0 ↔ v = 0 := by
simpa only using SetLike.ext_iff.mp (eval_ker K V) v
#align module.eval_apply_eq_zero_iff Module.eval_apply_eq_zero_iff
theorem eval_apply_injective : Function.Injective (eval K V) :=
(injective_iff_map_eq_zero' (eval K V)).mpr (eval_apply_eq_zero_iff K)
#align module.eval_apply_injective Module.eval_apply_injective
theorem forall_dual_apply_eq_zero_iff (v : V) : (∀ φ : Module.Dual K V, φ v = 0) ↔ v = 0 := by
rw [← eval_apply_eq_zero_iff K v, LinearMap.ext_iff]
rfl
#align module.forall_dual_apply_eq_zero_iff Module.forall_dual_apply_eq_zero_iff
@[simp]
theorem subsingleton_dual_iff :
Subsingleton (Dual K V) ↔ Subsingleton V := by
refine ⟨fun h ↦ ⟨fun v w ↦ ?_⟩, fun h ↦ ⟨fun f g ↦ ?_⟩⟩
· rw [← sub_eq_zero, ← forall_dual_apply_eq_zero_iff K (v - w)]
intros f
simp [Subsingleton.elim f 0]
· ext v
simp [Subsingleton.elim v 0]
instance instSubsingletonDual [Subsingleton V] : Subsingleton (Dual K V) :=
(subsingleton_dual_iff K).mp inferInstance
@[simp]
theorem nontrivial_dual_iff :
Nontrivial (Dual K V) ↔ Nontrivial V := by
rw [← not_iff_not, not_nontrivial_iff_subsingleton, not_nontrivial_iff_subsingleton,
subsingleton_dual_iff]
instance instNontrivialDual [Nontrivial V] : Nontrivial (Dual K V) :=
(nontrivial_dual_iff K).mpr inferInstance
theorem finite_dual_iff : Finite K (Dual K V) ↔ Finite K V := by
constructor <;> intro h
· obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V)
nontriviality K
obtain ⟨⟨s, span_s⟩⟩ := h
classical
haveI := (b.linearIndependent.map' _ b.toDual_ker).finite_of_le_span_finite _ s ?_
· exact Finite.of_basis b
· rw [span_s]; apply le_top
· infer_instance
end
theorem dual_rank_eq [Module.Finite K V] :
Cardinal.lift.{uK,uV} (Module.rank K V) = Module.rank K (Dual K V) :=
(Module.Free.chooseBasis K V).dual_rank_eq
#align module.dual_rank_eq Module.dual_rank_eq
-- Porting note (#11036): broken dot notation lean4#1910 LinearMap.range
theorem erange_coe [Module.Finite K V] : LinearMap.range (eval K V) = ⊤ :=
(Module.Free.chooseBasis K V).eval_range
#align module.erange_coe Module.erange_coe
section IsReflexive
open Function
variable (R M N : Type*) [CommRing R] [AddCommGroup M] [AddCommGroup N] [Module R M] [Module R N]
/-- A reflexive module is one for which the natural map to its double dual is a bijection.
Any finitely-generated free module (and thus any finite-dimensional vector space) is reflexive.
See `Module.IsReflexive.of_finite_of_free`. -/
class IsReflexive : Prop where
/-- A reflexive module is one for which the natural map to its double dual is a bijection. -/
bijective_dual_eval' : Bijective (Dual.eval R M)
lemma bijective_dual_eval [IsReflexive R M] : Bijective (Dual.eval R M) :=
IsReflexive.bijective_dual_eval'
instance IsReflexive.of_finite_of_free [Finite R M] [Free R M] : IsReflexive R M where
bijective_dual_eval' := ⟨LinearMap.ker_eq_bot.mp (Free.chooseBasis R M).eval_ker,
LinearMap.range_eq_top.mp (Free.chooseBasis R M).eval_range⟩
variable [IsReflexive R M]
/-- The bijection between a reflexive module and its double dual, bundled as a `LinearEquiv`. -/
def evalEquiv : M ≃ₗ[R] Dual R (Dual R M) :=
LinearEquiv.ofBijective _ (bijective_dual_eval R M)
#align module.eval_equiv Module.evalEquiv
@[simp] lemma evalEquiv_toLinearMap : evalEquiv R M = Dual.eval R M := rfl
#align module.eval_equiv_to_linear_map Module.evalEquiv_toLinearMap
@[simp] lemma evalEquiv_apply (m : M) : evalEquiv R M m = Dual.eval R M m := rfl
@[simp] lemma apply_evalEquiv_symm_apply (f : Dual R M) (g : Dual R (Dual R M)) :
f ((evalEquiv R M).symm g) = g f := by
set m := (evalEquiv R M).symm g
rw [← (evalEquiv R M).apply_symm_apply g, evalEquiv_apply, Dual.eval_apply]
@[simp] lemma symm_dualMap_evalEquiv :
(evalEquiv R M).symm.dualMap = Dual.eval R (Dual R M) := by
ext; simp
/-- The dual of a reflexive module is reflexive. -/
instance Dual.instIsReflecive : IsReflexive R (Dual R M) :=
⟨by simpa only [← symm_dualMap_evalEquiv] using (evalEquiv R M).dualMap.symm.bijective⟩
/-- The isomorphism `Module.evalEquiv` induces an order isomorphism on subspaces. -/
def mapEvalEquiv : Submodule R M ≃o Submodule R (Dual R (Dual R M)) :=
Submodule.orderIsoMapComap (evalEquiv R M)
#align module.map_eval_equiv Module.mapEvalEquiv
@[simp]
theorem mapEvalEquiv_apply (W : Submodule R M) :
mapEvalEquiv R M W = W.map (Dual.eval R M) :=
rfl
#align module.map_eval_equiv_apply Module.mapEvalEquiv_apply
@[simp]
theorem mapEvalEquiv_symm_apply (W'' : Submodule R (Dual R (Dual R M))) :
(mapEvalEquiv R M).symm W'' = W''.comap (Dual.eval R M) :=
rfl
#align module.map_eval_equiv_symm_apply Module.mapEvalEquiv_symm_apply
instance _root_.Prod.instModuleIsReflexive [IsReflexive R N] :
IsReflexive R (M × N) where
bijective_dual_eval' := by
let e : Dual R (Dual R (M × N)) ≃ₗ[R] Dual R (Dual R M) × Dual R (Dual R N) :=
(dualProdDualEquivDual R M N).dualMap.trans
(dualProdDualEquivDual R (Dual R M) (Dual R N)).symm
have : Dual.eval R (M × N) = e.symm.comp ((Dual.eval R M).prodMap (Dual.eval R N)) := by
ext m f <;> simp [e]
simp only [this, LinearEquiv.trans_symm, LinearEquiv.symm_symm, LinearEquiv.dualMap_symm,
coe_comp, LinearEquiv.coe_coe, EquivLike.comp_bijective]
exact (bijective_dual_eval R M).prodMap (bijective_dual_eval R N)
variable {R M N} in
lemma equiv (e : M ≃ₗ[R] N) : IsReflexive R N where
bijective_dual_eval' := by
let ed : Dual R (Dual R N) ≃ₗ[R] Dual R (Dual R M) := e.symm.dualMap.dualMap
have : Dual.eval R N = ed.symm.comp ((Dual.eval R M).comp e.symm.toLinearMap) := by
ext m f
exact DFunLike.congr_arg f (e.apply_symm_apply m).symm
simp only [this, LinearEquiv.trans_symm, LinearEquiv.symm_symm, LinearEquiv.dualMap_symm,
coe_comp, LinearEquiv.coe_coe, EquivLike.comp_bijective]
exact Bijective.comp (bijective_dual_eval R M) (LinearEquiv.bijective _)
instance _root_.MulOpposite.instModuleIsReflexive : IsReflexive R (MulOpposite M) :=
equiv <| MulOpposite.opLinearEquiv _
instance _root_.ULift.instModuleIsReflexive.{w} : IsReflexive R (ULift.{w} M) :=
equiv ULift.moduleEquiv.symm
end IsReflexive
end Module
namespace Submodule
open Module
variable {R M : Type*} [CommRing R] [AddCommGroup M] [Module R M] {p : Submodule R M}
theorem exists_dual_map_eq_bot_of_nmem {x : M} (hx : x ∉ p) (hp' : Free R (M ⧸ p)) :
∃ f : Dual R M, f x ≠ 0 ∧ p.map f = ⊥ := by
suffices ∃ f : Dual R (M ⧸ p), f (p.mkQ x) ≠ 0 by
obtain ⟨f, hf⟩ := this; exact ⟨f.comp p.mkQ, hf, by simp [Submodule.map_comp]⟩
rwa [← Submodule.Quotient.mk_eq_zero, ← Submodule.mkQ_apply,
← forall_dual_apply_eq_zero_iff (K := R), not_forall] at hx
theorem exists_dual_map_eq_bot_of_lt_top (hp : p < ⊤) (hp' : Free R (M ⧸ p)) :
∃ f : Dual R M, f ≠ 0 ∧ p.map f = ⊥ := by
obtain ⟨x, hx⟩ : ∃ x : M, x ∉ p := by rw [lt_top_iff_ne_top] at hp; contrapose! hp; ext; simp [hp]
obtain ⟨f, hf, hf'⟩ := p.exists_dual_map_eq_bot_of_nmem hx hp'
exact ⟨f, by aesop, hf'⟩
end Submodule
section DualBases
open Module
variable {R M ι : Type*}
variable [CommSemiring R] [AddCommMonoid M] [Module R M] [DecidableEq ι]
-- Porting note: replace use_finite_instance tactic
open Lean.Elab.Tactic in
/-- Try using `Set.toFinite` to dispatch a `Set.Finite` goal. -/
def evalUseFiniteInstance : TacticM Unit := do
evalTactic (← `(tactic| intros; apply Set.toFinite))
elab "use_finite_instance" : tactic => evalUseFiniteInstance
/-- `e` and `ε` have characteristic properties of a basis and its dual -/
-- @[nolint has_nonempty_instance] Porting note (#5171): removed
structure Module.DualBases (e : ι → M) (ε : ι → Dual R M) : Prop where
eval : ∀ i j : ι, ε i (e j) = if i = j then 1 else 0
protected total : ∀ {m : M}, (∀ i, ε i m = 0) → m = 0
protected finite : ∀ m : M, { i | ε i m ≠ 0 }.Finite := by
use_finite_instance
#align module.dual_bases Module.DualBases
end DualBases
namespace Module.DualBases
open Module Module.Dual LinearMap Function
variable {R M ι : Type*}
variable [CommRing R] [AddCommGroup M] [Module R M]
variable {e : ι → M} {ε : ι → Dual R M}
/-- The coefficients of `v` on the basis `e` -/
def coeffs [DecidableEq ι] (h : DualBases e ε) (m : M) : ι →₀ R where
toFun i := ε i m
support := (h.finite m).toFinset
mem_support_toFun i := by rw [Set.Finite.mem_toFinset, Set.mem_setOf_eq]
#align module.dual_bases.coeffs Module.DualBases.coeffs
@[simp]
theorem coeffs_apply [DecidableEq ι] (h : DualBases e ε) (m : M) (i : ι) : h.coeffs m i = ε i m :=
rfl
#align module.dual_bases.coeffs_apply Module.DualBases.coeffs_apply
/-- linear combinations of elements of `e`.
This is a convenient abbreviation for `Finsupp.total _ M R e l` -/
def lc {ι} (e : ι → M) (l : ι →₀ R) : M :=
l.sum fun (i : ι) (a : R) => a • e i
#align module.dual_bases.lc Module.DualBases.lc
theorem lc_def (e : ι → M) (l : ι →₀ R) : lc e l = Finsupp.total _ _ R e l :=
rfl
#align module.dual_bases.lc_def Module.DualBases.lc_def
open Module
variable [DecidableEq ι] (h : DualBases e ε)
theorem dual_lc (l : ι →₀ R) (i : ι) : ε i (DualBases.lc e l) = l i := by
rw [lc, _root_.map_finsupp_sum, Finsupp.sum_eq_single i (g := fun a b ↦ (ε i) (b • e a))]
-- Porting note: cannot get at •
-- simp only [h.eval, map_smul, smul_eq_mul]
· simp [h.eval, smul_eq_mul]
· intro q _ q_ne
simp [q_ne.symm, h.eval, smul_eq_mul]
· simp
#align module.dual_bases.dual_lc Module.DualBases.dual_lc
@[simp]
theorem coeffs_lc (l : ι →₀ R) : h.coeffs (DualBases.lc e l) = l := by
ext i
rw [h.coeffs_apply, h.dual_lc]
#align module.dual_bases.coeffs_lc Module.DualBases.coeffs_lc
/-- For any m : M n, \sum_{p ∈ Q n} (ε p m) • e p = m -/
@[simp]
theorem lc_coeffs (m : M) : DualBases.lc e (h.coeffs m) = m := by
refine eq_of_sub_eq_zero <| h.total fun i ↦ ?_
simp [LinearMap.map_sub, h.dual_lc, sub_eq_zero]
#align module.dual_bases.lc_coeffs Module.DualBases.lc_coeffs
/-- `(h : DualBases e ε).basis` shows the family of vectors `e` forms a basis. -/
@[simps]
def basis : Basis ι R M :=
Basis.ofRepr
{ toFun := coeffs h
invFun := lc e
left_inv := lc_coeffs h
right_inv := coeffs_lc h
map_add' := fun v w => by
ext i
exact (ε i).map_add v w
map_smul' := fun c v => by
ext i
exact (ε i).map_smul c v }
#align module.dual_bases.basis Module.DualBases.basis
-- Porting note: from simpNF the LHS simplifies; it yields lc_def.symm
-- probably not a useful simp lemma; nolint simpNF since it cannot see this removal
attribute [-simp, nolint simpNF] basis_repr_symm_apply
@[simp]
theorem coe_basis : ⇑h.basis = e := by
ext i
rw [Basis.apply_eq_iff]
ext j
rw [h.basis_repr_apply, coeffs_apply, h.eval, Finsupp.single_apply]
convert if_congr (eq_comm (a := j) (b := i)) rfl rfl
#align module.dual_bases.coe_basis Module.DualBases.coe_basis
-- `convert` to get rid of a `DecidableEq` mismatch
theorem mem_of_mem_span {H : Set ι} {x : M} (hmem : x ∈ Submodule.span R (e '' H)) :
∀ i : ι, ε i x ≠ 0 → i ∈ H := by
intro i hi
rcases (Finsupp.mem_span_image_iff_total _).mp hmem with ⟨l, supp_l, rfl⟩
apply not_imp_comm.mp ((Finsupp.mem_supported' _ _).mp supp_l i)
rwa [← lc_def, h.dual_lc] at hi
#align module.dual_bases.mem_of_mem_span Module.DualBases.mem_of_mem_span
theorem coe_dualBasis [_root_.Finite ι] : ⇑h.basis.dualBasis = ε :=
funext fun i =>
h.basis.ext fun j => by
rw [h.basis.dualBasis_apply_self, h.coe_basis, h.eval, if_congr eq_comm rfl rfl]
#align module.dual_bases.coe_dual_basis Module.DualBases.coe_dualBasis
end Module.DualBases
namespace Submodule
universe u v w
variable {R : Type u} {M : Type v} [CommSemiring R] [AddCommMonoid M] [Module R M]
variable {W : Submodule R M}
/-- The `dualRestrict` of a submodule `W` of `M` is the linear map from the
dual of `M` to the dual of `W` such that the domain of each linear map is
restricted to `W`. -/
def dualRestrict (W : Submodule R M) : Module.Dual R M →ₗ[R] Module.Dual R W :=
LinearMap.domRestrict' W
#align submodule.dual_restrict Submodule.dualRestrict
theorem dualRestrict_def (W : Submodule R M) : W.dualRestrict = W.subtype.dualMap :=
rfl
#align submodule.dual_restrict_def Submodule.dualRestrict_def
@[simp]
theorem dualRestrict_apply (W : Submodule R M) (φ : Module.Dual R M) (x : W) :
W.dualRestrict φ x = φ (x : M) :=
rfl
#align submodule.dual_restrict_apply Submodule.dualRestrict_apply
/-- The `dualAnnihilator` of a submodule `W` is the set of linear maps `φ` such
that `φ w = 0` for all `w ∈ W`. -/
def dualAnnihilator {R : Type u} {M : Type v} [CommSemiring R] [AddCommMonoid M] [Module R M]
(W : Submodule R M) : Submodule R <| Module.Dual R M :=
-- Porting note (#11036): broken dot notation lean4#1910 LinearMap.ker
LinearMap.ker W.dualRestrict
#align submodule.dual_annihilator Submodule.dualAnnihilator
@[simp]
theorem mem_dualAnnihilator (φ : Module.Dual R M) : φ ∈ W.dualAnnihilator ↔ ∀ w ∈ W, φ w = 0 := by
refine LinearMap.mem_ker.trans ?_
simp_rw [LinearMap.ext_iff, dualRestrict_apply]
exact ⟨fun h w hw => h ⟨w, hw⟩, fun h w => h w.1 w.2⟩
#align submodule.mem_dual_annihilator Submodule.mem_dualAnnihilator
/-- That $\operatorname{ker}(\iota^* : V^* \to W^*) = \operatorname{ann}(W)$.
This is the definition of the dual annihilator of the submodule $W$. -/
theorem dualRestrict_ker_eq_dualAnnihilator (W : Submodule R M) :
-- Porting note (#11036): broken dot notation lean4#1910 LinearMap.ker
LinearMap.ker W.dualRestrict = W.dualAnnihilator :=
rfl
#align submodule.dual_restrict_ker_eq_dual_annihilator Submodule.dualRestrict_ker_eq_dualAnnihilator
/-- The `dualAnnihilator` of a submodule of the dual space pulled back along the evaluation map
`Module.Dual.eval`. -/
def dualCoannihilator (Φ : Submodule R (Module.Dual R M)) : Submodule R M :=
Φ.dualAnnihilator.comap (Module.Dual.eval R M)
#align submodule.dual_coannihilator Submodule.dualCoannihilator
@[simp]
theorem mem_dualCoannihilator {Φ : Submodule R (Module.Dual R M)} (x : M) :
x ∈ Φ.dualCoannihilator ↔ ∀ φ ∈ Φ, (φ x : R) = 0 := by
simp_rw [dualCoannihilator, mem_comap, mem_dualAnnihilator, Module.Dual.eval_apply]
#align submodule.mem_dual_coannihilator Submodule.mem_dualCoannihilator
theorem comap_dualAnnihilator (Φ : Submodule R (Module.Dual R M)) :
Φ.dualAnnihilator.comap (Module.Dual.eval R M) = Φ.dualCoannihilator := rfl
theorem map_dualCoannihilator_le (Φ : Submodule R (Module.Dual R M)) :
Φ.dualCoannihilator.map (Module.Dual.eval R M) ≤ Φ.dualAnnihilator :=
map_le_iff_le_comap.mpr (comap_dualAnnihilator Φ).le
variable (R M) in
theorem dualAnnihilator_gc :
GaloisConnection
(OrderDual.toDual ∘ (dualAnnihilator : Submodule R M → Submodule R (Module.Dual R M)))
(dualCoannihilator ∘ OrderDual.ofDual) := by
intro a b
induction b using OrderDual.rec
simp only [Function.comp_apply, OrderDual.toDual_le_toDual, OrderDual.ofDual_toDual]
constructor <;>
· intro h x hx
simp only [mem_dualAnnihilator, mem_dualCoannihilator]
intro y hy
have := h hy
simp only [mem_dualAnnihilator, mem_dualCoannihilator] at this
exact this x hx
#align submodule.dual_annihilator_gc Submodule.dualAnnihilator_gc
theorem le_dualAnnihilator_iff_le_dualCoannihilator {U : Submodule R (Module.Dual R M)}
{V : Submodule R M} : U ≤ V.dualAnnihilator ↔ V ≤ U.dualCoannihilator :=
(dualAnnihilator_gc R M).le_iff_le
#align submodule.le_dual_annihilator_iff_le_dual_coannihilator Submodule.le_dualAnnihilator_iff_le_dualCoannihilator
@[simp]
theorem dualAnnihilator_bot : (⊥ : Submodule R M).dualAnnihilator = ⊤ :=
(dualAnnihilator_gc R M).l_bot
#align submodule.dual_annihilator_bot Submodule.dualAnnihilator_bot
@[simp]
theorem dualAnnihilator_top : (⊤ : Submodule R M).dualAnnihilator = ⊥ := by
rw [eq_bot_iff]
intro v
simp_rw [mem_dualAnnihilator, mem_bot, mem_top, forall_true_left]
exact fun h => LinearMap.ext h
#align submodule.dual_annihilator_top Submodule.dualAnnihilator_top
@[simp]
theorem dualCoannihilator_bot : (⊥ : Submodule R (Module.Dual R M)).dualCoannihilator = ⊤ :=
(dualAnnihilator_gc R M).u_top
#align submodule.dual_coannihilator_bot Submodule.dualCoannihilator_bot
@[mono]
theorem dualAnnihilator_anti {U V : Submodule R M} (hUV : U ≤ V) :
V.dualAnnihilator ≤ U.dualAnnihilator :=
(dualAnnihilator_gc R M).monotone_l hUV
#align submodule.dual_annihilator_anti Submodule.dualAnnihilator_anti
@[mono]
theorem dualCoannihilator_anti {U V : Submodule R (Module.Dual R M)} (hUV : U ≤ V) :
V.dualCoannihilator ≤ U.dualCoannihilator :=
(dualAnnihilator_gc R M).monotone_u hUV
#align submodule.dual_coannihilator_anti Submodule.dualCoannihilator_anti
theorem le_dualAnnihilator_dualCoannihilator (U : Submodule R M) :
U ≤ U.dualAnnihilator.dualCoannihilator :=
(dualAnnihilator_gc R M).le_u_l U
#align submodule.le_dual_annihilator_dual_coannihilator Submodule.le_dualAnnihilator_dualCoannihilator
theorem le_dualCoannihilator_dualAnnihilator (U : Submodule R (Module.Dual R M)) :
U ≤ U.dualCoannihilator.dualAnnihilator :=
(dualAnnihilator_gc R M).l_u_le U
#align submodule.le_dual_coannihilator_dual_annihilator Submodule.le_dualCoannihilator_dualAnnihilator
theorem dualAnnihilator_dualCoannihilator_dualAnnihilator (U : Submodule R M) :
U.dualAnnihilator.dualCoannihilator.dualAnnihilator = U.dualAnnihilator :=
(dualAnnihilator_gc R M).l_u_l_eq_l U
#align submodule.dual_annihilator_dual_coannihilator_dual_annihilator Submodule.dualAnnihilator_dualCoannihilator_dualAnnihilator
theorem dualCoannihilator_dualAnnihilator_dualCoannihilator (U : Submodule R (Module.Dual R M)) :
U.dualCoannihilator.dualAnnihilator.dualCoannihilator = U.dualCoannihilator :=
(dualAnnihilator_gc R M).u_l_u_eq_u U
#align submodule.dual_coannihilator_dual_annihilator_dual_coannihilator Submodule.dualCoannihilator_dualAnnihilator_dualCoannihilator