Skip to content

Commit e40e2a7

Browse files
committed
feat: improve toAdditive.guessName (#715)
* The heuristic to split names did it wrong on a long sequence of capital letters. The new heuristic is to have a sequence of "white-listed" names that only consist of capital letters (currently `["LE", "LT", "WF"]`). This new heuristic correctly splits `ZeroLEHAdd` and `HSMul` * translate `[h]pow` to `[h]smul` (see #706). I believe Mathlib4 never used the previous automatic translation `pow -> nsmul` (I used regex `@\[to_additive\]\n?.*(_p|P| p)ow` to search). Since capitalization goes wrong in this case, add some cases in `fixAbbreviation` to fix it. * Fix all places where the capitalization `Smul` was used instead of `SMul`.
1 parent abaaf02 commit e40e2a7

File tree

5 files changed

+47
-64
lines changed

5 files changed

+47
-64
lines changed

Mathlib/Algebra/Group/Defs.lean

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,13 @@ attribute [to_additive_reorder 1] HPow
9797
attribute [to_additive_reorder 1 5] HPow.hPow
9898
attribute [to_additive_reorder 1] Pow
9999
attribute [to_additive_reorder 1 4] Pow.pow
100-
attribute [to_additive SMul] Pow
100+
attribute [to_additive] Pow
101101
attribute [to_additive_reorder 1] instHPow
102-
attribute [to_additive instHSMul] instHPow
103-
attribute [to_additive HSMul] HPow
102+
attribute [to_additive] instHPow
103+
attribute [to_additive] HPow
104104

105-
attribute [to_additive instHVAdd] instHSMul
106-
attribute [to_additive HVAdd] HSMul
105+
attribute [to_additive] instHSMul
106+
attribute [to_additive] HSMul
107107

108108
universe u
109109

@@ -531,7 +531,7 @@ section
531531

532532
variable {M : Type _} [Monoid M]
533533

534-
@[simp, to_additive nsmul_eq_smul]
534+
@[simp, to_additive]
535535
theorem npow_eq_pow (n : ℕ) (x : M) : Monoid.npow n x = x ^ n :=
536536
rfl
537537

@@ -770,7 +770,7 @@ section DivInvMonoid
770770

771771
variable [DivInvMonoid G] {a b : G}
772772

773-
@[simp, to_additive zsmul_eq_smul] theorem zpow_eq_pow (n : ℤ) (x : G) :
773+
@[simp, to_additive] theorem zpow_eq_pow (n : ℤ) (x : G) :
774774
DivInvMonoid.zpow n x = x ^ n :=
775775
rfl
776776

Mathlib/Algebra/Group/OrderSynonym.lean

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ instance [h : Div α] : Div αᵒᵈ := h
3636
instance [h : SMul α β] : SMul α βᵒᵈ := h
3737

3838
@[to_additive]
39-
instance OrderDual.hasSmul' [h : SMul α β] : SMul αᵒᵈ β := h
40-
#align order_dual.has_smul' OrderDual.hasSmul'
39+
instance OrderDual.SMul' [h : SMul α β] : SMul αᵒᵈ β := h
40+
#align order_dual.has_smul' OrderDual.SMul'
4141

42-
@[to_additive OrderDual.hasSmul]
42+
@[to_additive OrderDual.SMul]
4343
instance OrderDual.hasPow [h : Pow α β] : Pow αᵒᵈ β := h
4444
#align order_dual.has_pow OrderDual.hasPow
4545

46-
@[to_additive OrderDual.hasSmul']
46+
@[to_additive OrderDual.SMul']
4747
instance OrderDual.hasPow' [h : Pow α β] : Pow α βᵒᵈ := h
4848
#align order_dual.has_pow' OrderDual.hasPow'
4949

@@ -146,11 +146,11 @@ theorem toDual_smul' [SMul α β] (a : α) (b : β) : toDual a • b = a • b :
146146
theorem ofDual_smul' [SMul α β] (a : αᵒᵈ) (b : β) : ofDual a • b = a • b := rfl
147147
#align of_dual_smul' ofDual_smul'
148148

149-
@[simp, to_additive toDual_smul, to_additive_reorder 1 4]
149+
@[simp, to_additive, to_additive_reorder 1 4]
150150
theorem toDual_pow [Pow α β] (a : α) (b : β) : toDual (a ^ b) = toDual a ^ b := rfl
151151
#align to_dual_pow toDual_pow
152152

153-
@[simp, to_additive ofDual_smul, to_additive_reorder 1 4]
153+
@[simp, to_additive, to_additive_reorder 1 4]
154154
theorem ofDual_pow [Pow α β] (a : αᵒᵈ) (b : β) : ofDual (a ^ b) = ofDual a ^ b := rfl
155155
#align of_dual_pow ofDual_pow
156156

@@ -181,14 +181,14 @@ instance [h : Div α] : Div (Lex α) := h
181181
instance [h : SMul α β] : SMul α (Lex β) := h
182182

183183
@[to_additive]
184-
instance Lex.hasSmul' [h : SMul α β] : SMul (Lex α) β := h
185-
#align lex.has_smul' Lex.hasSmul'
184+
instance Lex.SMul' [h : SMul α β] : SMul (Lex α) β := h
185+
#align lex.has_smul' Lex.SMul'
186186

187-
@[to_additive Lex.hasSmul]
187+
@[to_additive Lex.SMul]
188188
instance Lex.hasPow [h : Pow α β] : Pow (Lex α) β := h
189189
#align lex.has_pow Lex.hasPow
190190

191-
@[to_additive Lex.hasSmul']
191+
@[to_additive Lex.SMul']
192192
instance Lex.hasPow' [h : Pow α β] : Pow α (Lex β) := h
193193
#align lex.has_pow' Lex.hasPow'
194194

@@ -291,11 +291,11 @@ theorem toLex_smul' [SMul α β] (a : α) (b : β) : toLex a • b = a • b :=
291291
theorem ofLex_smul' [SMul α β] (a : Lex α) (b : β) : ofLex a • b = a • b := rfl
292292
#align of_lex_smul' ofLex_smul'
293293

294-
@[simp, to_additive toLex_smul, to_additive_reorder 1 4]
294+
@[simp, to_additive, to_additive_reorder 1 4]
295295
theorem toLex_pow [Pow α β] (a : α) (b : β) : toLex (a ^ b) = toLex a ^ b := rfl
296296
#align to_lex_pow toLex_pow
297297

298-
@[simp, to_additive ofLex_smul, to_additive_reorder 1 4]
298+
@[simp, to_additive, to_additive_reorder 1 4]
299299
theorem ofLex_pow [Pow α β] (a : Lex α) (b : β) : ofLex (a ^ b) = ofLex a ^ b := rfl
300300
#align of_lex_pow ofLex_pow
301301

Mathlib/Data/Bracket.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ these are the Unicode "square with quill" brackets rather than the usual square
2525
1. for certain binary operations on structures, like the product `⁅x, y⁆` of two elements
2626
`x`, `y` in a Lie algebra or the commutator of two elements `x` and `y` in a group.
2727
2. for certain actions of one structure on another, like the action `⁅x, m⁆` of an element `x`
28-
of a Lie algebra on an element `m` in one of its modules (analogous to `Smul` in the
28+
of a Lie algebra on an element `m` in one of its modules (analogous to `SMul` in the
2929
associative setting).
3030
3. for binary operations on substructures, like the commutator `⁅H, K⁆` of two subgroups `H` and
3131
`K` of a group. -/

Mathlib/Tactic/ToAdditive.lean

Lines changed: 24 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ macro "to_additive!?" rest:to_additiveRest : attr => `(attr| to_additive ! ? $re
4949
/-- The `to_additive` attribute. -/
5050
macro "to_additive?!" rest:to_additiveRest : attr => `(attr| to_additive ! ? $rest)
5151

52+
/-- A set of strings of names that are written in all-caps. -/
53+
def allCapitalNames : RBTree String compare :=
54+
.ofList ["LE", "LT", "WF"]
55+
5256
/--
5357
This function takes a String and splits it into separate parts based on the following
5458
(naming conventions)[https://github.com/leanprover-community/mathlib4/wiki#naming-convention].
@@ -59,31 +63,17 @@ E.g. `#eval "InvHMulLEConjugate₂Smul_ne_top".splitCase` yields
5963
partial def String.splitCase (s : String) (i₀ : Pos := 0) (r : List String := []) : List String :=
6064
-- We test if we need to split between `i₀` and `i₁`.
6165
let i₁ := s.next i₀
62-
let i₂ := s.next i₁
6366
if s.atEnd i₁ then
6467
-- If `i₀` is the last position, return the list.
6568
let r := s::r
6669
r.reverse
67-
-- First, we split on both sides of `_` to keep them there when rejoining the string.
68-
else if (s.get i₀ = '_') || (s.get i₁ = '_') then
69-
let r := (s.extract 0 i₁)::r
70-
splitCase (s.extract i₁ s.endPos) 0 r
71-
-- Otherwise, we only ever split when there is an upper case at `i₁`.
72-
else if (s.get i₁).isUpper then
73-
-- There are two cases we need to split:
74-
if (s.get i₀).isUpper then
75-
-- 1) If `i₀` and `i₁` are upper, `i₂` is not upper, and `i₀ > 0`.
76-
-- This prevents single capital letters being split.
77-
-- Example: Splits `LEOne`to `LE`, `One` but leaves `HMul` together.
78-
if (i₀ ≠ 0) && ¬((s.get i₂).isUpper) then
79-
let r := (s.extract 0 i₁)::r
80-
splitCase (s.extract i₁ s.endPos) 0 r
81-
else
82-
splitCase s i₁ r
83-
-- 2) Upper `i₁` is preceeded by non-upper `i₀`.
84-
else
85-
let r := (s.extract 0 i₁)::r
86-
splitCase (s.extract i₁ s.endPos) 0 r
70+
/- We split the string in three cases
71+
* We split on both sides of `_` to keep them there when rejoining the string;
72+
* We split after a sequence of capital letters in `allCapitalNames`;
73+
* We split after a lower-case letter that is followed by an upper-case letter. -/
74+
else if s.get i₀ == '_' || s.get i₁ == '_' ||
75+
((s.get i₁).isUpper && (!(s.get i₀).isUpper || allCapitalNames.contains (s.extract 0 i₁))) then
76+
splitCase (s.extract i₁ s.endPos) 0 <| (s.extract 0 i₁)::r
8777
else
8878
splitCase s i₁ r
8979

@@ -107,8 +97,7 @@ initialize ignoreArgsAttr : NameMapExtension (List Nat) ←
10797
let ids ← match stx with
10898
| `(attr| to_additive_ignore_args $[$ids:num]*) => pure <| ids.map (·.1.isNatLit?.get!)
10999
| _ => throwUnsupportedSyntax
110-
return ids.toList
111-
}
100+
return ids.toList }
112101

113102
/-- Gets the set of arguments that should be ignored for the given name
114103
(according to `@[to_additive_ignore_args ...]`).
@@ -407,7 +396,7 @@ partial def transformDeclAux
407396
return
408397
let srcDecl ← getConstInfo src
409398
let prefixes : NameSet := .ofList [pre, env.mainModule ++ `_auxLemma]
410-
-- we first transform all auxilliary declarations generated when elaborating `pre`
399+
-- we first transform all auxiliary declarations generated when elaborating `pre`
411400
for n in srcDecl.type.listNamesWithPrefixes prefixes do
412401
transformDeclAux none pre tgt_pre n
413402
if let some value := srcDecl.value? then
@@ -541,8 +530,7 @@ structure ValueType : Type where
541530
deriving Repr
542531

543532
/-- Helper for `capitalizeLike`. -/
544-
partial def capitalizeLikeAux (s : String) (i : String.Pos := 0) : String → String :=
545-
fun p =>
533+
partial def capitalizeLikeAux (s : String) (i : String.Pos := 0) (p : String) : String :=
546534
if p.atEnd i || s.atEnd i then
547535
p
548536
else
@@ -558,7 +546,9 @@ partial def capitalizeLikeAux (s : String) (i : String.Pos := 0) : String → S
558546
def capitalizeLike (r : String) (s : String) :=
559547
capitalizeLikeAux r 0 s
560548

561-
/-- Capitalize First element of a list like `s`. -/
549+
/-- Capitalize First element of a list like `s`.
550+
Note that we need to capitalize multiple characters in some cases,
551+
in examples like `HMul` or `hAdd`. -/
562552
def capitalizeFirstLike (s : String) : List String → List String
563553
| x :: r => capitalizeLike s x :: r
564554
| [] => []
@@ -578,10 +568,11 @@ private def nameDict : String → List String
578568
| "div" => ["sub"]
579569
| "prod" => ["sum"]
580570
| "hmul" => ["hadd"]
571+
| "hsmul" => ["hvadd"]
581572
| "hdiv" => ["hsub"]
582-
| "hpow" => ["hmul"]
573+
| "hpow" => ["hsmul"]
583574
| "finprod" => ["finsum"]
584-
| "pow" => ["nsmul"]
575+
| "pow" => ["smul"]
585576
| "npow" => ["nsmul"]
586577
| "zpow" => ["zsmul"]
587578
| "monoid" => ["add", "Monoid"]
@@ -634,19 +625,16 @@ def fixAbbreviation : List String → List String
634625
| "Add" :: "Support" :: s => "Support" :: fixAbbreviation s
635626
| "add" :: "Support" :: s => "support" :: fixAbbreviation s
636627
| "add" :: "_" :: "support" :: s => "support" :: fixAbbreviation s
637-
-- TODO: Is it `TSupport` or `Tsupport`?
638628
| "Add" :: "TSupport" :: s => "TSupport" :: fixAbbreviation s
639629
| "add" :: "TSupport" :: s => "tsupport" :: fixAbbreviation s
640630
| "add" :: "_" :: "tsupport" :: s => "tsupport" :: fixAbbreviation s
641631
| "Add" :: "Indicator" :: s => "Indicator" :: fixAbbreviation s
642632
| "add" :: "Indicator" :: s => "indicator" :: fixAbbreviation s
643633
| "add" :: "_" :: "indicator" :: s => "indicator" :: fixAbbreviation s
644-
-- TODO: Bug in `splitCase` splits like ["LEH", "Pow"] instead of ["LE", "HPow"].
645-
-- Currently we just fix these cases manually.
646-
| "HNsmul" :: s => "HMul" :: fixAbbreviation s
647-
| "hnsmul" :: s => "hmul" :: fixAbbreviation s
648-
| "Zero" :: "LEH" :: s => "NonnegH" :: fixAbbreviation s
649-
| "Zero" :: "LTH" :: s => "PosH" :: fixAbbreviation s
634+
-- the capitalization heuristic of `applyNameDict` doesn't work in the following cases
635+
| "Smul" :: s => "SMul" :: fixAbbreviation s
636+
| "HSmul" :: s => "HSMul" :: fixAbbreviation s
637+
| "hSmul" :: s => "hSMul" :: fixAbbreviation s
650638
| x :: s => x :: fixAbbreviation s
651639
| [] => []
652640

test/toAdditive.lean

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ def checkGuessName (s t : String) : Elab.Command.CommandElabM Unit :=
222222

223223
run_cmd
224224
checkGuessName "HMul_Eq_LEOne_Conj₂MulLT'" "HAdd_Eq_Nonpos_Conj₂AddLT'"
225-
checkGuessName "OneMulSmulInvDivPow" "ZeroAddVaddNegSubNsmul"
225+
checkGuessName "OneMulSMulInvDivPow" "ZeroAddVAddNegSubSMul"
226226
checkGuessName "ProdFinprodNpowZpow" "SumFinsumNsmulZsmul"
227227

228228
-- The current design swaps all instances of `Comm`+`Add` in order to have
@@ -247,14 +247,9 @@ run_cmd
247247
checkGuessName "leftCancelMonoid" "addLeftCancelMonoid"
248248

249249
checkGuessName "LTOne_LEOne_OneLE_OneLT" "Neg_Nonpos_Nonneg_Pos"
250-
251-
-- The current design splits this as `LTH, Mul, HPow, LEH, Div` before it translates.
252-
-- This is kinda a bug.
253-
checkGuessName "LTHMulHPowLEHDiv" "LTHAddHMulLEHSub"
250+
checkGuessName "LTHMulHPowLEHDiv" "LTHAddHSMulLEHSub"
254251
checkGuessName "OneLEHMul" "NonnegHAdd"
255-
256-
-- -- TODO: This fails at the moment:
257-
-- checkGuessName "OneLTHPow" "PosHMul"
252+
checkGuessName "OneLTHPow" "PosHSMul"
258253

259254
end guessName
260255

0 commit comments

Comments
 (0)