-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathDefs.lean
More file actions
1472 lines (1123 loc) · 60.3 KB
/
Defs.lean
File metadata and controls
1472 lines (1123 loc) · 60.3 KB
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) 2014 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jeremy Avigad, Leonardo de Moura, Simon Hudon, Mario Carneiro
-/
module
public import Batteries.Logic
public import Batteries.Util.LibraryNote
public import Mathlib.Algebra.Notation.Defs
public import Mathlib.Algebra.Regular.Defs
public import Mathlib.Data.Int.Notation
public import Mathlib.Data.Nat.BinaryRec
public import Mathlib.Tactic.MkIffOfInductiveProp
public import Mathlib.Tactic.OfNat
public import Mathlib.Data.Nat.Notation
public import Mathlib.Tactic.Simps.Basic
/-!
# Typeclasses for (semi)groups and monoids
In this file we define typeclasses for algebraic structures with one binary operation.
The classes are named `(Add)?(Comm)?(Semigroup|Monoid|Group)`, where `Add` means that
the class uses additive notation and `Comm` means that the class assumes that the binary
operation is commutative.
The file does not contain any lemmas except for
* axioms of typeclasses restated in the root namespace;
* lemmas required for instances.
For basic lemmas about these classes see `Mathlib/Algebra/Group/Basic.lean`.
We register the following instances:
- `Pow M ℕ`, for monoids `M`, and `Pow G ℤ` for groups `G`;
- `SMul ℕ M` for additive monoids `M`, and `SMul ℤ G` for additive groups `G`.
## Notation
- `+`, `-`, `*`, `/`, `^` : the usual arithmetic operations; the underlying functions are
`Add.add`, `Neg.neg`/`Sub.sub`, `Mul.mul`, `Div.div`, and `HPow.hPow`.
-/
@[expose] public section
assert_not_exists MonoidWithZero DenselyOrdered Function.const_injective
universe u v w
open Function
variable {G : Type*}
section Mul
variable [Mul G]
/-- A mixin for left cancellative multiplication. -/
@[mk_iff] class IsLeftCancelMul (G : Type u) [Mul G] : Prop where
/-- Multiplication is left cancellative (i.e. left regular). -/
protected mul_left_cancel (a : G) : IsLeftRegular a
/-- A mixin for right cancellative multiplication. -/
@[mk_iff] class IsRightCancelMul (G : Type u) [Mul G] : Prop where
/-- Multiplication is right cancellative (i.e. right regular). -/
protected mul_right_cancel (a : G) : IsRightRegular a
/-- A mixin for cancellative multiplication. -/
@[mk_iff]
class IsCancelMul (G : Type u) [Mul G] : Prop extends IsLeftCancelMul G, IsRightCancelMul G
/-- A mixin for left cancellative addition. -/
class IsLeftCancelAdd (G : Type u) [Add G] : Prop where
/-- Addition is left cancellative (i.e. left regular). -/
protected add_left_cancel (a : G) : IsAddLeftRegular a
attribute [to_additive] IsLeftCancelMul
attribute [to_additive] isLeftCancelMul_iff
/-- A mixin for right cancellative addition. -/
class IsRightCancelAdd (G : Type u) [Add G] : Prop where
/-- Addition is right cancellative (i.e. right regular). -/
protected add_right_cancel (a : G) : IsAddRightRegular a
attribute [to_additive] IsRightCancelMul
attribute [to_additive] isRightCancelMul_iff
/-- A mixin for cancellative addition. -/
@[mk_iff]
class IsCancelAdd (G : Type u) [Add G] : Prop extends IsLeftCancelAdd G, IsRightCancelAdd G
attribute [to_additive] IsCancelMul
attribute [to_additive existing] isCancelMul_iff
section Regular
variable {R : Type*}
@[to_additive] theorem isCancelMul_iff_forall_isRegular [Mul R] :
IsCancelMul R ↔ ∀ r : R, IsRegular r := by
rw [isCancelMul_iff, isLeftCancelMul_iff, isRightCancelMul_iff, ← forall_and]
exact forall_congr' fun _ ↦ isRegular_iff.symm
/-- If all multiplications cancel on the left then every element is left-regular. -/
@[to_additive /-- If all additions cancel on the left then every element is add-left-regular. -/]
theorem IsLeftRegular.all [Mul R] [IsLeftCancelMul R] (g : R) : IsLeftRegular g :=
(isLeftCancelMul_iff R).mp ‹_› _
/-- If all multiplications cancel on the right then every element is right-regular. -/
@[to_additive /-- If all additions cancel on the right then every element is add-right-regular. -/]
theorem IsRightRegular.all [Mul R] [IsRightCancelMul R] (g : R) : IsRightRegular g :=
(isRightCancelMul_iff R).mp ‹_› _
/-- If all multiplications cancel then every element is regular. -/
@[to_additive /-- If all additions cancel then every element is add-regular. -/]
theorem IsRegular.all [Mul R] [IsCancelMul R] (g : R) : IsRegular g := ⟨.all g, .all g⟩
end Regular
section IsLeftCancelMul
variable [IsLeftCancelMul G] {a b c : G}
@[to_additive]
theorem mul_left_cancel : a * b = a * c → b = c :=
(IsLeftCancelMul.mul_left_cancel a ·)
@[to_additive]
theorem mul_left_cancel_iff : a * b = a * c ↔ b = c :=
⟨mul_left_cancel, congrArg _⟩
@[to_additive]
theorem mul_right_injective (a : G) : Injective (a * ·) := fun _ _ ↦ mul_left_cancel
@[to_additive (attr := simp)]
theorem mul_right_inj (a : G) {b c : G} : a * b = a * c ↔ b = c :=
(mul_right_injective a).eq_iff
@[to_additive]
theorem mul_ne_mul_right (a : G) {b c : G} : a * b ≠ a * c ↔ b ≠ c :=
(mul_right_injective a).ne_iff
end IsLeftCancelMul
section IsRightCancelMul
variable [IsRightCancelMul G] {a b c : G}
@[to_additive]
theorem mul_right_cancel : a * b = c * b → a = c :=
(IsRightCancelMul.mul_right_cancel b ·)
@[to_additive]
theorem mul_right_cancel_iff : b * a = c * a ↔ b = c :=
⟨mul_right_cancel, congrArg (· * a)⟩
@[to_additive]
theorem mul_left_injective (a : G) : Function.Injective (· * a) := fun _ _ ↦ mul_right_cancel
@[to_additive (attr := simp)]
theorem mul_left_inj (a : G) {b c : G} : b * a = c * a ↔ b = c :=
(mul_left_injective a).eq_iff
@[to_additive]
theorem mul_ne_mul_left (a : G) {b c : G} : b * a ≠ c * a ↔ b ≠ c :=
(mul_left_injective a).ne_iff
end IsRightCancelMul
end Mul
/-- A semigroup is a type with an associative `(*)`. -/
@[ext]
class Semigroup (G : Type u) extends Mul G where
/-- Multiplication is associative -/
protected mul_assoc : ∀ a b c : G, a * b * c = a * (b * c)
/-- An additive semigroup is a type with an associative `(+)`. -/
@[ext]
class AddSemigroup (G : Type u) extends Add G where
/-- Addition is associative -/
protected add_assoc : ∀ a b c : G, a + b + c = a + (b + c)
attribute [to_additive] Semigroup
section Semigroup
variable [Semigroup G]
@[to_additive]
theorem mul_assoc : ∀ a b c : G, a * b * c = a * (b * c) :=
Semigroup.mul_assoc
end Semigroup
section IsCommutative
/-- A Prop stating that the addition is commutative. -/
class IsAddCommutative (M : Type*) [Add M] : Prop where
is_comm : Std.Commutative (α := M) (· + ·)
/-- A Prop stating that the multiplication is commutative. -/
@[to_additive existing]
class IsMulCommutative (M : Type*) [Mul M] : Prop where
is_comm : Std.Commutative (α := M) (· * ·)
attribute [instance] IsAddCommutative.is_comm
attribute [instance] IsMulCommutative.is_comm
@[to_additive]
lemma isMulCommutative_iff {M : Type*} [Mul M] : IsMulCommutative M ↔ ∀ a b : M, a * b = b * a := by
grind [IsMulCommutative, Std.Commutative]
@[to_additive]
alias ⟨_, IsMulCommutative.of_comm⟩ := isMulCommutative_iff
/-- An alternative to `mul_comm` which uses the mixin `IsMulCommutative` instead of bundled
commutative algebraic structures. In general, you should prefer `mul_comm` unless you are working
with commutative subobjects in a noncommutative algebraic structure. -/
@[to_additive
/-- An alternative to `add_comm` which uses the mixin `IsAddCommutative` instead of bundled
commutative algebraic structures. In general, you should prefer `add_comm` unless you are working
with commutative subobjects in a noncommutative algebraic structure. -/ ]
lemma mul_comm' {M : Type*} [Mul M] [IsMulCommutative M] (a b : M) : a * b = b * a :=
IsMulCommutative.is_comm.comm ..
end IsCommutative
/-- A commutative additive magma is a type with an addition which commutes. -/
@[ext]
class AddCommMagma (G : Type u) extends Add G where
/-- Addition is commutative in a commutative additive magma. -/
protected add_comm : ∀ a b : G, a + b = b + a
/-- A commutative multiplicative magma is a type with a multiplication which commutes. -/
@[ext]
class CommMagma (G : Type u) extends Mul G where
/-- Multiplication is commutative in a commutative multiplicative magma. -/
protected mul_comm : ∀ a b : G, a * b = b * a
attribute [to_additive] CommMagma
/-- A commutative semigroup is a type with an associative commutative `(*)`. -/
@[ext]
class CommSemigroup (G : Type u) extends Semigroup G, CommMagma G where
/-- A commutative additive semigroup is a type with an associative commutative `(+)`. -/
@[ext]
class AddCommSemigroup (G : Type u) extends AddSemigroup G, AddCommMagma G where
attribute [to_additive] CommSemigroup
section CommMagma
variable [CommMagma G] {a : G}
@[to_additive]
theorem mul_comm : ∀ a b : G, a * b = b * a := CommMagma.mul_comm
@[to_additive]
instance CommMagma.to_isCommutative : IsMulCommutative G := ⟨⟨mul_comm⟩⟩
@[to_additive (attr := simp)]
lemma isLeftRegular_iff_isRegular : IsLeftRegular a ↔ IsRegular a := by
simp [isRegular_iff, IsLeftRegular, IsRightRegular, mul_comm]
@[to_additive (attr := simp)]
lemma isRightRegular_iff_isRegular : IsRightRegular a ↔ IsRegular a := by
simp [isRegular_iff, IsLeftRegular, IsRightRegular, mul_comm]
/-- Any `CommMagma G` that satisfies `IsRightCancelMul G` also satisfies `IsLeftCancelMul G`. -/
@[to_additive AddCommMagma.IsRightCancelAdd.toIsLeftCancelAdd /-- Any `AddCommMagma G` that
satisfies `IsRightCancelAdd G` also satisfies `IsLeftCancelAdd G`. -/]
lemma CommMagma.IsRightCancelMul.toIsLeftCancelMul (G : Type u) [CommMagma G] [IsRightCancelMul G] :
IsLeftCancelMul G :=
⟨fun _ _ _ h => mul_right_cancel <| (mul_comm _ _).trans (h.trans (mul_comm _ _))⟩
/-- Any `CommMagma G` that satisfies `IsLeftCancelMul G` also satisfies `IsRightCancelMul G`. -/
@[to_additive AddCommMagma.IsLeftCancelAdd.toIsRightCancelAdd /-- Any `AddCommMagma G` that
satisfies `IsLeftCancelAdd G` also satisfies `IsRightCancelAdd G`. -/]
lemma CommMagma.IsLeftCancelMul.toIsRightCancelMul (G : Type u) [CommMagma G] [IsLeftCancelMul G] :
IsRightCancelMul G :=
⟨fun _ _ _ h => mul_left_cancel <| (mul_comm _ _).trans (h.trans (mul_comm _ _))⟩
/-- Any `CommMagma G` that satisfies `IsLeftCancelMul G` also satisfies `IsCancelMul G`. -/
@[to_additive AddCommMagma.IsLeftCancelAdd.toIsCancelAdd /-- Any `AddCommMagma G` that satisfies
`IsLeftCancelAdd G` also satisfies `IsCancelAdd G`. -/]
lemma CommMagma.IsLeftCancelMul.toIsCancelMul (G : Type u) [CommMagma G] [IsLeftCancelMul G] :
IsCancelMul G := { CommMagma.IsLeftCancelMul.toIsRightCancelMul G with }
/-- Any `CommMagma G` that satisfies `IsRightCancelMul G` also satisfies `IsCancelMul G`. -/
@[to_additive AddCommMagma.IsRightCancelAdd.toIsCancelAdd /-- Any `AddCommMagma G` that satisfies
`IsRightCancelAdd G` also satisfies `IsCancelAdd G`. -/]
lemma CommMagma.IsRightCancelMul.toIsCancelMul (G : Type u) [CommMagma G] [IsRightCancelMul G] :
IsCancelMul G := { CommMagma.IsRightCancelMul.toIsLeftCancelMul G with }
end CommMagma
/-- A `LeftCancelSemigroup` is a semigroup such that `a * b = a * c` implies `b = c`. -/
@[ext]
class LeftCancelSemigroup (G : Type u) extends Semigroup G, IsLeftCancelMul G
library_note «lower cancel priority» /--
We lower the priority of inheriting from cancellative structures.
This attempts to avoid expensive checks involving bundling and unbundling with the `IsDomain` class.
since `IsDomain` already depends on `Semiring`, we can synthesize that one first.
Zulip discussion: https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/Why.20is.20.60simpNF.60.20complaining.20here.3F
-/
attribute [instance 75] LeftCancelSemigroup.toSemigroup -- See note [lower cancel priority]
/-- An `AddLeftCancelSemigroup` is an additive semigroup such that
`a + b = a + c` implies `b = c`. -/
@[ext]
class AddLeftCancelSemigroup (G : Type u) extends AddSemigroup G, IsLeftCancelAdd G
attribute [instance 75] AddLeftCancelSemigroup.toAddSemigroup -- See note [lower cancel priority]
attribute [to_additive] LeftCancelSemigroup
/-- Any `LeftCancelSemigroup` satisfies `IsLeftCancelMul`. -/
add_decl_doc LeftCancelSemigroup.toIsLeftCancelMul
/-- Any `AddLeftCancelSemigroup` satisfies `IsLeftCancelAdd`. -/
add_decl_doc AddLeftCancelSemigroup.toIsLeftCancelAdd
/-- A `RightCancelSemigroup` is a semigroup such that `a * b = c * b` implies `a = c`. -/
@[ext]
class RightCancelSemigroup (G : Type u) extends Semigroup G, IsRightCancelMul G
attribute [instance 75] RightCancelSemigroup.toSemigroup -- See note [lower cancel priority]
/-- An `AddRightCancelSemigroup` is an additive semigroup such that
`a + b = c + b` implies `a = c`. -/
@[ext]
class AddRightCancelSemigroup (G : Type u) extends AddSemigroup G, IsRightCancelAdd G
attribute [instance 75] AddRightCancelSemigroup.toAddSemigroup -- See note [lower cancel priority]
attribute [to_additive] RightCancelSemigroup
/-- Any `RightCancelSemigroup` satisfies `IsRightCancelMul`. -/
add_decl_doc RightCancelSemigroup.toIsRightCancelMul
/-- Any `AddRightCancelSemigroup` satisfies `IsRightCancelAdd`. -/
add_decl_doc AddRightCancelSemigroup.toIsRightCancelAdd
/-- Bundling an `Add` and `Zero` structure together without any axioms about their
compatibility. See `AddZeroClass` for the additional assumption that 0 is an identity. -/
class AddZero (M : Type*) extends Zero M, Add M
/-- Bundling a `Mul` and `One` structure together without any axioms about their
compatibility. See `MulOneClass` for the additional assumption that 1 is an identity. -/
@[to_additive (attr := ext)]
class MulOne (M : Type*) extends One M, Mul M
/-- An additive monoid is Dedekind-finite if every left inverse is also a right inverse.
Also called von Neumann-finite or directly finite. -/
class IsDedekindFiniteAddMonoid (M : Type*) [AddZero M] : Prop where
add_eq_zero_symm {a b : M} : a + b = 0 → b + a = 0
/-- A monoid is Dedekind-finite if every left inverse is also a right inverse.
It is more common to talk about Dedekind-finite rings, but https://arxiv.org/abs/2102.01598
does define Dedekind-finite monoids in §2.2. -/
@[to_additive (attr := mk_iff)] class IsDedekindFiniteMonoid (M : Type*) [MulOne M] : Prop where
mul_eq_one_symm {a b : M} : a * b = 1 → b * a = 1
export IsDedekindFiniteMonoid (mul_eq_one_symm)
export IsDedekindFiniteAddMonoid (add_eq_zero_symm)
attribute [to_additive existing] isDedekindFiniteMonoid_iff
@[to_additive] theorem mul_eq_one_comm {M} [MulOne M] [IsDedekindFiniteMonoid M] {a b : M} :
a * b = 1 ↔ b * a = 1 where
mp := mul_eq_one_symm
mpr := mul_eq_one_symm
@[to_additive] instance (priority := low) (M) [MulOne M] [IsMulCommutative M] :
IsDedekindFiniteMonoid M where
mul_eq_one_symm := mul_comm' .. |>.trans
/-- Typeclass for expressing that a type `M` with addition and a zero satisfies
`0 + a = a` and `a + 0 = a` for all `a : M`. -/
class AddZeroClass (M : Type u) extends AddZero M where
/-- Zero is a left neutral element for addition -/
protected zero_add : ∀ a : M, 0 + a = a
/-- Zero is a right neutral element for addition -/
protected add_zero : ∀ a : M, a + 0 = a
/-- Typeclass for expressing that a type `M` with multiplication and a one satisfies
`1 * a = a` and `a * 1 = a` for all `a : M`. -/
@[to_additive]
class MulOneClass (M : Type u) extends MulOne M where
/-- One is a left neutral element for multiplication -/
protected one_mul : ∀ a : M, 1 * a = a
/-- One is a right neutral element for multiplication -/
protected mul_one : ∀ a : M, a * 1 = a
@[to_additive (attr := ext)]
theorem MulOneClass.ext {M : Type u} : ∀ ⦃m₁ m₂ : MulOneClass M⦄, m₁.mul = m₂.mul → m₁ = m₂ := by
rintro @⟨@⟨⟨one₁⟩, ⟨mul₁⟩⟩, one_mul₁, mul_one₁⟩ @⟨@⟨⟨one₂⟩, ⟨mul₂⟩⟩, one_mul₂, mul_one₂⟩ ⟨rfl⟩
-- FIXME (See https://github.com/leanprover/lean4/issues/1711)
-- congr
suffices one₁ = one₂ by cases this; rfl
exact (one_mul₂ one₁).symm.trans (mul_one₁ one₂)
section MulOneClass
variable {M : Type u} [MulOneClass M]
@[to_additive (attr := simp)]
theorem one_mul : ∀ a : M, 1 * a = a :=
MulOneClass.one_mul
@[to_additive (attr := simp)]
theorem mul_one : ∀ a : M, a * 1 = a :=
MulOneClass.mul_one
end MulOneClass
section
variable {M : Type u}
attribute [to_additive existing] npowRec
variable [One M] [Semigroup M] (m n : ℕ) (hn : n ≠ 0) (a : M) (ha : 1 * a = a)
include hn ha
@[to_additive] theorem npowRec_add : npowRec (m + n) a = npowRec m a * npowRec n a := by
obtain _ | n := n; · exact (hn rfl).elim
induction n with
| zero => simp only [npowRec, ha]
| succ n ih => rw [← Nat.add_assoc, npowRec, ih n.succ_ne_zero]; simp only [npowRec, mul_assoc]
@[to_additive] theorem npowRec_succ : npowRec (n + 1) a = a * npowRec n a := by
rw [Nat.add_comm, npowRec_add 1 n hn a ha, npowRec, npowRec, ha]
end
library_note «forgetful inheritance» /--
Suppose that one can put two mathematical structures on a type, a rich one `R` and a poor one
`P`, and that one can deduce the poor structure from the rich structure through a map `F` (called a
forgetful functor) (think `R = MetricSpace` and `P = TopologicalSpace`). A possible
implementation would be to have a type class `rich` containing a field `R`, a type class `poor`
containing a field `P`, and an instance from `rich` to `poor`. However, this creates diamond
problems, and a better approach is to let `rich` extend `poor` and have a field saying that
`F R = P`.
To illustrate this, consider the pair `MetricSpace` / `TopologicalSpace`. Consider the topology
on a product of two metric spaces. With the first approach, it could be obtained by going first from
each metric space to its topology, and then taking the product topology. But it could also be
obtained by considering the product metric space (with its sup distance) and then the topology
coming from this distance. These would be the same topology, but not definitionally, which means
that from the point of view of Lean's kernel, there would be two different `TopologicalSpace`
instances on the product. This is not compatible with the way instances are designed and used:
there should be at most one instance of a kind on each type. This approach has created an instance
diamond that does not commute definitionally.
The second approach solves this issue. Now, a metric space contains both a distance, a topology, and
a proof that the topology coincides with the one coming from the distance. When one defines the
product of two metric spaces, one uses the sup distance and the product topology, and one has to
give the proof that the sup distance induces the product topology. Following both sides of the
instance diamond then gives rise (definitionally) to the product topology on the product space.
Another approach would be to have the rich type class take the poor type class as an instance
parameter. It would solve the diamond problem, but it would lead to a blow up of the number
of type classes one would need to declare to work with complicated classes, say a real inner
product space, and would create exponential complexity when working with products of
such complicated spaces, that are avoided by bundling things carefully as above.
Note that this description of this specific case of the product of metric spaces is oversimplified
compared to mathlib, as there is an intermediate typeclass between `MetricSpace` and
`TopologicalSpace` called `UniformSpace`. The above scheme is used at both levels, embedding a
topology in the uniform space structure, and a uniform structure in the metric space structure.
Note also that, when `P` is a proposition, there is no such issue as any two proofs of `P` are
definitionally equivalent in Lean.
To avoid boilerplate, there are some designs that can automatically fill the poor fields when
creating a rich structure if one doesn't want to do something special about them. For instance,
in the definition of metric spaces, default tactics fill the uniform space fields if they are
not given explicitly. One can also have a helper function creating the rich structure from a
structure with fewer fields, where the helper function fills the remaining fields. See for instance
`UniformSpace.ofCore` or `RealInnerProduct.ofCore`.
For more details on this question, called the forgetful inheritance pattern, see [Competing
inheritance paths in dependent type theory: a case study in functional
analysis](https://hal.inria.fr/hal-02463336).
-/
/-!
### Design note on `AddMonoid` and `Monoid`
An `AddMonoid` has a natural `ℕ`-action, defined by `n • a = a + ... + a`, that we want to declare
as an instance as it makes it possible to use the language of linear algebra. However, there are
often other natural `ℕ`-actions. For instance, for any semiring `R`, the space of polynomials
`Polynomial R` has a natural `R`-action defined by multiplication on the coefficients. This means
that `Polynomial ℕ` would have two natural `ℕ`-actions, which are equal but not defeq. The same
goes for linear maps, tensor products, and so on (and even for `ℕ` itself).
To solve this issue, we embed an `ℕ`-action in the definition of an `AddMonoid` (which is by
default equal to the naive action `a + ... + a`, but can be adjusted when needed), and declare
a `SMul ℕ α` instance using this action. See Note [forgetful inheritance] for more
explanations on this pattern.
For example, when we define `Polynomial R`, then we declare the `ℕ`-action to be by multiplication
on each coefficient (using the `ℕ`-action on `R` that comes from the fact that `R` is
an `AddMonoid`). In this way, the two natural `SMul ℕ (Polynomial ℕ)` instances are defeq.
The tactic `to_additive` transfers definitions and results from multiplicative monoids to additive
monoids. To work, it has to map fields to fields. This means that we should also add corresponding
fields to the multiplicative structure `Monoid`, which could solve defeq problems for powers if
needed. These problems do not come up in practice, so most of the time we will not need to adjust
the `npow` field when defining multiplicative objects.
-/
/-- Exponentiation by repeated squaring. -/
@[to_additive /-- Scalar multiplication by repeated self-addition,
the additive version of exponentiation by repeated squaring. -/]
def npowBinRec {M : Type*} [One M] [Mul M] (k : ℕ) : M → M :=
npowBinRec.go k 1
where
/-- Auxiliary tail-recursive implementation for `npowBinRec`. -/
@[to_additive nsmulBinRec.go /-- Auxiliary tail-recursive implementation for `nsmulBinRec`. -/]
go (k : ℕ) : M → M → M :=
k.binaryRec (fun y _ ↦ y) fun bn _n fn y x ↦ fn (cond bn (y * x) y) (x * x)
/--
A variant of `npowRec` which is a semigroup homomorphism from `ℕ₊` to `M`.
-/
def npowRec' {M : Type*} [One M] [Mul M] : ℕ → M → M
| 0, _ => 1
| 1, m => m
| k + 2, m => npowRec' (k + 1) m * m
/--
A variant of `nsmulRec` which is a semigroup homomorphism from `ℕ₊` to `M`.
-/
def nsmulRec' {M : Type*} [Zero M] [Add M] : ℕ → M → M
| 0, _ => 0
| 1, m => m
| k + 2, m => nsmulRec' (k + 1) m + m
attribute [to_additive existing] npowRec'
@[to_additive]
theorem npowRec'_succ {M : Type*} [Mul M] [One M] {k : ℕ} (_ : k ≠ 0) (m : M) :
npowRec' (k + 1) m = npowRec' k m * m :=
match k with
| _ + 1 => rfl
@[to_additive]
theorem npowRec'_two_mul {M : Type*} [Semigroup M] [One M] (k : ℕ) (m : M) :
npowRec' (2 * k) m = npowRec' k (m * m) := by
induction k using Nat.strongRecOn with
| ind k' ih =>
match k' with
| 0 => rfl
| 1 => simp [npowRec']
| k + 2 => simp [npowRec', ← mul_assoc, ← ih]
@[to_additive]
theorem npowRec'_mul_comm {M : Type*} [Semigroup M] [One M] {k : ℕ} (k0 : k ≠ 0) (m : M) :
m * npowRec' k m = npowRec' k m * m := by
induction k using Nat.strongRecOn with
| ind k' ih =>
match k' with
| 1 => simp [npowRec']
| k + 2 => simp [npowRec', ← mul_assoc, ih]
@[to_additive]
theorem npowRec_eq {M : Type*} [Semigroup M] [One M] (k : ℕ) (m : M) :
npowRec (k + 1) m = 1 * npowRec' (k + 1) m := by
induction k using Nat.strongRecOn with
| ind k' ih =>
match k' with
| 0 => rfl
| k + 1 =>
rw [npowRec, npowRec'_succ k.succ_ne_zero, ← mul_assoc]
congr
simp [ih]
@[to_additive]
theorem npowBinRec.go_spec {M : Type*} [Semigroup M] [One M] (k : ℕ) (m n : M) :
npowBinRec.go (k + 1) m n = m * npowRec' (k + 1) n := by
unfold go
generalize hk : k + 1 = k'
replace hk : k' ≠ 0 := by lia
induction k' using Nat.binaryRecFromOne generalizing n m with
| zero => simp at hk
| one => simp [npowRec']
| bit b k' k'0 ih =>
rw [Nat.binaryRec_eq _ _ (Or.inl rfl), ih _ _ k'0]
cases b <;> simp only [Nat.bit, cond_false, cond_true, npowRec'_two_mul]
rw [npowRec'_succ (by lia), npowRec'_two_mul, ← npowRec'_two_mul,
← npowRec'_mul_comm (by lia), mul_assoc]
/--
An abbreviation for `npowRec` with an additional typeclass assumption on associativity
so that we can use `@[csimp]` to replace it with an implementation by repeated squaring
in compiled code.
-/
@[to_additive
/-- An abbreviation for `nsmulRec` with an additional typeclass assumptions on associativity
so that we can use `@[csimp]` to replace it with an implementation by repeated doubling in compiled
code as an automatic parameter. -/]
abbrev npowRecAuto {M : Type*} [Semigroup M] [One M] (k : ℕ) (m : M) : M :=
npowRec k m
/--
An abbreviation for `npowBinRec` with an additional typeclass assumption on associativity
so that we can use it in `@[csimp]` for more performant code generation.
-/
@[to_additive
/-- An abbreviation for `nsmulBinRec` with an additional typeclass assumption on associativity
so that we can use it in `@[csimp]` for more performant code generation
as an automatic parameter. -/]
abbrev npowBinRecAuto {M : Type*} [Semigroup M] [One M] (k : ℕ) (m : M) : M :=
npowBinRec k m
@[to_additive (attr := csimp)]
theorem npowRec_eq_npowBinRec : @npowRecAuto = @npowBinRecAuto := by
funext M _ _ k m
rw [npowBinRecAuto, npowRecAuto, npowBinRec]
match k with
| 0 => rw [npowRec, npowBinRec.go, Nat.binaryRec_zero]
| k + 1 => rw [npowBinRec.go_spec, npowRec_eq]
@[to_additive] theorem npowBinRec_zero {M : Type*} [Mul M] [One M] (m : M) :
npowBinRec 0 m = 1 := rfl
@[to_additive] theorem npowBinRec_succ {M : Type*} [Semigroup M] [One M] (n : ℕ) (m : M) :
npowBinRec (n + 1) m = npowBinRec n m * m := by
iterate 2 rw [← npowBinRecAuto, ← npowRec_eq_npowBinRec]
rfl
/-- `NSMul` is an implementation detail of `AddMonoid`. It is necessary because it is not
possible to extend `SMUl ℕ M` and `SMul ℤ M` at the same time. -/
class NSMul (M : Type u) where
/-- Multiplication by a natural number.
Set this to `nsmulRec` unless `Module` diamonds are possible. -/
protected nsmul : ℕ → M → M
/-- `NPow` is an implementation detail of `Monoid`. It is necessary because it is not
possible to extend `Pow M ℕ` and `Pow M ℤ` at the same time. -/
@[to_additive]
class NPow (M : Type u) where
/-- Raising to the power of a natural number. -/
protected npow : ℕ → M → M
@[to_additive toSMul, default_instance high]
instance NPow.toPow {M : Type*} [NPow M] : Pow M ℕ :=
⟨fun x n ↦ NPow.npow n x⟩
@[to_additive ofSMul]
instance NPow.ofPow {M : Type*} [Pow M ℕ] : NPow M := ⟨fun n x ↦ x ^ n⟩
/-- An `AddMonoid` is an `AddSemigroup` with an element `0` such that `0 + a = a + 0 = a`. -/
class AddMonoid (M : Type u) extends AddSemigroup M, AddZeroClass M, NSMul M where
/-- Multiplication by `(0 : ℕ)` gives `0`. -/
protected nsmul_zero (x : M) : 0 • x = 0 := by intros; rfl
/-- Multiplication by `(n + 1 : ℕ)` behaves as expected. -/
protected nsmul_succ (n : ℕ) (x : M) : (n + 1) • x = n • x + x := by intros; rfl
attribute [instance 150] AddSemigroup.toAdd
attribute [instance 50] AddZero.toAdd
/-- A `Monoid` is a `Semigroup` with an element `1` such that `1 * a = a * 1 = a`. -/
@[to_additive]
class Monoid (M : Type u) extends Semigroup M, MulOneClass M, NPow M where
npow := npowRecAuto
/-- Raising to the power `(0 : ℕ)` gives `1`. -/
protected npow_zero (x : M) : x ^ 0 = 1 := by intros; rfl
/-- Raising to the power `(n + 1 : ℕ)` behaves as expected. -/
protected npow_succ (n : ℕ) (x : M) : x ^ (n + 1) = x ^ n * x := by intros; rfl
section Monoid
variable {M : Type*} [Monoid M] {a b c : M}
@[to_additive (attr := simp) nsmul_eq_smul]
theorem npow_eq_pow (n : ℕ) (x : M) : NPow.npow n x = x ^ n :=
rfl
@[to_additive] lemma left_inv_eq_right_inv (hba : b * a = 1) (hac : a * c = 1) : b = c := by
rw [← one_mul c, ← hba, mul_assoc, hac, mul_one b]
-- This lemma is higher priority than later `zero_smul` so that the `simpNF` is happy
@[to_additive (attr := simp high) zero_nsmul]
theorem pow_zero (a : M) : a ^ 0 = 1 :=
Monoid.npow_zero _
@[to_additive succ_nsmul]
theorem pow_succ (a : M) (n : ℕ) : a ^ (n + 1) = a ^ n * a :=
Monoid.npow_succ n a
@[to_additive one_nsmul, simp]
lemma pow_one (a : M) : a ^ 1 = a := by rw [pow_succ, pow_zero, one_mul]
@[to_additive succ_nsmul'] lemma pow_succ' (a : M) : ∀ n, a ^ (n + 1) = a * a ^ n
| 0 => by simp
| n + 1 => by rw [pow_succ _ n, pow_succ, pow_succ', mul_assoc]
@[to_additive] lemma mul_pow_mul (a b : M) (n : ℕ) :
(a * b) ^ n * a = a * (b * a) ^ n := by
induction n with
| zero => simp
| succ n ih => simp [pow_succ', ← ih, mul_assoc]
@[to_additive]
lemma pow_mul_comm' (a : M) (n : ℕ) : a ^ n * a = a * a ^ n := by rw [← pow_succ, pow_succ']
/-- Note that most of the lemmas about powers of two refer to it as `sq`. -/
@[to_additive two_nsmul] lemma pow_two (a : M) : a ^ 2 = a * a := by rw [pow_succ, pow_one]
-- TODO: Should `alias` automatically transfer `to_additive` statements?
@[to_additive existing two_nsmul] alias sq := pow_two
@[to_additive three'_nsmul]
lemma pow_three' (a : M) : a ^ 3 = a * a * a := by rw [pow_succ, pow_two]
@[to_additive three_nsmul]
lemma pow_three (a : M) : a ^ 3 = a * (a * a) := by rw [pow_succ', pow_two]
-- This lemma is higher priority than later `smul_zero` so that the `simpNF` is happy
@[to_additive (attr := simp high) nsmul_zero] lemma one_pow : ∀ n, (1 : M) ^ n = 1
| 0 => pow_zero _
| n + 1 => by rw [pow_succ, one_pow, one_mul]
@[to_additive add_nsmul]
lemma pow_add (a : M) (m : ℕ) : ∀ n, a ^ (m + n) = a ^ m * a ^ n
| 0 => by rw [Nat.add_zero, pow_zero, mul_one]
| n + 1 => by rw [pow_succ, ← mul_assoc, ← pow_add, ← pow_succ, Nat.add_assoc]
@[to_additive] lemma pow_mul_comm (a : M) (m n : ℕ) : a ^ m * a ^ n = a ^ n * a ^ m := by
rw [← pow_add, ← pow_add, Nat.add_comm]
@[to_additive mul_nsmul] lemma pow_mul (a : M) (m : ℕ) : ∀ n, a ^ (m * n) = (a ^ m) ^ n
| 0 => by rw [Nat.mul_zero, pow_zero, pow_zero]
| n + 1 => by rw [Nat.mul_succ, pow_add, pow_succ, pow_mul]
@[to_additive mul_nsmul']
lemma pow_mul' (a : M) (m n : ℕ) : a ^ (m * n) = (a ^ n) ^ m := by rw [Nat.mul_comm, pow_mul]
@[to_additive nsmul_left_comm]
lemma pow_right_comm (a : M) (m n : ℕ) : (a ^ m) ^ n = (a ^ n) ^ m := by
rw [← pow_mul, Nat.mul_comm, pow_mul]
@[to_additive] protected lemma IsLeftRegular.mul_eq_one_symm {a b : M} (reg : IsLeftRegular a)
(eq : a * b = 1) : b * a = 1 :=
reg <| by simp [← mul_assoc, eq]
@[to_additive] protected lemma IsRightRegular.mul_eq_one_symm {a b : M} (reg : IsRightRegular a)
(eq : b * a = 1) : a * b = 1 :=
reg <| by simp [mul_assoc, eq]
variable (M)
@[to_additive] instance [IsLeftCancelMul M] : IsDedekindFiniteMonoid M where
mul_eq_one_symm := (IsLeftCancelMul.mul_left_cancel _).mul_eq_one_symm
@[to_additive] instance [IsRightCancelMul M] : IsDedekindFiniteMonoid M where
mul_eq_one_symm := (IsRightCancelMul.mul_right_cancel _).mul_eq_one_symm
namespace IsDedekindFiniteMonoid
/-- A monoid is Dedekind-finite if every element with a left inverse also has a right inverse. -/
@[to_additive] lemma of_exists_self_mul_eq_one (ex : ∀ x y : M, x * y = 1 → ∃ z, y * z = 1) :
IsDedekindFiniteMonoid M where
mul_eq_one_symm {x y} h := by
have ⟨z, hz⟩ := ex x y h
rwa [show x = z by simpa [← mul_assoc, h] using congr_arg (x * ·) hz.symm]
/-- A monoid is Dedekind-finite if every element with a right inverse also has a left inverse. -/
@[to_additive] lemma of_exists_mul_self_eq_one (ex : ∀ x y : M, x * y = 1 → ∃ z, z * x = 1) :
IsDedekindFiniteMonoid M where
mul_eq_one_symm {x y} h := by
have ⟨z, hz⟩ := ex x y h
rwa [show y = z by simpa [mul_assoc, h] using congr_arg (· * y) hz.symm]
end IsDedekindFiniteMonoid
end Monoid
/-- An additive monoid is torsion-free if scalar multiplication by every non-zero element `n : ℕ` is
injective. -/
@[mk_iff]
class IsAddTorsionFree (M : Type*) [AddMonoid M] where
protected nsmul_right_injective ⦃n : ℕ⦄ (hn : n ≠ 0) : Injective fun a : M ↦ n • a
/-- A monoid is torsion-free if power by every non-zero element `n : ℕ` is injective. -/
@[to_additive, mk_iff]
class IsMulTorsionFree (M : Type*) [Monoid M] where
protected pow_left_injective ⦃n : ℕ⦄ (hn : n ≠ 0) : Injective fun a : M ↦ a ^ n
attribute [to_additive existing] isMulTorsionFree_iff
/-- An additive commutative monoid is an additive monoid with commutative `(+)`. -/
class AddCommMonoid (M : Type u) extends AddMonoid M, AddCommSemigroup M
/-- A commutative monoid is a monoid with commutative `(*)`. -/
@[to_additive]
class CommMonoid (M : Type u) extends Monoid M, CommSemigroup M
/- This is assigned default rather than low priority because it gives the most common examples
of Dedekind-finite monoids and is used the most often. Benchmark results indicate default
priority performs better than low or high priority. -/
@[to_additive] instance (M) [CommMonoid M] : IsDedekindFiniteMonoid M := inferInstance
section LeftCancelMonoid
/-- An additive monoid in which addition is left-cancellative.
Main examples are `ℕ` and groups. This is the right typeclass for many sum lemmas, as having a zero
is useful to define the sum over the empty set, so `AddLeftCancelSemigroup` is not enough. -/
class AddLeftCancelMonoid (M : Type u) extends AddMonoid M, AddLeftCancelSemigroup M
attribute [instance 75] AddLeftCancelMonoid.toAddMonoid -- See note [lower cancel priority]
/-- A monoid in which multiplication is left-cancellative. -/
@[to_additive]
class LeftCancelMonoid (M : Type u) extends Monoid M, LeftCancelSemigroup M
attribute [instance 75] LeftCancelMonoid.toMonoid -- See note [lower cancel priority]
end LeftCancelMonoid
section RightCancelMonoid
/-- An additive monoid in which addition is right-cancellative.
Main examples are `ℕ` and groups. This is the right typeclass for many sum lemmas, as having a zero
is useful to define the sum over the empty set, so `AddRightCancelSemigroup` is not enough. -/
class AddRightCancelMonoid (M : Type u) extends AddMonoid M, AddRightCancelSemigroup M
attribute [instance 75] AddRightCancelMonoid.toAddMonoid -- See note [lower cancel priority]
/-- A monoid in which multiplication is right-cancellative. -/
@[to_additive]
class RightCancelMonoid (M : Type u) extends Monoid M, RightCancelSemigroup M
attribute [instance 75] RightCancelMonoid.toMonoid -- See note [lower cancel priority]
end RightCancelMonoid
section CancelMonoid
/-- An additive monoid in which addition is cancellative on both sides.
Main examples are `ℕ` and groups. This is the right typeclass for many sum lemmas, as having a zero
is useful to define the sum over the empty set, so `AddRightCancelMonoid` is not enough. -/
class AddCancelMonoid (M : Type u) extends AddLeftCancelMonoid M, AddRightCancelMonoid M
/-- A monoid in which multiplication is cancellative. -/
@[to_additive]
class CancelMonoid (M : Type u) extends LeftCancelMonoid M, RightCancelMonoid M
/-- Commutative version of `AddCancelMonoid`. -/
class AddCancelCommMonoid (M : Type u) extends AddCommMonoid M, AddLeftCancelMonoid M
attribute [instance 75] AddCancelCommMonoid.toAddCommMonoid -- See note [lower cancel priority]
/-- Commutative version of `CancelMonoid`. -/
@[to_additive]
class CancelCommMonoid (M : Type u) extends CommMonoid M, LeftCancelMonoid M
attribute [instance 75] CancelCommMonoid.toCommMonoid -- See note [lower cancel priority]
-- see Note [lower instance priority]
@[to_additive]
instance (priority := 100) CancelCommMonoid.toCancelMonoid (M : Type u) [CancelCommMonoid M] :
CancelMonoid M :=
{ CommMagma.IsLeftCancelMul.toIsRightCancelMul M with }
/-- Any `CancelMonoid G` satisfies `IsCancelMul G`. -/
@[to_additive /-- Any `AddCancelMonoid G` satisfies `IsCancelAdd G`. -/]
instance (priority := 100) CancelMonoid.toIsCancelMul (M : Type u) [CancelMonoid M] :
IsCancelMul M where
end CancelMonoid
/-- The fundamental power operation in a group. `zpowRec n a = a*a*...*a` n times, for integer `n`.
Use instead `a ^ n`, which has better definitional behavior. -/
def zpowRec [One G] [Mul G] [Inv G] (npow : ℕ → G → G := npowRec) : ℤ → G → G
| Int.ofNat n, a => npow n a
| Int.negSucc n, a => (npow n.succ a)⁻¹
/-- The fundamental scalar multiplication in an additive group. `zpowRec n a = a+a+...+a` n
times, for integer `n`. Use instead `n • a`, which has better definitional behavior. -/
def zsmulRec [Zero G] [Add G] [Neg G] (nsmul : ℕ → G → G := nsmulRec) : ℤ → G → G
| Int.ofNat n, a => nsmul n a
| Int.negSucc n, a => -nsmul n.succ a
attribute [to_additive existing] zpowRec
section InvolutiveInv
/-- Auxiliary typeclass for types with an involutive `Neg`. -/
class InvolutiveNeg (A : Type*) extends Neg A where
protected neg_neg : ∀ x : A, - -x = x
/-- Auxiliary typeclass for types with an involutive `Inv`. -/
@[to_additive]
class InvolutiveInv (G : Type*) extends Inv G where
protected inv_inv : ∀ x : G, x⁻¹⁻¹ = x
variable [InvolutiveInv G]
@[to_additive (attr := simp)]
theorem inv_inv (a : G) : a⁻¹⁻¹ = a :=
InvolutiveInv.inv_inv _
end InvolutiveInv
/-!
### Design note on `DivInvMonoid`/`SubNegMonoid` and `DivisionMonoid`/`SubtractionMonoid`
Those two pairs of made-up classes fulfill slightly different roles.
`DivInvMonoid`/`SubNegMonoid` provides the minimum amount of information to define the
`ℤ` action (`zpow` or `zsmul`). Further, it provides a `div` field, matching the forgetful
inheritance pattern. This is useful to shorten extension clauses of stronger structures (`Group`,
`GroupWithZero`, `DivisionRing`, `Field`) and for a few structures with a rather weak
pseudo-inverse (`Matrix`).
`DivisionMonoid`/`SubtractionMonoid` is targeted at structures with stronger pseudo-inverses. It
is an ad hoc collection of axioms that are mainly respected by three things:
* Groups
* Groups with zero
* The pointwise monoids `Set α`, `Finset α`, `Filter α`
It acts as a middle ground for structures with an inversion operator that plays well with
multiplication, except for the fact that it might not be a true inverse (`a / a ≠ 1` in general).
The axioms are pretty arbitrary (many other combinations are equivalent to it), but they are
independent:
* Without `DivisionMonoid.div_eq_mul_inv`, you can define `/` arbitrarily.
* Without `DivisionMonoid.inv_inv`, you can consider `WithTop Unit` with `a⁻¹ = ⊤` for all `a`.
* Without `DivisionMonoid.mul_inv_rev`, you can consider `WithTop α` with `a⁻¹ = a` for all `a`
where `α` noncommutative.
* Without `DivisionMonoid.inv_eq_of_mul`, you can consider any `CommMonoid` with `a⁻¹ = a` for all
`a`.
As a consequence, a few natural structures do not fit in this framework. For example, `ENNReal`
respects everything except for the fact that `(0 * ∞)⁻¹ = 0⁻¹ = ∞` while `∞⁻¹ * 0⁻¹ = 0 * ∞ = 0`.
-/
/-- In a class equipped with instances of both `Monoid` and `Inv`, this definition records what the
default definition for `Div` would be: `a * b⁻¹`. This is later provided as the default value for
the `Div` instance in `DivInvMonoid`.
We keep it as a separate definition rather than inlining it in `DivInvMonoid` so that the `Div`
field of individual `DivInvMonoid`s constructed using that default value will not be unfolded at
`.instance` transparency. -/
def DivInvMonoid.div' {G : Type u} [Monoid G] [Inv G] (a b : G) : G := a * b⁻¹
/-- `NSMul` is an implementation detail of `SubNegMonoid`. It is necessary because it is not
possible to extend `SMUl ℕ M` and `SMul ℤ M` at the same time. -/
class ZSMul (G : Type u) where
/-- Multiplication by an integer.
Set this to `zsmulRec` unless `Module` diamonds are possible. -/
protected zsmul : ℤ → G → G
/-- `NPow` is an implementation detail of `SubNegMonoid`. It is necessary because it is not
possible to extend `Pow M ℕ` and `Pow M ℤ` at the same time. -/
@[to_additive]
class ZPow (G : Type u) where
/-- The power operation: `a ^ n = a * ··· * a`; `a ^ (-n) = a⁻¹ * ··· a⁻¹` (`n` times) -/
protected zpow : ℤ → G → G
@[to_additive toSMul]
instance ZPow.toPow {M : Type*} [ZPow M] : Pow M ℤ :=
⟨fun x n ↦ ZPow.zpow n x⟩
@[to_additive ofSMul]
instance ZPow.ofPow {M : Type*} [Pow M ℤ] : ZPow M := ⟨fun n x ↦ x ^ n⟩
/-- A `DivInvMonoid` is a `Monoid` with operations `/` and `⁻¹` satisfying
`div_eq_mul_inv : ∀ a b, a / b = a * b⁻¹`.
This deduplicates the name `div_eq_mul_inv`.
The default for `div` is such that `a / b = a * b⁻¹` holds by definition.
Adding `div` as a field rather than defining `a / b := a * b⁻¹` allows us to
avoid certain classes of unification failures, for example:
Let `Foo X` be a type with a `∀ X, Div (Foo X)` instance but no
`∀ X, Inv (Foo X)`, e.g. when `Foo X` is a `EuclideanDomain`. Suppose we
also have an instance `∀ X [Cromulent X], GroupWithZero (Foo X)`. Then the
`(/)` coming from `GroupWithZero.div` cannot be definitionally equal to
the `(/)` coming from `Foo.Div`.
In the same way, adding a `zpow` field makes it possible to avoid definitional failures
in diamonds. See the definition of `Monoid` and Note [forgetful inheritance] for more
explanations on this.
-/
class DivInvMonoid (G : Type u) extends Monoid G, Inv G, Div G, ZPow G where
protected div := DivInvMonoid.div'
/-- `a / b := a * b⁻¹` -/
protected div_eq_mul_inv : ∀ a b : G, a / b = a * b⁻¹ := by intros; rfl
zpow := zpowRec npowRec
/-- `a ^ 0 = 1` -/
protected zpow_zero' (a : G) : a ^ (0 : ℤ) = 1 := by intros; rfl
/-- `a ^ (n + 1) = a ^ n * a` -/
protected zpow_succ' (n : ℕ) (a : G) : a ^ (n.succ : ℤ) = a ^ (n : ℤ) * a := by
intros; rfl