l3lab/ntp-mathlib huggingface dataset:
theorem inverse_mul_eq_iff_eq_mul (x y z : M₀) (h : IsUnit x) : inverse x * y = z ↔ y = x * z :=
  ⟨fun h1 => by 

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
x y z : M₀
h : IsUnit x
h1 : inverse x * y = z
⊢ y = x * z

Next tactic:
rw [← h1, mul_inverse_cancel_left _ _ h]
theorem inverse_mul_eq_iff_eq_mul (x y z : M₀) (h : IsUnit x) : inverse x * y = z ↔ y = x * z :=
  ⟨fun h1 => by rw [← h1, mul_inverse_cancel_left _ _ h],
  fun h1 => by 

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
x y z : M₀
h : IsUnit x
h1 : y = x * z
⊢ inverse x * y = z

Next tactic:
rw [h1, inverse_mul_cancel_left _ _ h]
theorem eq_mul_inverse_iff_mul_eq (x y z : M₀) (h : IsUnit z) : x = y * inverse z ↔ x * z = y :=
  ⟨fun h1 => by 

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
x y z : M₀
h : IsUnit z
h1 : x = y * inverse z
⊢ x * z = y

Next tactic:
rw [h1, inverse_mul_cancel_right _ _ h]
theorem eq_mul_inverse_iff_mul_eq (x y z : M₀) (h : IsUnit z) : x = y * inverse z ↔ x * z = y :=
  ⟨fun h1 => by rw [h1, inverse_mul_cancel_right _ _ h],
  fun h1 => by 

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
x y z : M₀
h : IsUnit z
h1 : x * z = y
⊢ x = y * inverse z

Next tactic:
rw [← h1, mul_inverse_cancel_right _ _ h]
@[simp]
theorem inverse_zero : inverse (0 : M₀) = 0 := by
  

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
⊢ inverse 0 = 0

Next tactic:
nontriviality
@[simp]
theorem inverse_zero : inverse (0 : M₀) = 0 := by
  nontriviality
  

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
✝ : Nontrivial M₀
⊢ inverse 0 = 0

Next tactic:
exact inverse_non_unit _ not_isUnit_zero
@[simp]
theorem isUnit_ring_inverse {a : M₀} : IsUnit (Ring.inverse a) ↔ IsUnit a :=
  ⟨fun h => by
    

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
a : M₀
h : IsUnit (Ring.inverse a)
⊢ IsUnit a

Next tactic:
cases subsingleton_or_nontrivial M₀
@[simp]
theorem isUnit_ring_inverse {a : M₀} : IsUnit (Ring.inverse a) ↔ IsUnit a :=
  ⟨fun h => by
    cases subsingleton_or_nontrivial M₀
    · 

Proof state:
case inl
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
a : M₀
h : IsUnit (Ring.inverse a)
h✝ : Subsingleton M₀
⊢ IsUnit a

Next tactic:
convert h
@[simp]
theorem isUnit_ring_inverse {a : M₀} : IsUnit (Ring.inverse a) ↔ IsUnit a :=
  ⟨fun h => by
    cases subsingleton_or_nontrivial M₀
    · convert h
    · 

Proof state:
case inr
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
a : M₀
h : IsUnit (Ring.inverse a)
h✝ : Nontrivial M₀
⊢ IsUnit a

Next tactic:
contrapose h
@[simp]
theorem isUnit_ring_inverse {a : M₀} : IsUnit (Ring.inverse a) ↔ IsUnit a :=
  ⟨fun h => by
    cases subsingleton_or_nontrivial M₀
    · convert h
    · contrapose h
      

Proof state:
case inr
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
a : M₀
h✝ : Nontrivial M₀
h : ¬IsUnit a
⊢ ¬IsUnit (Ring.inverse a)

Next tactic:
rw [Ring.inverse_non_unit _ h]
@[simp]
theorem isUnit_ring_inverse {a : M₀} : IsUnit (Ring.inverse a) ↔ IsUnit a :=
  ⟨fun h => by
    cases subsingleton_or_nontrivial M₀
    · convert h
    · contrapose h
      rw [Ring.inverse_non_unit _ h]
      

Proof state:
case inr
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝ : MonoidWithZero M₀
a : M₀
h✝ : Nontrivial M₀
h : ¬IsUnit a
⊢ ¬IsUnit 0

Next tactic:
exact not_isUnit_zero
@[simp]
theorem mk0_one (h := one_ne_zero) : mk0 (1 : G₀) h = 1 := by
  

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a b : G₀
h : optParam (1 ≠ 0) (_ : 1 ≠ 0)
⊢ mk0 1 h = 1

Next tactic:
ext
@[simp]
theorem mk0_one (h := one_ne_zero) : mk0 (1 : G₀) h = 1 := by
  ext
  

Proof state:
case a
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a b : G₀
h : optParam (1 ≠ 0) (_ : 1 ≠ 0)
⊢ ↑(mk0 1 h) = ↑1

Next tactic:
rfl
@[simp]
theorem mk0_inj {a b : G₀} (ha : a ≠ 0) (hb : b ≠ 0) : Units.mk0 a ha = Units.mk0 b hb ↔ a = b :=
  ⟨fun h => by 

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a✝ b✝ a b : G₀
ha : a ≠ 0
hb : b ≠ 0
h : mk0 a ha = mk0 b hb
⊢ a = b

Next tactic:
injection h
/-- An alternative version of `Units.exists0`. This one is useful if Lean cannot
figure out `p` when using `Units.exists0` from right to left. -/
theorem exists0' {p : ∀ g : G₀, g ≠ 0 → Prop} :
    (∃ (g : G₀) (hg : g ≠ 0), p g hg) ↔ ∃ g : G₀ˣ, p g g.ne_zero :=
  Iff.trans (by 

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a b : G₀
p : (g : G₀) → g ≠ 0 → Prop
⊢ (∃ g hg, p g hg) ↔ ∃ g hg, p ↑(mk0 g hg) (_ : ↑(mk0 g hg) ≠ 0)

Next tactic:
simp_rw [val_mk0]
@[simp]
theorem exists_iff_ne_zero {x : G₀} : (∃ u : G₀ˣ, ↑u = x) ↔ x ≠ 0 := by 

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a b x : G₀
⊢ (∃ u, ↑u = x) ↔ x ≠ 0

Next tactic:
simp [exists0]
theorem _root_.GroupWithZero.eq_zero_or_unit (a : G₀) : a = 0 ∨ ∃ u : G₀ˣ, a = u := by
  

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a✝ b a : G₀
⊢ a = 0 ∨ ∃ u, a = ↑u

Next tactic:
by_cases h : a = 0
theorem _root_.GroupWithZero.eq_zero_or_unit (a : G₀) : a = 0 ∨ ∃ u : G₀ˣ, a = u := by
  by_cases h : a = 0
  · 

Proof state:
case pos
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a✝ b a : G₀
h : a = 0
⊢ a = 0 ∨ ∃ u, a = ↑u

Next tactic:
left
theorem _root_.GroupWithZero.eq_zero_or_unit (a : G₀) : a = 0 ∨ ∃ u : G₀ˣ, a = u := by
  by_cases h : a = 0
  · left
    

Proof state:
case pos.h
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a✝ b a : G₀
h : a = 0
⊢ a = 0

Next tactic:
exact h
theorem _root_.GroupWithZero.eq_zero_or_unit (a : G₀) : a = 0 ∨ ∃ u : G₀ˣ, a = u := by
  by_cases h : a = 0
  · left
    exact h
  · 

Proof state:
case neg
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a✝ b a : G₀
h : ¬a = 0
⊢ a = 0 ∨ ∃ u, a = ↑u

Next tactic:
right
theorem _root_.GroupWithZero.eq_zero_or_unit (a : G₀) : a = 0 ∨ ∃ u : G₀ˣ, a = u := by
  by_cases h : a = 0
  · left
    exact h
  · right
    

Proof state:
case neg.h
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a✝ b a : G₀
h : ¬a = 0
⊢ ∃ u, a = ↑u

Next tactic:
simpa only [eq_comm] using Units.exists_iff_ne_zero.mpr h
instance (priority := 10) GroupWithZero.noZeroDivisors : NoZeroDivisors G₀ :=
  { (‹_› : GroupWithZero G₀) with
    eq_zero_or_eq_zero_of_mul_eq_zero := @fun a b h => by
      

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a✝ b✝ c : G₀
src✝ : GroupWithZero G₀ := inst✝
a b : G₀
h : a * b = 0
⊢ a = 0 ∨ b = 0

Next tactic:
contrapose! h
instance (priority := 10) GroupWithZero.noZeroDivisors : NoZeroDivisors G₀ :=
  { (‹_› : GroupWithZero G₀) with
    eq_zero_or_eq_zero_of_mul_eq_zero := @fun a b h => by
      contrapose! h
      

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a✝ b✝ c : G₀
src✝ : GroupWithZero G₀ := inst✝
a b : G₀
h : a ≠ 0 ∧ b ≠ 0
⊢ a * b ≠ 0

Next tactic:
exact (Units.mk0 a h.1 * Units.mk0 b h.2).ne_zero
@[simp]
theorem Units.mk0_mul (x y : G₀) (hxy) :
    Units.mk0 (x * y) hxy =
      Units.mk0 x (mul_ne_zero_iff.mp hxy).1 * Units.mk0 y (mul_ne_zero_iff.mp hxy).2 := by
  

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a b c x y : G₀
hxy : x * y ≠ 0
⊢ mk0 (x * y) hxy = mk0 x (_ : x ≠ 0) * mk0 y (_ : y ≠ 0)

Next tactic:
ext
@[simp]
theorem Units.mk0_mul (x y : G₀) (hxy) :
    Units.mk0 (x * y) hxy =
      Units.mk0 x (mul_ne_zero_iff.mp hxy).1 * Units.mk0 y (mul_ne_zero_iff.mp hxy).2 := by
  ext; 

Proof state:
case a
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a b c x y : G₀
hxy : x * y ≠ 0
⊢ ↑(mk0 (x * y) hxy) = ↑(mk0 x (_ : x ≠ 0) * mk0 y (_ : y ≠ 0))

Next tactic:
rfl
theorem div_ne_zero (ha : a ≠ 0) (hb : b ≠ 0) : a / b ≠ 0 := by
  

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a b c : G₀
ha : a ≠ 0
hb : b ≠ 0
⊢ a / b ≠ 0

Next tactic:
rw [div_eq_mul_inv]
theorem div_ne_zero (ha : a ≠ 0) (hb : b ≠ 0) : a / b ≠ 0 := by
  rw [div_eq_mul_inv]
  

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a b c : G₀
ha : a ≠ 0
hb : b ≠ 0
⊢ a * b⁻¹ ≠ 0

Next tactic:
exact mul_ne_zero ha (inv_ne_zero hb)
@[simp]
theorem div_eq_zero_iff : a / b = 0 ↔ a = 0 ∨ b = 0 := by 

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a b c : G₀
⊢ a / b = 0 ↔ a = 0 ∨ b = 0

Next tactic:
simp [div_eq_mul_inv]
theorem Ring.inverse_eq_inv (a : G₀) : Ring.inverse a = a⁻¹ := by
  

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a✝ b c a : G₀
⊢ inverse a = a⁻¹

Next tactic:
obtain rfl | ha := eq_or_ne a 0
theorem Ring.inverse_eq_inv (a : G₀) : Ring.inverse a = a⁻¹ := by
  obtain rfl | ha := eq_or_ne a 0
  · 

Proof state:
case inl
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a b c : G₀
⊢ inverse 0 = 0⁻¹

Next tactic:
simp
theorem Ring.inverse_eq_inv (a : G₀) : Ring.inverse a = a⁻¹ := by
  obtain rfl | ha := eq_or_ne a 0
  · simp
  · 

Proof state:
case inr
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
inst✝ : GroupWithZero G₀
a✝ b c a : G₀
ha : a ≠ 0
⊢ inverse a = a⁻¹

Next tactic:
exact Ring.inverse_unit (Units.mk0 a ha)
/-- Constructs a `GroupWithZero` structure on a `MonoidWithZero`
  consisting only of units and 0. -/
noncomputable def groupWithZeroOfIsUnitOrEqZero [hM : MonoidWithZero M]
    (h : ∀ a : M, IsUnit a ∨ a = 0) : GroupWithZero M :=
  { hM with
    inv := fun a => if h0 : a = 0 then 0 else ↑((h a).resolve_right h0).unit⁻¹,
    inv_zero := dif_pos rfl,
    mul_inv_cancel := fun a h0 => by
      

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
M : Type u_8
inst✝ : Nontrivial M
hM : MonoidWithZero M
h : ∀ (a : M), IsUnit a ∨ a = 0
a : M
h0 : a ≠ 0
⊢ a * a⁻¹ = 1

Next tactic:
change (a * if h0 : a = 0 then 0 else ↑((h a).resolve_right h0).unit⁻¹) = 1
/-- Constructs a `GroupWithZero` structure on a `MonoidWithZero`
  consisting only of units and 0. -/
noncomputable def groupWithZeroOfIsUnitOrEqZero [hM : MonoidWithZero M]
    (h : ∀ a : M, IsUnit a ∨ a = 0) : GroupWithZero M :=
  { hM with
    inv := fun a => if h0 : a = 0 then 0 else ↑((h a).resolve_right h0).unit⁻¹,
    inv_zero := dif_pos rfl,
    mul_inv_cancel := fun a h0 => by
      change (a * if h0 : a = 0 then 0 else ↑((h a).resolve_right h0).unit⁻¹) = 1
      

Proof state:
α : Type u_1
M₀ : Type u_2
G₀ : Type u_3
M₀' : Type u_4
G₀' : Type u_5
F : Type u_6
F' : Type u_7
inst✝¹ : MonoidWithZero M₀
M : Type u_8
inst✝ : Nontrivial M
hM : MonoidWithZero M
h : ∀ (a : M), IsUnit a ∨ a = 0
a : M
h0 : a ≠ 0
⊢ (a * if h0 : a = 0 then 0 else ↑(IsUnit.unit (_ : IsUnit a))⁻¹) = 1

Next tactic:
rw [dif_neg h0, Units.mul_inv_eq_iff_eq_mul, one_mul, IsUnit.unit_spec]
theorem abs_mul (a b : α) : |a * b| = |a| * |b| := by
  

Proof state:
α : Type u_1
inst✝ : LinearOrderedRing α
a✝ b✝ c a b : α
⊢ |a * b| = |a| * |b|

Next tactic:
rw [abs_eq (mul_nonneg (abs_nonneg a) (abs_nonneg b))]
theorem abs_mul (a b : α) : |a * b| = |a| * |b| := by
  rw [abs_eq (mul_nonneg (abs_nonneg a) (abs_nonneg b))]
  

Proof state:
α : Type u_1
inst✝ : LinearOrderedRing α
a✝ b✝ c a b : α
⊢ a * b = |a| * |b| ∨ a * b = -(|a| * |b|)

Next tactic:
rcases le_total a 0 with ha | ha
theorem abs_mul (a b : α) : |a * b| = |a| * |b| := by
  rw [abs_eq (mul_nonneg (abs_nonneg a) (abs_nonneg b))]
  rcases le_total a 0 with ha | ha <;> 

Proof state:
case inl
α : Type u_1
inst✝ : LinearOrderedRing α
a✝ b✝ c a b : α
ha : a ≤ 0
⊢ a * b = |a| * |b| ∨ a * b = -(|a| * |b|)

Next tactic:
rcases le_total b 0 with hb | hb
theorem abs_mul (a b : α) : |a * b| = |a| * |b| := by
  rw [abs_eq (mul_nonneg (abs_nonneg a) (abs_nonneg b))]
  rcases le_total a 0 with ha | ha <;> 

Proof state:
case inr
α : Type u_1
inst✝ : LinearOrderedRing α
a✝ b✝ c a b : α
ha : 0 ≤ a
⊢ a * b = |a| * |b| ∨ a * b = -(|a| * |b|)

Next tactic:
rcases le_total b 0 with hb | hb
theorem abs_mul (a b : α) : |a * b| = |a| * |b| := by
  rw [abs_eq (mul_nonneg (abs_nonneg a) (abs_nonneg b))]
  rcases le_total a 0 with ha | ha <;> rcases le_total b 0 with hb | hb <;>
    

Proof state:
case inl.inl
α : Type u_1
inst✝ : LinearOrderedRing α
a✝ b✝ c a b : α
ha : a ≤ 0
hb : b ≤ 0
⊢ a * b = |a| * |b| ∨ a * b = -(|a| * |b|)

Next tactic:
simp only [abs_of_nonpos, abs_of_nonneg, true_or_iff, or_true_iff, eq_self_iff_true, neg_mul,
      mul_neg, neg_neg, *]
theorem abs_mul (a b : α) : |a * b| = |a| * |b| := by
  rw [abs_eq (mul_nonneg (abs_nonneg a) (abs_nonneg b))]
  rcases le_total a 0 with ha | ha <;> rcases le_total b 0 with hb | hb <;>
    

Proof state:
case inl.inr
α : Type u_1
inst✝ : LinearOrderedRing α
a✝ b✝ c a b : α
ha : a ≤ 0
hb : 0 ≤ b
⊢ a * b = |a| * |b| ∨ a * b = -(|a| * |b|)

Next tactic:
simp only [abs_of_nonpos, abs_of_nonneg, true_or_iff, or_true_iff, eq_self_iff_true, neg_mul,
      mul_neg, neg_neg, *]
theorem abs_mul (a b : α) : |a * b| = |a| * |b| := by
  rw [abs_eq (mul_nonneg (abs_nonneg a) (abs_nonneg b))]
  rcases le_total a 0 with ha | ha <;> rcases le_total b 0 with hb | hb <;>
    

Proof state:
case inr.inl
α : Type u_1
inst✝ : LinearOrderedRing α
a✝ b✝ c a b : α
ha : 0 ≤ a
hb : b ≤ 0
⊢ a * b = |a| * |b| ∨ a * b = -(|a| * |b|)

Next tactic:
simp only [abs_of_nonpos, abs_of_nonneg, true_or_iff, or_true_iff, eq_self_iff_true, neg_mul,
      mul_neg, neg_neg, *]
theorem abs_mul (a b : α) : |a * b| = |a| * |b| := by
  rw [abs_eq (mul_nonneg (abs_nonneg a) (abs_nonneg b))]
  rcases le_total a 0 with ha | ha <;> rcases le_total b 0 with hb | hb <;>
    

Proof state:
case inr.inr
α : Type u_1
inst✝ : LinearOrderedRing α
a✝ b✝ c a b : α
ha : 0 ≤ a
hb : 0 ≤ b
⊢ a * b = |a| * |b| ∨ a * b = -(|a| * |b|)

Next tactic:
simp only [abs_of_nonpos, abs_of_nonneg, true_or_iff, or_true_iff, eq_self_iff_true, neg_mul,
      mul_neg, neg_neg, *]
@[simp]
theorem abs_mul_self (a : α) : |a * a| = a * a := by 

Proof state:
α : Type u_1
inst✝ : LinearOrderedRing α
a✝ b c a : α
⊢ |a * a| = a * a

Next tactic:
rw [abs_mul, abs_mul_abs_self]
theorem abs_eq_iff_mul_self_eq : |a| = |b| ↔ a * a = b * b := by
  

Proof state:
α : Type u_1
inst✝ : LinearOrderedRing α
a b c : α
⊢ |a| = |b| ↔ a * a = b * b

Next tactic:
rw [← abs_mul_abs_self, ← abs_mul_abs_self b]
theorem abs_eq_iff_mul_self_eq : |a| = |b| ↔ a * a = b * b := by
  rw [← abs_mul_abs_self, ← abs_mul_abs_self b]
  

Proof state:
α : Type u_1
inst✝ : LinearOrderedRing α
a b c : α
⊢ |a| = |b| ↔ |a| * |a| = |b| * |b|

Next tactic:
exact (mul_self_inj (abs_nonneg a) (abs_nonneg b)).symm
theorem abs_lt_iff_mul_self_lt : |a| < |b| ↔ a * a < b * b := by
  

Proof state:
α : Type u_1
inst✝ : LinearOrderedRing α
a b c : α
⊢ |a| < |b| ↔ a * a < b * b

Next tactic:
rw [← abs_mul_abs_self, ← abs_mul_abs_self b]
theorem abs_lt_iff_mul_self_lt : |a| < |b| ↔ a * a < b * b := by
  rw [← abs_mul_abs_self, ← abs_mul_abs_self b]
  

Proof state:
α : Type u_1
inst✝ : LinearOrderedRing α
a b c : α
⊢ |a| < |b| ↔ |a| * |a| < |b| * |b|

Next tactic:
exact mul_self_lt_mul_self_iff (abs_nonneg a) (abs_nonneg b)
theorem abs_le_iff_mul_self_le : |a| ≤ |b| ↔ a * a ≤ b * b := by
  

Proof state:
α : Type u_1
inst✝ : LinearOrderedRing α
a b c : α
⊢ |a| ≤ |b| ↔ a * a ≤ b * b

Next tactic:
rw [← abs_mul_abs_self, ← abs_mul_abs_self b]
theorem abs_le_iff_mul_self_le : |a| ≤ |b| ↔ a * a ≤ b * b := by
  rw [← abs_mul_abs_self, ← abs_mul_abs_self b]
  

Proof state:
α : Type u_1
inst✝ : LinearOrderedRing α
a b c : α
⊢ |a| ≤ |b| ↔ |a| * |a| ≤ |b| * |b|

Next tactic:
exact mul_self_le_mul_self_iff (abs_nonneg a) (abs_nonneg b)
theorem abs_le_one_iff_mul_self_le_one : |a| ≤ 1 ↔ a * a ≤ 1 := by
  

Proof state:
α : Type u_1
inst✝ : LinearOrderedRing α
a b c : α
⊢ |a| ≤ 1 ↔ a * a ≤ 1

Next tactic:
simpa only [abs_one, one_mul] using @abs_le_iff_mul_self_le α _ a 1
theorem abs_sub_sq (a b : α) : |a - b| * |a - b| = a * a + b * b - (1 + 1) * a * b := by
  

Proof state:
α : Type u_1
inst✝ : LinearOrderedCommRing α
a✝ b✝ c d a b : α
⊢ |a - b| * |a - b| = a * a + b * b - (1 + 1) * a * b

Next tactic:
rw [abs_mul_abs_self]
theorem abs_sub_sq (a b : α) : |a - b| * |a - b| = a * a + b * b - (1 + 1) * a * b := by
  rw [abs_mul_abs_self]
  

Proof state:
α : Type u_1
inst✝ : LinearOrderedCommRing α
a✝ b✝ c d a b : α
⊢ (a - b) * (a - b) = a * a + b * b - (1 + 1) * a * b

Next tactic:
simp only [mul_add, add_comm, add_left_comm, mul_comm, sub_eq_add_neg, mul_one, mul_neg,
    neg_add_rev, neg_neg, add_assoc]
@[simp]
theorem abs_dvd (a b : α) : |a| ∣ b ↔ a ∣ b := by
  

Proof state:
α : Type u_1
inst✝¹ : Ring α
inst✝ : LinearOrder α
a✝ b✝ a b : α
⊢ |a| ∣ b ↔ a ∣ b

Next tactic:
cases' abs_choice a with h h
@[simp]
theorem abs_dvd (a b : α) : |a| ∣ b ↔ a ∣ b := by
  cases' abs_choice a with h h <;> 

Proof state:
case inl
α : Type u_1
inst✝¹ : Ring α
inst✝ : LinearOrder α
a✝ b✝ a b : α
h : |a| = a
⊢ |a| ∣ b ↔ a ∣ b

Next tactic:
simp only [h, neg_dvd]
@[simp]
theorem abs_dvd (a b : α) : |a| ∣ b ↔ a ∣ b := by
  cases' abs_choice a with h h <;> 

Proof state:
case inr
α : Type u_1
inst✝¹ : Ring α
inst✝ : LinearOrder α
a✝ b✝ a b : α
h : |a| = -a
⊢ |a| ∣ b ↔ a ∣ b

Next tactic:
simp only [h, neg_dvd]
@[simp]
theorem dvd_abs (a b : α) : a ∣ |b| ↔ a ∣ b := by
  

Proof state:
α : Type u_1
inst✝¹ : Ring α
inst✝ : LinearOrder α
a✝ b✝ a b : α
⊢ a ∣ |b| ↔ a ∣ b

Next tactic:
cases' abs_choice b with h h
@[simp]
theorem dvd_abs (a b : α) : a ∣ |b| ↔ a ∣ b := by
  cases' abs_choice b with h h <;> 

Proof state:
case inl
α : Type u_1
inst✝¹ : Ring α
inst✝ : LinearOrder α
a✝ b✝ a b : α
h : |b| = b
⊢ a ∣ |b| ↔ a ∣ b

Next tactic:
simp only [h, dvd_neg]
@[simp]
theorem dvd_abs (a b : α) : a ∣ |b| ↔ a ∣ b := by
  cases' abs_choice b with h h <;> 

Proof state:
case inr
α : Type u_1
inst✝¹ : Ring α
inst✝ : LinearOrder α
a✝ b✝ a b : α
h : |b| = -b
⊢ a ∣ |b| ↔ a ∣ b

Next tactic:
simp only [h, dvd_neg]
/-- The linear map built from `TensorProduct.map` corresponds to the matrix built from
`Matrix.kronecker`. -/
theorem TensorProduct.toMatrix_map (f : M →ₗ[R] M') (g : N →ₗ[R] N') :
    toMatrix (bM.tensorProduct bN) (bM'.tensorProduct bN') (TensorProduct.map f g) =
      toMatrix bM bM' f ⊗ₖ toMatrix bN bN' g := by
  

Proof state:
R : Type u_1
M : Type u_2
N : Type u_3
P : Type u_4
M' : Type u_5
N' : Type u_6
ι : Type u_7
κ : Type u_8
τ : Type u_9
ι' : Type u_10
κ' : Type u_11
inst✝¹⁸ : DecidableEq ι
inst✝¹⁷ : DecidableEq κ
inst✝¹⁶ : DecidableEq τ
inst✝¹⁵ : Fintype ι
inst✝¹⁴ : Fintype κ
inst✝¹³ : Fintype τ
inst✝¹² : Fintype ι'
inst✝¹¹ : Fintype κ'
inst✝¹⁰ : CommRing R
inst✝⁹ : AddCommGroup M
inst✝⁸ : AddCommGroup N
inst✝⁷ : AddCommGroup P
inst✝⁶ : AddCommGroup M'
inst✝⁵ : AddCommGroup N'
inst✝⁴ : Module R M
inst✝³ : Module R N
inst✝² : Module R P
inst✝¹ : Module R M'
inst✝ : Module R N'
bM : Basis ι R M
bN : Basis κ R N
bP : Basis τ R P
bM' : Basis ι' R M'
bN' : Basis κ' R N'
f : M →ₗ[R] M'
g : N →ₗ[R] N'
⊢ (toMatrix (Basis.tensorProduct bM bN) (Basis.tensorProduct bM' bN')) (map f g) =
    kroneckerMap (fun x x_1 => x * x_1) ((toMatrix bM bM') f) ((toMatrix bN bN') g)

Next tactic:
ext ⟨i, j⟩ ⟨i', j'⟩
/-- The linear map built from `TensorProduct.map` corresponds to the matrix built from
`Matrix.kronecker`. -/
theorem TensorProduct.toMatrix_map (f : M →ₗ[R] M') (g : N →ₗ[R] N') :
    toMatrix (bM.tensorProduct bN) (bM'.tensorProduct bN') (TensorProduct.map f g) =
      toMatrix bM bM' f ⊗ₖ toMatrix bN bN' g := by
  ext ⟨i, j⟩ ⟨i', j'⟩
  

Proof state:
case a.mk.h.mk
R : Type u_1
M : Type u_2
N : Type u_3
P : Type u_4
M' : Type u_5
N' : Type u_6
ι : Type u_7
κ : Type u_8
τ : Type u_9
ι' : Type u_10
κ' : Type u_11
inst✝¹⁸ : DecidableEq ι
inst✝¹⁷ : DecidableEq κ
inst✝¹⁶ : DecidableEq τ
inst✝¹⁵ : Fintype ι
inst✝¹⁴ : Fintype κ
inst✝¹³ : Fintype τ
inst✝¹² : Fintype ι'
inst✝¹¹ : Fintype κ'
inst✝¹⁰ : CommRing R
inst✝⁹ : AddCommGroup M
inst✝⁸ : AddCommGroup N
inst✝⁷ : AddCommGroup P
inst✝⁶ : AddCommGroup M'
inst✝⁵ : AddCommGroup N'
inst✝⁴ : Module R M
inst✝³ : Module R N
inst✝² : Module R P
inst✝¹ : Module R M'
inst✝ : Module R N'
bM : Basis ι R M
bN : Basis κ R N
bP : Basis τ R P
bM' : Basis ι' R M'
bN' : Basis κ' R N'
f : M →ₗ[R] M'
g : N →ₗ[R] N'
i : ι'
j : κ'
i' : ι
j' : κ
⊢ (toMatrix (Basis.tensorProduct bM bN) (Basis.tensorProduct bM' bN')) (map f g) (i, j) (i', j') =
    kroneckerMap (fun x x_1 => x * x_1) ((toMatrix bM bM') f) ((toMatrix bN bN') g) (i, j) (i', j')

Next tactic:
simp_rw [Matrix.kroneckerMap_apply, toMatrix_apply, Basis.tensorProduct_apply,
    TensorProduct.map_tmul, Basis.tensorProduct_repr_tmul_apply]
/-- The matrix built from `Matrix.kronecker` corresponds to the linear map built from
`TensorProduct.map`. -/
theorem Matrix.toLin_kronecker (A : Matrix ι' ι R) (B : Matrix κ' κ R) :
    toLin (bM.tensorProduct bN) (bM'.tensorProduct bN') (A ⊗ₖ B) =
      TensorProduct.map (toLin bM bM' A) (toLin bN bN' B) := by
  

Proof state:
R : Type u_1
M : Type u_2
N : Type u_3
P : Type u_4
M' : Type u_5
N' : Type u_6
ι : Type u_7
κ : Type u_8
τ : Type u_9
ι' : Type u_10
κ' : Type u_11
inst✝¹⁸ : DecidableEq ι
inst✝¹⁷ : DecidableEq κ
inst✝¹⁶ : DecidableEq τ
inst✝¹⁵ : Fintype ι
inst✝¹⁴ : Fintype κ
inst✝¹³ : Fintype τ
inst✝¹² : Fintype ι'
inst✝¹¹ : Fintype κ'
inst✝¹⁰ : CommRing R
inst✝⁹ : AddCommGroup M
inst✝⁸ : AddCommGroup N
inst✝⁷ : AddCommGroup P
inst✝⁶ : AddCommGroup M'
inst✝⁵ : AddCommGroup N'
inst✝⁴ : Module R M
inst✝³ : Module R N
inst✝² : Module R P
inst✝¹ : Module R M'
inst✝ : Module R N'
bM : Basis ι R M
bN : Basis κ R N
bP : Basis τ R P
bM' : Basis ι' R M'
bN' : Basis κ' R N'
A : Matrix ι' ι R
B : Matrix κ' κ R
⊢ (toLin (Basis.tensorProduct bM bN) (Basis.tensorProduct bM' bN')) (kroneckerMap (fun x x_1 => x * x_1) A B) =
    TensorProduct.map ((toLin bM bM') A) ((toLin bN bN') B)

Next tactic:
rw [← LinearEquiv.eq_symm_apply, toLin_symm, TensorProduct.toMatrix_map, toMatrix_toLin,
    toMatrix_toLin]