algebra.group.unique_prodsMathlib.Algebra.Group.UniqueProds

This file has been ported!

Changes since the initial port

The following section lists changes to this file in mathlib3 and mathlib4 that occured after the initial port. Most recent changes are shown first. Hovering over a commit will show all commits associated with the same mathlib3 commit.

Changes in mathlib3

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(last sync)

Changes in mathlib3port

mathlib3
mathlib3port
Diff
@@ -84,7 +84,7 @@ theorem set_subsingleton (A B : Finset G) (a0 b0 : G) (h : UniqueMul A B a0 b0)
 #align unique_add.set_subsingleton UniqueAdd.set_subsingleton
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:641:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:642:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
 /- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
 @[to_additive]
 theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
@@ -98,7 +98,7 @@ theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
 #align unique_mul.iff_exists_unique UniqueMul.iff_existsUniqueₓ
 #align unique_add.iff_exists_unique UniqueAdd.iff_existsUniqueₓ
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:641:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:642:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
 /- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
 @[to_additive]
 theorem exists_iff_exists_existsUnique :
Diff
@@ -123,7 +123,7 @@ theorem mulHom_preimage (f : G →ₙ* H) (hf : Function.Injective f) (a0 b0 : G
   by
   intro a b ha hb ab
   rw [← hf.eq_iff, ← hf.eq_iff]
-  rw [← hf.eq_iff, map_mul, map_mul] at ab 
+  rw [← hf.eq_iff, map_mul, map_mul] at ab
   exact u (finset.mem_preimage.mp ha) (finset.mem_preimage.mp hb) ab
 #align unique_mul.mul_hom_preimage UniqueMul.mulHom_preimage
 #align unique_add.add_hom_preimage UniqueAdd.addHom_preimage
@@ -141,13 +141,13 @@ theorem mulHom_image_iff [DecidableEq H] (f : G →ₙ* H) (hf : Function.Inject
   refine' ⟨fun h => _, fun h => _⟩
   · intro a b ha hb ab
     rw [← hf.eq_iff, ← hf.eq_iff]
-    rw [← hf.eq_iff, map_mul, map_mul] at ab 
+    rw [← hf.eq_iff, map_mul, map_mul] at ab
     exact h (finset.mem_image.mpr ⟨_, ha, rfl⟩) (finset.mem_image.mpr ⟨_, hb, rfl⟩) ab
   · intro a b aA bB ab
     obtain ⟨a, ha, rfl⟩ : ∃ a' ∈ A, f a' = a := finset.mem_image.mp aA
     obtain ⟨b, hb, rfl⟩ : ∃ b' ∈ B, f b' = b := finset.mem_image.mp bB
     rw [hf.eq_iff, hf.eq_iff]
-    rw [← map_mul, ← map_mul, hf.eq_iff] at ab 
+    rw [← map_mul, ← map_mul, hf.eq_iff] at ab
     exact h ha hb ab
 #align unique_mul.mul_hom_image_iff UniqueMul.mulHom_image_iff
 #align unique_add.add_hom_image_iff UniqueAdd.addHom_image_iff
@@ -225,7 +225,7 @@ theorem eq_and_eq_of_le_of_le_of_hMul_le {A} [Mul A] [LinearOrder A]
   haveI := Mul.to_covariantClass_right A
   have ha' : ¬a0 * b0 < a * b → ¬a0 < a := mt fun h => mul_lt_mul_of_lt_of_le h hb
   have hb' : ¬a0 * b0 < a * b → ¬b0 < b := mt fun h => mul_lt_mul_of_le_of_lt ha h
-  push_neg at ha' hb' 
+  push_neg at ha' hb'
   exact ⟨ha.antisymm' (ha' ab), hb.antisymm' (hb' ab)⟩
 #align eq_and_eq_of_le_of_le_of_mul_le eq_and_eq_of_le_of_le_of_hMul_le
 #align eq_and_eq_of_le_of_le_of_add_le eq_and_eq_of_le_of_le_of_add_le
Diff
@@ -160,7 +160,10 @@ See `unique_mul.mul_hom_image_iff` for a version with swapped bundling. -/
 @[to_additive
       "`unique_add` is preserved under embeddings that are additive.\n\nSee `unique_add.add_hom_image_iff` for a version with swapped bundling."]
 theorem mulHom_map_iff (f : G ↪ H) (mul : ∀ x y, f (x * y) = f x * f y) :
-    UniqueMul (A.map f) (B.map f) (f a0) (f b0) ↔ UniqueMul A B a0 b0 := by classical
+    UniqueMul (A.map f) (B.map f) (f a0) (f b0) ↔ UniqueMul A B a0 b0 := by
+  classical convert mul_hom_image_iff ⟨f, mul⟩ f.2 <;>
+    · ext
+      simp only [Finset.mem_map, MulHom.coe_mk, Finset.mem_image]
 #align unique_mul.mul_hom_map_iff UniqueMul.mulHom_map_iff
 #align unique_add.add_hom_map_iff UniqueAdd.addHom_map_iff
 -/
Diff
@@ -160,10 +160,7 @@ See `unique_mul.mul_hom_image_iff` for a version with swapped bundling. -/
 @[to_additive
       "`unique_add` is preserved under embeddings that are additive.\n\nSee `unique_add.add_hom_image_iff` for a version with swapped bundling."]
 theorem mulHom_map_iff (f : G ↪ H) (mul : ∀ x y, f (x * y) = f x * f y) :
-    UniqueMul (A.map f) (B.map f) (f a0) (f b0) ↔ UniqueMul A B a0 b0 := by
-  classical convert mul_hom_image_iff ⟨f, mul⟩ f.2 <;>
-    · ext
-      simp only [Finset.mem_map, MulHom.coe_mk, Finset.mem_image]
+    UniqueMul (A.map f) (B.map f) (f a0) (f b0) ↔ UniqueMul A B a0 b0 := by classical
 #align unique_mul.mul_hom_map_iff UniqueMul.mulHom_map_iff
 #align unique_add.add_hom_map_iff UniqueAdd.addHom_map_iff
 -/
Diff
@@ -3,7 +3,7 @@ Copyright (c) 2022 Damiano Testa. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Damiano Testa
 -/
-import Mathbin.Data.Finset.Preimage
+import Data.Finset.Preimage
 
 #align_import algebra.group.unique_prods from "leanprover-community/mathlib"@"63f84d91dd847f50bae04a01071f3a5491934e36"
 
@@ -84,7 +84,7 @@ theorem set_subsingleton (A B : Finset G) (a0 b0 : G) (h : UniqueMul A B a0 b0)
 #align unique_add.set_subsingleton UniqueAdd.set_subsingleton
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:641:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
 /- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
 @[to_additive]
 theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
@@ -98,7 +98,7 @@ theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
 #align unique_mul.iff_exists_unique UniqueMul.iff_existsUniqueₓ
 #align unique_add.iff_exists_unique UniqueAdd.iff_existsUniqueₓ
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:641:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
 /- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
 @[to_additive]
 theorem exists_iff_exists_existsUnique :
Diff
@@ -86,7 +86,6 @@ theorem set_subsingleton (A B : Finset G) (a0 b0 : G) (h : UniqueMul A B a0 b0)
 
 /- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
 /- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
-#print UniqueMul.iff_existsUnique /-
 @[to_additive]
 theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
     UniqueMul A B a0 b0 ↔ ∃! (ab : _) (_ : ab ∈ A ×ˢ B), ab.1 * ab.2 = a0 * b0 :=
@@ -96,13 +95,11 @@ theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
         rintro ⟨x1, x2⟩ _ _ J x y hx hy l
         rcases prod.mk.inj_iff.mp (J (a0, b0) (Finset.mk_mem_product aA bB) rfl) with ⟨rfl, rfl⟩
         exact prod.mk.inj_iff.mp (J (x, y) (Finset.mk_mem_product hx hy) l))⟩
-#align unique_mul.iff_exists_unique UniqueMul.iff_existsUnique
-#align unique_add.iff_exists_unique UniqueAdd.iff_existsUnique
--/
+#align unique_mul.iff_exists_unique UniqueMul.iff_existsUniqueₓ
+#align unique_add.iff_exists_unique UniqueAdd.iff_existsUniqueₓ
 
 /- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
 /- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
-#print UniqueMul.exists_iff_exists_existsUnique /-
 @[to_additive]
 theorem exists_iff_exists_existsUnique :
     (∃ a0 b0 : G, a0 ∈ A ∧ b0 ∈ B ∧ UniqueMul A B a0 b0) ↔
@@ -113,9 +110,8 @@ theorem exists_iff_exists_existsUnique :
     rcases h' with ⟨⟨a, b⟩, ⟨hab, rfl, -⟩, -⟩
     cases' finset.mem_product.mp hab with ha hb
     exact ⟨a, b, ha, hb, (iff_exists_unique ha hb).mpr h⟩⟩
-#align unique_mul.exists_iff_exists_exists_unique UniqueMul.exists_iff_exists_existsUnique
-#align unique_add.exists_iff_exists_exists_unique UniqueAdd.exists_iff_exists_existsUnique
--/
+#align unique_mul.exists_iff_exists_exists_unique UniqueMul.exists_iff_exists_existsUniqueₓ
+#align unique_add.exists_iff_exists_exists_unique UniqueAdd.exists_iff_exists_existsUniqueₓ
 
 #print UniqueMul.mulHom_preimage /-
 /-- `unique_mul` is preserved by inverse images under injective, multiplicative maps. -/
Diff
@@ -220,9 +220,8 @@ instance {M} [Mul M] [UniqueProds M] : UniqueSums (Additive M)
 
 end Additive
 
-#print eq_and_eq_of_le_of_le_of_mul_le /-
 @[to_additive]
-theorem eq_and_eq_of_le_of_le_of_mul_le {A} [Mul A] [LinearOrder A]
+theorem eq_and_eq_of_le_of_le_of_hMul_le {A} [Mul A] [LinearOrder A]
     [CovariantClass A A (· * ·) (· ≤ ·)] [CovariantClass A A (Function.swap (· * ·)) (· < ·)]
     [ContravariantClass A A (· * ·) (· ≤ ·)] {a b a0 b0 : A} (ha : a0 ≤ a) (hb : b0 ≤ b)
     (ab : a * b ≤ a0 * b0) : a = a0 ∧ b = b0 :=
@@ -232,11 +231,9 @@ theorem eq_and_eq_of_le_of_le_of_mul_le {A} [Mul A] [LinearOrder A]
   have hb' : ¬a0 * b0 < a * b → ¬b0 < b := mt fun h => mul_lt_mul_of_le_of_lt ha h
   push_neg at ha' hb' 
   exact ⟨ha.antisymm' (ha' ab), hb.antisymm' (hb' ab)⟩
-#align eq_and_eq_of_le_of_le_of_mul_le eq_and_eq_of_le_of_le_of_mul_le
+#align eq_and_eq_of_le_of_le_of_mul_le eq_and_eq_of_le_of_le_of_hMul_le
 #align eq_and_eq_of_le_of_le_of_add_le eq_and_eq_of_le_of_le_of_add_le
--/
 
-#print Covariants.to_uniqueProds /-
 -- see Note [lower instance priority]
 /-- This instance asserts that if `A` has a multiplication, a linear order, and multiplication
 is 'very monotone', then `A` also has `unique_prods`. -/
@@ -247,8 +244,7 @@ instance (priority := 100) Covariants.to_uniqueProds {A} [Mul A] [LinearOrder A]
     [ContravariantClass A A (· * ·) (· ≤ ·)] : UniqueProds A
     where uniqueMul_of_nonempty A B hA hB :=
     ⟨_, A.min'_mem ‹_›, _, B.min'_mem ‹_›, fun a b ha hb ab =>
-      eq_and_eq_of_le_of_le_of_mul_le (Finset.min'_le _ _ ‹_›) (Finset.min'_le _ _ ‹_›) ab.le⟩
+      eq_and_eq_of_le_of_le_of_hMul_le (Finset.min'_le _ _ ‹_›) (Finset.min'_le _ _ ‹_›) ab.le⟩
 #align covariants.to_unique_prods Covariants.to_uniqueProds
-#align covariants.to_unique_sums Covariants.to_uniqueSums
--/
+#align covariants.to_unique_sums Covariants.to_unique_sums
 
Diff
@@ -2,14 +2,11 @@
 Copyright (c) 2022 Damiano Testa. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Damiano Testa
-
-! This file was ported from Lean 3 source module algebra.group.unique_prods
-! leanprover-community/mathlib commit 63f84d91dd847f50bae04a01071f3a5491934e36
-! Please do not edit these lines, except to modify the commit id
-! if you have ported upstream changes.
 -/
 import Mathbin.Data.Finset.Preimage
 
+#align_import algebra.group.unique_prods from "leanprover-community/mathlib"@"63f84d91dd847f50bae04a01071f3a5491934e36"
+
 /-!
 #  Unique products and related notions
 
@@ -87,7 +84,7 @@ theorem set_subsingleton (A B : Finset G) (a0 b0 : G) (h : UniqueMul A B a0 b0)
 #align unique_add.set_subsingleton UniqueAdd.set_subsingleton
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:638:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
 /- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
 #print UniqueMul.iff_existsUnique /-
 @[to_additive]
@@ -103,7 +100,7 @@ theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
 #align unique_add.iff_exists_unique UniqueAdd.iff_existsUnique
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:638:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
 /- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
 #print UniqueMul.exists_iff_exists_existsUnique /-
 @[to_additive]
Diff
@@ -120,6 +120,7 @@ theorem exists_iff_exists_existsUnique :
 #align unique_add.exists_iff_exists_exists_unique UniqueAdd.exists_iff_exists_existsUnique
 -/
 
+#print UniqueMul.mulHom_preimage /-
 /-- `unique_mul` is preserved by inverse images under injective, multiplicative maps. -/
 @[to_additive "`unique_add` is preserved by inverse images under injective, additive maps."]
 theorem mulHom_preimage (f : G →ₙ* H) (hf : Function.Injective f) (a0 b0 : G) {A B : Finset H}
@@ -133,6 +134,7 @@ theorem mulHom_preimage (f : G →ₙ* H) (hf : Function.Injective f) (a0 b0 : G
   exact u (finset.mem_preimage.mp ha) (finset.mem_preimage.mp hb) ab
 #align unique_mul.mul_hom_preimage UniqueMul.mulHom_preimage
 #align unique_add.add_hom_preimage UniqueAdd.addHom_preimage
+-/
 
 #print UniqueMul.mulHom_image_iff /-
 /-- `unique_mul` is preserved under multiplicative maps that are injective.
@@ -158,6 +160,7 @@ theorem mulHom_image_iff [DecidableEq H] (f : G →ₙ* H) (hf : Function.Inject
 #align unique_add.add_hom_image_iff UniqueAdd.addHom_image_iff
 -/
 
+#print UniqueMul.mulHom_map_iff /-
 /-- `unique_mul` is preserved under embeddings that are multiplicative.
 
 See `unique_mul.mul_hom_image_iff` for a version with swapped bundling. -/
@@ -170,6 +173,7 @@ theorem mulHom_map_iff (f : G ↪ H) (mul : ∀ x y, f (x * y) = f x * f y) :
       simp only [Finset.mem_map, MulHom.coe_mk, Finset.mem_image]
 #align unique_mul.mul_hom_map_iff UniqueMul.mulHom_map_iff
 #align unique_add.add_hom_map_iff UniqueAdd.addHom_map_iff
+-/
 
 end UniqueMul
 
Diff
@@ -87,7 +87,7 @@ theorem set_subsingleton (A B : Finset G) (a0 b0 : G) (h : UniqueMul A B a0 b0)
 #align unique_add.set_subsingleton UniqueAdd.set_subsingleton
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:638:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
 /- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
 #print UniqueMul.iff_existsUnique /-
 @[to_additive]
@@ -103,7 +103,7 @@ theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
 #align unique_add.iff_exists_unique UniqueAdd.iff_existsUnique
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:638:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
 /- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
 #print UniqueMul.exists_iff_exists_existsUnique /-
 @[to_additive]
Diff
@@ -76,7 +76,7 @@ theorem subsingleton (A B : Finset G) (a0 b0 : G) (h : UniqueMul A B a0 b0) :
 #print UniqueMul.set_subsingleton /-
 @[to_additive]
 theorem set_subsingleton (A B : Finset G) (a0 b0 : G) (h : UniqueMul A B a0 b0) :
-    Set.Subsingleton { ab : G × G | ab.1 ∈ A ∧ ab.2 ∈ B ∧ ab.1 * ab.2 = a0 * b0 } :=
+    Set.Subsingleton {ab : G × G | ab.1 ∈ A ∧ ab.2 ∈ B ∧ ab.1 * ab.2 = a0 * b0} :=
   by
   rintro ⟨x1, y1⟩ (hx : x1 ∈ A ∧ y1 ∈ B ∧ x1 * y1 = a0 * b0) ⟨x2, y2⟩
     (hy : x2 ∈ A ∧ y2 ∈ B ∧ x2 * y2 = a0 * b0)
@@ -166,8 +166,8 @@ See `unique_mul.mul_hom_image_iff` for a version with swapped bundling. -/
 theorem mulHom_map_iff (f : G ↪ H) (mul : ∀ x y, f (x * y) = f x * f y) :
     UniqueMul (A.map f) (B.map f) (f a0) (f b0) ↔ UniqueMul A B a0 b0 := by
   classical convert mul_hom_image_iff ⟨f, mul⟩ f.2 <;>
-      · ext
-        simp only [Finset.mem_map, MulHom.coe_mk, Finset.mem_image]
+    · ext
+      simp only [Finset.mem_map, MulHom.coe_mk, Finset.mem_image]
 #align unique_mul.mul_hom_map_iff UniqueMul.mulHom_map_iff
 #align unique_add.add_hom_map_iff UniqueAdd.addHom_map_iff
 
@@ -229,7 +229,7 @@ theorem eq_and_eq_of_le_of_le_of_mul_le {A} [Mul A] [LinearOrder A]
   haveI := Mul.to_covariantClass_right A
   have ha' : ¬a0 * b0 < a * b → ¬a0 < a := mt fun h => mul_lt_mul_of_lt_of_le h hb
   have hb' : ¬a0 * b0 < a * b → ¬b0 < b := mt fun h => mul_lt_mul_of_le_of_lt ha h
-  push_neg  at ha' hb' 
+  push_neg at ha' hb' 
   exact ⟨ha.antisymm' (ha' ab), hb.antisymm' (hb' ab)⟩
 #align eq_and_eq_of_le_of_le_of_mul_le eq_and_eq_of_le_of_le_of_mul_le
 #align eq_and_eq_of_le_of_le_of_add_le eq_and_eq_of_le_of_le_of_add_le
Diff
@@ -92,7 +92,7 @@ theorem set_subsingleton (A B : Finset G) (a0 b0 : G) (h : UniqueMul A B a0 b0)
 #print UniqueMul.iff_existsUnique /-
 @[to_additive]
 theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
-    UniqueMul A B a0 b0 ↔ ∃! (ab : _)(_ : ab ∈ A ×ˢ B), ab.1 * ab.2 = a0 * b0 :=
+    UniqueMul A B a0 b0 ↔ ∃! (ab : _) (_ : ab ∈ A ×ˢ B), ab.1 * ab.2 = a0 * b0 :=
   ⟨fun _ => ⟨(a0, b0), ⟨Finset.mem_product.mpr ⟨aA, bB⟩, rfl, by simp⟩, by simpa⟩, fun h =>
     h.elim₂
       (by
@@ -109,7 +109,7 @@ theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
 @[to_additive]
 theorem exists_iff_exists_existsUnique :
     (∃ a0 b0 : G, a0 ∈ A ∧ b0 ∈ B ∧ UniqueMul A B a0 b0) ↔
-      ∃ g : G, ∃! (ab : _)(_ : ab ∈ A ×ˢ B), ab.1 * ab.2 = g :=
+      ∃ g : G, ∃! (ab : _) (_ : ab ∈ A ×ˢ B), ab.1 * ab.2 = g :=
   ⟨fun ⟨a0, b0, hA, hB, h⟩ => ⟨_, (iff_existsUnique hA hB).mp h⟩, fun ⟨g, h⟩ =>
     by
     have h' := h
@@ -129,7 +129,7 @@ theorem mulHom_preimage (f : G →ₙ* H) (hf : Function.Injective f) (a0 b0 : G
   by
   intro a b ha hb ab
   rw [← hf.eq_iff, ← hf.eq_iff]
-  rw [← hf.eq_iff, map_mul, map_mul] at ab
+  rw [← hf.eq_iff, map_mul, map_mul] at ab 
   exact u (finset.mem_preimage.mp ha) (finset.mem_preimage.mp hb) ab
 #align unique_mul.mul_hom_preimage UniqueMul.mulHom_preimage
 #align unique_add.add_hom_preimage UniqueAdd.addHom_preimage
@@ -146,13 +146,13 @@ theorem mulHom_image_iff [DecidableEq H] (f : G →ₙ* H) (hf : Function.Inject
   refine' ⟨fun h => _, fun h => _⟩
   · intro a b ha hb ab
     rw [← hf.eq_iff, ← hf.eq_iff]
-    rw [← hf.eq_iff, map_mul, map_mul] at ab
+    rw [← hf.eq_iff, map_mul, map_mul] at ab 
     exact h (finset.mem_image.mpr ⟨_, ha, rfl⟩) (finset.mem_image.mpr ⟨_, hb, rfl⟩) ab
   · intro a b aA bB ab
     obtain ⟨a, ha, rfl⟩ : ∃ a' ∈ A, f a' = a := finset.mem_image.mp aA
     obtain ⟨b, hb, rfl⟩ : ∃ b' ∈ B, f b' = b := finset.mem_image.mp bB
     rw [hf.eq_iff, hf.eq_iff]
-    rw [← map_mul, ← map_mul, hf.eq_iff] at ab
+    rw [← map_mul, ← map_mul, hf.eq_iff] at ab 
     exact h ha hb ab
 #align unique_mul.mul_hom_image_iff UniqueMul.mulHom_image_iff
 #align unique_add.add_hom_image_iff UniqueAdd.addHom_image_iff
@@ -229,7 +229,7 @@ theorem eq_and_eq_of_le_of_le_of_mul_le {A} [Mul A] [LinearOrder A]
   haveI := Mul.to_covariantClass_right A
   have ha' : ¬a0 * b0 < a * b → ¬a0 < a := mt fun h => mul_lt_mul_of_lt_of_le h hb
   have hb' : ¬a0 * b0 < a * b → ¬b0 < b := mt fun h => mul_lt_mul_of_le_of_lt ha h
-  push_neg  at ha' hb'
+  push_neg  at ha' hb' 
   exact ⟨ha.antisymm' (ha' ab), hb.antisymm' (hb' ab)⟩
 #align eq_and_eq_of_le_of_le_of_mul_le eq_and_eq_of_le_of_le_of_mul_le
 #align eq_and_eq_of_le_of_le_of_add_le eq_and_eq_of_le_of_le_of_add_le
Diff
@@ -219,6 +219,7 @@ instance {M} [Mul M] [UniqueProds M] : UniqueSums (Additive M)
 
 end Additive
 
+#print eq_and_eq_of_le_of_le_of_mul_le /-
 @[to_additive]
 theorem eq_and_eq_of_le_of_le_of_mul_le {A} [Mul A] [LinearOrder A]
     [CovariantClass A A (· * ·) (· ≤ ·)] [CovariantClass A A (Function.swap (· * ·)) (· < ·)]
@@ -232,7 +233,9 @@ theorem eq_and_eq_of_le_of_le_of_mul_le {A} [Mul A] [LinearOrder A]
   exact ⟨ha.antisymm' (ha' ab), hb.antisymm' (hb' ab)⟩
 #align eq_and_eq_of_le_of_le_of_mul_le eq_and_eq_of_le_of_le_of_mul_le
 #align eq_and_eq_of_le_of_le_of_add_le eq_and_eq_of_le_of_le_of_add_le
+-/
 
+#print Covariants.to_uniqueProds /-
 -- see Note [lower instance priority]
 /-- This instance asserts that if `A` has a multiplication, a linear order, and multiplication
 is 'very monotone', then `A` also has `unique_prods`. -/
@@ -246,4 +249,5 @@ instance (priority := 100) Covariants.to_uniqueProds {A} [Mul A] [LinearOrder A]
       eq_and_eq_of_le_of_le_of_mul_le (Finset.min'_le _ _ ‹_›) (Finset.min'_le _ _ ‹_›) ab.le⟩
 #align covariants.to_unique_prods Covariants.to_uniqueProds
 #align covariants.to_unique_sums Covariants.to_uniqueSums
+-/
 
Diff
@@ -120,9 +120,6 @@ theorem exists_iff_exists_existsUnique :
 #align unique_add.exists_iff_exists_exists_unique UniqueAdd.exists_iff_exists_existsUnique
 -/
 
-/- warning: unique_mul.mul_hom_preimage -> UniqueMul.mulHom_preimage is a dubious translation:
-<too large>
-Case conversion may be inaccurate. Consider using '#align unique_mul.mul_hom_preimage UniqueMul.mulHom_preimageₓ'. -/
 /-- `unique_mul` is preserved by inverse images under injective, multiplicative maps. -/
 @[to_additive "`unique_add` is preserved by inverse images under injective, additive maps."]
 theorem mulHom_preimage (f : G →ₙ* H) (hf : Function.Injective f) (a0 b0 : G) {A B : Finset H}
@@ -161,12 +158,6 @@ theorem mulHom_image_iff [DecidableEq H] (f : G →ₙ* H) (hf : Function.Inject
 #align unique_add.add_hom_image_iff UniqueAdd.addHom_image_iff
 -/
 
-/- warning: unique_mul.mul_hom_map_iff -> UniqueMul.mulHom_map_iff is a dubious translation:
-lean 3 declaration is
-  forall {G : Type.{u1}} {H : Type.{u2}} [_inst_1 : Mul.{u1} G] [_inst_2 : Mul.{u2} H] {A : Finset.{u1} G} {B : Finset.{u1} G} {a0 : G} {b0 : G} (f : Function.Embedding.{succ u1, succ u2} G H), (forall (x : G) (y : G), Eq.{succ u2} H (coeFn.{max 1 (succ u1) (succ u2), max (succ u1) (succ u2)} (Function.Embedding.{succ u1, succ u2} G H) (fun (_x : Function.Embedding.{succ u1, succ u2} G H) => G -> H) (Function.Embedding.hasCoeToFun.{succ u1, succ u2} G H) f (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G _inst_1) x y)) (HMul.hMul.{u2, u2, u2} H H H (instHMul.{u2} H _inst_2) (coeFn.{max 1 (succ u1) (succ u2), max (succ u1) (succ u2)} (Function.Embedding.{succ u1, succ u2} G H) (fun (_x : Function.Embedding.{succ u1, succ u2} G H) => G -> H) (Function.Embedding.hasCoeToFun.{succ u1, succ u2} G H) f x) (coeFn.{max 1 (succ u1) (succ u2), max (succ u1) (succ u2)} (Function.Embedding.{succ u1, succ u2} G H) (fun (_x : Function.Embedding.{succ u1, succ u2} G H) => G -> H) (Function.Embedding.hasCoeToFun.{succ u1, succ u2} G H) f y))) -> (Iff (UniqueMul.{u2} H _inst_2 (Finset.map.{u1, u2} G H f A) (Finset.map.{u1, u2} G H f B) (coeFn.{max 1 (succ u1) (succ u2), max (succ u1) (succ u2)} (Function.Embedding.{succ u1, succ u2} G H) (fun (_x : Function.Embedding.{succ u1, succ u2} G H) => G -> H) (Function.Embedding.hasCoeToFun.{succ u1, succ u2} G H) f a0) (coeFn.{max 1 (succ u1) (succ u2), max (succ u1) (succ u2)} (Function.Embedding.{succ u1, succ u2} G H) (fun (_x : Function.Embedding.{succ u1, succ u2} G H) => G -> H) (Function.Embedding.hasCoeToFun.{succ u1, succ u2} G H) f b0)) (UniqueMul.{u1} G _inst_1 A B a0 b0))
-but is expected to have type
-  forall {G : Type.{u2}} {H : Type.{u1}} [_inst_1 : Mul.{u2} G] [_inst_2 : Mul.{u1} H] {A : Finset.{u2} G} {B : Finset.{u2} G} {a0 : G} {b0 : G} (f : Function.Embedding.{succ u2, succ u1} G H), (forall (x : G) (y : G), Eq.{succ u1} ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : G) => H) (HMul.hMul.{u2, u2, u2} G G G (instHMul.{u2} G _inst_1) x y)) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} G H) G (fun (_x : G) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : G) => H) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} G H) G H (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} G H)) f (HMul.hMul.{u2, u2, u2} G G G (instHMul.{u2} G _inst_1) x y)) (HMul.hMul.{u1, u1, u1} ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : G) => H) x) ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : G) => H) y) ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : G) => H) x) (instHMul.{u1} ((fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : G) => H) x) _inst_2) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} G H) G (fun (_x : G) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : G) => H) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} G H) G H (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} G H)) f x) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} G H) G (fun (_x : G) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : G) => H) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} G H) G H (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} G H)) f y))) -> (Iff (UniqueMul.{u1} H _inst_2 (Finset.map.{u2, u1} G H f A) (Finset.map.{u2, u1} G H f B) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} G H) G (fun (_x : G) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : G) => H) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} G H) G H (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} G H)) f a0) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} G H) G (fun (_x : G) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : G) => H) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} G H) G H (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} G H)) f b0)) (UniqueMul.{u2} G _inst_1 A B a0 b0))
-Case conversion may be inaccurate. Consider using '#align unique_mul.mul_hom_map_iff UniqueMul.mulHom_map_iffₓ'. -/
 /-- `unique_mul` is preserved under embeddings that are multiplicative.
 
 See `unique_mul.mul_hom_image_iff` for a version with swapped bundling. -/
@@ -228,12 +219,6 @@ instance {M} [Mul M] [UniqueProds M] : UniqueSums (Additive M)
 
 end Additive
 
-/- warning: eq_and_eq_of_le_of_le_of_mul_le -> eq_and_eq_of_le_of_le_of_mul_le is a dubious translation:
-lean 3 declaration is
-  forall {A : Type.{u1}} [_inst_1 : Mul.{u1} A] [_inst_2 : LinearOrder.{u1} A] [_inst_3 : CovariantClass.{u1, u1} A A (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1)) (LE.le.{u1} A (Preorder.toHasLe.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))))] [_inst_4 : CovariantClass.{u1, u1} A A (Function.swap.{succ u1, succ u1, succ u1} A A (fun (ᾰ : A) (ᾰ : A) => A) (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1))) (LT.lt.{u1} A (Preorder.toHasLt.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))))] [_inst_5 : ContravariantClass.{u1, u1} A A (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1)) (LE.le.{u1} A (Preorder.toHasLe.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))))] {a : A} {b : A} {a0 : A} {b0 : A}, (LE.le.{u1} A (Preorder.toHasLe.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))) a0 a) -> (LE.le.{u1} A (Preorder.toHasLe.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))) b0 b) -> (LE.le.{u1} A (Preorder.toHasLe.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))) (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) a b) (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) a0 b0)) -> (And (Eq.{succ u1} A a a0) (Eq.{succ u1} A b b0))
-but is expected to have type
-  forall {A : Type.{u1}} [_inst_1 : Mul.{u1} A] [_inst_2 : LinearOrder.{u1} A] [_inst_3 : CovariantClass.{u1, u1} A A (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1830 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1832 : A) => HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1830 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1832) (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1845 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1847 : A) => LE.le.{u1} A (Preorder.toLE.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1845 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1847)] [_inst_4 : CovariantClass.{u1, u1} A A (Function.swap.{succ u1, succ u1, succ u1} A A (fun (ᾰ : A) (ᾰ : A) => A) (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1867 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1869 : A) => HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1867 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1869)) (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1882 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1884 : A) => LT.lt.{u1} A (Preorder.toLT.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1882 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1884)] [_inst_5 : ContravariantClass.{u1, u1} A A (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1901 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1903 : A) => HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1901 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1903) (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1916 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1918 : A) => LE.le.{u1} A (Preorder.toLE.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1916 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1918)] {a : A} {b : A} {a0 : A} {b0 : A}, (LE.le.{u1} A (Preorder.toLE.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) a0 a) -> (LE.le.{u1} A (Preorder.toLE.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) b0 b) -> (LE.le.{u1} A (Preorder.toLE.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) a b) (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) a0 b0)) -> (And (Eq.{succ u1} A a a0) (Eq.{succ u1} A b b0))
-Case conversion may be inaccurate. Consider using '#align eq_and_eq_of_le_of_le_of_mul_le eq_and_eq_of_le_of_le_of_mul_leₓ'. -/
 @[to_additive]
 theorem eq_and_eq_of_le_of_le_of_mul_le {A} [Mul A] [LinearOrder A]
     [CovariantClass A A (· * ·) (· ≤ ·)] [CovariantClass A A (Function.swap (· * ·)) (· < ·)]
@@ -248,12 +233,6 @@ theorem eq_and_eq_of_le_of_le_of_mul_le {A} [Mul A] [LinearOrder A]
 #align eq_and_eq_of_le_of_le_of_mul_le eq_and_eq_of_le_of_le_of_mul_le
 #align eq_and_eq_of_le_of_le_of_add_le eq_and_eq_of_le_of_le_of_add_le
 
-/- warning: covariants.to_unique_prods -> Covariants.to_uniqueProds is a dubious translation:
-lean 3 declaration is
-  forall {A : Type.{u1}} [_inst_1 : Mul.{u1} A] [_inst_2 : LinearOrder.{u1} A] [_inst_3 : CovariantClass.{u1, u1} A A (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1)) (LE.le.{u1} A (Preorder.toHasLe.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))))] [_inst_4 : CovariantClass.{u1, u1} A A (Function.swap.{succ u1, succ u1, succ u1} A A (fun (ᾰ : A) (ᾰ : A) => A) (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1))) (LT.lt.{u1} A (Preorder.toHasLt.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))))] [_inst_5 : ContravariantClass.{u1, u1} A A (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1)) (LE.le.{u1} A (Preorder.toHasLe.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))))], UniqueProds.{u1} A _inst_1
-but is expected to have type
-  forall {A : Type.{u1}} [_inst_1 : Mul.{u1} A] [_inst_2 : LinearOrder.{u1} A] [_inst_3 : CovariantClass.{u1, u1} A A (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2108 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2110 : A) => HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2108 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2110) (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2123 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2125 : A) => LE.le.{u1} A (Preorder.toLE.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2123 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2125)] [_inst_4 : CovariantClass.{u1, u1} A A (Function.swap.{succ u1, succ u1, succ u1} A A (fun (ᾰ : A) (ᾰ : A) => A) (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2145 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2147 : A) => HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2145 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2147)) (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2160 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2162 : A) => LT.lt.{u1} A (Preorder.toLT.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2160 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2162)] [_inst_5 : ContravariantClass.{u1, u1} A A (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2179 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2181 : A) => HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2179 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2181) (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2194 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2196 : A) => LE.le.{u1} A (Preorder.toLE.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2194 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2196)], UniqueProds.{u1} A _inst_1
-Case conversion may be inaccurate. Consider using '#align covariants.to_unique_prods Covariants.to_uniqueProdsₓ'. -/
 -- see Note [lower instance priority]
 /-- This instance asserts that if `A` has a multiplication, a linear order, and multiplication
 is 'very monotone', then `A` also has `unique_prods`. -/
Diff
@@ -56,10 +56,8 @@ variable {G H : Type _} [Mul G] [Mul H] {A B : Finset G} {a0 b0 : G}
 
 #print UniqueMul.mt /-
 theorem mt {G} [Mul G] {A B : Finset G} {a0 b0 : G} (h : UniqueMul A B a0 b0) :
-    ∀ ⦃a b⦄, a ∈ A → b ∈ B → a ≠ a0 ∨ b ≠ b0 → a * b ≠ a0 * b0 := fun _ _ ha hb k =>
-  by
-  contrapose! k
-  exact h ha hb k
+    ∀ ⦃a b⦄, a ∈ A → b ∈ B → a ≠ a0 ∨ b ≠ b0 → a * b ≠ a0 * b0 := fun _ _ ha hb k => by
+  contrapose! k; exact h ha hb k
 #align unique_mul.mt UniqueMul.mt
 -/
 
Diff
@@ -123,10 +123,7 @@ theorem exists_iff_exists_existsUnique :
 -/
 
 /- warning: unique_mul.mul_hom_preimage -> UniqueMul.mulHom_preimage is a dubious translation:
-lean 3 declaration is
-  forall {G : Type.{u1}} {H : Type.{u2}} [_inst_1 : Mul.{u1} G] [_inst_2 : Mul.{u2} H] (f : MulHom.{u1, u2} G H _inst_1 _inst_2) (hf : Function.Injective.{succ u1, succ u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f)) (a0 : G) (b0 : G) {A : Finset.{u2} H} {B : Finset.{u2} H}, (UniqueMul.{u2} H _inst_2 A B (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f a0) (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f b0)) -> (UniqueMul.{u1} G _inst_1 (Finset.preimage.{u1, u2} G H A (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) (Set.injOn_of_injective.{u1, u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) hf (Set.preimage.{u1, u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) ((fun (a : Type.{u2}) (b : Type.{u2}) [self : HasLiftT.{succ u2, succ u2} a b] => self.0) (Finset.{u2} H) (Set.{u2} H) (HasLiftT.mk.{succ u2, succ u2} (Finset.{u2} H) (Set.{u2} H) (CoeTCₓ.coe.{succ u2, succ u2} (Finset.{u2} H) (Set.{u2} H) (Finset.Set.hasCoeT.{u2} H))) A)))) (Finset.preimage.{u1, u2} G H B (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) (Set.injOn_of_injective.{u1, u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) hf (Set.preimage.{u1, u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) ((fun (a : Type.{u2}) (b : Type.{u2}) [self : HasLiftT.{succ u2, succ u2} a b] => self.0) (Finset.{u2} H) (Set.{u2} H) (HasLiftT.mk.{succ u2, succ u2} (Finset.{u2} H) (Set.{u2} H) (CoeTCₓ.coe.{succ u2, succ u2} (Finset.{u2} H) (Set.{u2} H) (Finset.Set.hasCoeT.{u2} H))) B)))) a0 b0)
-but is expected to have type
-  forall {G : Type.{u2}} {H : Type.{u1}} [_inst_1 : Mul.{u2} G] [_inst_2 : Mul.{u1} H] (f : MulHom.{u2, u1} G H _inst_1 _inst_2) (hf : Function.Injective.{succ u2, succ u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f)) (a0 : G) (b0 : G) {A : Finset.{u1} H} {B : Finset.{u1} H}, (UniqueMul.{u1} H _inst_2 A B (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f a0) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f b0)) -> (UniqueMul.{u2} G _inst_1 (Finset.preimage.{u2, u1} G H A (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Set.injOn_of_injective.{u1, u2} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) hf (Set.preimage.{u2, u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Finset.toSet.{u1} H A)))) (Finset.preimage.{u2, u1} G H B (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Set.injOn_of_injective.{u1, u2} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) hf (Set.preimage.{u2, u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Finset.toSet.{u1} H B)))) a0 b0)
+<too large>
 Case conversion may be inaccurate. Consider using '#align unique_mul.mul_hom_preimage UniqueMul.mulHom_preimageₓ'. -/
 /-- `unique_mul` is preserved by inverse images under injective, multiplicative maps. -/
 @[to_additive "`unique_add` is preserved by inverse images under injective, additive maps."]
Diff
@@ -126,7 +126,7 @@ theorem exists_iff_exists_existsUnique :
 lean 3 declaration is
   forall {G : Type.{u1}} {H : Type.{u2}} [_inst_1 : Mul.{u1} G] [_inst_2 : Mul.{u2} H] (f : MulHom.{u1, u2} G H _inst_1 _inst_2) (hf : Function.Injective.{succ u1, succ u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f)) (a0 : G) (b0 : G) {A : Finset.{u2} H} {B : Finset.{u2} H}, (UniqueMul.{u2} H _inst_2 A B (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f a0) (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f b0)) -> (UniqueMul.{u1} G _inst_1 (Finset.preimage.{u1, u2} G H A (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) (Set.injOn_of_injective.{u1, u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) hf (Set.preimage.{u1, u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) ((fun (a : Type.{u2}) (b : Type.{u2}) [self : HasLiftT.{succ u2, succ u2} a b] => self.0) (Finset.{u2} H) (Set.{u2} H) (HasLiftT.mk.{succ u2, succ u2} (Finset.{u2} H) (Set.{u2} H) (CoeTCₓ.coe.{succ u2, succ u2} (Finset.{u2} H) (Set.{u2} H) (Finset.Set.hasCoeT.{u2} H))) A)))) (Finset.preimage.{u1, u2} G H B (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) (Set.injOn_of_injective.{u1, u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) hf (Set.preimage.{u1, u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) ((fun (a : Type.{u2}) (b : Type.{u2}) [self : HasLiftT.{succ u2, succ u2} a b] => self.0) (Finset.{u2} H) (Set.{u2} H) (HasLiftT.mk.{succ u2, succ u2} (Finset.{u2} H) (Set.{u2} H) (CoeTCₓ.coe.{succ u2, succ u2} (Finset.{u2} H) (Set.{u2} H) (Finset.Set.hasCoeT.{u2} H))) B)))) a0 b0)
 but is expected to have type
-  forall {G : Type.{u2}} {H : Type.{u1}} [_inst_1 : Mul.{u2} G] [_inst_2 : Mul.{u1} H] (f : MulHom.{u2, u1} G H _inst_1 _inst_2) (hf : Function.Injective.{succ u2, succ u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f)) (a0 : G) (b0 : G) {A : Finset.{u1} H} {B : Finset.{u1} H}, (UniqueMul.{u1} H _inst_2 A B (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f a0) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f b0)) -> (UniqueMul.{u2} G _inst_1 (Finset.preimage.{u2, u1} G H A (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Set.injOn_of_injective.{u1, u2} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) hf (Set.preimage.{u2, u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Finset.toSet.{u1} H A)))) (Finset.preimage.{u2, u1} G H B (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Set.injOn_of_injective.{u1, u2} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) hf (Set.preimage.{u2, u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Finset.toSet.{u1} H B)))) a0 b0)
+  forall {G : Type.{u2}} {H : Type.{u1}} [_inst_1 : Mul.{u2} G] [_inst_2 : Mul.{u1} H] (f : MulHom.{u2, u1} G H _inst_1 _inst_2) (hf : Function.Injective.{succ u2, succ u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f)) (a0 : G) (b0 : G) {A : Finset.{u1} H} {B : Finset.{u1} H}, (UniqueMul.{u1} H _inst_2 A B (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f a0) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f b0)) -> (UniqueMul.{u2} G _inst_1 (Finset.preimage.{u2, u1} G H A (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Set.injOn_of_injective.{u1, u2} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) hf (Set.preimage.{u2, u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Finset.toSet.{u1} H A)))) (Finset.preimage.{u2, u1} G H B (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Set.injOn_of_injective.{u1, u2} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) hf (Set.preimage.{u2, u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2397 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Finset.toSet.{u1} H B)))) a0 b0)
 Case conversion may be inaccurate. Consider using '#align unique_mul.mul_hom_preimage UniqueMul.mulHom_preimageₓ'. -/
 /-- `unique_mul` is preserved by inverse images under injective, multiplicative maps. -/
 @[to_additive "`unique_add` is preserved by inverse images under injective, additive maps."]
Diff
@@ -233,7 +233,12 @@ instance {M} [Mul M] [UniqueProds M] : UniqueSums (Additive M)
 
 end Additive
 
-#print eq_and_eq_of_le_of_le_of_mul_le /-
+/- warning: eq_and_eq_of_le_of_le_of_mul_le -> eq_and_eq_of_le_of_le_of_mul_le is a dubious translation:
+lean 3 declaration is
+  forall {A : Type.{u1}} [_inst_1 : Mul.{u1} A] [_inst_2 : LinearOrder.{u1} A] [_inst_3 : CovariantClass.{u1, u1} A A (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1)) (LE.le.{u1} A (Preorder.toHasLe.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))))] [_inst_4 : CovariantClass.{u1, u1} A A (Function.swap.{succ u1, succ u1, succ u1} A A (fun (ᾰ : A) (ᾰ : A) => A) (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1))) (LT.lt.{u1} A (Preorder.toHasLt.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))))] [_inst_5 : ContravariantClass.{u1, u1} A A (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1)) (LE.le.{u1} A (Preorder.toHasLe.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))))] {a : A} {b : A} {a0 : A} {b0 : A}, (LE.le.{u1} A (Preorder.toHasLe.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))) a0 a) -> (LE.le.{u1} A (Preorder.toHasLe.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))) b0 b) -> (LE.le.{u1} A (Preorder.toHasLe.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))) (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) a b) (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) a0 b0)) -> (And (Eq.{succ u1} A a a0) (Eq.{succ u1} A b b0))
+but is expected to have type
+  forall {A : Type.{u1}} [_inst_1 : Mul.{u1} A] [_inst_2 : LinearOrder.{u1} A] [_inst_3 : CovariantClass.{u1, u1} A A (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1830 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1832 : A) => HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1830 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1832) (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1845 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1847 : A) => LE.le.{u1} A (Preorder.toLE.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1845 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1847)] [_inst_4 : CovariantClass.{u1, u1} A A (Function.swap.{succ u1, succ u1, succ u1} A A (fun (ᾰ : A) (ᾰ : A) => A) (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1867 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1869 : A) => HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1867 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1869)) (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1882 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1884 : A) => LT.lt.{u1} A (Preorder.toLT.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1882 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1884)] [_inst_5 : ContravariantClass.{u1, u1} A A (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1901 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1903 : A) => HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1901 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1903) (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1916 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1918 : A) => LE.le.{u1} A (Preorder.toLE.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1916 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.1918)] {a : A} {b : A} {a0 : A} {b0 : A}, (LE.le.{u1} A (Preorder.toLE.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) a0 a) -> (LE.le.{u1} A (Preorder.toLE.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) b0 b) -> (LE.le.{u1} A (Preorder.toLE.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) a b) (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) a0 b0)) -> (And (Eq.{succ u1} A a a0) (Eq.{succ u1} A b b0))
+Case conversion may be inaccurate. Consider using '#align eq_and_eq_of_le_of_le_of_mul_le eq_and_eq_of_le_of_le_of_mul_leₓ'. -/
 @[to_additive]
 theorem eq_and_eq_of_le_of_le_of_mul_le {A} [Mul A] [LinearOrder A]
     [CovariantClass A A (· * ·) (· ≤ ·)] [CovariantClass A A (Function.swap (· * ·)) (· < ·)]
@@ -247,9 +252,13 @@ theorem eq_and_eq_of_le_of_le_of_mul_le {A} [Mul A] [LinearOrder A]
   exact ⟨ha.antisymm' (ha' ab), hb.antisymm' (hb' ab)⟩
 #align eq_and_eq_of_le_of_le_of_mul_le eq_and_eq_of_le_of_le_of_mul_le
 #align eq_and_eq_of_le_of_le_of_add_le eq_and_eq_of_le_of_le_of_add_le
--/
 
-#print Covariants.to_uniqueProds /-
+/- warning: covariants.to_unique_prods -> Covariants.to_uniqueProds is a dubious translation:
+lean 3 declaration is
+  forall {A : Type.{u1}} [_inst_1 : Mul.{u1} A] [_inst_2 : LinearOrder.{u1} A] [_inst_3 : CovariantClass.{u1, u1} A A (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1)) (LE.le.{u1} A (Preorder.toHasLe.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))))] [_inst_4 : CovariantClass.{u1, u1} A A (Function.swap.{succ u1, succ u1, succ u1} A A (fun (ᾰ : A) (ᾰ : A) => A) (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1))) (LT.lt.{u1} A (Preorder.toHasLt.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))))] [_inst_5 : ContravariantClass.{u1, u1} A A (HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1)) (LE.le.{u1} A (Preorder.toHasLe.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (LinearOrder.toLattice.{u1} A _inst_2))))))], UniqueProds.{u1} A _inst_1
+but is expected to have type
+  forall {A : Type.{u1}} [_inst_1 : Mul.{u1} A] [_inst_2 : LinearOrder.{u1} A] [_inst_3 : CovariantClass.{u1, u1} A A (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2108 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2110 : A) => HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2108 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2110) (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2123 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2125 : A) => LE.le.{u1} A (Preorder.toLE.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2123 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2125)] [_inst_4 : CovariantClass.{u1, u1} A A (Function.swap.{succ u1, succ u1, succ u1} A A (fun (ᾰ : A) (ᾰ : A) => A) (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2145 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2147 : A) => HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2145 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2147)) (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2160 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2162 : A) => LT.lt.{u1} A (Preorder.toLT.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2160 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2162)] [_inst_5 : ContravariantClass.{u1, u1} A A (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2179 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2181 : A) => HMul.hMul.{u1, u1, u1} A A A (instHMul.{u1} A _inst_1) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2179 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2181) (fun (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2194 : A) (x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2196 : A) => LE.le.{u1} A (Preorder.toLE.{u1} A (PartialOrder.toPreorder.{u1} A (SemilatticeInf.toPartialOrder.{u1} A (Lattice.toSemilatticeInf.{u1} A (DistribLattice.toLattice.{u1} A (instDistribLattice.{u1} A _inst_2)))))) x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2194 x._@.Mathlib.Algebra.Group.UniqueProds._hyg.2196)], UniqueProds.{u1} A _inst_1
+Case conversion may be inaccurate. Consider using '#align covariants.to_unique_prods Covariants.to_uniqueProdsₓ'. -/
 -- see Note [lower instance priority]
 /-- This instance asserts that if `A` has a multiplication, a linear order, and multiplication
 is 'very monotone', then `A` also has `unique_prods`. -/
@@ -263,5 +272,4 @@ instance (priority := 100) Covariants.to_uniqueProds {A} [Mul A] [LinearOrder A]
       eq_and_eq_of_le_of_le_of_mul_le (Finset.min'_le _ _ ‹_›) (Finset.min'_le _ _ ‹_›) ab.le⟩
 #align covariants.to_unique_prods Covariants.to_uniqueProds
 #align covariants.to_unique_sums Covariants.to_uniqueSums
--/
 
Diff
@@ -126,7 +126,7 @@ theorem exists_iff_exists_existsUnique :
 lean 3 declaration is
   forall {G : Type.{u1}} {H : Type.{u2}} [_inst_1 : Mul.{u1} G] [_inst_2 : Mul.{u2} H] (f : MulHom.{u1, u2} G H _inst_1 _inst_2) (hf : Function.Injective.{succ u1, succ u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f)) (a0 : G) (b0 : G) {A : Finset.{u2} H} {B : Finset.{u2} H}, (UniqueMul.{u2} H _inst_2 A B (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f a0) (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f b0)) -> (UniqueMul.{u1} G _inst_1 (Finset.preimage.{u1, u2} G H A (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) (Set.injOn_of_injective.{u1, u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) hf (Set.preimage.{u1, u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) ((fun (a : Type.{u2}) (b : Type.{u2}) [self : HasLiftT.{succ u2, succ u2} a b] => self.0) (Finset.{u2} H) (Set.{u2} H) (HasLiftT.mk.{succ u2, succ u2} (Finset.{u2} H) (Set.{u2} H) (CoeTCₓ.coe.{succ u2, succ u2} (Finset.{u2} H) (Set.{u2} H) (Finset.Set.hasCoeT.{u2} H))) A)))) (Finset.preimage.{u1, u2} G H B (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) (Set.injOn_of_injective.{u1, u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) hf (Set.preimage.{u1, u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) ((fun (a : Type.{u2}) (b : Type.{u2}) [self : HasLiftT.{succ u2, succ u2} a b] => self.0) (Finset.{u2} H) (Set.{u2} H) (HasLiftT.mk.{succ u2, succ u2} (Finset.{u2} H) (Set.{u2} H) (CoeTCₓ.coe.{succ u2, succ u2} (Finset.{u2} H) (Set.{u2} H) (Finset.Set.hasCoeT.{u2} H))) B)))) a0 b0)
 but is expected to have type
-  forall {G : Type.{u2}} {H : Type.{u1}} [_inst_1 : Mul.{u2} G] [_inst_2 : Mul.{u1} H] (f : MulHom.{u2, u1} G H _inst_1 _inst_2) (hf : Function.Injective.{succ u2, succ u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f)) (a0 : G) (b0 : G) {A : Finset.{u1} H} {B : Finset.{u1} H}, (UniqueMul.{u1} H _inst_2 A B (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f a0) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f b0)) -> (UniqueMul.{u2} G _inst_1 (Finset.preimage.{u2, u1} G H A (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Set.injOn_of_injective.{u1, u2} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) hf (Set.preimage.{u2, u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Finset.toSet.{u1} H A)))) (Finset.preimage.{u2, u1} G H B (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Set.injOn_of_injective.{u1, u2} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) hf (Set.preimage.{u2, u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Finset.toSet.{u1} H B)))) a0 b0)
+  forall {G : Type.{u2}} {H : Type.{u1}} [_inst_1 : Mul.{u2} G] [_inst_2 : Mul.{u1} H] (f : MulHom.{u2, u1} G H _inst_1 _inst_2) (hf : Function.Injective.{succ u2, succ u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f)) (a0 : G) (b0 : G) {A : Finset.{u1} H} {B : Finset.{u1} H}, (UniqueMul.{u1} H _inst_2 A B (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f a0) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f b0)) -> (UniqueMul.{u2} G _inst_1 (Finset.preimage.{u2, u1} G H A (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Set.injOn_of_injective.{u1, u2} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) hf (Set.preimage.{u2, u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Finset.toSet.{u1} H A)))) (Finset.preimage.{u2, u1} G H B (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Set.injOn_of_injective.{u1, u2} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) hf (Set.preimage.{u2, u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Finset.toSet.{u1} H B)))) a0 b0)
 Case conversion may be inaccurate. Consider using '#align unique_mul.mul_hom_preimage UniqueMul.mulHom_preimageₓ'. -/
 /-- `unique_mul` is preserved by inverse images under injective, multiplicative maps. -/
 @[to_additive "`unique_add` is preserved by inverse images under injective, additive maps."]
Diff
@@ -126,7 +126,7 @@ theorem exists_iff_exists_existsUnique :
 lean 3 declaration is
   forall {G : Type.{u1}} {H : Type.{u2}} [_inst_1 : Mul.{u1} G] [_inst_2 : Mul.{u2} H] (f : MulHom.{u1, u2} G H _inst_1 _inst_2) (hf : Function.Injective.{succ u1, succ u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f)) (a0 : G) (b0 : G) {A : Finset.{u2} H} {B : Finset.{u2} H}, (UniqueMul.{u2} H _inst_2 A B (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f a0) (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f b0)) -> (UniqueMul.{u1} G _inst_1 (Finset.preimage.{u1, u2} G H A (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) (Set.injOn_of_injective.{u1, u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) hf (Set.preimage.{u1, u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) ((fun (a : Type.{u2}) (b : Type.{u2}) [self : HasLiftT.{succ u2, succ u2} a b] => self.0) (Finset.{u2} H) (Set.{u2} H) (HasLiftT.mk.{succ u2, succ u2} (Finset.{u2} H) (Set.{u2} H) (CoeTCₓ.coe.{succ u2, succ u2} (Finset.{u2} H) (Set.{u2} H) (Finset.Set.hasCoeT.{u2} H))) A)))) (Finset.preimage.{u1, u2} G H B (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) (Set.injOn_of_injective.{u1, u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) hf (Set.preimage.{u1, u2} G H (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MulHom.{u1, u2} G H _inst_1 _inst_2) (fun (_x : MulHom.{u1, u2} G H _inst_1 _inst_2) => G -> H) (MulHom.hasCoeToFun.{u1, u2} G H _inst_1 _inst_2) f) ((fun (a : Type.{u2}) (b : Type.{u2}) [self : HasLiftT.{succ u2, succ u2} a b] => self.0) (Finset.{u2} H) (Set.{u2} H) (HasLiftT.mk.{succ u2, succ u2} (Finset.{u2} H) (Set.{u2} H) (CoeTCₓ.coe.{succ u2, succ u2} (Finset.{u2} H) (Set.{u2} H) (Finset.Set.hasCoeT.{u2} H))) B)))) a0 b0)
 but is expected to have type
-  forall {G : Type.{u2}} {H : Type.{u1}} [_inst_1 : Mul.{u2} G] [_inst_2 : Mul.{u1} H] (f : MulHom.{u2, u1} G H _inst_1 _inst_2) (hf : Function.Injective.{succ u2, succ u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2398 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f)) (a0 : G) (b0 : G) {A : Finset.{u1} H} {B : Finset.{u1} H}, (UniqueMul.{u1} H _inst_2 A B (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2398 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f a0) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2398 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f b0)) -> (UniqueMul.{u2} G _inst_1 (Finset.preimage.{u2, u1} G H A (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2398 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Set.injOn_of_injective.{u1, u2} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2398 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) hf (Set.preimage.{u2, u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2398 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Finset.toSet.{u1} H A)))) (Finset.preimage.{u2, u1} G H B (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2398 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Set.injOn_of_injective.{u1, u2} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2398 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) hf (Set.preimage.{u2, u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2398 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Finset.toSet.{u1} H B)))) a0 b0)
+  forall {G : Type.{u2}} {H : Type.{u1}} [_inst_1 : Mul.{u2} G] [_inst_2 : Mul.{u1} H] (f : MulHom.{u2, u1} G H _inst_1 _inst_2) (hf : Function.Injective.{succ u2, succ u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f)) (a0 : G) (b0 : G) {A : Finset.{u1} H} {B : Finset.{u1} H}, (UniqueMul.{u1} H _inst_2 A B (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f a0) (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f b0)) -> (UniqueMul.{u2} G _inst_1 (Finset.preimage.{u2, u1} G H A (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Set.injOn_of_injective.{u1, u2} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) hf (Set.preimage.{u2, u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Finset.toSet.{u1} H A)))) (Finset.preimage.{u2, u1} G H B (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Set.injOn_of_injective.{u1, u2} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) hf (Set.preimage.{u2, u1} G H (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2372 : G) => H) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MulHom.{u2, u1} G H _inst_1 _inst_2) G H _inst_1 _inst_2 (MulHom.mulHomClass.{u2, u1} G H _inst_1 _inst_2)) f) (Finset.toSet.{u1} H B)))) a0 b0)
 Case conversion may be inaccurate. Consider using '#align unique_mul.mul_hom_preimage UniqueMul.mulHom_preimageₓ'. -/
 /-- `unique_mul` is preserved by inverse images under injective, multiplicative maps. -/
 @[to_additive "`unique_add` is preserved by inverse images under injective, additive maps."]
Diff
@@ -89,7 +89,7 @@ theorem set_subsingleton (A B : Finset G) (a0 b0 : G) (h : UniqueMul A B a0 b0)
 #align unique_add.set_subsingleton UniqueAdd.set_subsingleton
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:628:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
 /- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
 #print UniqueMul.iff_existsUnique /-
 @[to_additive]
@@ -105,7 +105,7 @@ theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
 #align unique_add.iff_exists_unique UniqueAdd.iff_existsUnique
 -/
 
-/- ./././Mathport/Syntax/Translate/Basic.lean:628:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
+/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
 /- ./././Mathport/Syntax/Translate/Expr.lean:177:8: unsupported: ambiguous notation -/
 #print UniqueMul.exists_iff_exists_existsUnique /-
 @[to_additive]

Changes in mathlib4

mathlib3
mathlib4
chore: adaptations to lean 4.8.0 (#12549)
Diff
@@ -444,7 +444,7 @@ open MulOpposite in
     all_goals apply_rules [Nonempty.mul, Nonempty.image, Finset.Nonempty.map, hc.1, hc.2.1]
 
 open UniqueMul in
-@[to_additive] instance {ι} (G : ι → Type*) [∀ i, Mul (G i)] [∀ i, UniqueProds (G i)] :
+@[to_additive] instance instForall {ι} (G : ι → Type*) [∀ i, Mul (G i)] [∀ i, UniqueProds (G i)] :
     UniqueProds (∀ i, G i) where
   uniqueMul_of_nonempty {A} := by
     classical
@@ -472,7 +472,7 @@ open ULift in
   have : ∀ b, UniqueProds (I G H b) := Bool.rec ?_ ?_
   · exact of_injective_mulHom (downMulHom H) down_injective ‹_›
   · refine of_injective_mulHom (Prod.upMulHom G H) (fun x y he => Prod.ext ?_ ?_)
-      (instUniqueProdsForAllInstMul <| I G H) <;> apply up_injective
+      (UniqueProds.instForall <| I G H) <;> apply up_injective
     exacts [congr_fun he false, congr_fun he true]
   · exact of_injective_mulHom (downMulHom G) down_injective ‹_›
 
@@ -521,7 +521,8 @@ theorem of_injective_mulHom (f : H →ₙ* G) (hf : Function.Injective f)
 theorem _root_.MulEquiv.twoUniqueProds_iff (f : G ≃* H) : TwoUniqueProds G ↔ TwoUniqueProds H :=
   ⟨of_injective_mulHom f.symm f.symm.injective, of_injective_mulHom f f.injective⟩
 
-@[to_additive] instance {ι} (G : ι → Type*) [∀ i, Mul (G i)] [∀ i, TwoUniqueProds (G i)] :
+@[to_additive]
+instance instForall {ι} (G : ι → Type*) [∀ i, Mul (G i)] [∀ i, TwoUniqueProds (G i)] :
     TwoUniqueProds (∀ i, G i) where
   uniqueMul_of_one_lt_card {A} := by
     classical
@@ -561,7 +562,7 @@ open ULift in
   have : ∀ b, TwoUniqueProds (I G H b) := Bool.rec ?_ ?_
   · exact of_injective_mulHom (downMulHom H) down_injective ‹_›
   · refine of_injective_mulHom (Prod.upMulHom G H) (fun x y he ↦ Prod.ext ?_ ?_)
-      (instTwoUniqueProdsForAllInstMul <| I G H) <;> apply up_injective
+      (TwoUniqueProds.instForall <| I G H) <;> apply up_injective
     exacts [congr_fun he false, congr_fun he true]
   · exact of_injective_mulHom (downMulHom G) down_injective ‹_›
 
chore: adapt to multiple goal linter 3 (#12372)

A PR analogous to #12338 and #12361: reformatting proofs following the multiple goals linter of #12339.

Diff
@@ -123,7 +123,9 @@ theorem iff_card_le_one [DecidableEq G] (ha0 : a0 ∈ A) (hb0 : b0 ∈ B) :
   simp_rw [card_le_one_iff, mem_filter, mem_product]
   refine ⟨fun h p1 p2 ⟨⟨ha1, hb1⟩, he1⟩ ⟨⟨ha2, hb2⟩, he2⟩ ↦ ?_, fun h a b ha hb he ↦ ?_⟩
   · have h1 := h ha1 hb1 he1; have h2 := h ha2 hb2 he2
-    ext; rw [h1.1, h2.1]; rw [h1.2, h2.2]
+    ext
+    · rw [h1.1, h2.1]
+    · rw [h1.2, h2.2]
   · exact Prod.ext_iff.1 (@h (a, b) (a0, b0) ⟨⟨ha, hb⟩, he⟩ ⟨⟨ha0, hb0⟩, rfl⟩)
 
 -- Porting note: mathport warning: expanding binder collection
@@ -407,8 +409,8 @@ open MulOpposite in
       obtain ⟨a0, ha0, rfl⟩ := mem_map.mp hc
       obtain ⟨b0, hb0, rfl⟩ := mem_map.mp hd
       refine ⟨(_, _), ⟨ha0, hb0⟩, (a, b), ⟨ha, hb⟩, ?_, fun a' b' ha' hb' he => ?_, hu⟩
-      simp_rw [Function.Embedding.coeFn_mk, Ne, inv_mul_eq_one, mul_inv_eq_one] at hne
-      · rwa [Ne, Prod.mk.inj_iff, not_and_or, eq_comm]
+      · simp_rw [Function.Embedding.coeFn_mk, Ne, inv_mul_eq_one, mul_inv_eq_one] at hne
+        rwa [Ne, Prod.mk.inj_iff, not_and_or, eq_comm]
       specialize hu' (mem_map_of_mem _ ha') (mem_map_of_mem _ hb')
       simp_rw [Function.Embedding.coeFn_mk, mul_left_cancel_iff, mul_right_cancel_iff] at hu'
       rw [mul_assoc, ← mul_assoc a', he, mul_assoc, mul_assoc] at hu'
@@ -458,8 +460,10 @@ open UniqueMul in
     let A' := A.filter (· i = ai); let B' := B.filter (· i = bi)
     obtain ⟨a0, ha0, b0, hb0, hu⟩ : ∃ a0 ∈ A', ∃ b0 ∈ B', UniqueMul A' B' a0 b0
     · rcases hc with hc | hc; · exact ihA A' (hc.2 ai) hA hB
-      by_cases hA' : A' = A; rw [hA']
-      exacts [ihB B' (hc.2 bi) hB, ihA A' ((A.filter_subset _).ssubset_of_ne hA') hA hB]
+      by_cases hA' : A' = A
+      · rw [hA']
+        exact ihB B' (hc.2 bi) hB
+      · exact ihA A' ((A.filter_subset _).ssubset_of_ne hA') hA hB
     rw [mem_filter] at ha0 hb0
     exact ⟨a0, ha0.1, b0, hb0.1, of_image_filter (Pi.evalMulHom G i) ha0.2 hb0.2 hi hu⟩
 
@@ -531,7 +535,7 @@ theorem _root_.MulEquiv.twoUniqueProds_iff (f : G ≃* H) : TwoUniqueProds G ↔
       ⟨card_pos.2 (hA.image _), card_pos.2 (hB.image _), hc.imp And.left And.left⟩)
     simp_rw [mem_product, mem_image, ← filter_nonempty_iff] at h1 h2
     replace h1 := uniqueMul_of_twoUniqueMul ?_ h1.1 h1.2
-    replace h2 := uniqueMul_of_twoUniqueMul ?_ h2.1 h2.2
+    on_goal 1 => replace h2 := uniqueMul_of_twoUniqueMul ?_ h2.1 h2.2
 
     · obtain ⟨a1, ha1, b1, hb1, hu1⟩ := h1
       obtain ⟨a2, ha2, b2, hb2, hu2⟩ := h2
@@ -543,10 +547,14 @@ theorem _root_.MulEquiv.twoUniqueProds_iff (f : G ≃* H) : TwoUniqueProds G ↔
       contrapose! hne; rw [Prod.mk.inj_iff] at hne ⊢
       rw [← ha1.2, ← hb1.2, ← ha2.2, ← hb2.2, hne.1, hne.2]; exact ⟨rfl, rfl⟩
     all_goals rcases hc with hc | hc; · exact ihA _ (hc.2 _)
-    · by_cases hA : A.filter (· i = p2.1) = A; rw [hA]
-      exacts [ihB _ (hc.2 _), ihA _ ((A.filter_subset _).ssubset_of_ne hA)]
-    · by_cases hA : A.filter (· i = p1.1) = A; rw [hA]
-      exacts [ihB _ (hc.2 _), ihA _ ((A.filter_subset _).ssubset_of_ne hA)]
+    · by_cases hA : A.filter (· i = p2.1) = A
+      · rw [hA]
+        exact ihB _ (hc.2 _)
+      · exact ihA _ ((A.filter_subset _).ssubset_of_ne hA)
+    · by_cases hA : A.filter (· i = p1.1) = A
+      · rw [hA]
+        exact ihB _ (hc.2 _)
+      · exact ihA _ ((A.filter_subset _).ssubset_of_ne hA)
 
 open ULift in
 @[to_additive] instance [TwoUniqueProds G] [TwoUniqueProds H] : TwoUniqueProds (G × H) := by
chore(Algebra.Group.UniqueProds): remove private instance (#12037)

This is an inferInstance. Removing it doesn't seem to cause issues. Currently, it causes elaboration issues Zulip.

Diff
@@ -310,7 +310,6 @@ variable (G : Type u) (H : Type v) [Mul G] [Mul H]
 
 private abbrev I : Bool → Type max u v := Bool.rec (ULift.{v} G) (ULift.{u} H)
 @[to_additive] private instance : ∀ b, Mul (I G H b) := Bool.rec ULift.mul ULift.mul
-@[to_additive] private instance : Mul (∀ b, I G H b) := inferInstance
 @[to_additive] private def Prod.upMulHom : G × H →ₙ* ∀ b, I G H b :=
   ⟨fun x ↦ Bool.rec ⟨x.1⟩ ⟨x.2⟩, fun x y ↦ by ext (_|_) <;> rfl⟩
 @[to_additive] private def downMulHom : ULift G →ₙ* G := ⟨ULift.down, fun _ _ ↦ rfl⟩
chore: move Mathlib to v4.7.0-rc1 (#11162)

This is a very large PR, but it has been reviewed piecemeal already in PRs to the bump/v4.7.0 branch as we update to intermediate nightlies.

Co-authored-by: Scott Morrison <scott.morrison@gmail.com> Co-authored-by: Kyle Miller <kmill31415@gmail.com> Co-authored-by: damiano <adomani@gmail.com>

Diff
@@ -399,7 +399,7 @@ open MulOpposite in
     obtain ⟨a, ha, b, hb, hu⟩ := uniqueMul_of_nonempty hc.1 hc.2.1
     let C := A.map ⟨_, mul_right_injective a⁻¹⟩ -- C = a⁻¹A
     let D := B.map ⟨_, mul_left_injective b⁻¹⟩  -- D = Bb⁻¹
-    have hcard : 1 < C.card ∨ 1 < D.card := by simp_rw [card_map]; exact hc.2.2
+    have hcard : 1 < C.card ∨ 1 < D.card := by simp_rw [C, D, card_map]; exact hc.2.2
     have hC : 1 ∈ C := mem_map.mpr ⟨a, ha, inv_mul_self a⟩
     have hD : 1 ∈ D := mem_map.mpr ⟨b, hb, mul_inv_self b⟩
     suffices ∃ c ∈ C, ∃ d ∈ D, (c ≠ 1 ∨ d ≠ 1) ∧ UniqueMul C D c d by
chore: remove stream-of-consciousness uses of have, replace and suffices (#10640)

No changes to tactic file, it's just boring fixes throughout the library.

This follows on from #6964.

Co-authored-by: sgouezel <sebastien.gouezel@univ-rennes1.fr> Co-authored-by: Eric Wieser <wieser.eric@gmail.com>

Diff
@@ -399,11 +399,11 @@ open MulOpposite in
     obtain ⟨a, ha, b, hb, hu⟩ := uniqueMul_of_nonempty hc.1 hc.2.1
     let C := A.map ⟨_, mul_right_injective a⁻¹⟩ -- C = a⁻¹A
     let D := B.map ⟨_, mul_left_injective b⁻¹⟩  -- D = Bb⁻¹
-    have hcard : 1 < C.card ∨ 1 < D.card; · simp_rw [card_map]; exact hc.2.2
+    have hcard : 1 < C.card ∨ 1 < D.card := by simp_rw [card_map]; exact hc.2.2
     have hC : 1 ∈ C := mem_map.mpr ⟨a, ha, inv_mul_self a⟩
     have hD : 1 ∈ D := mem_map.mpr ⟨b, hb, mul_inv_self b⟩
-    suffices : ∃ c ∈ C, ∃ d ∈ D, (c ≠ 1 ∨ d ≠ 1) ∧ UniqueMul C D c d
-    · simp_rw [mem_product]
+    suffices ∃ c ∈ C, ∃ d ∈ D, (c ≠ 1 ∨ d ≠ 1) ∧ UniqueMul C D c d by
+      simp_rw [mem_product]
       obtain ⟨c, hc, d, hd, hne, hu'⟩ := this
       obtain ⟨a0, ha0, rfl⟩ := mem_map.mp hc
       obtain ⟨b0, hb0, rfl⟩ := mem_map.mp hd
@@ -591,8 +591,8 @@ instance (priority := 100) of_covariant_right [IsRightCancelMul G]
     rw [← card_product] at hc
     obtain ⟨a0, ha0, b0, hb0, he0⟩ := mem_mul.mp (max'_mem _ <| hA.mul hB)
     obtain ⟨a1, ha1, b1, hb1, he1⟩ := mem_mul.mp (min'_mem _ <| hA.mul hB)
-    have : UniqueMul A B a0 b0
-    · intro a b ha hb he
+    have : UniqueMul A B a0 b0 := by
+      intro a b ha hb he
       obtain hl | rfl | hl := lt_trichotomy b b0
       · exact ((he0 ▸ he ▸ mul_lt_mul_left' hl a).not_le <| le_max' _ _ <| mul_mem_mul ha hb0).elim
       · exact ⟨mul_right_cancel he, rfl⟩
chore: bump dependencies (#10446)

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -533,6 +533,7 @@ theorem _root_.MulEquiv.twoUniqueProds_iff (f : G ≃* H) : TwoUniqueProds G ↔
     simp_rw [mem_product, mem_image, ← filter_nonempty_iff] at h1 h2
     replace h1 := uniqueMul_of_twoUniqueMul ?_ h1.1 h1.2
     replace h2 := uniqueMul_of_twoUniqueMul ?_ h2.1 h2.2
+
     · obtain ⟨a1, ha1, b1, hb1, hu1⟩ := h1
       obtain ⟨a2, ha2, b2, hb2, hu2⟩ := h2
       rw [mem_filter] at ha1 hb1 ha2 hb2
@@ -542,9 +543,10 @@ theorem _root_.MulEquiv.twoUniqueProds_iff (f : G ≃* H) : TwoUniqueProds G ↔
         UniqueMul.of_image_filter (Pi.evalMulHom G i) ha2.2 hb2.2 hi2 hu2⟩
       contrapose! hne; rw [Prod.mk.inj_iff] at hne ⊢
       rw [← ha1.2, ← hb1.2, ← ha2.2, ← hb2.2, hne.1, hne.2]; exact ⟨rfl, rfl⟩
-    all_goals
-      rcases hc with hc | hc; · exact ihA _ (hc.2 _)
-      by_cases hA : A.filter (· i = _) = A; rw [hA]
+    all_goals rcases hc with hc | hc; · exact ihA _ (hc.2 _)
+    · by_cases hA : A.filter (· i = p2.1) = A; rw [hA]
+      exacts [ihB _ (hc.2 _), ihA _ ((A.filter_subset _).ssubset_of_ne hA)]
+    · by_cases hA : A.filter (· i = p1.1) = A; rw [hA]
       exacts [ihB _ (hc.2 _), ihA _ ((A.filter_subset _).ssubset_of_ne hA)]
 
 open ULift in
refactor(Data/FunLike): use unbundled inheritance from FunLike (#8386)

The FunLike hierarchy is very big and gets scanned through each time we need a coercion (via the CoeFun instance). It looks like unbundled inheritance suits Lean 4 better here. The only class that still extends FunLike is EquivLike, since that has a custom coe_injective' field that is easier to implement. All other classes should take FunLike or EquivLike as a parameter.

Zulip thread

Important changes

Previously, morphism classes would be Type-valued and extend FunLike:

/-- `MyHomClass F A B` states that `F` is a type of `MyClass.op`-preserving morphisms.
You should extend this class when you extend `MyHom`. -/
class MyHomClass (F : Type*) (A B : outParam <| Type*) [MyClass A] [MyClass B]
  extends FunLike F A B :=
(map_op : ∀ (f : F) (x y : A), f (MyClass.op x y) = MyClass.op (f x) (f y))

After this PR, they should be Prop-valued and take FunLike as a parameter:

/-- `MyHomClass F A B` states that `F` is a type of `MyClass.op`-preserving morphisms.
You should extend this class when you extend `MyHom`. -/
class MyHomClass (F : Type*) (A B : outParam <| Type*) [MyClass A] [MyClass B]
  [FunLike F A B] : Prop :=
(map_op : ∀ (f : F) (x y : A), f (MyClass.op x y) = MyClass.op (f x) (f y))

(Note that A B stay marked as outParam even though they are not purely required to be so due to the FunLike parameter already filling them in. This is required to see through type synonyms, which is important in the category theory library. Also, I think keeping them as outParam is slightly faster.)

Similarly, MyEquivClass should take EquivLike as a parameter.

As a result, every mention of [MyHomClass F A B] should become [FunLike F A B] [MyHomClass F A B].

Remaining issues

Slower (failing) search

While overall this gives some great speedups, there are some cases that are noticeably slower. In particular, a failing application of a lemma such as map_mul is more expensive. This is due to suboptimal processing of arguments. For example:

variable [FunLike F M N] [Mul M] [Mul N] (f : F) (x : M) (y : M)

theorem map_mul [MulHomClass F M N] : f (x * y) = f x * f y

example [AddHomClass F A B] : f (x * y) = f x * f y := map_mul f _ _

Before this PR, applying map_mul f gives the goals [Mul ?M] [Mul ?N] [MulHomClass F ?M ?N]. Since M and N are out_params, [MulHomClass F ?M ?N] is synthesized first, supplies values for ?M and ?N and then the Mul M and Mul N instances can be found.

After this PR, the goals become [FunLike F ?M ?N] [Mul ?M] [Mul ?N] [MulHomClass F ?M ?N]. Now [FunLike F ?M ?N] is synthesized first, supplies values for ?M and ?N and then the Mul M and Mul N instances can be found, before trying MulHomClass F M N which fails. Since the Mul hierarchy is very big, this can be slow to fail, especially when there is no such Mul instance.

A long-term but harder to achieve solution would be to specify the order in which instance goals get solved. For example, we'd like to change the arguments to map_mul to look like [FunLike F M N] [Mul M] [Mul N] [highPriority <| MulHomClass F M N] because MulHomClass fails or succeeds much faster than the others.

As a consequence, the simpNF linter is much slower since by design it tries and fails to apply many map_ lemmas. The same issue occurs a few times in existing calls to simp [map_mul], where map_mul is tried "too soon" and fails. Thanks to the speedup of leanprover/lean4#2478 the impact is very limited, only in files that already were close to the timeout.

simp not firing sometimes

This affects map_smulₛₗ and related definitions. For simp lemmas Lean apparently uses a slightly different mechanism to find instances, so that rw can find every argument to map_smulₛₗ successfully but simp can't: leanprover/lean4#3701.

Missing instances due to unification failing

Especially in the category theory library, we might sometimes have a type A which is also accessible as a synonym (Bundled A hA).1. Instance synthesis doesn't always work if we have f : A →* B but x * y : (Bundled A hA).1 or vice versa. This seems to be mostly fixed by keeping A B as outParams in MulHomClass F A B. (Presumably because Lean will do a definitional check A =?= (Bundled A hA).1 instead of using the syntax in the discrimination tree.)

Workaround for issues

The timeouts can be worked around for now by specifying which map_mul we mean, either as map_mul f for some explicit f, or as e.g. MonoidHomClass.map_mul.

map_smulₛₗ not firing as simp lemma can be worked around by going back to the pre-FunLike situation and making LinearMap.map_smulₛₗ a simp lemma instead of the generic map_smulₛₗ. Writing simp [map_smulₛₗ _] also works.

Co-authored-by: Matthew Ballard <matt@mrb.email> Co-authored-by: Scott Morrison <scott.morrison@gmail.com> Co-authored-by: Scott Morrison <scott@tqft.net> Co-authored-by: Anne Baanen <Vierkantor@users.noreply.github.com>

Diff
@@ -652,7 +652,7 @@ instance [AddCommGroup G] [Module ℚ G] : TwoUniqueSums G :=
 /-- Any `FreeMonoid` has the `TwoUniqueProds` property. -/
 instance FreeMonoid.instTwoUniqueProds {κ : Type*} : TwoUniqueProds (FreeMonoid κ) :=
   .of_mulHom ⟨Multiplicative.ofAdd ∘ List.length, fun _ _ ↦ congr_arg _ (List.length_append _ _)⟩
-    (fun _ _ _ _ h h' ↦ List.append_inj h <| Equiv.injective _ h'.1)
+    (fun _ _ _ _ h h' ↦ List.append_inj h <| Equiv.injective Multiplicative.ofAdd h'.1)
 
 /-- Any `FreeAddMonoid` has the `TwoUniqueSums` property. -/
 instance FreeAddMonoid.instTwoUniqueSums {κ : Type*} : TwoUniqueSums (FreeAddMonoid κ) :=
feat: tensor algebra of free module over integral domain is a domain (#9890)

Provide instances

  • Nontrivial (TensorAlgebra R M) when M is a module over a nontrivial semiring R
  • NoZeroDivisors (FreeAlgebra R X) when R is a commutative semiring with no zero-divisors and X any type
  • IsDomain (FreeAlgebra R X) when R is an integral domain and X is any type
  • TwoUniqueProds (FreeMonoid X) where X is any type (this provides NoZeroDivisors (MonoidAlgebra R (FreeMonoid X)) when R is a semiring and X any type, via TwoUniqueProds.toUniqueProds and MonoidAlgebra.instNoZeroDivisorsOfUniqueProds)
  • NoZeroDivisors (TensorAlgebra R M) when M is a free module over a commutative semiring R with no zero-divisors
  • IsDomain (TensorAlgebra R M) when M is a free module over an integral domain R

In Algebra.Group.UniqueProds:

  • Rename UniqueProds.mulHom_image_of_injective to UniqueProds.of_injective_mulHom.
  • New lemmas UniqueMul.of_mulHom_image, UniqueProds.of_mulHom, TwoUniqueProds.of_mulHom show the relevant property holds in the domain of a multiplicative homomorphism if it holds in the codomain, under a certain hypothesis on the homomorphism.

Co-authored-by: Richard Copley <rcopley@gmail.com> Co-authored-by: Eric Wieser <wieser.eric@gmail.com> Co-authored-by: Junyan Xu <junyanxu.math@gmail.com>

Diff
@@ -152,6 +152,12 @@ theorem mulHom_preimage (f : G →ₙ* H) (hf : Function.Injective f) (a0 b0 : G
 #align unique_mul.mul_hom_preimage UniqueMul.mulHom_preimage
 #align unique_add.add_hom_preimage UniqueAdd.addHom_preimage
 
+@[to_additive] theorem of_mulHom_image [DecidableEq H] (f : G →ₙ* H)
+    (hf : ∀ ⦃a b c d : G⦄, a * b = c * d → f a = f c ∧ f b = f d → a = c ∧ b = d)
+    (h : UniqueMul (A.image f) (B.image f) (f a0) (f b0)) : UniqueMul A B a0 b0 :=
+  fun a b ha hb ab ↦ hf ab
+    (h (Finset.mem_image_of_mem f ha) (Finset.mem_image_of_mem f hb) <| by simp_rw [← map_mul, ab])
+
 /-- `Unique_Mul` is preserved under multiplicative maps that are injective.
 
 See `UniqueMul.mulHom_map_iff` for a version with swapped bundling. -/
@@ -160,15 +166,12 @@ See `UniqueMul.mulHom_map_iff` for a version with swapped bundling. -/
 
 See `UniqueAdd.addHom_map_iff` for a version with swapped bundling."]
 theorem mulHom_image_iff [DecidableEq H] (f : G →ₙ* H) (hf : Function.Injective f) :
-    UniqueMul (A.image f) (B.image f) (f a0) (f b0) ↔ UniqueMul A B a0 b0 := by
-  simp_rw [UniqueMul, Finset.mem_image]
-  refine ⟨fun h a b ha hb ab ↦ ?_, fun h _ _ ↦ ?_⟩
-  · rw [← hf.eq_iff, map_mul, map_mul] at ab
-    have := h ⟨a, ha, rfl⟩ ⟨b, hb, rfl⟩ ab
-    exact ⟨hf this.1, hf this.2⟩
-  · rintro ⟨a, aA, rfl⟩ ⟨b, bB, rfl⟩ ab
-    simp only [← map_mul, hf.eq_iff] at ab ⊢
-    exact h aA bB ab
+    UniqueMul (A.image f) (B.image f) (f a0) (f b0) ↔ UniqueMul A B a0 b0 :=
+  ⟨of_mulHom_image f fun _ _ _ _ _ ↦ .imp (hf ·) (hf ·), fun h _ _ ↦ by
+    simp_rw [Finset.mem_image]
+    rintro ⟨a, aA, rfl⟩ ⟨b, bB, rfl⟩ ab
+    simp_rw [← map_mul, hf.eq_iff] at ab ⊢
+    exact h aA bB ab⟩
 #align unique_mul.mul_hom_image_iff UniqueMul.mulHom_image_iff
 #align unique_add.add_hom_image_iff UniqueAdd.addHom_image_iff
 
@@ -318,21 +321,24 @@ namespace UniqueProds
 
 open Finset
 
-@[to_additive]
-theorem mulHom_image_of_injective (f : H →ₙ* G) (hf : Function.Injective f) (uG : UniqueProds G) :
-    UniqueProds H where
+@[to_additive] theorem of_mulHom (f : H →ₙ* G)
+    (hf : ∀ ⦃a b c d : H⦄, a * b = c * d → f a = f c ∧ f b = f d → a = c ∧ b = d)
+    [UniqueProds G] : UniqueProds H where
   uniqueMul_of_nonempty {A B} A0 B0 := by
     classical
-    obtain ⟨a0, ha0, b0, hb0, h⟩ := uG.uniqueMul_of_nonempty (A0.image f) (B0.image f)
-    rcases mem_image.mp ha0 with ⟨a', ha', rfl⟩
-    rcases mem_image.mp hb0 with ⟨b', hb', rfl⟩
-    exact ⟨a', ha', b', hb', (UniqueMul.mulHom_image_iff f hf).mp h⟩
+    obtain ⟨a0, ha0, b0, hb0, h⟩ := uniqueMul_of_nonempty (A0.image f) (B0.image f)
+    obtain ⟨a', ha', rfl⟩ := mem_image.mp ha0
+    obtain ⟨b', hb', rfl⟩ := mem_image.mp hb0
+    exact ⟨a', ha', b', hb', UniqueMul.of_mulHom_image f hf h⟩
+
+@[to_additive]
+theorem of_injective_mulHom (f : H →ₙ* G) (hf : Function.Injective f) (_ : UniqueProds G) :
+    UniqueProds H := of_mulHom f (fun _ _ _ _ _ ↦ .imp (hf ·) (hf ·))
 
 /-- `UniqueProd` is preserved under multiplicative equivalences. -/
 @[to_additive "`UniqueSums` is preserved under additive equivalences."]
-theorem mulHom_image_iff (f : G ≃* H) :
-    UniqueProds G ↔ UniqueProds H :=
-  ⟨mulHom_image_of_injective f.symm f.symm.injective, mulHom_image_of_injective f f.injective⟩
+theorem _root_.MulEquiv.uniqueProds_iff (f : G ≃* H) : UniqueProds G ↔ UniqueProds H :=
+  ⟨of_injective_mulHom f.symm f.symm.injective, of_injective_mulHom f f.injective⟩
 
 open Finset MulOpposite in
 @[to_additive]
@@ -343,7 +349,7 @@ theorem of_mulOpposite (h : UniqueProds Gᵐᵒᵖ) : UniqueProds G where
     ⟨unop x, (mem_map' _).mp xA, unop y, (mem_map' _).mp yB, hxy.of_mulOpposite⟩
 
 @[to_additive] instance [h : UniqueProds G] : UniqueProds Gᵐᵒᵖ :=
-  of_mulOpposite <| (mulHom_image_iff <| MulEquiv.opOp G).mp h
+  of_mulOpposite <| (MulEquiv.opOp G).uniqueProds_iff.mp h
 
 @[to_additive] private theorem toIsLeftCancelMul [UniqueProds G] : IsLeftCancelMul G where
   mul_left_cancel a b1 b2 he := by
@@ -461,46 +467,56 @@ open UniqueMul in
 open ULift in
 @[to_additive] instance [UniqueProds G] [UniqueProds H] : UniqueProds (G × H) := by
   have : ∀ b, UniqueProds (I G H b) := Bool.rec ?_ ?_
-  · exact mulHom_image_of_injective (downMulHom H) down_injective ‹_›
-  · refine mulHom_image_of_injective (Prod.upMulHom G H) (fun x y he => Prod.ext ?_ ?_)
+  · exact of_injective_mulHom (downMulHom H) down_injective ‹_›
+  · refine of_injective_mulHom (Prod.upMulHom G H) (fun x y he => Prod.ext ?_ ?_)
       (instUniqueProdsForAllInstMul <| I G H) <;> apply up_injective
     exacts [congr_fun he false, congr_fun he true]
-  · exact mulHom_image_of_injective (downMulHom G) down_injective ‹_›
+  · exact of_injective_mulHom (downMulHom G) down_injective ‹_›
 
 end UniqueProds
 
 instance {ι} (G : ι → Type*) [∀ i, AddZeroClass (G i)] [∀ i, UniqueSums (G i)] :
     UniqueSums (Π₀ i, G i) :=
-  UniqueSums.addHom_image_of_injective
+  UniqueSums.of_injective_addHom
     DFinsupp.coeFnAddMonoidHom.toAddHom DFunLike.coe_injective inferInstance
 
 instance {ι G} [AddZeroClass G] [UniqueSums G] : UniqueSums (ι →₀ G) :=
-  UniqueSums.addHom_image_of_injective
+  UniqueSums.of_injective_addHom
     Finsupp.coeFnAddHom.toAddHom DFunLike.coe_injective inferInstance
 
 namespace TwoUniqueProds
 
 open Finset
 
-@[to_additive]
-theorem mulHom_image_of_injective (f : H →ₙ* G) (hf : Function.Injective f)
-    (uG : TwoUniqueProds G) : TwoUniqueProds H where
+@[to_additive] theorem of_mulHom (f : H →ₙ* G)
+    (hf : ∀ ⦃a b c d : H⦄, a * b = c * d → f a = f c ∧ f b = f d → a = c ∧ b = d)
+    [TwoUniqueProds G] : TwoUniqueProds H where
   uniqueMul_of_one_lt_card {A B} hc := by
     classical
-    simp_rw [← card_map ⟨f, hf⟩] at hc
-    obtain ⟨⟨a1, b1⟩, h1, ⟨a2, b2⟩, h2, hne, hu1, hu2⟩ := uG.uniqueMul_of_one_lt_card hc
-    simp only [mem_product, mem_map] at h1 h2 ⊢
-    obtain ⟨⟨a1, ha1, rfl⟩, ⟨b1, hb1, rfl⟩⟩ := h1
-    obtain ⟨⟨a2, ha2, rfl⟩, ⟨b2, hb2, rfl⟩⟩ := h2
-    refine ⟨(a1, b1), ⟨ha1, hb1⟩, (a2, b2), ⟨ha2, hb2⟩, ?_, ?_, ?_⟩
-    · rw [Ne, Prod.ext_iff] at hne ⊢; simp_rw [← hf.eq_iff]; exact hne
-    all_goals apply (UniqueMul.mulHom_map_iff ⟨f, hf⟩ f.2).mp
-    exacts [hu1, hu2]
+    obtain hc' | hc' := lt_or_le 1 ((A.image f).card * (B.image f).card)
+    · obtain ⟨⟨a1, b1⟩, h1, ⟨a2, b2⟩, h2, hne, hu1, hu2⟩ := uniqueMul_of_one_lt_card hc'
+      simp_rw [mem_product, mem_image] at h1 h2 ⊢
+      obtain ⟨⟨a1, ha1, rfl⟩, b1, hb1, rfl⟩ := h1
+      obtain ⟨⟨a2, ha2, rfl⟩, b2, hb2, rfl⟩ := h2
+      exact ⟨(a1, b1), ⟨ha1, hb1⟩, (a2, b2), ⟨ha2, hb2⟩, mt (congr_arg (Prod.map f f)) hne,
+        UniqueMul.of_mulHom_image f hf hu1, UniqueMul.of_mulHom_image f hf hu2⟩
+    rw [← card_product] at hc hc'
+    obtain ⟨p1, h1, p2, h2, hne⟩ := one_lt_card_iff_nontrivial.mp hc
+    refine ⟨p1, h1, p2, h2, hne, ?_⟩
+    cases mem_product.mp h1; cases mem_product.mp h2
+    constructor <;> refine UniqueMul.of_mulHom_image f hf
+      ((UniqueMul.iff_card_le_one ?_ ?_).mpr <| (card_filter_le _ _).trans hc') <;>
+    apply mem_image_of_mem <;> assumption
+
+@[to_additive]
+theorem of_injective_mulHom (f : H →ₙ* G) (hf : Function.Injective f)
+    (_ : TwoUniqueProds G) : TwoUniqueProds H :=
+  of_mulHom f (fun _ _ _ _ _ ↦ .imp (hf ·) (hf ·))
 
 /-- `TwoUniqueProd` is preserved under multiplicative equivalences. -/
 @[to_additive "`TwoUniqueSums` is preserved under additive equivalences."]
-theorem mulHom_image_iff (f : G ≃* H) : TwoUniqueProds G ↔ TwoUniqueProds H :=
-  ⟨mulHom_image_of_injective f.symm f.symm.injective, mulHom_image_of_injective f f.injective⟩
+theorem _root_.MulEquiv.twoUniqueProds_iff (f : G ≃* H) : TwoUniqueProds G ↔ TwoUniqueProds H :=
+  ⟨of_injective_mulHom f.symm f.symm.injective, of_injective_mulHom f f.injective⟩
 
 @[to_additive] instance {ι} (G : ι → Type*) [∀ i, Mul (G i)] [∀ i, TwoUniqueProds (G i)] :
     TwoUniqueProds (∀ i, G i) where
@@ -534,11 +550,11 @@ theorem mulHom_image_iff (f : G ≃* H) : TwoUniqueProds G ↔ TwoUniqueProds H
 open ULift in
 @[to_additive] instance [TwoUniqueProds G] [TwoUniqueProds H] : TwoUniqueProds (G × H) := by
   have : ∀ b, TwoUniqueProds (I G H b) := Bool.rec ?_ ?_
-  · exact mulHom_image_of_injective (downMulHom H) down_injective ‹_›
-  · refine mulHom_image_of_injective (Prod.upMulHom G H) (fun x y he ↦ Prod.ext ?_ ?_)
+  · exact of_injective_mulHom (downMulHom H) down_injective ‹_›
+  · refine of_injective_mulHom (Prod.upMulHom G H) (fun x y he ↦ Prod.ext ?_ ?_)
       (instTwoUniqueProdsForAllInstMul <| I G H) <;> apply up_injective
     exacts [congr_fun he false, congr_fun he true]
-  · exact mulHom_image_of_injective (downMulHom G) down_injective ‹_›
+  · exact of_injective_mulHom (downMulHom G) down_injective ‹_›
 
 open MulOpposite in
 @[to_additive]
@@ -556,7 +572,7 @@ theorem of_mulOpposite (h : TwoUniqueProds Gᵐᵒᵖ) : TwoUniqueProds G where
     exacts [h1.2, h1.1, h2.2, h2.1]
 
 @[to_additive] instance [h : TwoUniqueProds G] : TwoUniqueProds Gᵐᵒᵖ :=
-  of_mulOpposite <| (mulHom_image_iff <| MulEquiv.opOp G).mp h
+  of_mulOpposite <| (MulEquiv.opOp G).twoUniqueProds_iff.mp h
 
 -- see Note [lower instance priority]
 /-- This instance asserts that if `G` has a right-cancellative multiplication, a linear order, and
@@ -608,17 +624,36 @@ instance (priority := 100) of_covariant_left [IsLeftCancelMul G]
 
 end TwoUniqueProds
 
+-- deprecated 2024-02-04
+@[deprecated] alias UniqueProds.mulHom_image_of_injective := UniqueProds.of_injective_mulHom
+@[deprecated] alias UniqueSums.addHom_image_of_injective := UniqueSums.of_injective_addHom
+@[deprecated] alias UniqueProds.mulHom_image_iff := MulEquiv.uniqueProds_iff
+@[deprecated] alias UniqueSums.addHom_image_iff := AddEquiv.uniqueSums_iff
+@[deprecated] alias TwoUniqueProds.mulHom_image_of_injective := TwoUniqueProds.of_injective_mulHom
+@[deprecated] alias TwoUniqueSums.addHom_image_of_injective := TwoUniqueSums.of_injective_addHom
+@[deprecated] alias TwoUniqueProds.mulHom_image_iff := MulEquiv.twoUniqueProds_iff
+@[deprecated] alias TwoUniqueSums.addHom_image_iff := AddEquiv.twoUniqueSums_iff
+
 instance {ι} (G : ι → Type*) [∀ i, AddZeroClass (G i)] [∀ i, TwoUniqueSums (G i)] :
     TwoUniqueSums (Π₀ i, G i) :=
-  TwoUniqueSums.addHom_image_of_injective
+  TwoUniqueSums.of_injective_addHom
     DFinsupp.coeFnAddMonoidHom.toAddHom DFunLike.coe_injective inferInstance
 
 instance {ι G} [AddZeroClass G] [TwoUniqueSums G] : TwoUniqueSums (ι →₀ G) :=
-  TwoUniqueSums.addHom_image_of_injective
+  TwoUniqueSums.of_injective_addHom
     Finsupp.coeFnAddHom.toAddHom DFunLike.coe_injective inferInstance
 
 /-- Any `ℚ`-vector space has `TwoUniqueSums`, because it is isomorphic to some
   `(Basis.ofVectorSpaceIndex ℚ G) →₀ ℚ` by choosing a basis, and `ℚ` already has
   `TwoUniqueSums` because it's ordered. -/
 instance [AddCommGroup G] [Module ℚ G] : TwoUniqueSums G :=
-  TwoUniqueSums.addHom_image_of_injective _ (Basis.ofVectorSpace ℚ G).repr.injective inferInstance
+  TwoUniqueSums.of_injective_addHom _ (Basis.ofVectorSpace ℚ G).repr.injective inferInstance
+
+/-- Any `FreeMonoid` has the `TwoUniqueProds` property. -/
+instance FreeMonoid.instTwoUniqueProds {κ : Type*} : TwoUniqueProds (FreeMonoid κ) :=
+  .of_mulHom ⟨Multiplicative.ofAdd ∘ List.length, fun _ _ ↦ congr_arg _ (List.length_append _ _)⟩
+    (fun _ _ _ _ h h' ↦ List.append_inj h <| Equiv.injective _ h'.1)
+
+/-- Any `FreeAddMonoid` has the `TwoUniqueSums` property. -/
+instance FreeAddMonoid.instTwoUniqueSums {κ : Type*} : TwoUniqueSums (FreeAddMonoid κ) :=
+  .of_addHom ⟨_, List.length_append⟩ (fun _ _ _ _ h h' ↦ List.append_inj h h'.1)
chore(*): rename FunLike to DFunLike (#9785)

This prepares for the introduction of a non-dependent synonym of FunLike, which helps a lot with keeping #8386 readable.

This is entirely search-and-replace in 680197f combined with manual fixes in 4145626, e900597 and b8428f8. The commands that generated this change:

sed -i 's/\bFunLike\b/DFunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean
sed -i 's/\btoFunLike\b/toDFunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean
sed -i 's/import Mathlib.Data.DFunLike/import Mathlib.Data.FunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean
sed -i 's/\bHom_FunLike\b/Hom_DFunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean     
sed -i 's/\binstFunLike\b/instDFunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean
sed -i 's/\bfunLike\b/instDFunLike/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean
sed -i 's/\btoo many metavariables to apply `fun_like.has_coe_to_fun`/too many metavariables to apply `DFunLike.hasCoeToFun`/g' {Archive,Counterexamples,Mathlib,test}/**/*.lean

Co-authored-by: Anne Baanen <Vierkantor@users.noreply.github.com>

Diff
@@ -472,11 +472,11 @@ end UniqueProds
 instance {ι} (G : ι → Type*) [∀ i, AddZeroClass (G i)] [∀ i, UniqueSums (G i)] :
     UniqueSums (Π₀ i, G i) :=
   UniqueSums.addHom_image_of_injective
-    DFinsupp.coeFnAddMonoidHom.toAddHom FunLike.coe_injective inferInstance
+    DFinsupp.coeFnAddMonoidHom.toAddHom DFunLike.coe_injective inferInstance
 
 instance {ι G} [AddZeroClass G] [UniqueSums G] : UniqueSums (ι →₀ G) :=
   UniqueSums.addHom_image_of_injective
-    Finsupp.coeFnAddHom.toAddHom FunLike.coe_injective inferInstance
+    Finsupp.coeFnAddHom.toAddHom DFunLike.coe_injective inferInstance
 
 namespace TwoUniqueProds
 
@@ -611,11 +611,11 @@ end TwoUniqueProds
 instance {ι} (G : ι → Type*) [∀ i, AddZeroClass (G i)] [∀ i, TwoUniqueSums (G i)] :
     TwoUniqueSums (Π₀ i, G i) :=
   TwoUniqueSums.addHom_image_of_injective
-    DFinsupp.coeFnAddMonoidHom.toAddHom FunLike.coe_injective inferInstance
+    DFinsupp.coeFnAddMonoidHom.toAddHom DFunLike.coe_injective inferInstance
 
 instance {ι G} [AddZeroClass G] [TwoUniqueSums G] : TwoUniqueSums (ι →₀ G) :=
   TwoUniqueSums.addHom_image_of_injective
-    Finsupp.coeFnAddHom.toAddHom FunLike.coe_injective inferInstance
+    Finsupp.coeFnAddHom.toAddHom DFunLike.coe_injective inferInstance
 
 /-- Any `ℚ`-vector space has `TwoUniqueSums`, because it is isomorphic to some
   `(Basis.ofVectorSpaceIndex ℚ G) →₀ ℚ` by choosing a basis, and `ℚ` already has
refactor(*): change definition of Set.image2 etc (#9275)
  • Redefine Set.image2 to use ∃ a ∈ s, ∃ b ∈ t, f a b = c instead of ∃ a b, a ∈ s ∧ b ∈ t ∧ f a b = c.
  • Redefine Set.seq as Set.image2. The new definition is equal to the old one but rw [Set.seq] gives a different result.
  • Redefine Filter.map₂ to use ∃ u ∈ f, ∃ v ∈ g, image2 m u v ⊆ s instead of ∃ u v, u ∈ f ∧ v ∈ g ∧ ...
  • Update lemmas like Set.mem_image2, Finset.mem_image₂, Set.mem_mul, Finset.mem_div etc

The two reasons to make the change are:

  • ∃ a ∈ s, ∃ b ∈ t, _ is a simp-normal form, and
  • it looks a bit nicer.
Diff
@@ -375,8 +375,8 @@ open MulOpposite in
   uniqueMul_of_nonempty {A B} hA hB := by
     classical
     obtain ⟨g1, h1, g2, h2, hu⟩ := h (hB.mul hA)
-    obtain ⟨b1, a1, hb1, ha1, rfl⟩ := mem_mul.mp h1
-    obtain ⟨b2, a2, hb2, ha2, rfl⟩ := mem_mul.mp h2
+    obtain ⟨b1, hb1, a1, ha1, rfl⟩ := mem_mul.mp h1
+    obtain ⟨b2, hb2, a2, ha2, rfl⟩ := mem_mul.mp h2
     refine ⟨a1, ha1, b2, hb2, fun a b ha hb he => ?_⟩
     specialize hu (mul_mem_mul hb1 ha) (mul_mem_mul hb ha2) _
     · rw [mul_assoc b1, ← mul_assoc a, he, mul_assoc a1, ← mul_assoc b1]
@@ -414,26 +414,26 @@ open MulOpposite in
     · obtain ⟨e, he, f, hf, hu⟩ := this
       clear_value C D
       simp only [UniqueMul, mem_mul, mem_image] at he hf hu
-      obtain ⟨_, c1, ⟨d1, hd1, rfl⟩, hc1, rfl⟩ := he
-      obtain ⟨d2, _, hd2, ⟨c2, hc2, rfl⟩, rfl⟩ := hf
+      obtain ⟨_, ⟨d1, hd1, rfl⟩, c1, hc1, rfl⟩ := he
+      obtain ⟨d2, hd2, _, ⟨c2, hc2, rfl⟩, rfl⟩ := hf
       by_cases h12 : c1 ≠ 1 ∨ d2 ≠ 1
       · refine ⟨c1, hc1, d2, hd2, h12, fun c3 d3 hc3 hd3 he => ?_⟩
-        specialize hu ⟨_, _, ⟨_, hd1, rfl⟩, hc3, rfl⟩ ⟨_, _, hd3, ⟨_, hc2, rfl⟩, rfl⟩
+        specialize hu ⟨_, ⟨_, hd1, rfl⟩, _, hc3, rfl⟩ ⟨_, hd3, _, ⟨_, hc2, rfl⟩, rfl⟩
         rw [mul_left_cancel_iff, mul_right_cancel_iff,
             mul_assoc, ← mul_assoc c3, he, mul_assoc, mul_assoc] at hu; exact hu rfl
       push_neg at h12; obtain ⟨rfl, rfl⟩ := h12
       by_cases h21 : c2 ≠ 1 ∨ d1 ≠ 1
       · refine ⟨c2, hc2, d1, hd1, h21, fun c4 d4 hc4 hd4 he => ?_⟩
-        specialize hu ⟨_, _, ⟨_, hd4, rfl⟩, hC, rfl⟩ ⟨_, _, hD, ⟨_, hc4, rfl⟩, rfl⟩
+        specialize hu ⟨_, ⟨_, hd4, rfl⟩, _, hC, rfl⟩ ⟨_, hD, _, ⟨_, hc4, rfl⟩, rfl⟩
         simpa only [mul_one, one_mul, ← mul_inv_rev, he, true_imp_iff, inv_inj, and_comm] using hu
       push_neg at h21; obtain ⟨rfl, rfl⟩ := h21
       rcases hcard with hC | hD
       · obtain ⟨c, hc, hc1⟩ := exists_ne_of_one_lt_card hC 1
         refine (hc1 ?_).elim
-        simpa using hu ⟨_, _, ⟨_, hD, rfl⟩, hc, rfl⟩ ⟨_, _, hD, ⟨_, hc, rfl⟩, rfl⟩
+        simpa using hu ⟨_, ⟨_, hD, rfl⟩, _, hc, rfl⟩ ⟨_, hD, _, ⟨_, hc, rfl⟩, rfl⟩
       · obtain ⟨d, hd, hd1⟩ := exists_ne_of_one_lt_card hD 1
         refine (hd1 ?_).elim
-        simpa using hu ⟨_, _, ⟨_, hd, rfl⟩, hC, rfl⟩ ⟨_, _, hd, ⟨_, hC, rfl⟩, rfl⟩
+        simpa using hu ⟨_, ⟨_, hd, rfl⟩, _, hC, rfl⟩ ⟨_, hd, _, ⟨_, hC, rfl⟩, rfl⟩
     all_goals apply_rules [Nonempty.mul, Nonempty.image, Finset.Nonempty.map, hc.1, hc.2.1]
 
 open UniqueMul in
@@ -571,8 +571,8 @@ instance (priority := 100) of_covariant_right [IsRightCancelMul G]
     obtain ⟨hA, hB, -⟩ := Nat.one_lt_mul_iff.mp hc
     rw [card_pos] at hA hB
     rw [← card_product] at hc
-    obtain ⟨a0, b0, ha0, hb0, he0⟩ := mem_mul.mp (max'_mem _ <| hA.mul hB)
-    obtain ⟨a1, b1, ha1, hb1, he1⟩ := mem_mul.mp (min'_mem _ <| hA.mul hB)
+    obtain ⟨a0, ha0, b0, hb0, he0⟩ := mem_mul.mp (max'_mem _ <| hA.mul hB)
+    obtain ⟨a1, ha1, b1, hb1, he1⟩ := mem_mul.mp (min'_mem _ <| hA.mul hB)
     have : UniqueMul A B a0 b0
     · intro a b ha hb he
       obtain hl | rfl | hl := lt_trichotomy b b0
chore: space after (#8178)

Co-authored-by: Moritz Firsching <firsching@google.com>

Diff
@@ -420,7 +420,7 @@ open MulOpposite in
       · refine ⟨c1, hc1, d2, hd2, h12, fun c3 d3 hc3 hd3 he => ?_⟩
         specialize hu ⟨_, _, ⟨_, hd1, rfl⟩, hc3, rfl⟩ ⟨_, _, hd3, ⟨_, hc2, rfl⟩, rfl⟩
         rw [mul_left_cancel_iff, mul_right_cancel_iff,
-            mul_assoc, ←mul_assoc c3, he, mul_assoc, mul_assoc] at hu; exact hu rfl
+            mul_assoc, ← mul_assoc c3, he, mul_assoc, mul_assoc] at hu; exact hu rfl
       push_neg at h12; obtain ⟨rfl, rfl⟩ := h12
       by_cases h21 : c2 ≠ 1 ∨ d1 ≠ 1
       · refine ⟨c2, hc2, d1, hd1, h21, fun c4 d4 hc4 hd4 he => ?_⟩
chore: tidy various files (#8409)
Diff
@@ -203,7 +203,7 @@ theorem to_mulOpposite (h : UniqueMul A B a0 b0) :
 theorem iff_mulOpposite :
     UniqueMul (B.map ⟨_, op_injective⟩) (A.map ⟨_, op_injective⟩) (op b0) (op a0) ↔
       UniqueMul A B a0 b0 :=
-⟨of_mulOpposite, to_mulOpposite⟩
+  ⟨of_mulOpposite, to_mulOpposite⟩
 
 end Opposites
 
@@ -332,7 +332,7 @@ theorem mulHom_image_of_injective (f : H →ₙ* G) (hf : Function.Injective f)
 @[to_additive "`UniqueSums` is preserved under additive equivalences."]
 theorem mulHom_image_iff (f : G ≃* H) :
     UniqueProds G ↔ UniqueProds H :=
-⟨mulHom_image_of_injective f.symm f.symm.injective, mulHom_image_of_injective f f.injective⟩
+  ⟨mulHom_image_of_injective f.symm f.symm.injective, mulHom_image_of_injective f f.injective⟩
 
 open Finset MulOpposite in
 @[to_additive]
@@ -500,7 +500,7 @@ theorem mulHom_image_of_injective (f : H →ₙ* G) (hf : Function.Injective f)
 /-- `TwoUniqueProd` is preserved under multiplicative equivalences. -/
 @[to_additive "`TwoUniqueSums` is preserved under additive equivalences."]
 theorem mulHom_image_iff (f : G ≃* H) : TwoUniqueProds G ↔ TwoUniqueProds H :=
-⟨mulHom_image_of_injective f.symm f.symm.injective, mulHom_image_of_injective f f.injective⟩
+  ⟨mulHom_image_of_injective f.symm f.symm.injective, mulHom_image_of_injective f f.injective⟩
 
 @[to_additive] instance {ι} (G : ι → Type*) [∀ i, Mul (G i)] [∀ i, TwoUniqueProds (G i)] :
     TwoUniqueProds (∀ i, G i) where
@@ -564,7 +564,7 @@ theorem of_mulOpposite (h : TwoUniqueProds Gᵐᵒᵖ) : TwoUniqueProds G where
 @[to_additive
   "This instance asserts that if `G` has a right-cancellative addition, a linear order,
   and addition is strictly monotone w.r.t. the second argument, then `G` has `TwoUniqueSums`." ]
-instance (priority := 100) of_Covariant_right [IsRightCancelMul G]
+instance (priority := 100) of_covariant_right [IsRightCancelMul G]
     [LinearOrder G] [CovariantClass G G (· * ·) (· < ·)] :
     TwoUniqueProds G where
   uniqueMul_of_one_lt_card {A B} hc := by
@@ -598,13 +598,13 @@ open MulOpposite in
 @[to_additive
   "This instance asserts that if `G` has a left-cancellative addition, a linear order, and
   addition is strictly monotone w.r.t. the first argument, then `G` has `TwoUniqueSums`." ]
-instance (priority := 100) of_Covariant_left [IsLeftCancelMul G]
+instance (priority := 100) of_covariant_left [IsLeftCancelMul G]
     [LinearOrder G] [CovariantClass G G (Function.swap (· * ·)) (· < ·)] :
     TwoUniqueProds G :=
   let _ := LinearOrder.lift' (unop : Gᵐᵒᵖ → G) unop_injective
   let _ : CovariantClass Gᵐᵒᵖ Gᵐᵒᵖ (· * ·) (· < ·) :=
-  { elim := fun _ _ _ bc ↦ mul_lt_mul_right' (α := G) bc (unop _) }
-  of_mulOpposite of_Covariant_right
+    { elim := fun _ _ _ bc ↦ mul_lt_mul_right' (α := G) bc (unop _) }
+  of_mulOpposite of_covariant_right
 
 end TwoUniqueProds
 
fix: attribute [simp] ... in -> attribute [local simp] ... in (#7678)

Mathlib.Logic.Unique contains the line attribute [simp] eq_iff_true_of_subsingleton in ...:

https://github.com/leanprover-community/mathlib4/blob/96a11c7aac574c00370c2b3dab483cb676405c5d/Mathlib/Logic/Unique.lean#L255-L256

Despite what the in part may imply, this adds the lemma to the simp set "globally", including for downstream files; it is likely that attribute [local simp] eq_iff_true_of_subsingleton in ... was meant instead (or maybe scoped simp, but I think "scoped" refers to the current namespace). Indeed, the relevant lemma is not marked with @[simp] for possible slowness: https://github.com/leanprover/std4/blob/846e9e1d6bb534774d1acd2dc430e70987da3c18/Std/Logic.lean#L749. Adding it to the simp set causes the example at https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Regression.20in.20simp to slow down.

This PR changes this and fixes the relevant downstream simps. There was also one ocurrence of attribute [simp] FullSubcategory.comp_def FullSubcategory.id_def in in Mathlib.CategoryTheory.Monoidal.Subcategory but that was much easier to fix.

https://github.com/leanprover-community/mathlib4/blob/bc49eb9ba756a233370b4b68bcdedd60402f71ed/Mathlib/CategoryTheory/Monoidal/Subcategory.lean#L118-L119

Diff
@@ -64,7 +64,8 @@ namespace UniqueMul
 variable {G H : Type*} [Mul G] [Mul H] {A B : Finset G} {a0 b0 : G}
 
 @[to_additive (attr := nontriviality, simp)]
-theorem of_subsingleton [Subsingleton G] : UniqueMul A B a0 b0 := by simp [UniqueMul]
+theorem of_subsingleton [Subsingleton G] : UniqueMul A B a0 b0 := by
+  simp [UniqueMul, eq_iff_true_of_subsingleton]
 
 @[to_additive]
 theorem of_card_le_one (hA : A.Nonempty) (hB : B.Nonempty) (hA1 : A.card ≤ 1) (hB1 : B.card ≤ 1) :
feat(UniqueProds): two theorems of Strojnowski (#7171)

Co-authored-by: Junyan Xu <junyanxu.math@gmail.com>

Diff
@@ -344,6 +344,97 @@ theorem of_mulOpposite (h : UniqueProds Gᵐᵒᵖ) : UniqueProds G where
 @[to_additive] instance [h : UniqueProds G] : UniqueProds Gᵐᵒᵖ :=
   of_mulOpposite <| (mulHom_image_iff <| MulEquiv.opOp G).mp h
 
+@[to_additive] private theorem toIsLeftCancelMul [UniqueProds G] : IsLeftCancelMul G where
+  mul_left_cancel a b1 b2 he := by
+    classical
+    have := mem_insert_self b1 {b2}
+    obtain ⟨a, ha, b, hb, hu⟩ := uniqueMul_of_nonempty ⟨a, mem_singleton_self a⟩ ⟨b1, this⟩
+    cases mem_singleton.mp ha
+    simp_rw [mem_insert, mem_singleton] at hb
+    obtain rfl | rfl := hb
+    · exact (hu ha (mem_insert_of_mem <| mem_singleton_self b2) he.symm).2.symm
+    · exact (hu ha this he).2
+
+open MulOpposite in
+@[to_additive] theorem toIsCancelMul [UniqueProds G] : IsCancelMul G where
+  mul_left_cancel := toIsLeftCancelMul.mul_left_cancel
+  mul_right_cancel _ _ _ h :=
+    op_injective <| toIsLeftCancelMul.mul_left_cancel _ _ _ <| unop_injective h
+
+/-! Two theorems in [Andrzej Strojnowski, *A note on u.p. groups*][Strojnowski1980] -/
+
+/-- `UniqueProds G` says that for any two nonempty `Finset`s `A` and `B` in `G`, `A × B`
+  contains a unique pair with the `UniqueMul` property. Strojnowski showed that if `G` is
+  a group, then we only need to check this when `A = B`.
+  Here we generalize the result to cancellative semigroups.
+  Non-cancellative counterexample: the AddMonoid {0,1} with 1+1=1. -/
+@[to_additive] theorem of_same {G} [Semigroup G] [IsCancelMul G]
+    (h : ∀ {A : Finset G}, A.Nonempty → ∃ a1 ∈ A, ∃ a2 ∈ A, UniqueMul A A a1 a2) :
+    UniqueProds G where
+  uniqueMul_of_nonempty {A B} hA hB := by
+    classical
+    obtain ⟨g1, h1, g2, h2, hu⟩ := h (hB.mul hA)
+    obtain ⟨b1, a1, hb1, ha1, rfl⟩ := mem_mul.mp h1
+    obtain ⟨b2, a2, hb2, ha2, rfl⟩ := mem_mul.mp h2
+    refine ⟨a1, ha1, b2, hb2, fun a b ha hb he => ?_⟩
+    specialize hu (mul_mem_mul hb1 ha) (mul_mem_mul hb ha2) _
+    · rw [mul_assoc b1, ← mul_assoc a, he, mul_assoc a1, ← mul_assoc b1]
+    exact ⟨mul_left_cancel hu.1, mul_right_cancel hu.2⟩
+
+/-- If a group has `UniqueProds`, then it actually has `TwoUniqueProds`.
+  For an example of a semigroup `G` embeddable into a group that has `UniqueProds`
+  but not `TwoUniqueProds`, see Example 10.13 in
+  [J. Okniński, *Semigroup Algebras*][Okninski1991]. -/
+@[to_additive] theorem toTwoUniqueProds_of_group {G}
+    [Group G] [UniqueProds G] : TwoUniqueProds G where
+  uniqueMul_of_one_lt_card {A B} hc := by
+    simp_rw [Nat.one_lt_mul_iff, card_pos] at hc
+    obtain ⟨a, ha, b, hb, hu⟩ := uniqueMul_of_nonempty hc.1 hc.2.1
+    let C := A.map ⟨_, mul_right_injective a⁻¹⟩ -- C = a⁻¹A
+    let D := B.map ⟨_, mul_left_injective b⁻¹⟩  -- D = Bb⁻¹
+    have hcard : 1 < C.card ∨ 1 < D.card; · simp_rw [card_map]; exact hc.2.2
+    have hC : 1 ∈ C := mem_map.mpr ⟨a, ha, inv_mul_self a⟩
+    have hD : 1 ∈ D := mem_map.mpr ⟨b, hb, mul_inv_self b⟩
+    suffices : ∃ c ∈ C, ∃ d ∈ D, (c ≠ 1 ∨ d ≠ 1) ∧ UniqueMul C D c d
+    · simp_rw [mem_product]
+      obtain ⟨c, hc, d, hd, hne, hu'⟩ := this
+      obtain ⟨a0, ha0, rfl⟩ := mem_map.mp hc
+      obtain ⟨b0, hb0, rfl⟩ := mem_map.mp hd
+      refine ⟨(_, _), ⟨ha0, hb0⟩, (a, b), ⟨ha, hb⟩, ?_, fun a' b' ha' hb' he => ?_, hu⟩
+      simp_rw [Function.Embedding.coeFn_mk, Ne, inv_mul_eq_one, mul_inv_eq_one] at hne
+      · rwa [Ne, Prod.mk.inj_iff, not_and_or, eq_comm]
+      specialize hu' (mem_map_of_mem _ ha') (mem_map_of_mem _ hb')
+      simp_rw [Function.Embedding.coeFn_mk, mul_left_cancel_iff, mul_right_cancel_iff] at hu'
+      rw [mul_assoc, ← mul_assoc a', he, mul_assoc, mul_assoc] at hu'
+      exact hu' rfl
+    classical
+    let _ := Finset.mul (α := G)              -- E = D⁻¹C, F = DC⁻¹
+    have := uniqueMul_of_nonempty (A := D.image (·⁻¹) * C) (B := D * C.image (·⁻¹)) ?_ ?_
+    · obtain ⟨e, he, f, hf, hu⟩ := this
+      clear_value C D
+      simp only [UniqueMul, mem_mul, mem_image] at he hf hu
+      obtain ⟨_, c1, ⟨d1, hd1, rfl⟩, hc1, rfl⟩ := he
+      obtain ⟨d2, _, hd2, ⟨c2, hc2, rfl⟩, rfl⟩ := hf
+      by_cases h12 : c1 ≠ 1 ∨ d2 ≠ 1
+      · refine ⟨c1, hc1, d2, hd2, h12, fun c3 d3 hc3 hd3 he => ?_⟩
+        specialize hu ⟨_, _, ⟨_, hd1, rfl⟩, hc3, rfl⟩ ⟨_, _, hd3, ⟨_, hc2, rfl⟩, rfl⟩
+        rw [mul_left_cancel_iff, mul_right_cancel_iff,
+            mul_assoc, ←mul_assoc c3, he, mul_assoc, mul_assoc] at hu; exact hu rfl
+      push_neg at h12; obtain ⟨rfl, rfl⟩ := h12
+      by_cases h21 : c2 ≠ 1 ∨ d1 ≠ 1
+      · refine ⟨c2, hc2, d1, hd1, h21, fun c4 d4 hc4 hd4 he => ?_⟩
+        specialize hu ⟨_, _, ⟨_, hd4, rfl⟩, hC, rfl⟩ ⟨_, _, hD, ⟨_, hc4, rfl⟩, rfl⟩
+        simpa only [mul_one, one_mul, ← mul_inv_rev, he, true_imp_iff, inv_inj, and_comm] using hu
+      push_neg at h21; obtain ⟨rfl, rfl⟩ := h21
+      rcases hcard with hC | hD
+      · obtain ⟨c, hc, hc1⟩ := exists_ne_of_one_lt_card hC 1
+        refine (hc1 ?_).elim
+        simpa using hu ⟨_, _, ⟨_, hD, rfl⟩, hc, rfl⟩ ⟨_, _, hD, ⟨_, hc, rfl⟩, rfl⟩
+      · obtain ⟨d, hd, hd1⟩ := exists_ne_of_one_lt_card hD 1
+        refine (hd1 ?_).elim
+        simpa using hu ⟨_, _, ⟨_, hd, rfl⟩, hC, rfl⟩ ⟨_, _, hd, ⟨_, hC, rfl⟩, rfl⟩
+    all_goals apply_rules [Nonempty.mul, Nonempty.image, Finset.Nonempty.map, hc.1, hc.2.1]
+
 open UniqueMul in
 @[to_additive] instance {ι} (G : ι → Type*) [∀ i, Mul (G i)] [∀ i, UniqueProds (G i)] :
     UniqueProds (∀ i, G i) where
feat: TwoUniqueProds (#7169)
  • Introduce TwoUniqueProds/Sums: let R[G] be a monoid algebra over a semiring R without zero-divisors. A natural sufficient condition for R[G] to have no zero-divisors is that G has UniqueProds, as is shown by MonoidAlgebra.instNoZeroDivisorsOfUniqueProds. Similarly, a natural sufficient condition for R[G] to have only trivial units (of the form rg with r a unit in R and g a unit in G) is that G has TwoUniqueProds, but we don't prove this yet in this PR. TwoUniqueProds G is also a natural sufficient condition in order for factors of a homogeneous element in an algebra graded by G without zero-divisors to themselves be homogeneous.

  • Show TwoUniqueProds implies UniqueProds: TwoUniqueProds.toUniqueProds

  • Strengthen of_Covariant_right/left to have TwoUniqueProds as conclusion

  • Extract of_image_filter from the proof of the instance UniqueProds (∀ i, G i) and use it also in the proof of TwoUniqueProds (∀ i, G i)

  • Use some private defs (starting from private abbrev I) to transfer (Two)UniqueProds (∀ i, G i) instances to (Two)UniqueProds (G × H)

  • Move the [Module ℚ G] : UniqueSums G instance from NoZeroDivisors.lean to UniqueProds.lean and strengthen to TwoUniqueSums

New lemmas about UniqueMul:

  • of_card_le_one, iff_card_le_one, UniqueMul_of_TwoUniqueMul

Co-authored-by: Junyan Xu <junyanxu.math@gmail.com>

Diff
@@ -5,15 +5,14 @@ Authors: Damiano Testa
 -/
 import Mathlib.Data.DFinsupp.Basic
 import Mathlib.Data.Finset.Pointwise
-import Mathlib.Data.Finset.Preimage
-import Mathlib.Data.Finsupp.Defs
+import Mathlib.LinearAlgebra.Basis.VectorSpace
 
 #align_import algebra.group.unique_prods from "leanprover-community/mathlib"@"d6fad0e5bf2d6f48da9175d25c3dc5706b3834ce"
 
 /-!
 # Unique products and related notions
 
-A group `G` has *unique products* if for any two non-empty finite subsets `A, B ⊂ G`, there is an
+A group `G` has *unique products* if for any two non-empty finite subsets `A, B ⊆ G`, there is an
 element `g ∈ A * B` that can be written uniquely as a product of an element of `A` and an element
 of `B`.  We call the formalization this property `UniqueProds`.  Since the condition requires no
 property of the group operation, we define it for a Type simply satisfying `Mul`.  We also
@@ -68,14 +67,21 @@ variable {G H : Type*} [Mul G] [Mul H] {A B : Finset G} {a0 b0 : G}
 theorem of_subsingleton [Subsingleton G] : UniqueMul A B a0 b0 := by simp [UniqueMul]
 
 @[to_additive]
-theorem mt {G} [Mul G] {A B : Finset G} {a0 b0 : G} (h : UniqueMul A B a0 b0) :
+theorem of_card_le_one (hA : A.Nonempty) (hB : B.Nonempty) (hA1 : A.card ≤ 1) (hB1 : B.card ≤ 1) :
+    ∃ a ∈ A, ∃ b ∈ B, UniqueMul A B a b := by
+  rw [Finset.card_le_one_iff] at hA1 hB1
+  obtain ⟨a, ha⟩ := hA; obtain ⟨b, hb⟩ := hB
+  exact ⟨a, ha, b, hb, fun _ _ ha' hb' _ ↦ ⟨hA1 ha' ha, hB1 hb' hb⟩⟩
+
+@[to_additive]
+theorem mt (h : UniqueMul A B a0 b0) :
     ∀ ⦃a b⦄, a ∈ A → b ∈ B → a ≠ a0 ∨ b ≠ b0 → a * b ≠ a0 * b0 := fun _ _ ha hb k ↦ by
   contrapose! k
   exact h ha hb k
 #align unique_mul.mt UniqueMul.mt
 
 @[to_additive]
-theorem subsingleton (A B : Finset G) (a0 b0 : G) (h : UniqueMul A B a0 b0) :
+theorem subsingleton (h : UniqueMul A B a0 b0) :
     Subsingleton { ab : G × G // ab.1 ∈ A ∧ ab.2 ∈ B ∧ ab.1 * ab.2 = a0 * b0 } :=
   ⟨fun ⟨⟨_a, _b⟩, ha, hb, ab⟩ ⟨⟨_a', _b'⟩, ha', hb', ab'⟩ ↦
     Subtype.ext <|
@@ -85,7 +91,7 @@ theorem subsingleton (A B : Finset G) (a0 b0 : G) (h : UniqueMul A B a0 b0) :
 #align unique_add.subsingleton UniqueAdd.subsingleton
 
 @[to_additive]
-theorem set_subsingleton (A B : Finset G) (a0 b0 : G) (h : UniqueMul A B a0 b0) :
+theorem set_subsingleton (h : UniqueMul A B a0 b0) :
     Set.Subsingleton { ab : G × G | ab.1 ∈ A ∧ ab.2 ∈ B ∧ ab.1 * ab.2 = a0 * b0 } := by
   rintro ⟨x1, y1⟩ (hx : x1 ∈ A ∧ y1 ∈ B ∧ x1 * y1 = a0 * b0) ⟨x2, y2⟩
     (hy : x2 ∈ A ∧ y2 ∈ B ∧ x2 * y2 = a0 * b0)
@@ -99,29 +105,39 @@ theorem set_subsingleton (A B : Finset G) (a0 b0 : G) (h : UniqueMul A B a0 b0)
 --  (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
 @[to_additive]
 theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
-    UniqueMul A B a0 b0 ↔ ∃! (ab : _) (_ : ab ∈ A ×ˢ B), ab.1 * ab.2 = a0 * b0 :=
-  ⟨fun _ ↦ ⟨(a0, b0), ⟨Finset.mem_product.mpr ⟨aA, bB⟩, rfl, by simp⟩, by simpa⟩,
-    fun h ↦ h.elim₂
+    UniqueMul A B a0 b0 ↔ ∃! ab, ab ∈ A ×ˢ B ∧ ab.1 * ab.2 = a0 * b0 :=
+  ⟨fun _ ↦ ⟨(a0, b0), ⟨Finset.mk_mem_product aA bB, rfl⟩, by simpa⟩,
+    fun h ↦ h.elim
       (by
-        rintro ⟨x1, x2⟩ _ _ J x y hx hy l
-        rcases Prod.mk.inj_iff.mp (J (a0, b0) (Finset.mk_mem_product aA bB) rfl) with ⟨rfl, rfl⟩
-        exact Prod.mk.inj_iff.mp (J (x, y) (Finset.mk_mem_product hx hy) l))⟩
-#align unique_mul.iff_exists_unique UniqueMul.iff_existsUnique
-#align unique_add.iff_exists_unique UniqueAdd.iff_existsUnique
+        rintro ⟨x1, x2⟩ _ J x y hx hy l
+        rcases Prod.mk.inj_iff.mp (J (a0, b0) ⟨Finset.mk_mem_product aA bB, rfl⟩) with ⟨rfl, rfl⟩
+        exact Prod.mk.inj_iff.mp (J (x, y) ⟨Finset.mk_mem_product hx hy, l⟩))⟩
+#align unique_mul.iff_exists_unique UniqueMul.iff_existsUniqueₓ
+#align unique_add.iff_exists_unique UniqueAdd.iff_existsUniqueₓ
+
+open Finset in
+@[to_additive]
+theorem iff_card_le_one [DecidableEq G] (ha0 : a0 ∈ A) (hb0 : b0 ∈ B) :
+    UniqueMul A B a0 b0 ↔ ((A ×ˢ B).filter (fun p ↦ p.1 * p.2 = a0 * b0)).card ≤ 1 := by
+  simp_rw [card_le_one_iff, mem_filter, mem_product]
+  refine ⟨fun h p1 p2 ⟨⟨ha1, hb1⟩, he1⟩ ⟨⟨ha2, hb2⟩, he2⟩ ↦ ?_, fun h a b ha hb he ↦ ?_⟩
+  · have h1 := h ha1 hb1 he1; have h2 := h ha2 hb2 he2
+    ext; rw [h1.1, h2.1]; rw [h1.2, h2.2]
+  · exact Prod.ext_iff.1 (@h (a, b) (a0, b0) ⟨⟨ha, hb⟩, he⟩ ⟨⟨ha0, hb0⟩, rfl⟩)
 
 -- Porting note: mathport warning: expanding binder collection
 --  (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
 @[to_additive]
 theorem exists_iff_exists_existsUnique :
     (∃ a0 b0 : G, a0 ∈ A ∧ b0 ∈ B ∧ UniqueMul A B a0 b0) ↔
-      ∃ g : G, ∃! (ab : _) (_ : ab ∈ A ×ˢ B), ab.1 * ab.2 = g :=
+      ∃ g : G, ∃! ab, ab ∈ A ×ˢ B ∧ ab.1 * ab.2 = g :=
   ⟨fun ⟨a0, b0, hA, hB, h⟩ ↦ ⟨_, (iff_existsUnique hA hB).mp h⟩, fun ⟨g, h⟩ ↦ by
     have h' := h
     rcases h' with ⟨⟨a, b⟩, ⟨hab, rfl, -⟩, -⟩
     cases' Finset.mem_product.mp hab with ha hb
     exact ⟨a, b, ha, hb, (iff_existsUnique ha hb).mpr h⟩⟩
-#align unique_mul.exists_iff_exists_exists_unique UniqueMul.exists_iff_exists_existsUnique
-#align unique_add.exists_iff_exists_exists_unique UniqueAdd.exists_iff_exists_existsUnique
+#align unique_mul.exists_iff_exists_exists_unique UniqueMul.exists_iff_exists_existsUniqueₓ
+#align unique_add.exists_iff_exists_exists_unique UniqueAdd.exists_iff_exists_existsUniqueₓ
 
 /-- `UniqueMul` is preserved by inverse images under injective, multiplicative maps. -/
 @[to_additive "`UniqueAdd` is preserved by inverse images under injective, additive maps."]
@@ -145,11 +161,11 @@ See `UniqueAdd.addHom_map_iff` for a version with swapped bundling."]
 theorem mulHom_image_iff [DecidableEq H] (f : G →ₙ* H) (hf : Function.Injective f) :
     UniqueMul (A.image f) (B.image f) (f a0) (f b0) ↔ UniqueMul A B a0 b0 := by
   simp_rw [UniqueMul, Finset.mem_image]
-  refine' ⟨fun h a b ha hb ab ↦ _, fun h ↦ _⟩
+  refine ⟨fun h a b ha hb ab ↦ ?_, fun h _ _ ↦ ?_⟩
   · rw [← hf.eq_iff, map_mul, map_mul] at ab
     have := h ⟨a, ha, rfl⟩ ⟨b, hb, rfl⟩ ab
     exact ⟨hf this.1, hf this.2⟩
-  · rintro _ _ ⟨a, aA, rfl⟩ ⟨b, bB, rfl⟩ ab
+  · rintro ⟨a, aA, rfl⟩ ⟨b, bB, rfl⟩ ab
     simp only [← map_mul, hf.eq_iff] at ab ⊢
     exact h aA bB ab
 #align unique_mul.mul_hom_image_iff UniqueMul.mulHom_image_iff
@@ -164,10 +180,7 @@ See `UniqueMul.mulHom_image_iff` for a version with swapped bundling. -/
 See `UniqueAdd.addHom_image_iff` for a version with swapped bundling."]
 theorem mulHom_map_iff (f : G ↪ H) (mul : ∀ x y, f (x * y) = f x * f y) :
     UniqueMul (A.map f) (B.map f) (f a0) (f b0) ↔ UniqueMul A B a0 b0 := by
-  classical
-  convert @mulHom_image_iff G H _ _ A B a0 b0 _ ⟨f, mul⟩ f.2 using 2 <;>
-    · ext
-      simp only [Finset.mem_map, MulHom.coe_mk, Finset.mem_image]
+  classical simp_rw [← mulHom_image_iff ⟨f, mul⟩ f.2, Finset.map_eq_image]; rfl
 #align unique_mul.mul_hom_map_iff UniqueMul.mulHom_map_iff
 #align unique_add.add_hom_map_iff UniqueAdd.addHom_map_iff
 
@@ -177,22 +190,13 @@ open Finset MulOpposite
 @[to_additive]
 theorem of_mulOpposite
     (h : UniqueMul (B.map ⟨_, op_injective⟩) (A.map ⟨_, op_injective⟩) (op b0) (op a0)) :
-    UniqueMul A B a0 b0 := by
-  intros a b aA bB ab
-  have := h (mem_map_of_mem _ bB) (mem_map_of_mem _ aA) (by simpa using congr_arg op ab)
-  simpa [and_comm] using this
+    UniqueMul A B a0 b0 := fun a b aA bB ab ↦ by
+  simpa [and_comm] using h (mem_map_of_mem _ bB) (mem_map_of_mem _ aA) (congr_arg op ab)
 
 @[to_additive]
 theorem to_mulOpposite (h : UniqueMul A B a0 b0) :
-    UniqueMul (B.map ⟨_, op_injective⟩) (A.map ⟨_, op_injective⟩) (op b0) (op a0) := by
-  refine of_mulOpposite (G := MulOpposite G) <| fun a b ha hb hab ↦ ?_
-  simp only [mem_map, Function.Embedding.coeFn_mk, exists_exists_and_eq_and] at ha hb
-  rcases ha with ⟨a, ha, rfl⟩
-  rcases hb with ⟨b, hb, rfl⟩
-  rw [op_inj, op_inj, op_inj, op_inj]
-  apply h ha hb ?_
-  apply_fun op ∘ op using op_injective.comp op_injective
-  exact hab
+    UniqueMul (B.map ⟨_, op_injective⟩) (A.map ⟨_, op_injective⟩) (op b0) (op a0) :=
+  of_mulOpposite (by simp_rw [map_map]; exact (mulHom_map_iff _ fun _ _ ↦ by rfl).mpr h)
 
 @[to_additive]
 theorem iff_mulOpposite :
@@ -202,6 +206,18 @@ theorem iff_mulOpposite :
 
 end Opposites
 
+open Finset in
+@[to_additive]
+theorem of_image_filter [DecidableEq H]
+    (f : G →ₙ* H) {A B : Finset G} {aG bG : G} {aH bH : H} (hae : f aG = aH) (hbe : f bG = bH)
+    (huH : UniqueMul (A.image f) (B.image f) aH bH)
+    (huG : UniqueMul (A.filter (f · = aH)) (B.filter (f · = bH)) aG bG) :
+    UniqueMul A B aG bG := fun a b ha hb he ↦ by
+  specialize huH (mem_image_of_mem _ ha) (mem_image_of_mem _ hb)
+  rw [← map_mul, he, map_mul, hae, hbe] at huH
+  refine huG ?_ ?_ he <;> rw [mem_filter]
+  exacts [⟨ha, (huH rfl).1⟩, ⟨hb, (huH rfl).2⟩]
+
 end UniqueMul
 
 /-- Let `G` be a Type with addition.  `UniqueSums G` asserts that any two non-empty
@@ -211,7 +227,7 @@ class UniqueSums (G) [Add G] : Prop where
 /-- For `A B` two nonempty finite sets, there always exist `a0 ∈ A, b0 ∈ B` such that
 `UniqueAdd A B a0 b0` -/
   uniqueAdd_of_nonempty :
-    ∀ {A B : Finset G} (_ : A.Nonempty) (_ : B.Nonempty), ∃ a0 ∈ A, ∃ b0 ∈ B, UniqueAdd A B a0 b0
+    ∀ {A B : Finset G}, A.Nonempty → B.Nonempty → ∃ a0 ∈ A, ∃ b0 ∈ B, UniqueAdd A B a0 b0
 #align unique_sums UniqueSums
 
 /-- Let `G` be a Type with multiplication.  `UniqueProds G` asserts that any two non-empty
@@ -221,16 +237,55 @@ class UniqueProds (G) [Mul G] : Prop where
 /-- For `A B` two nonempty finite sets, there always exist `a0 ∈ A, b0 ∈ B` such that
 `UniqueMul A B a0 b0` -/
   uniqueMul_of_nonempty :
-    ∀ {A B : Finset G} (_ : A.Nonempty) (_ : B.Nonempty), ∃ a0 ∈ A, ∃ b0 ∈ B, UniqueMul A B a0 b0
+    ∀ {A B : Finset G}, A.Nonempty → B.Nonempty → ∃ a0 ∈ A, ∃ b0 ∈ B, UniqueMul A B a0 b0
 #align unique_prods UniqueProds
 
 attribute [to_additive] UniqueProds
 
+/-- Let `G` be a Type with addition. `TwoUniqueSums G` asserts that any two non-empty
+finite subsets of `G`, at least one of which is not a singleton, possesses at least two pairs
+of elements satisfying the `UniqueAdd` property. -/
+class TwoUniqueSums (G) [Add G] : Prop where
+/-- For `A B` two finite sets whose product has cardinality at least 2,
+  we can find at least two unique pairs. -/
+  uniqueAdd_of_one_lt_card : ∀ {A B : Finset G}, 1 < A.card * B.card →
+    ∃ p1 ∈ A ×ˢ B, ∃ p2 ∈ A ×ˢ B, p1 ≠ p2 ∧ UniqueAdd A B p1.1 p1.2 ∧ UniqueAdd A B p2.1 p2.2
+
+/-- Let `G` be a Type with multiplication. `TwoUniqueProds G` asserts that any two non-empty
+finite subsets of `G`, at least one of which is not a singleton, possesses at least two pairs
+of elements satisfying the `UniqueMul` property. -/
+class TwoUniqueProds (G) [Mul G] : Prop where
+/-- For `A B` two finite sets whose product has cardinality at least 2,
+  we can find at least two unique pairs. -/
+  uniqueMul_of_one_lt_card : ∀ {A B : Finset G}, 1 < A.card * B.card →
+    ∃ p1 ∈ A ×ˢ B, ∃ p2 ∈ A ×ˢ B, p1 ≠ p2 ∧ UniqueMul A B p1.1 p1.2 ∧ UniqueMul A B p2.1 p2.2
+
+attribute [to_additive] TwoUniqueProds
+
+@[to_additive]
+lemma uniqueMul_of_twoUniqueMul {G} [Mul G] {A B : Finset G} (h : 1 < A.card * B.card →
+    ∃ p1 ∈ A ×ˢ B, ∃ p2 ∈ A ×ˢ B, p1 ≠ p2 ∧ UniqueMul A B p1.1 p1.2 ∧ UniqueMul A B p2.1 p2.2)
+    (hA : A.Nonempty) (hB : B.Nonempty) : ∃ a ∈ A, ∃ b ∈ B, UniqueMul A B a b := by
+  by_cases hc : A.card ≤ 1 ∧ B.card ≤ 1
+  · exact UniqueMul.of_card_le_one hA hB hc.1 hc.2
+  simp_rw [not_and_or, not_le] at hc
+  rw [← Finset.card_pos] at hA hB
+  obtain ⟨p, hp, _, _, _, hu, _⟩ := h (Nat.one_lt_mul_iff.mpr ⟨hA, hB, hc⟩)
+  rw [Finset.mem_product] at hp
+  exact ⟨p.1, hp.1, p.2, hp.2, hu⟩
+
+@[to_additive] instance TwoUniqueProds.toUniqueProds (G) [Mul G] [TwoUniqueProds G] :
+    UniqueProds G where
+  uniqueMul_of_nonempty := uniqueMul_of_twoUniqueMul uniqueMul_of_one_lt_card
+
 namespace Multiplicative
 
 instance {M} [Add M] [UniqueSums M] : UniqueProds (Multiplicative M) where
   uniqueMul_of_nonempty := UniqueSums.uniqueAdd_of_nonempty (G := M)
 
+instance {M} [Add M] [TwoUniqueSums M] : TwoUniqueProds (Multiplicative M) where
+  uniqueMul_of_one_lt_card := TwoUniqueSums.uniqueAdd_of_one_lt_card (G := M)
+
 end Multiplicative
 
 namespace Additive
@@ -238,70 +293,39 @@ namespace Additive
 instance {M} [Mul M] [UniqueProds M] : UniqueSums (Additive M) where
   uniqueAdd_of_nonempty := UniqueProds.uniqueMul_of_nonempty (G := M)
 
+instance {M} [Mul M] [TwoUniqueProds M] : TwoUniqueSums (Additive M) where
+  uniqueAdd_of_one_lt_card := TwoUniqueProds.uniqueMul_of_one_lt_card (G := M)
+
 end Additive
 
 #noalign covariants.to_unique_prods
 #noalign covariants.to_unique_sums
 
-namespace UniqueProds
+universe u v
+variable (G : Type u) (H : Type v) [Mul G] [Mul H]
 
-variable {G H : Type*} [Mul G] [Mul H]
+private abbrev I : Bool → Type max u v := Bool.rec (ULift.{v} G) (ULift.{u} H)
+@[to_additive] private instance : ∀ b, Mul (I G H b) := Bool.rec ULift.mul ULift.mul
+@[to_additive] private instance : Mul (∀ b, I G H b) := inferInstance
+@[to_additive] private def Prod.upMulHom : G × H →ₙ* ∀ b, I G H b :=
+  ⟨fun x ↦ Bool.rec ⟨x.1⟩ ⟨x.2⟩, fun x y ↦ by ext (_|_) <;> rfl⟩
+@[to_additive] private def downMulHom : ULift G →ₙ* G := ⟨ULift.down, fun _ _ ↦ rfl⟩
 
-open Finset MulOpposite in
-@[to_additive]
-theorem of_mulOpposite (h : @UniqueProds Gᵐᵒᵖ (MulOpposite.mul G)) :
-    UniqueProds G :=
-⟨fun hA hB =>
-  let f : G ↪ Gᵐᵒᵖ := ⟨op, op_injective⟩
-  let ⟨y, yB, x, xA, hxy⟩ := h.uniqueMul_of_nonempty (hB.map (f := f)) (hA.map (f := f))
-  ⟨unop x, (mem_map' _).mp xA, unop y, (mem_map' _).mp yB, hxy.of_mulOpposite⟩⟩
+variable {G H}
 
--- see Note [lower instance priority]
-/-- This instance asserts that if `G` has a right-cancellative multiplication, a linear order,
-  and multiplication is strictly monotone w.r.t. the second argument, then `G` has `UniqueProds`. -/
-@[to_additive
-  "This instance asserts that if `G` has a right-cancellative addition, a linear order,
-  and addition is strictly monotone w.r.t. the second argument, then `G` has `UniqueSums`." ]
-instance (priority := 100) of_Covariant_right [IsRightCancelMul G]
-    [LinearOrder G] [CovariantClass G G (· * ·) (· < ·)] :
-    UniqueProds G where
-  uniqueMul_of_nonempty {A B} hA hB := by
-    obtain ⟨a0, b0, ha0, hb0, he⟩ := Finset.mem_mul.mp (Finset.max'_mem _ <| hA.mul hB)
-    refine ⟨a0, ha0, b0, hb0, fun a b ha hb he' => ?_⟩
-    obtain hl | rfl | hl := lt_trichotomy b b0
-    · refine ((he'.trans he ▸ mul_lt_mul_left' hl a).not_le <| Finset.le_max' _ (a * b0) ?_).elim
-      exact Finset.mem_mul.mpr ⟨a, b0, ha, hb0, rfl⟩
-    · exact ⟨mul_right_cancel he', rfl⟩
-    · refine ((he ▸ mul_lt_mul_left' hl a0).not_le <| Finset.le_max' _ (a0 * b) ?_).elim
-      exact Finset.mem_mul.mpr ⟨a0, b, ha0, hb, rfl⟩
-
-open MulOpposite in
--- see Note [lower instance priority]
-/-- This instance asserts that if `G` has a left-cancellative multiplication, a linear order,
-  and multiplication is strictly monotone w.r.t. the first argument, then `G` has `UniqueProds`. -/
-@[to_additive
-  "This instance asserts that if `G` has a left-cancellative addition, a linear order,
-  and addition is strictly monotone w.r.t. the first argument, then `G` has `UniqueSums`." ]
-instance (priority := 100) of_Covariant_left [IsLeftCancelMul G]
-    [LinearOrder G] [CovariantClass G G (Function.swap (· * ·)) (· < ·)] :
-    UniqueProds G :=
-let _ := LinearOrder.lift' (unop : Gᵐᵒᵖ → G) unop_injective
-let _ : CovariantClass Gᵐᵒᵖ Gᵐᵒᵖ (· * ·) (· < ·) :=
-{ elim := fun _ _ _ bc =>
-          have : StrictMono (unop (α := G)) := fun _ _ => id
-          mul_lt_mul_right' (α := G) bc (unop _) }
-of_mulOpposite of_Covariant_right
+namespace UniqueProds
 
 open Finset
+
 @[to_additive]
 theorem mulHom_image_of_injective (f : H →ₙ* G) (hf : Function.Injective f) (uG : UniqueProds G) :
-    UniqueProds H := by
-  refine ⟨fun {A B} A0 B0 => ?_⟩
-  classical
-  obtain ⟨a0, ha0, b0, hb0, h⟩ := uG.uniqueMul_of_nonempty (A0.image f) (B0.image f)
-  rcases mem_image.mp ha0 with ⟨a', ha', rfl⟩
-  rcases mem_image.mp hb0 with ⟨b', hb', rfl⟩
-  exact ⟨a', ha', b', hb', (UniqueMul.mulHom_image_iff f hf).mp h⟩
+    UniqueProds H where
+  uniqueMul_of_nonempty {A B} A0 B0 := by
+    classical
+    obtain ⟨a0, ha0, b0, hb0, h⟩ := uG.uniqueMul_of_nonempty (A0.image f) (B0.image f)
+    rcases mem_image.mp ha0 with ⟨a', ha', rfl⟩
+    rcases mem_image.mp hb0 with ⟨b', hb', rfl⟩
+    exact ⟨a', ha', b', hb', (UniqueMul.mulHom_image_iff f hf).mp h⟩
 
 /-- `UniqueProd` is preserved under multiplicative equivalences. -/
 @[to_additive "`UniqueSums` is preserved under additive equivalences."]
@@ -309,61 +333,47 @@ theorem mulHom_image_iff (f : G ≃* H) :
     UniqueProds G ↔ UniqueProds H :=
 ⟨mulHom_image_of_injective f.symm f.symm.injective, mulHom_image_of_injective f f.injective⟩
 
-@[to_additive] instance [UniqueProds G] [UniqueProds H] : UniqueProds (G × H) where
-  uniqueMul_of_nonempty {A B} hA hB := by
-    classical
-    obtain ⟨aG, hA, bG, hB, hG⟩ := uniqueMul_of_nonempty (hA.image Prod.fst) (hB.image Prod.fst)
-    rw [mem_image, ← filter_nonempty_iff] at hA hB
-    obtain ⟨aH, hA, bH, hB, hH⟩ := uniqueMul_of_nonempty (hA.image Prod.snd) (hB.image Prod.snd)
-    simp_rw [mem_image, mem_filter] at hA hB
-    refine ⟨(aG, aH), ?_, (bG, bH), ?_, fun a b ha hb he => ?_⟩
-    · obtain ⟨a, ⟨ha, rfl⟩, rfl⟩ := hA; exact ha
-    · obtain ⟨b, ⟨hb, rfl⟩, rfl⟩ := hB; exact hb
-    rw [Prod.ext_iff] at he
-    specialize hG (mem_image.mpr ⟨a, ha, rfl⟩) (mem_image.mpr ⟨b, hb, rfl⟩) he.1
-    specialize hH _ _ he.2
-    all_goals try simp_rw [mem_image, mem_filter]
-    exacts [⟨a, ⟨ha, hG.1⟩, rfl⟩, ⟨b, ⟨hb, hG.2⟩, rfl⟩, ⟨Prod.ext hG.1 hH.1, Prod.ext hG.2 hH.2⟩]
+open Finset MulOpposite in
+@[to_additive]
+theorem of_mulOpposite (h : UniqueProds Gᵐᵒᵖ) : UniqueProds G where
+  uniqueMul_of_nonempty hA hB :=
+    let f : G ↪ Gᵐᵒᵖ := ⟨op, op_injective⟩
+    let ⟨y, yB, x, xA, hxy⟩ := h.uniqueMul_of_nonempty (hB.map (f := f)) (hA.map (f := f))
+    ⟨unop x, (mem_map' _).mp xA, unop y, (mem_map' _).mp yB, hxy.of_mulOpposite⟩
+
+@[to_additive] instance [h : UniqueProds G] : UniqueProds Gᵐᵒᵖ :=
+  of_mulOpposite <| (mulHom_image_iff <| MulEquiv.opOp G).mp h
 
+open UniqueMul in
 @[to_additive] instance {ι} (G : ι → Type*) [∀ i, Mul (G i)] [∀ i, UniqueProds (G i)] :
     UniqueProds (∀ i, G i) where
   uniqueMul_of_nonempty {A} := by
     classical
-    let _ := Finset.isWellFounded_ssubset (α := ∀ i, G i) -- why need this?
+    let _ := isWellFounded_ssubset (α := ∀ i, G i) -- why need this?
     apply IsWellFounded.induction (· ⊂ ·) A; intro A ihA B hA
     apply IsWellFounded.induction (· ⊂ ·) B; intro B ihB hB
-    obtain hc | ⟨i, hc⟩ : (A.card ≤ 1 ∧ B.card ≤ 1) ∨
-      ∃ i, (∃ a1 ∈ A, ∃ a2 ∈ A, a1 i ≠ a2 i) ∨ (∃ b1 ∈ B, ∃ b2 ∈ B, b1 i ≠ b2 i)
-    · obtain hA1 | h1A := le_or_lt A.card 1
-      · obtain hB1 | h1B := le_or_lt B.card 1
-        · exact Or.inl ⟨hA1, hB1⟩
-        obtain ⟨b1, h1, b2, h2, hne⟩ := Finset.one_lt_card.mp h1B
-        obtain ⟨i, hne⟩ := Function.ne_iff.mp hne
-        exact Or.inr ⟨i, Or.inr ⟨b1, h1, b2, h2, hne⟩⟩
-      obtain ⟨a1, h1, a2, h2, hne⟩ := Finset.one_lt_card.mp h1A
-      obtain ⟨i, hne⟩ := Function.ne_iff.mp hne
-      exact Or.inr ⟨i, Or.inl ⟨a1, h1, a2, h2, hne⟩⟩
-    · obtain ⟨a0, ha0⟩ := hA; obtain ⟨b0, hb0⟩ := hB
-      simp_rw [Finset.card_le_one_iff] at hc
-      exact ⟨a0, ha0, b0, hb0, fun a b ha hb _ => ⟨hc.1 ha ha0, hc.2 hb hb0⟩⟩
+    by_cases hc : A.card ≤ 1 ∧ B.card ≤ 1
+    · exact of_card_le_one hA hB hc.1 hc.2
+    simp_rw [not_and_or, not_le] at hc
+    obtain ⟨i, hc⟩ := exists_or.mpr (hc.imp exists_of_one_lt_card_pi exists_of_one_lt_card_pi)
     obtain ⟨ai, hA, bi, hB, hi⟩ := uniqueMul_of_nonempty (hA.image (· i)) (hB.image (· i))
     rw [mem_image, ← filter_nonempty_iff] at hA hB
     let A' := A.filter (· i = ai); let B' := B.filter (· i = bi)
     obtain ⟨a0, ha0, b0, hb0, hu⟩ : ∃ a0 ∈ A', ∃ b0 ∈ B', UniqueMul A' B' a0 b0
-    · rcases hc with ⟨a1, h1, a2, h2, hne⟩ | ⟨b1, h1, b2, h2, hne⟩
-      · refine ihA _ ⟨A.filter_subset _, fun h => ?_⟩ hA hB
-        obtain rfl | hai := eq_or_ne (a1 i) ai
-        exacts [hne (mem_filter.mp <| h h2).2.symm, hai (mem_filter.mp <| h h1).2]
-      by_cases hA' : A' = A
-      · rw [hA']; refine ihB _ ⟨B.filter_subset _, fun h => ?_⟩ hB
-        obtain rfl | hbi := eq_or_ne (b1 i) bi
-        exacts [hne (mem_filter.mp <| h h2).2.symm, hbi (mem_filter.mp <| h h1).2]
-      exact ihA A' ((A.filter_subset _).ssubset_of_ne hA') hA hB
+    · rcases hc with hc | hc; · exact ihA A' (hc.2 ai) hA hB
+      by_cases hA' : A' = A; rw [hA']
+      exacts [ihB B' (hc.2 bi) hB, ihA A' ((A.filter_subset _).ssubset_of_ne hA') hA hB]
     rw [mem_filter] at ha0 hb0
-    refine ⟨a0, ha0.1, b0, hb0.1, fun a b ha hb he => ?_⟩
-    specialize hi (mem_image_of_mem _ ha) (mem_image_of_mem _ hb) ?_
-    · refine (congr_arg (· i) he).trans ?_; rw [← ha0.2, ← hb0.2]; rfl
-    exact hu (mem_filter.mpr ⟨ha, hi.1⟩) (mem_filter.mpr ⟨hb, hi.2⟩) he
+    exact ⟨a0, ha0.1, b0, hb0.1, of_image_filter (Pi.evalMulHom G i) ha0.2 hb0.2 hi hu⟩
+
+open ULift in
+@[to_additive] instance [UniqueProds G] [UniqueProds H] : UniqueProds (G × H) := by
+  have : ∀ b, UniqueProds (I G H b) := Bool.rec ?_ ?_
+  · exact mulHom_image_of_injective (downMulHom H) down_injective ‹_›
+  · refine mulHom_image_of_injective (Prod.upMulHom G H) (fun x y he => Prod.ext ?_ ?_)
+      (instUniqueProdsForAllInstMul <| I G H) <;> apply up_injective
+    exacts [congr_fun he false, congr_fun he true]
+  · exact mulHom_image_of_injective (downMulHom G) down_injective ‹_›
 
 end UniqueProds
 
@@ -375,3 +385,148 @@ instance {ι} (G : ι → Type*) [∀ i, AddZeroClass (G i)] [∀ i, UniqueSums
 instance {ι G} [AddZeroClass G] [UniqueSums G] : UniqueSums (ι →₀ G) :=
   UniqueSums.addHom_image_of_injective
     Finsupp.coeFnAddHom.toAddHom FunLike.coe_injective inferInstance
+
+namespace TwoUniqueProds
+
+open Finset
+
+@[to_additive]
+theorem mulHom_image_of_injective (f : H →ₙ* G) (hf : Function.Injective f)
+    (uG : TwoUniqueProds G) : TwoUniqueProds H where
+  uniqueMul_of_one_lt_card {A B} hc := by
+    classical
+    simp_rw [← card_map ⟨f, hf⟩] at hc
+    obtain ⟨⟨a1, b1⟩, h1, ⟨a2, b2⟩, h2, hne, hu1, hu2⟩ := uG.uniqueMul_of_one_lt_card hc
+    simp only [mem_product, mem_map] at h1 h2 ⊢
+    obtain ⟨⟨a1, ha1, rfl⟩, ⟨b1, hb1, rfl⟩⟩ := h1
+    obtain ⟨⟨a2, ha2, rfl⟩, ⟨b2, hb2, rfl⟩⟩ := h2
+    refine ⟨(a1, b1), ⟨ha1, hb1⟩, (a2, b2), ⟨ha2, hb2⟩, ?_, ?_, ?_⟩
+    · rw [Ne, Prod.ext_iff] at hne ⊢; simp_rw [← hf.eq_iff]; exact hne
+    all_goals apply (UniqueMul.mulHom_map_iff ⟨f, hf⟩ f.2).mp
+    exacts [hu1, hu2]
+
+/-- `TwoUniqueProd` is preserved under multiplicative equivalences. -/
+@[to_additive "`TwoUniqueSums` is preserved under additive equivalences."]
+theorem mulHom_image_iff (f : G ≃* H) : TwoUniqueProds G ↔ TwoUniqueProds H :=
+⟨mulHom_image_of_injective f.symm f.symm.injective, mulHom_image_of_injective f f.injective⟩
+
+@[to_additive] instance {ι} (G : ι → Type*) [∀ i, Mul (G i)] [∀ i, TwoUniqueProds (G i)] :
+    TwoUniqueProds (∀ i, G i) where
+  uniqueMul_of_one_lt_card {A} := by
+    classical
+    let _ := isWellFounded_ssubset (α := ∀ i, G i) -- why need this?
+    apply IsWellFounded.induction (· ⊂ ·) A; intro A ihA B
+    apply IsWellFounded.induction (· ⊂ ·) B; intro B ihB hc
+    obtain ⟨hA, hB, hc⟩ := Nat.one_lt_mul_iff.mp hc
+    rw [card_pos] at hA hB
+    obtain ⟨i, hc⟩ := exists_or.mpr (hc.imp exists_of_one_lt_card_pi exists_of_one_lt_card_pi)
+    obtain ⟨p1, h1, p2, h2, hne, hi1, hi2⟩ := uniqueMul_of_one_lt_card (Nat.one_lt_mul_iff.mpr
+      ⟨card_pos.2 (hA.image _), card_pos.2 (hB.image _), hc.imp And.left And.left⟩)
+    simp_rw [mem_product, mem_image, ← filter_nonempty_iff] at h1 h2
+    replace h1 := uniqueMul_of_twoUniqueMul ?_ h1.1 h1.2
+    replace h2 := uniqueMul_of_twoUniqueMul ?_ h2.1 h2.2
+    · obtain ⟨a1, ha1, b1, hb1, hu1⟩ := h1
+      obtain ⟨a2, ha2, b2, hb2, hu2⟩ := h2
+      rw [mem_filter] at ha1 hb1 ha2 hb2
+      simp_rw [mem_product]
+      refine ⟨(a1, b1), ⟨ha1.1, hb1.1⟩, (a2, b2), ⟨ha2.1, hb2.1⟩, ?_,
+        UniqueMul.of_image_filter (Pi.evalMulHom G i) ha1.2 hb1.2 hi1 hu1,
+        UniqueMul.of_image_filter (Pi.evalMulHom G i) ha2.2 hb2.2 hi2 hu2⟩
+      contrapose! hne; rw [Prod.mk.inj_iff] at hne ⊢
+      rw [← ha1.2, ← hb1.2, ← ha2.2, ← hb2.2, hne.1, hne.2]; exact ⟨rfl, rfl⟩
+    all_goals
+      rcases hc with hc | hc; · exact ihA _ (hc.2 _)
+      by_cases hA : A.filter (· i = _) = A; rw [hA]
+      exacts [ihB _ (hc.2 _), ihA _ ((A.filter_subset _).ssubset_of_ne hA)]
+
+open ULift in
+@[to_additive] instance [TwoUniqueProds G] [TwoUniqueProds H] : TwoUniqueProds (G × H) := by
+  have : ∀ b, TwoUniqueProds (I G H b) := Bool.rec ?_ ?_
+  · exact mulHom_image_of_injective (downMulHom H) down_injective ‹_›
+  · refine mulHom_image_of_injective (Prod.upMulHom G H) (fun x y he ↦ Prod.ext ?_ ?_)
+      (instTwoUniqueProdsForAllInstMul <| I G H) <;> apply up_injective
+    exacts [congr_fun he false, congr_fun he true]
+  · exact mulHom_image_of_injective (downMulHom G) down_injective ‹_›
+
+open MulOpposite in
+@[to_additive]
+theorem of_mulOpposite (h : TwoUniqueProds Gᵐᵒᵖ) : TwoUniqueProds G where
+  uniqueMul_of_one_lt_card hc := by
+    let f : G ↪ Gᵐᵒᵖ := ⟨op, op_injective⟩
+    rw [← card_map f, ← card_map f, mul_comm] at hc
+    obtain ⟨p1, h1, p2, h2, hne, hu1, hu2⟩ := h.uniqueMul_of_one_lt_card hc
+    simp_rw [mem_product] at h1 h2 ⊢
+    refine ⟨(_, _), ⟨?_, ?_⟩, (_, _), ⟨?_, ?_⟩, ?_, hu1.of_mulOpposite, hu2.of_mulOpposite⟩
+    pick_goal 5
+    · contrapose! hne; rw [Prod.ext_iff] at hne ⊢
+      exact ⟨unop_injective hne.2, unop_injective hne.1⟩
+    all_goals apply (mem_map' f).mp
+    exacts [h1.2, h1.1, h2.2, h2.1]
+
+@[to_additive] instance [h : TwoUniqueProds G] : TwoUniqueProds Gᵐᵒᵖ :=
+  of_mulOpposite <| (mulHom_image_iff <| MulEquiv.opOp G).mp h
+
+-- see Note [lower instance priority]
+/-- This instance asserts that if `G` has a right-cancellative multiplication, a linear order, and
+  multiplication is strictly monotone w.r.t. the second argument, then `G` has `TwoUniqueProds`. -/
+@[to_additive
+  "This instance asserts that if `G` has a right-cancellative addition, a linear order,
+  and addition is strictly monotone w.r.t. the second argument, then `G` has `TwoUniqueSums`." ]
+instance (priority := 100) of_Covariant_right [IsRightCancelMul G]
+    [LinearOrder G] [CovariantClass G G (· * ·) (· < ·)] :
+    TwoUniqueProds G where
+  uniqueMul_of_one_lt_card {A B} hc := by
+    obtain ⟨hA, hB, -⟩ := Nat.one_lt_mul_iff.mp hc
+    rw [card_pos] at hA hB
+    rw [← card_product] at hc
+    obtain ⟨a0, b0, ha0, hb0, he0⟩ := mem_mul.mp (max'_mem _ <| hA.mul hB)
+    obtain ⟨a1, b1, ha1, hb1, he1⟩ := mem_mul.mp (min'_mem _ <| hA.mul hB)
+    have : UniqueMul A B a0 b0
+    · intro a b ha hb he
+      obtain hl | rfl | hl := lt_trichotomy b b0
+      · exact ((he0 ▸ he ▸ mul_lt_mul_left' hl a).not_le <| le_max' _ _ <| mul_mem_mul ha hb0).elim
+      · exact ⟨mul_right_cancel he, rfl⟩
+      · exact ((he0 ▸ mul_lt_mul_left' hl a0).not_le <| le_max' _ _ <| mul_mem_mul ha0 hb).elim
+    refine ⟨_, mk_mem_product ha0 hb0, _, mk_mem_product ha1 hb1, fun he ↦ ?_, this, ?_⟩
+    · rw [Prod.mk.inj_iff] at he; rw [he.1, he.2, he1] at he0
+      obtain ⟨⟨a2, b2⟩, h2, hne⟩ := exists_ne_of_one_lt_card hc (a0, b0)
+      rw [mem_product] at h2
+      refine (min'_lt_max' _ (mul_mem_mul ha0 hb0) (mul_mem_mul h2.1 h2.2) fun he ↦ hne ?_).ne he0
+      exact Prod.ext_iff.mpr (this h2.1 h2.2 he.symm)
+    · intro a b ha hb he
+      obtain hl | rfl | hl := lt_trichotomy b b1
+      · exact ((he1 ▸ mul_lt_mul_left' hl a1).not_le <| min'_le _ _ <| mul_mem_mul ha1 hb).elim
+      · exact ⟨mul_right_cancel he, rfl⟩
+      · exact ((he1 ▸ he ▸ mul_lt_mul_left' hl a).not_le <| min'_le _ _ <| mul_mem_mul ha hb1).elim
+
+open MulOpposite in
+-- see Note [lower instance priority]
+/-- This instance asserts that if `G` has a left-cancellative multiplication, a linear order, and
+  multiplication is strictly monotone w.r.t. the first argument, then `G` has `TwoUniqueProds`. -/
+@[to_additive
+  "This instance asserts that if `G` has a left-cancellative addition, a linear order, and
+  addition is strictly monotone w.r.t. the first argument, then `G` has `TwoUniqueSums`." ]
+instance (priority := 100) of_Covariant_left [IsLeftCancelMul G]
+    [LinearOrder G] [CovariantClass G G (Function.swap (· * ·)) (· < ·)] :
+    TwoUniqueProds G :=
+  let _ := LinearOrder.lift' (unop : Gᵐᵒᵖ → G) unop_injective
+  let _ : CovariantClass Gᵐᵒᵖ Gᵐᵒᵖ (· * ·) (· < ·) :=
+  { elim := fun _ _ _ bc ↦ mul_lt_mul_right' (α := G) bc (unop _) }
+  of_mulOpposite of_Covariant_right
+
+end TwoUniqueProds
+
+instance {ι} (G : ι → Type*) [∀ i, AddZeroClass (G i)] [∀ i, TwoUniqueSums (G i)] :
+    TwoUniqueSums (Π₀ i, G i) :=
+  TwoUniqueSums.addHom_image_of_injective
+    DFinsupp.coeFnAddMonoidHom.toAddHom FunLike.coe_injective inferInstance
+
+instance {ι G} [AddZeroClass G] [TwoUniqueSums G] : TwoUniqueSums (ι →₀ G) :=
+  TwoUniqueSums.addHom_image_of_injective
+    Finsupp.coeFnAddHom.toAddHom FunLike.coe_injective inferInstance
+
+/-- Any `ℚ`-vector space has `TwoUniqueSums`, because it is isomorphic to some
+  `(Basis.ofVectorSpaceIndex ℚ G) →₀ ℚ` by choosing a basis, and `ℚ` already has
+  `TwoUniqueSums` because it's ordered. -/
+instance [AddCommGroup G] [Module ℚ G] : TwoUniqueSums G :=
+  TwoUniqueSums.addHom_image_of_injective _ (Basis.ofVectorSpace ℚ G).repr.injective inferInstance
feat(UniqueProds + NoZeroDivisors): AddMonoidAlgebra instances (#6723)

Add UniqueProds/Sums and NoZeroDivisors instances.

This has recently been prompted by the port of the Lindemann-Weierstrass Theorem, but the results are self-contained. Instances such as the ones in this PR are the reasons why UniqueProds/Sums were introduced.

Affected files:

Algebra/
	Group/UniqueProds.lean
	MonoidAlgebra/NoZeroDivisors.lean

Co-authored-by: Junyan Xu <junyanxu.math@gmail.com>

Diff
@@ -3,7 +3,10 @@ Copyright (c) 2022 Damiano Testa. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Damiano Testa
 -/
+import Mathlib.Data.DFinsupp.Basic
+import Mathlib.Data.Finset.Pointwise
 import Mathlib.Data.Finset.Preimage
+import Mathlib.Data.Finsupp.Defs
 
 #align_import algebra.group.unique_prods from "leanprover-community/mathlib"@"d6fad0e5bf2d6f48da9175d25c3dc5706b3834ce"
 
@@ -45,7 +48,6 @@ about the grading type and then a generic statement of the form "look at the coe
 The file `Algebra/MonoidAlgebra/NoZeroDivisors` contains several examples of this use.
 -/
 
-
 /-- Let `G` be a Type with multiplication, let `A B : Finset G` be finite subsets and
 let `a0 b0 : G` be two elements.  `UniqueMul A B a0 b0` asserts `a0 * b0` can be written in at
 most one way as a product of an element of `A` and an element of `B`. -/
@@ -203,7 +205,7 @@ end Opposites
 end UniqueMul
 
 /-- Let `G` be a Type with addition.  `UniqueSums G` asserts that any two non-empty
-finite subsets of `A` have the `UniqueAdd` property, with respect to some element of their
+finite subsets of `G` have the `UniqueAdd` property, with respect to some element of their
 sum `A + B`. -/
 class UniqueSums (G) [Add G] : Prop where
 /-- For `A B` two nonempty finite sets, there always exist `a0 ∈ A, b0 ∈ B` such that
@@ -238,52 +240,138 @@ instance {M} [Mul M] [UniqueProds M] : UniqueSums (Additive M) where
 
 end Additive
 
--- see Note [lower instance priority]
-/-- This instance asserts that if `A` has a multiplication, a linear order, and multiplication
-is 'very monotone', then `A` also has `UniqueProds`. -/
-@[to_additive
-      "This instance asserts that if `A` has an addition, a linear order, and addition
-is 'very monotone', then `A` also has `UniqueSums`."]
-instance (priority := 100) Covariants.to_uniqueProds {A} [Mul A] [LinearOrder A]
-    [CovariantClass A A (· * ·) (· ≤ ·)] [CovariantClass A A (Function.swap (· * ·)) (· < ·)]
-    [ContravariantClass A A (· * ·) (· ≤ ·)] : UniqueProds A where
-  uniqueMul_of_nonempty {A B} hA hB :=
-    ⟨_, A.max'_mem ‹_›, _, B.max'_mem ‹_›, fun a b ha hb ↦
-      (mul_eq_mul_iff_eq_and_eq (Finset.le_max' _ _ ‹_›) (Finset.le_max' _ _ ‹_›)).mp⟩
-#align covariants.to_unique_prods Covariants.to_uniqueProds
-#align covariants.to_unique_sums Covariants.to_uniqueSums
+#noalign covariants.to_unique_prods
+#noalign covariants.to_unique_sums
 
 namespace UniqueProds
 
-@[to_additive (attr := nontriviality, simp)]
-theorem of_subsingleton {G : Type*} [Mul G] [Subsingleton G] : UniqueProds G where
-  uniqueMul_of_nonempty {A B} | ⟨a, hA⟩, ⟨b, hB⟩ => ⟨a, hA, b, hB, by simp⟩
+variable {G H : Type*} [Mul G] [Mul H]
 
 open Finset MulOpposite in
 @[to_additive]
-theorem of_mulOpposite (G : Type*) [Mul G] (h : UniqueProds Gᵐᵒᵖ) :
+theorem of_mulOpposite (h : @UniqueProds Gᵐᵒᵖ (MulOpposite.mul G)) :
     UniqueProds G :=
-  ⟨fun hA hB =>
-    let f : G ↪ Gᵐᵒᵖ := ⟨op, op_injective⟩
-    let ⟨y, yB, x, xA, hxy⟩ := h.uniqueMul_of_nonempty (hB.map (f := f)) (hA.map (f := f))
-    ⟨unop x, (mem_map' _).mp xA, unop y, (mem_map' _).mp yB, hxy.of_mulOpposite⟩⟩
+⟨fun hA hB =>
+  let f : G ↪ Gᵐᵒᵖ := ⟨op, op_injective⟩
+  let ⟨y, yB, x, xA, hxy⟩ := h.uniqueMul_of_nonempty (hB.map (f := f)) (hA.map (f := f))
+  ⟨unop x, (mem_map' _).mp xA, unop y, (mem_map' _).mp yB, hxy.of_mulOpposite⟩⟩
+
+-- see Note [lower instance priority]
+/-- This instance asserts that if `G` has a right-cancellative multiplication, a linear order,
+  and multiplication is strictly monotone w.r.t. the second argument, then `G` has `UniqueProds`. -/
+@[to_additive
+  "This instance asserts that if `G` has a right-cancellative addition, a linear order,
+  and addition is strictly monotone w.r.t. the second argument, then `G` has `UniqueSums`." ]
+instance (priority := 100) of_Covariant_right [IsRightCancelMul G]
+    [LinearOrder G] [CovariantClass G G (· * ·) (· < ·)] :
+    UniqueProds G where
+  uniqueMul_of_nonempty {A B} hA hB := by
+    obtain ⟨a0, b0, ha0, hb0, he⟩ := Finset.mem_mul.mp (Finset.max'_mem _ <| hA.mul hB)
+    refine ⟨a0, ha0, b0, hb0, fun a b ha hb he' => ?_⟩
+    obtain hl | rfl | hl := lt_trichotomy b b0
+    · refine ((he'.trans he ▸ mul_lt_mul_left' hl a).not_le <| Finset.le_max' _ (a * b0) ?_).elim
+      exact Finset.mem_mul.mpr ⟨a, b0, ha, hb0, rfl⟩
+    · exact ⟨mul_right_cancel he', rfl⟩
+    · refine ((he ▸ mul_lt_mul_left' hl a0).not_le <| Finset.le_max' _ (a0 * b) ?_).elim
+      exact Finset.mem_mul.mpr ⟨a0, b, ha0, hb, rfl⟩
 
 open MulOpposite in
-@[to_additive (attr := simp)]
-theorem iff_mulOpposite (G : Type*) [Mul G] :
-    UniqueProds Gᵐᵒᵖ ↔ UniqueProds G := by
-  refine ⟨of_mulOpposite G, fun h ↦ of_mulOpposite (Gᵐᵒᵖ) ⟨fun {A B} hA hB ↦ ?_⟩⟩
+-- see Note [lower instance priority]
+/-- This instance asserts that if `G` has a left-cancellative multiplication, a linear order,
+  and multiplication is strictly monotone w.r.t. the first argument, then `G` has `UniqueProds`. -/
+@[to_additive
+  "This instance asserts that if `G` has a left-cancellative addition, a linear order,
+  and addition is strictly monotone w.r.t. the first argument, then `G` has `UniqueSums`." ]
+instance (priority := 100) of_Covariant_left [IsLeftCancelMul G]
+    [LinearOrder G] [CovariantClass G G (Function.swap (· * ·)) (· < ·)] :
+    UniqueProds G :=
+let _ := LinearOrder.lift' (unop : Gᵐᵒᵖ → G) unop_injective
+let _ : CovariantClass Gᵐᵒᵖ Gᵐᵒᵖ (· * ·) (· < ·) :=
+{ elim := fun _ _ _ bc =>
+          have : StrictMono (unop (α := G)) := fun _ _ => id
+          mul_lt_mul_right' (α := G) bc (unop _) }
+of_mulOpposite of_Covariant_right
+
+open Finset
+@[to_additive]
+theorem mulHom_image_of_injective (f : H →ₙ* G) (hf : Function.Injective f) (uG : UniqueProds G) :
+    UniqueProds H := by
+  refine ⟨fun {A B} A0 B0 => ?_⟩
   classical
-  let f : Gᵐᵒᵖᵐᵒᵖ ↪ G := ⟨_, unop_injective.comp unop_injective⟩
-  obtain ⟨a0, ha0, b0, hb0, d⟩ :=
-    h.uniqueMul_of_nonempty (Finset.Nonempty.map (f := f) hA) (Finset.Nonempty.map (f := f) hB)
-  simp only [Finset.mem_map, Function.Embedding.coeFn_mk, Function.comp_apply] at ha0 hb0
-  rcases ha0 with ⟨a0, ha0, rfl⟩
-  rcases hb0 with ⟨b0, hb0, rfl⟩
-  refine ⟨a0, ha0, b0, hb0, ?_⟩
-  apply (UniqueMul.mulHom_map_iff (H := G) (⟨_, unop_injective.comp unop_injective⟩) ?_).mp
-  · simp only [Function.Embedding.coeFn_mk, Function.comp_apply]
-    convert d
-  · simp only [Function.Embedding.coeFn_mk, Function.comp_apply, unop_mul, implies_true]
+  obtain ⟨a0, ha0, b0, hb0, h⟩ := uG.uniqueMul_of_nonempty (A0.image f) (B0.image f)
+  rcases mem_image.mp ha0 with ⟨a', ha', rfl⟩
+  rcases mem_image.mp hb0 with ⟨b', hb', rfl⟩
+  exact ⟨a', ha', b', hb', (UniqueMul.mulHom_image_iff f hf).mp h⟩
+
+/-- `UniqueProd` is preserved under multiplicative equivalences. -/
+@[to_additive "`UniqueSums` is preserved under additive equivalences."]
+theorem mulHom_image_iff (f : G ≃* H) :
+    UniqueProds G ↔ UniqueProds H :=
+⟨mulHom_image_of_injective f.symm f.symm.injective, mulHom_image_of_injective f f.injective⟩
+
+@[to_additive] instance [UniqueProds G] [UniqueProds H] : UniqueProds (G × H) where
+  uniqueMul_of_nonempty {A B} hA hB := by
+    classical
+    obtain ⟨aG, hA, bG, hB, hG⟩ := uniqueMul_of_nonempty (hA.image Prod.fst) (hB.image Prod.fst)
+    rw [mem_image, ← filter_nonempty_iff] at hA hB
+    obtain ⟨aH, hA, bH, hB, hH⟩ := uniqueMul_of_nonempty (hA.image Prod.snd) (hB.image Prod.snd)
+    simp_rw [mem_image, mem_filter] at hA hB
+    refine ⟨(aG, aH), ?_, (bG, bH), ?_, fun a b ha hb he => ?_⟩
+    · obtain ⟨a, ⟨ha, rfl⟩, rfl⟩ := hA; exact ha
+    · obtain ⟨b, ⟨hb, rfl⟩, rfl⟩ := hB; exact hb
+    rw [Prod.ext_iff] at he
+    specialize hG (mem_image.mpr ⟨a, ha, rfl⟩) (mem_image.mpr ⟨b, hb, rfl⟩) he.1
+    specialize hH _ _ he.2
+    all_goals try simp_rw [mem_image, mem_filter]
+    exacts [⟨a, ⟨ha, hG.1⟩, rfl⟩, ⟨b, ⟨hb, hG.2⟩, rfl⟩, ⟨Prod.ext hG.1 hH.1, Prod.ext hG.2 hH.2⟩]
+
+@[to_additive] instance {ι} (G : ι → Type*) [∀ i, Mul (G i)] [∀ i, UniqueProds (G i)] :
+    UniqueProds (∀ i, G i) where
+  uniqueMul_of_nonempty {A} := by
+    classical
+    let _ := Finset.isWellFounded_ssubset (α := ∀ i, G i) -- why need this?
+    apply IsWellFounded.induction (· ⊂ ·) A; intro A ihA B hA
+    apply IsWellFounded.induction (· ⊂ ·) B; intro B ihB hB
+    obtain hc | ⟨i, hc⟩ : (A.card ≤ 1 ∧ B.card ≤ 1) ∨
+      ∃ i, (∃ a1 ∈ A, ∃ a2 ∈ A, a1 i ≠ a2 i) ∨ (∃ b1 ∈ B, ∃ b2 ∈ B, b1 i ≠ b2 i)
+    · obtain hA1 | h1A := le_or_lt A.card 1
+      · obtain hB1 | h1B := le_or_lt B.card 1
+        · exact Or.inl ⟨hA1, hB1⟩
+        obtain ⟨b1, h1, b2, h2, hne⟩ := Finset.one_lt_card.mp h1B
+        obtain ⟨i, hne⟩ := Function.ne_iff.mp hne
+        exact Or.inr ⟨i, Or.inr ⟨b1, h1, b2, h2, hne⟩⟩
+      obtain ⟨a1, h1, a2, h2, hne⟩ := Finset.one_lt_card.mp h1A
+      obtain ⟨i, hne⟩ := Function.ne_iff.mp hne
+      exact Or.inr ⟨i, Or.inl ⟨a1, h1, a2, h2, hne⟩⟩
+    · obtain ⟨a0, ha0⟩ := hA; obtain ⟨b0, hb0⟩ := hB
+      simp_rw [Finset.card_le_one_iff] at hc
+      exact ⟨a0, ha0, b0, hb0, fun a b ha hb _ => ⟨hc.1 ha ha0, hc.2 hb hb0⟩⟩
+    obtain ⟨ai, hA, bi, hB, hi⟩ := uniqueMul_of_nonempty (hA.image (· i)) (hB.image (· i))
+    rw [mem_image, ← filter_nonempty_iff] at hA hB
+    let A' := A.filter (· i = ai); let B' := B.filter (· i = bi)
+    obtain ⟨a0, ha0, b0, hb0, hu⟩ : ∃ a0 ∈ A', ∃ b0 ∈ B', UniqueMul A' B' a0 b0
+    · rcases hc with ⟨a1, h1, a2, h2, hne⟩ | ⟨b1, h1, b2, h2, hne⟩
+      · refine ihA _ ⟨A.filter_subset _, fun h => ?_⟩ hA hB
+        obtain rfl | hai := eq_or_ne (a1 i) ai
+        exacts [hne (mem_filter.mp <| h h2).2.symm, hai (mem_filter.mp <| h h1).2]
+      by_cases hA' : A' = A
+      · rw [hA']; refine ihB _ ⟨B.filter_subset _, fun h => ?_⟩ hB
+        obtain rfl | hbi := eq_or_ne (b1 i) bi
+        exacts [hne (mem_filter.mp <| h h2).2.symm, hbi (mem_filter.mp <| h h1).2]
+      exact ihA A' ((A.filter_subset _).ssubset_of_ne hA') hA hB
+    rw [mem_filter] at ha0 hb0
+    refine ⟨a0, ha0.1, b0, hb0.1, fun a b ha hb he => ?_⟩
+    specialize hi (mem_image_of_mem _ ha) (mem_image_of_mem _ hb) ?_
+    · refine (congr_arg (· i) he).trans ?_; rw [← ha0.2, ← hb0.2]; rfl
+    exact hu (mem_filter.mpr ⟨ha, hi.1⟩) (mem_filter.mpr ⟨hb, hi.2⟩) he
 
 end UniqueProds
+
+instance {ι} (G : ι → Type*) [∀ i, AddZeroClass (G i)] [∀ i, UniqueSums (G i)] :
+    UniqueSums (Π₀ i, G i) :=
+  UniqueSums.addHom_image_of_injective
+    DFinsupp.coeFnAddMonoidHom.toAddHom FunLike.coe_injective inferInstance
+
+instance {ι G} [AddZeroClass G] [UniqueSums G] : UniqueSums (ι →₀ G) :=
+  UniqueSums.addHom_image_of_injective
+    Finsupp.coeFnAddHom.toAddHom FunLike.coe_injective inferInstance
feat(UniqueProds): subsingleton and MulOpposite lemmas (#6755)

Basic support for subsingleton and MulOpposites. Helps #6723.

Co-authored-by: Junyan Xu <junyanxu.math@gmail.com>

Diff
@@ -62,6 +62,10 @@ namespace UniqueMul
 
 variable {G H : Type*} [Mul G] [Mul H] {A B : Finset G} {a0 b0 : G}
 
+@[to_additive (attr := nontriviality, simp)]
+theorem of_subsingleton [Subsingleton G] : UniqueMul A B a0 b0 := by simp [UniqueMul]
+
+@[to_additive]
 theorem mt {G} [Mul G] {A B : Finset G} {a0 b0 : G} (h : UniqueMul A B a0 b0) :
     ∀ ⦃a b⦄, a ∈ A → b ∈ B → a ≠ a0 ∨ b ≠ b0 → a * b ≠ a0 * b0 := fun _ _ ha hb k ↦ by
   contrapose! k
@@ -165,6 +169,37 @@ theorem mulHom_map_iff (f : G ↪ H) (mul : ∀ x y, f (x * y) = f x * f y) :
 #align unique_mul.mul_hom_map_iff UniqueMul.mulHom_map_iff
 #align unique_add.add_hom_map_iff UniqueAdd.addHom_map_iff
 
+section Opposites
+open Finset MulOpposite
+
+@[to_additive]
+theorem of_mulOpposite
+    (h : UniqueMul (B.map ⟨_, op_injective⟩) (A.map ⟨_, op_injective⟩) (op b0) (op a0)) :
+    UniqueMul A B a0 b0 := by
+  intros a b aA bB ab
+  have := h (mem_map_of_mem _ bB) (mem_map_of_mem _ aA) (by simpa using congr_arg op ab)
+  simpa [and_comm] using this
+
+@[to_additive]
+theorem to_mulOpposite (h : UniqueMul A B a0 b0) :
+    UniqueMul (B.map ⟨_, op_injective⟩) (A.map ⟨_, op_injective⟩) (op b0) (op a0) := by
+  refine of_mulOpposite (G := MulOpposite G) <| fun a b ha hb hab ↦ ?_
+  simp only [mem_map, Function.Embedding.coeFn_mk, exists_exists_and_eq_and] at ha hb
+  rcases ha with ⟨a, ha, rfl⟩
+  rcases hb with ⟨b, hb, rfl⟩
+  rw [op_inj, op_inj, op_inj, op_inj]
+  apply h ha hb ?_
+  apply_fun op ∘ op using op_injective.comp op_injective
+  exact hab
+
+@[to_additive]
+theorem iff_mulOpposite :
+    UniqueMul (B.map ⟨_, op_injective⟩) (A.map ⟨_, op_injective⟩) (op b0) (op a0) ↔
+      UniqueMul A B a0 b0 :=
+⟨of_mulOpposite, to_mulOpposite⟩
+
+end Opposites
+
 end UniqueMul
 
 /-- Let `G` be a Type with addition.  `UniqueSums G` asserts that any two non-empty
@@ -212,8 +247,43 @@ is 'very monotone', then `A` also has `UniqueSums`."]
 instance (priority := 100) Covariants.to_uniqueProds {A} [Mul A] [LinearOrder A]
     [CovariantClass A A (· * ·) (· ≤ ·)] [CovariantClass A A (Function.swap (· * ·)) (· < ·)]
     [ContravariantClass A A (· * ·) (· ≤ ·)] : UniqueProds A where
-      uniqueMul_of_nonempty {A} {B} hA hB :=
-        ⟨_, A.max'_mem ‹_›, _, B.max'_mem ‹_›, fun a b ha hb ↦
-          (mul_eq_mul_iff_eq_and_eq (Finset.le_max' _ _ ‹_›) (Finset.le_max' _ _ ‹_›)).mp⟩
+  uniqueMul_of_nonempty {A B} hA hB :=
+    ⟨_, A.max'_mem ‹_›, _, B.max'_mem ‹_›, fun a b ha hb ↦
+      (mul_eq_mul_iff_eq_and_eq (Finset.le_max' _ _ ‹_›) (Finset.le_max' _ _ ‹_›)).mp⟩
 #align covariants.to_unique_prods Covariants.to_uniqueProds
 #align covariants.to_unique_sums Covariants.to_uniqueSums
+
+namespace UniqueProds
+
+@[to_additive (attr := nontriviality, simp)]
+theorem of_subsingleton {G : Type*} [Mul G] [Subsingleton G] : UniqueProds G where
+  uniqueMul_of_nonempty {A B} | ⟨a, hA⟩, ⟨b, hB⟩ => ⟨a, hA, b, hB, by simp⟩
+
+open Finset MulOpposite in
+@[to_additive]
+theorem of_mulOpposite (G : Type*) [Mul G] (h : UniqueProds Gᵐᵒᵖ) :
+    UniqueProds G :=
+  ⟨fun hA hB =>
+    let f : G ↪ Gᵐᵒᵖ := ⟨op, op_injective⟩
+    let ⟨y, yB, x, xA, hxy⟩ := h.uniqueMul_of_nonempty (hB.map (f := f)) (hA.map (f := f))
+    ⟨unop x, (mem_map' _).mp xA, unop y, (mem_map' _).mp yB, hxy.of_mulOpposite⟩⟩
+
+open MulOpposite in
+@[to_additive (attr := simp)]
+theorem iff_mulOpposite (G : Type*) [Mul G] :
+    UniqueProds Gᵐᵒᵖ ↔ UniqueProds G := by
+  refine ⟨of_mulOpposite G, fun h ↦ of_mulOpposite (Gᵐᵒᵖ) ⟨fun {A B} hA hB ↦ ?_⟩⟩
+  classical
+  let f : Gᵐᵒᵖᵐᵒᵖ ↪ G := ⟨_, unop_injective.comp unop_injective⟩
+  obtain ⟨a0, ha0, b0, hb0, d⟩ :=
+    h.uniqueMul_of_nonempty (Finset.Nonempty.map (f := f) hA) (Finset.Nonempty.map (f := f) hB)
+  simp only [Finset.mem_map, Function.Embedding.coeFn_mk, Function.comp_apply] at ha0 hb0
+  rcases ha0 with ⟨a0, ha0, rfl⟩
+  rcases hb0 with ⟨b0, hb0, rfl⟩
+  refine ⟨a0, ha0, b0, hb0, ?_⟩
+  apply (UniqueMul.mulHom_map_iff (H := G) (⟨_, unop_injective.comp unop_injective⟩) ?_).mp
+  · simp only [Function.Embedding.coeFn_mk, Function.comp_apply]
+    convert d
+  · simp only [Function.Embedding.coeFn_mk, Function.comp_apply, unop_mul, implies_true]
+
+end UniqueProds
chore(Co(ntra)variantClass): generalize and remove duplicates (#6677)

4 files have major changes:

Algebra/CovariantAndContravariant.lean

  • Add new theorem contravariant_le_iff_contravariant_lt_and_eq.
  • Add covariantClass_le_of_lt generalizing and replacing Mul.to_covariantClass_left/right in Algebra/Order/Monoid/Defs.lean
  • Replace CommSemigroup by IsSymmOp N N mu and replace CancelSemigroup by IsMulCancel, removing superfluous associativity assumption.
  • new theorems covariant_lt_of_covariant_le_of_contravariant_eq and contravariant_le_of_contravariant_eq_and_lt that could replace eight instances when appropriate refactoring is in place.
  • Golfs
  • Fix changed names in other files.

Algebra/Order/Monoid/Lemmas.lean

  • Generalize mul_eq_mul_iff_eq_and_eq and remove the less general Left/Right.mul_eq_mul_iff_eq_and_eq.
  • Move mul_le_mul_iff_of_ge.
  • Introduce the more general Left/Right versions of min_le_max_of_mul_le_mul.
  • Move min_lt_max_of_mul_lt_mul here from Algebra/GroupPower/Order.lean.
  • Replace CommSemigroup by IsSymmOp.

Algebra/Order/Monoid/Basic.lean

  • Remove eq_and_eq_of_le_of_le_of_mul_le as it's just one direction of mul_le_mul_iff_of_ge but with more assumptions.

Algebra/Order/Ring/Lemmas.lean

  • Generalize two versions of mul_eq_mul_iff_eq_and_eq_of_pos
  • Golfs

Changes to Algebra/Group/UniqueProds.lean and Algebra/MonoidAlgebra/NoZeroDivisors.lean are in declarations that will be removed by #6723.

Co-authored-by: Junyan Xu <junyanxu.math@gmail.com>

Diff
@@ -213,7 +213,7 @@ instance (priority := 100) Covariants.to_uniqueProds {A} [Mul A] [LinearOrder A]
     [CovariantClass A A (· * ·) (· ≤ ·)] [CovariantClass A A (Function.swap (· * ·)) (· < ·)]
     [ContravariantClass A A (· * ·) (· ≤ ·)] : UniqueProds A where
       uniqueMul_of_nonempty {A} {B} hA hB :=
-        ⟨_, A.min'_mem ‹_›, _, B.min'_mem ‹_›, fun a b ha hb ab ↦
-        eq_and_eq_of_le_of_le_of_mul_le (Finset.min'_le _ _ ‹_›) (Finset.min'_le _ _ ‹_›) ab.le⟩
+        ⟨_, A.max'_mem ‹_›, _, B.max'_mem ‹_›, fun a b ha hb ↦
+          (mul_eq_mul_iff_eq_and_eq (Finset.le_max' _ _ ‹_›) (Finset.le_max' _ _ ‹_›)).mp⟩
 #align covariants.to_unique_prods Covariants.to_uniqueProds
 #align covariants.to_unique_sums Covariants.to_uniqueSums
feat(ToAdditive + UniqueProds): support [uU]niqueProds →[uU]niqueSums (#6751)

This PR adds to_additive support to convert

  • UniqueProds to UniqueSums and
  • uniqueProds to uniqueSums.

This is just the dictionary support, plus the removal of two, now correctly guessed, to_additive names.

Diff
@@ -187,7 +187,7 @@ class UniqueProds (G) [Mul G] : Prop where
     ∀ {A B : Finset G} (_ : A.Nonempty) (_ : B.Nonempty), ∃ a0 ∈ A, ∃ b0 ∈ B, UniqueMul A B a0 b0
 #align unique_prods UniqueProds
 
-attribute [to_additive UniqueSums] UniqueProds
+attribute [to_additive] UniqueProds
 
 namespace Multiplicative
 
@@ -206,7 +206,7 @@ end Additive
 -- see Note [lower instance priority]
 /-- This instance asserts that if `A` has a multiplication, a linear order, and multiplication
 is 'very monotone', then `A` also has `UniqueProds`. -/
-@[to_additive Covariants.to_uniqueSums
+@[to_additive
       "This instance asserts that if `A` has an addition, a linear order, and addition
 is 'very monotone', then `A` also has `UniqueSums`."]
 instance (priority := 100) Covariants.to_uniqueProds {A} [Mul A] [LinearOrder A]
golf(UniqueProds): Junyan's golf of some proofs. (#6753)
Diff
@@ -124,8 +124,7 @@ theorem mulHom_preimage (f : G →ₙ* H) (hf : Function.Injective f) (a0 b0 : G
     UniqueMul (A.preimage f (Set.injOn_of_injective hf _))
       (B.preimage f (Set.injOn_of_injective hf _)) a0 b0 := by
   intro a b ha hb ab
-  rw [← hf.eq_iff, ← hf.eq_iff]
-  rw [← hf.eq_iff, map_mul, map_mul] at ab
+  simp only [← hf.eq_iff, map_mul] at ab ⊢
   exact u (Finset.mem_preimage.mp ha) (Finset.mem_preimage.mp hb) ab
 #align unique_mul.mul_hom_preimage UniqueMul.mulHom_preimage
 #align unique_add.add_hom_preimage UniqueAdd.addHom_preimage
@@ -139,17 +138,14 @@ See `UniqueMul.mulHom_map_iff` for a version with swapped bundling. -/
 See `UniqueAdd.addHom_map_iff` for a version with swapped bundling."]
 theorem mulHom_image_iff [DecidableEq H] (f : G →ₙ* H) (hf : Function.Injective f) :
     UniqueMul (A.image f) (B.image f) (f a0) (f b0) ↔ UniqueMul A B a0 b0 := by
-  refine' ⟨fun h ↦ _, fun h ↦ _⟩
-  · intro a b ha hb ab
-    rw [← hf.eq_iff, ← hf.eq_iff]
-    rw [← hf.eq_iff, map_mul, map_mul] at ab
-    exact h (Finset.mem_image.mpr ⟨_, ha, rfl⟩) (Finset.mem_image.mpr ⟨_, hb, rfl⟩) ab
-  · intro a b aA bB ab
-    obtain ⟨a, ha, rfl⟩ : ∃ a' ∈ A, f a' = a := Finset.mem_image.mp aA
-    obtain ⟨b, hb, rfl⟩ : ∃ b' ∈ B, f b' = b := Finset.mem_image.mp bB
-    rw [hf.eq_iff, hf.eq_iff]
-    rw [← map_mul, ← map_mul, hf.eq_iff] at ab
-    exact h ha hb ab
+  simp_rw [UniqueMul, Finset.mem_image]
+  refine' ⟨fun h a b ha hb ab ↦ _, fun h ↦ _⟩
+  · rw [← hf.eq_iff, map_mul, map_mul] at ab
+    have := h ⟨a, ha, rfl⟩ ⟨b, hb, rfl⟩ ab
+    exact ⟨hf this.1, hf this.2⟩
+  · rintro _ _ ⟨a, aA, rfl⟩ ⟨b, bB, rfl⟩ ab
+    simp only [← map_mul, hf.eq_iff] at ab ⊢
+    exact h aA bB ab
 #align unique_mul.mul_hom_image_iff UniqueMul.mulHom_image_iff
 #align unique_add.add_hom_image_iff UniqueAdd.addHom_image_iff
 
@@ -196,22 +192,14 @@ attribute [to_additive UniqueSums] UniqueProds
 namespace Multiplicative
 
 instance {M} [Add M] [UniqueSums M] : UniqueProds (Multiplicative M) where
-  uniqueMul_of_nonempty {A} {B} hA hB := by
-    let A' : Finset M := A
-    have hA' : A'.Nonempty := hA
-    obtain ⟨a0, hA0, b0, hB0, J⟩ := UniqueSums.uniqueAdd_of_nonempty hA' hB
-    exact ⟨ofAdd a0, hA0, ofAdd b0, hB0, fun a b aA bB H ↦ J aA bB H⟩
+  uniqueMul_of_nonempty := UniqueSums.uniqueAdd_of_nonempty (G := M)
 
 end Multiplicative
 
 namespace Additive
 
 instance {M} [Mul M] [UniqueProds M] : UniqueSums (Additive M) where
-  uniqueAdd_of_nonempty {A} {B} hA hB := by
-    let A' : Finset M := A
-    have hA' : A'.Nonempty := hA
-    obtain ⟨a0, hA0, b0, hB0, J⟩ := UniqueProds.uniqueMul_of_nonempty hA' hB
-    exact ⟨ofMul a0, hA0, ofMul b0, hB0, fun a b aA bB H ↦ J aA bB H⟩
+  uniqueAdd_of_nonempty := UniqueProds.uniqueMul_of_nonempty (G := M)
 
 end Additive
 
docs(Algebra/Group/UniqueProds): update + mention MonoidAlgebras (#6741)

A simple update of the docs for UniqueProds/Sums. I also added a paragraph explaining the relationship between UniqueProds/Sums and (Add)MonoidAlgebras.

Diff
@@ -14,23 +14,35 @@ A group `G` has *unique products* if for any two non-empty finite subsets `A, B
 element `g ∈ A * B` that can be written uniquely as a product of an element of `A` and an element
 of `B`.  We call the formalization this property `UniqueProds`.  Since the condition requires no
 property of the group operation, we define it for a Type simply satisfying `Mul`.  We also
-introduce the analogous "additive" companion, `UniqueSums` and link the two so that `to_additive`
+introduce the analogous "additive" companion, `UniqueSums`, and link the two so that `to_additive`
 converts `UniqueProds` into `UniqueSums`.
 
+A common way of *proving* that a group satisfies the `UniqueProds/Sums` property is by assuming
+the existence of some kind of ordering on the group that is well-behaved with respect to the
+group operation and showing that minima/maxima are the "unique products/sums".
+However, the order is just a convenience and is not part of the `UniqueProds/Sums` setup.
+
 Here you can see several examples of Types that have `UniqueSums/Prods`
-(`infer_instance` uses `Covariants.to_uniqueProds` and `Covariants.to_uniqueSums`).
+(`inferInstance` uses `Covariant.to_uniqueProds_left` and `Covariant.to_uniqueSums_left`).
 ```lean
 import Mathlib.Data.Real.Basic
 import Mathlib.Data.PNat.Basic
 import Mathlib.Algebra.Group.UniqueProds
 
-example : UniqueSums ℕ   := by infer_instance
-example : UniqueSums ℕ+  := by infer_instance
-example : UniqueSums ℤ   := by infer_instance
-example : UniqueSums ℚ   := by infer_instance
-example : UniqueSums ℝ   := by infer_instance
-example : UniqueProds ℕ+ := by infer_instance
+example : UniqueSums ℕ   := inferInstance
+example : UniqueSums ℕ+  := inferInstance
+example : UniqueSums ℤ   := inferInstance
+example : UniqueSums ℚ   := inferInstance
+example : UniqueSums ℝ   := inferInstance
+example : UniqueProds ℕ+ := inferInstance
 ```
+
+## Use in `(Add)MonoidAlgebra`s
+
+`UniqueProds/Sums` allow to decouple certain arguments about `(Add)MonoidAlgebra`s into an argument
+about the grading type and then a generic statement of the form "look at the coefficient of the
+'unique product/sum'".
+The file `Algebra/MonoidAlgebra/NoZeroDivisors` contains several examples of this use.
 -/
 
 
chore: banish Type _ and Sort _ (#6499)

We remove all possible occurences of Type _ and Sort _ in favor of Type* and Sort*.

This has nice performance benefits.

Diff
@@ -48,7 +48,7 @@ def UniqueMul {G} [Mul G] (A B : Finset G) (a0 b0 : G) : Prop :=
 
 namespace UniqueMul
 
-variable {G H : Type _} [Mul G] [Mul H] {A B : Finset G} {a0 b0 : G}
+variable {G H : Type*} [Mul G] [Mul H] {A B : Finset G} {a0 b0 : G}
 
 theorem mt {G} [Mul G] {A B : Finset G} {a0 b0 : G} (h : UniqueMul A B a0 b0) :
     ∀ ⦃a b⦄, a ∈ A → b ∈ B → a ≠ a0 ∨ b ≠ b0 → a * b ≠ a0 * b0 := fun _ _ ha hb k ↦ by
chore(Algebra/{ Group/UniqueProds, Order/Monoid/Basic }): move eq_and_eq_of_le_of_le_of_mul_le earlier (#6483)

This move was suggested in #6220. In fact, the lemma is a general fact about an inequality involving multiplications and did not really belong in the file where it was.

Affected files:

Algebra.Group.UniqueProds
Algebra.Order.Monoid.Basic
Diff
@@ -203,19 +203,6 @@ instance {M} [Mul M] [UniqueProds M] : UniqueSums (Additive M) where
 
 end Additive
 
-@[to_additive]
-theorem eq_and_eq_of_le_of_le_of_mul_le {A} [Mul A] [LinearOrder A]
-    [CovariantClass A A (· * ·) (· ≤ ·)] [CovariantClass A A (Function.swap (· * ·)) (· < ·)]
-    [ContravariantClass A A (· * ·) (· ≤ ·)] {a b a0 b0 : A} (ha : a0 ≤ a) (hb : b0 ≤ b)
-    (ab : a * b ≤ a0 * b0) : a = a0 ∧ b = b0 := by
-  haveI := Mul.to_covariantClass_right A
-  have ha' : ¬a0 * b0 < a * b → ¬a0 < a := mt fun h ↦ mul_lt_mul_of_lt_of_le h hb
-  have hb' : ¬a0 * b0 < a * b → ¬b0 < b := mt fun h ↦ mul_lt_mul_of_le_of_lt ha h
-  push_neg at ha' hb'
-  exact ⟨ha.antisymm' (ha' ab), hb.antisymm' (hb' ab)⟩
-#align eq_and_eq_of_le_of_le_of_mul_le eq_and_eq_of_le_of_le_of_mul_le
-#align eq_and_eq_of_le_of_le_of_add_le eq_and_eq_of_le_of_le_of_add_le
-
 -- see Note [lower instance priority]
 /-- This instance asserts that if `A` has a multiplication, a linear order, and multiplication
 is 'very monotone', then `A` also has `UniqueProds`. -/
chore: tidy various files (#6158)
Diff
@@ -18,7 +18,7 @@ introduce the analogous "additive" companion, `UniqueSums` and link the two so t
 converts `UniqueProds` into `UniqueSums`.
 
 Here you can see several examples of Types that have `UniqueSums/Prods`
-(`infer_instance` uses `covariants.to_uniqueProds` and `covariants.to_uniqueSums`).
+(`infer_instance` uses `Covariants.to_uniqueProds` and `Covariants.to_uniqueSums`).
 ```lean
 import Mathlib.Data.Real.Basic
 import Mathlib.Data.PNat.Basic
chore: script to replace headers with #align_import statements (#5979)

Open in Gitpod

Co-authored-by: Eric Wieser <wieser.eric@gmail.com> Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -2,14 +2,11 @@
 Copyright (c) 2022 Damiano Testa. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Damiano Testa
-
-! This file was ported from Lean 3 source module algebra.group.unique_prods
-! leanprover-community/mathlib commit d6fad0e5bf2d6f48da9175d25c3dc5706b3834ce
-! Please do not edit these lines, except to modify the commit id
-! if you have ported upstream changes.
 -/
 import Mathlib.Data.Finset.Preimage
 
+#align_import algebra.group.unique_prods from "leanprover-community/mathlib"@"d6fad0e5bf2d6f48da9175d25c3dc5706b3834ce"
+
 /-!
 # Unique products and related notions
 
chore: cleanup whitespace (#5988)

Grepping for [^ .:{-] [^ :] and reviewing the results. Once I started I couldn't stop. :-)

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -11,7 +11,7 @@ Authors: Damiano Testa
 import Mathlib.Data.Finset.Preimage
 
 /-!
-#  Unique products and related notions
+# Unique products and related notions
 
 A group `G` has *unique products* if for any two non-empty finite subsets `A, B ⊂ G`, there is an
 element `g ∈ A * B` that can be written uniquely as a product of an element of `A` and an element
chore: clean up spacing around at and goals (#5387)

Changes are of the form

  • some_tactic at h⊢ -> some_tactic at h ⊢
  • some_tactic at h -> some_tactic at h
Diff
@@ -214,7 +214,7 @@ theorem eq_and_eq_of_le_of_le_of_mul_le {A} [Mul A] [LinearOrder A]
   haveI := Mul.to_covariantClass_right A
   have ha' : ¬a0 * b0 < a * b → ¬a0 < a := mt fun h ↦ mul_lt_mul_of_lt_of_le h hb
   have hb' : ¬a0 * b0 < a * b → ¬b0 < b := mt fun h ↦ mul_lt_mul_of_le_of_lt ha h
-  push_neg  at ha' hb'
+  push_neg at ha' hb'
   exact ⟨ha.antisymm' (ha' ab), hb.antisymm' (hb' ab)⟩
 #align eq_and_eq_of_le_of_le_of_mul_le eq_and_eq_of_le_of_le_of_mul_le
 #align eq_and_eq_of_le_of_le_of_add_le eq_and_eq_of_le_of_le_of_add_le
chore: formatting issues (#4947)

Co-authored-by: Scott Morrison <scott.morrison@anu.edu.au> Co-authored-by: Parcly Taxel <reddeloostw@gmail.com>

Diff
@@ -84,7 +84,7 @@ theorem set_subsingleton (A B : Finset G) (a0 b0 : G) (h : UniqueMul A B a0 b0)
 --  (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
 @[to_additive]
 theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
-    UniqueMul A B a0 b0 ↔ ∃! (ab : _)(_ : ab ∈ A ×ˢ B), ab.1 * ab.2 = a0 * b0 :=
+    UniqueMul A B a0 b0 ↔ ∃! (ab : _) (_ : ab ∈ A ×ˢ B), ab.1 * ab.2 = a0 * b0 :=
   ⟨fun _ ↦ ⟨(a0, b0), ⟨Finset.mem_product.mpr ⟨aA, bB⟩, rfl, by simp⟩, by simpa⟩,
     fun h ↦ h.elim₂
       (by
@@ -99,7 +99,7 @@ theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
 @[to_additive]
 theorem exists_iff_exists_existsUnique :
     (∃ a0 b0 : G, a0 ∈ A ∧ b0 ∈ B ∧ UniqueMul A B a0 b0) ↔
-      ∃ g : G, ∃! (ab : _)(_ : ab ∈ A ×ˢ B), ab.1 * ab.2 = g :=
+      ∃ g : G, ∃! (ab : _) (_ : ab ∈ A ×ˢ B), ab.1 * ab.2 = g :=
   ⟨fun ⟨a0, b0, hA, hB, h⟩ ↦ ⟨_, (iff_existsUnique hA hB).mp h⟩, fun ⟨g, h⟩ ↦ by
     have h' := h
     rcases h' with ⟨⟨a, b⟩, ⟨hab, rfl, -⟩, -⟩
refactor: use the typeclass SProd to implement overloaded notation · ×ˢ · (#4200)

Currently, the following notations are changed from · ×ˢ · because Lean 4 can't deal with ambiguous notations. | Definition | Notation | | :

Co-authored-by: Jeremy Tan Jie Rui <reddeloostw@gmail.com> Co-authored-by: Kyle Miller <kmill31415@gmail.com> Co-authored-by: Chris Hughes <chrishughes24@gmail.com>

Diff
@@ -82,10 +82,9 @@ theorem set_subsingleton (A B : Finset G) (a0 b0 : G) (h : UniqueMul A B a0 b0)
 
 -- Porting note: mathport warning: expanding binder collection
 --  (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
--- Porting note: replaced `xˢ` by `xᶠ`
 @[to_additive]
 theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
-    UniqueMul A B a0 b0 ↔ ∃! (ab : _)(_ : ab ∈ A ×ᶠ B), ab.1 * ab.2 = a0 * b0 :=
+    UniqueMul A B a0 b0 ↔ ∃! (ab : _)(_ : ab ∈ A ×ˢ B), ab.1 * ab.2 = a0 * b0 :=
   ⟨fun _ ↦ ⟨(a0, b0), ⟨Finset.mem_product.mpr ⟨aA, bB⟩, rfl, by simp⟩, by simpa⟩,
     fun h ↦ h.elim₂
       (by
@@ -97,11 +96,10 @@ theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
 
 -- Porting note: mathport warning: expanding binder collection
 --  (ab «expr ∈ » [finset.product/multiset.product/set.prod/list.product](A, B)) -/
--- Porting note: replaced `xˢ` by `xᶠ`
 @[to_additive]
 theorem exists_iff_exists_existsUnique :
     (∃ a0 b0 : G, a0 ∈ A ∧ b0 ∈ B ∧ UniqueMul A B a0 b0) ↔
-      ∃ g : G, ∃! (ab : _)(_ : ab ∈ A ×ᶠ B), ab.1 * ab.2 = g :=
+      ∃ g : G, ∃! (ab : _)(_ : ab ∈ A ×ˢ B), ab.1 * ab.2 = g :=
   ⟨fun ⟨a0, b0, hA, hB, h⟩ ↦ ⟨_, (iff_existsUnique hA hB).mp h⟩, fun ⟨g, h⟩ ↦ by
     have h' := h
     rcases h' with ⟨⟨a, b⟩, ⟨hab, rfl, -⟩, -⟩
chore: bye-bye, solo bys! (#3825)

This PR puts, with one exception, every single remaining by that lies all by itself on its own line to the previous line, thus matching the current behaviour of start-port.sh. The exception is when the by begins the second or later argument to a tuple or anonymous constructor; see https://github.com/leanprover-community/mathlib4/pull/3825#discussion_r1186702599.

Essentially this is s/\n *by$/ by/g, but with manual editing to satisfy the linter's max-100-char-line requirement. The Python style linter is also modified to catch these "isolated bys".

Diff
@@ -102,8 +102,7 @@ theorem iff_existsUnique (aA : a0 ∈ A) (bB : b0 ∈ B) :
 theorem exists_iff_exists_existsUnique :
     (∃ a0 b0 : G, a0 ∈ A ∧ b0 ∈ B ∧ UniqueMul A B a0 b0) ↔
       ∃ g : G, ∃! (ab : _)(_ : ab ∈ A ×ᶠ B), ab.1 * ab.2 = g :=
-  ⟨fun ⟨a0, b0, hA, hB, h⟩ ↦ ⟨_, (iff_existsUnique hA hB).mp h⟩, fun ⟨g, h⟩ ↦
-    by
+  ⟨fun ⟨a0, b0, hA, hB, h⟩ ↦ ⟨_, (iff_existsUnique hA hB).mp h⟩, fun ⟨g, h⟩ ↦ by
     have h' := h
     rcases h' with ⟨⟨a, b⟩, ⟨hab, rfl, -⟩, -⟩
     cases' Finset.mem_product.mp hab with ha hb
feat: improvements to congr! and convert (#2606)
  • There is now configuration for congr!, convert, and convert_to to control parts of the congruence algorithm, in particular transparency settings when applying congruence lemmas.
  • congr! now applies congruence lemmas with reducible transparency by default. This prevents it from unfolding definitions when applying congruence lemmas. It also now tries both the LHS-biased and RHS-biased simp congruence lemmas, with a configuration option to set which it should try first.
  • There is now a new HEq congruence lemma generator that gives each hypothesis access to the proofs of previous hypotheses. This means that if you have an equality ⊢ ⟨a, x⟩ = ⟨b, y⟩ of sigma types, congr! turns this into goals ⊢ a = b and ⊢ a = b → HEq x y (note that congr! will also auto-introduce a = b for you in the second goal). This congruence lemma generator applies to more cases than the simp congruence lemma generator does.
  • congr! (and hence convert) are more careful about applying lemmas that don't force definitions to unfold. There were a number of cases in mathlib where the implementation of congr was being abused to unfold definitions.
  • With set_option trace.congr! true you can see what congr! sees when it is deciding on congruence lemmas.
  • There is also a bug fix in convert_to to do using 1 when there is no using clause, to match its documentation.

Note that congr! is more capable than congr at finding a way to equate left-hand sides and right-hand sides, so you will frequently need to limit its depth with a using clause. However, there is also a new heuristic to prevent considering unlikely-to-be-provable type equalities (controlled by the typeEqs option), which can help limit the depth automatically.

There is also a predefined configuration that you can invoke with, for example, convert (config := .unfoldSameFun) h, that causes it to behave more like congr, including using default transparency when unfolding.

Diff
@@ -156,7 +156,8 @@ See `UniqueMul.mulHom_image_iff` for a version with swapped bundling. -/
 See `UniqueAdd.addHom_image_iff` for a version with swapped bundling."]
 theorem mulHom_map_iff (f : G ↪ H) (mul : ∀ x y, f (x * y) = f x * f y) :
     UniqueMul (A.map f) (B.map f) (f a0) (f b0) ↔ UniqueMul A B a0 b0 := by
-  classical convert @mulHom_image_iff G H _ _ A B a0 b0 _ ⟨f, mul⟩ f.2 <;>
+  classical
+  convert @mulHom_image_iff G H _ _ A B a0 b0 _ ⟨f, mul⟩ f.2 using 2 <;>
     · ext
       simp only [Finset.mem_map, MulHom.coe_mk, Finset.mem_image]
 #align unique_mul.mul_hom_map_iff UniqueMul.mulHom_map_iff
feat: port Algebra.Group.UniqueProds (#1764)

Dependencies 7 + 224

225 files ported (97.0%)
98438 lines ported (97.0%)
Show graph

The unported dependencies are