/-
Copyright (c) 2021 Jordan Brown, Thomas Browning, Patrick Lutz. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jordan Brown, Thomas Browning, Patrick Lutz

! This file was ported from Lean 3 source module group_theory.commutator
! leanprover-community/mathlib commit 34ee86e6a59d911a8e4f89b68793ee7577ae79c7
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Data.Bracket
import Mathbin.GroupTheory.Subgroup.Finite
import Mathbin.Tactic.Group

/-!
# Commutators of Subgroups

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.

If `G` is a group and `H₁ H₂ : subgroup G` then the commutator `⁅H₁, H₂⁆ : subgroup G`
is the subgroup of `G` generated by the commutators `h₁ * h₂ * h₁⁻¹ * h₂⁻¹`.

## Main definitions

* `⁅g₁, g₂⁆` : the commutator of the elements `g₁` and `g₂`
    (defined by `commutator_element` elsewhere).
* `⁅H₁, H₂⁆` : the commutator of the subgroups `H₁` and `H₂`.
-/

variable {G G' F : Type _} [Group G] [Group G'] [MonoidHomClass F G G'] (f : F) {g₁ g₂ g₃ g : G}

/- warning: commutator_element_eq_one_iff_mul_comm -> commutatorElement_eq_one_iff_mul_comm is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {g₁ : G} {g₂ : G}, Iff (Eq.{succ u1} G (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂) (OfNat.ofNat.{u1} G 1 (OfNat.mk.{u1} G 1 (One.one.{u1} G (MulOneClass.toHasOne.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))))))) (Eq.{succ u1} G (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G (MulOneClass.toHasMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))) g₁ g₂) (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G (MulOneClass.toHasMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))) g₂ g₁))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {g₁ : G} {g₂ : G}, Iff (Eq.{succ u1} G (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂) (OfNat.ofNat.{u1} G 1 (One.toOfNat1.{u1} G (InvOneClass.toOne.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1))))))) (Eq.{succ u1} G (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G (MulOneClass.toMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))) g₁ g₂) (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G (MulOneClass.toMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))) g₂ g₁))
Case conversion may be inaccurate. Consider using '#align commutator_element_eq_one_iff_mul_comm commutatorElement_eq_one_iff_mul_commₓ'. -/
theorem commutatorElement_eq_one_iff_mul_comm : ⁅g₁, g₂⁆ = 1 ↔ g₁ * g₂ = g₂ * g₁ := by
  rw [commutatorElement_def, mul_inv_eq_one, mul_inv_eq_iff_eq_mul]
#align commutator_element_eq_one_iff_mul_comm commutatorElement_eq_one_iff_mul_comm

/- warning: commutator_element_eq_one_iff_commute -> commutatorElement_eq_one_iff_commute is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {g₁ : G} {g₂ : G}, Iff (Eq.{succ u1} G (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂) (OfNat.ofNat.{u1} G 1 (OfNat.mk.{u1} G 1 (One.one.{u1} G (MulOneClass.toHasOne.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))))))) (Commute.{u1} G (MulOneClass.toHasMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))) g₁ g₂)
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {g₁ : G} {g₂ : G}, Iff (Eq.{succ u1} G (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂) (OfNat.ofNat.{u1} G 1 (One.toOfNat1.{u1} G (InvOneClass.toOne.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1))))))) (Commute.{u1} G (MulOneClass.toMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))) g₁ g₂)
Case conversion may be inaccurate. Consider using '#align commutator_element_eq_one_iff_commute commutatorElement_eq_one_iff_commuteₓ'. -/
theorem commutatorElement_eq_one_iff_commute : ⁅g₁, g₂⁆ = 1 ↔ Commute g₁ g₂ :=
  commutatorElement_eq_one_iff_mul_comm
#align commutator_element_eq_one_iff_commute commutatorElement_eq_one_iff_commute

/- warning: commute.commutator_eq -> Commute.commutator_eq is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {g₁ : G} {g₂ : G}, (Commute.{u1} G (MulOneClass.toHasMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))) g₁ g₂) -> (Eq.{succ u1} G (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂) (OfNat.ofNat.{u1} G 1 (OfNat.mk.{u1} G 1 (One.one.{u1} G (MulOneClass.toHasOne.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))))))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {g₁ : G} {g₂ : G}, (Commute.{u1} G (MulOneClass.toMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))) g₁ g₂) -> (Eq.{succ u1} G (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂) (OfNat.ofNat.{u1} G 1 (One.toOfNat1.{u1} G (InvOneClass.toOne.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1)))))))
Case conversion may be inaccurate. Consider using '#align commute.commutator_eq Commute.commutator_eqₓ'. -/
theorem Commute.commutator_eq (h : Commute g₁ g₂) : ⁅g₁, g₂⁆ = 1 :=
  commutatorElement_eq_one_iff_commute.mpr h
#align commute.commutator_eq Commute.commutator_eq

variable (g₁ g₂ g₃ g)

/- warning: commutator_element_one_right -> commutatorElement_one_right is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (g : G), Eq.{succ u1} G (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g (OfNat.ofNat.{u1} G 1 (OfNat.mk.{u1} G 1 (One.one.{u1} G (MulOneClass.toHasOne.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))))))) (OfNat.ofNat.{u1} G 1 (OfNat.mk.{u1} G 1 (One.one.{u1} G (MulOneClass.toHasOne.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))))))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (g : G), Eq.{succ u1} G (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g (OfNat.ofNat.{u1} G 1 (One.toOfNat1.{u1} G (InvOneClass.toOne.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1))))))) (OfNat.ofNat.{u1} G 1 (One.toOfNat1.{u1} G (InvOneClass.toOne.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1))))))
Case conversion may be inaccurate. Consider using '#align commutator_element_one_right commutatorElement_one_rightₓ'. -/
@[simp]
theorem commutatorElement_one_right : ⁅g, (1 : G)⁆ = 1 :=
  (Commute.one_right g).commutator_eq
#align commutator_element_one_right commutatorElement_one_right

/- warning: commutator_element_one_left -> commutatorElement_one_left is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (g : G), Eq.{succ u1} G (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) (OfNat.ofNat.{u1} G 1 (OfNat.mk.{u1} G 1 (One.one.{u1} G (MulOneClass.toHasOne.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))))) g) (OfNat.ofNat.{u1} G 1 (OfNat.mk.{u1} G 1 (One.one.{u1} G (MulOneClass.toHasOne.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))))))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (g : G), Eq.{succ u1} G (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) (OfNat.ofNat.{u1} G 1 (One.toOfNat1.{u1} G (InvOneClass.toOne.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1)))))) g) (OfNat.ofNat.{u1} G 1 (One.toOfNat1.{u1} G (InvOneClass.toOne.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1))))))
Case conversion may be inaccurate. Consider using '#align commutator_element_one_left commutatorElement_one_leftₓ'. -/
@[simp]
theorem commutatorElement_one_left : ⁅(1 : G), g⁆ = 1 :=
  (Commute.one_left g).commutator_eq
#align commutator_element_one_left commutatorElement_one_left

/- warning: commutator_element_self -> commutatorElement_self is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (g : G), Eq.{succ u1} G (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g g) (OfNat.ofNat.{u1} G 1 (OfNat.mk.{u1} G 1 (One.one.{u1} G (MulOneClass.toHasOne.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))))))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (g : G), Eq.{succ u1} G (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g g) (OfNat.ofNat.{u1} G 1 (One.toOfNat1.{u1} G (InvOneClass.toOne.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1))))))
Case conversion may be inaccurate. Consider using '#align commutator_element_self commutatorElement_selfₓ'. -/
@[simp]
theorem commutatorElement_self : ⁅g, g⁆ = 1 :=
  (Commute.refl g).commutator_eq
#align commutator_element_self commutatorElement_self

/- warning: commutator_element_inv -> commutatorElement_inv is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (g₁ : G) (g₂ : G), Eq.{succ u1} G (Inv.inv.{u1} G (DivInvMonoid.toHasInv.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)) (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂)) (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₂ g₁)
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (g₁ : G) (g₂ : G), Eq.{succ u1} G (Inv.inv.{u1} G (InvOneClass.toInv.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1)))) (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂)) (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₂ g₁)
Case conversion may be inaccurate. Consider using '#align commutator_element_inv commutatorElement_invₓ'. -/
@[simp]
theorem commutatorElement_inv : ⁅g₁, g₂⁆⁻¹ = ⁅g₂, g₁⁆ := by
  simp_rw [commutatorElement_def, mul_inv_rev, inv_inv, mul_assoc]
#align commutator_element_inv commutatorElement_inv

/- warning: map_commutator_element -> map_commutatorElement is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} {G' : Type.{u2}} {F : Type.{u3}} [_inst_1 : Group.{u1} G] [_inst_2 : Group.{u2} G'] [_inst_3 : MonoidHomClass.{u3, u1, u2} F G G' (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) (Monoid.toMulOneClass.{u2} G' (DivInvMonoid.toMonoid.{u2} G' (Group.toDivInvMonoid.{u2} G' _inst_2)))] (f : F) (g₁ : G) (g₂ : G), Eq.{succ u2} G' (coeFn.{succ u3, max (succ u1) (succ u2)} F (fun (_x : F) => G -> G') (FunLike.hasCoeToFun.{succ u3, succ u1, succ u2} F G (fun (_x : G) => G') (MulHomClass.toFunLike.{u3, u1, u2} F G G' (MulOneClass.toHasMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))) (MulOneClass.toHasMul.{u2} G' (Monoid.toMulOneClass.{u2} G' (DivInvMonoid.toMonoid.{u2} G' (Group.toDivInvMonoid.{u2} G' _inst_2)))) (MonoidHomClass.toMulHomClass.{u3, u1, u2} F G G' (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) (Monoid.toMulOneClass.{u2} G' (DivInvMonoid.toMonoid.{u2} G' (Group.toDivInvMonoid.{u2} G' _inst_2))) _inst_3))) f (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂)) (Bracket.bracket.{u2, u2} G' G' (commutatorElement.{u2} G' _inst_2) (coeFn.{succ u3, max (succ u1) (succ u2)} F (fun (_x : F) => G -> G') (FunLike.hasCoeToFun.{succ u3, succ u1, succ u2} F G (fun (_x : G) => G') (MulHomClass.toFunLike.{u3, u1, u2} F G G' (MulOneClass.toHasMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))) (MulOneClass.toHasMul.{u2} G' (Monoid.toMulOneClass.{u2} G' (DivInvMonoid.toMonoid.{u2} G' (Group.toDivInvMonoid.{u2} G' _inst_2)))) (MonoidHomClass.toMulHomClass.{u3, u1, u2} F G G' (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) (Monoid.toMulOneClass.{u2} G' (DivInvMonoid.toMonoid.{u2} G' (Group.toDivInvMonoid.{u2} G' _inst_2))) _inst_3))) f g₁) (coeFn.{succ u3, max (succ u1) (succ u2)} F (fun (_x : F) => G -> G') (FunLike.hasCoeToFun.{succ u3, succ u1, succ u2} F G (fun (_x : G) => G') (MulHomClass.toFunLike.{u3, u1, u2} F G G' (MulOneClass.toHasMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))) (MulOneClass.toHasMul.{u2} G' (Monoid.toMulOneClass.{u2} G' (DivInvMonoid.toMonoid.{u2} G' (Group.toDivInvMonoid.{u2} G' _inst_2)))) (MonoidHomClass.toMulHomClass.{u3, u1, u2} F G G' (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) (Monoid.toMulOneClass.{u2} G' (DivInvMonoid.toMonoid.{u2} G' (Group.toDivInvMonoid.{u2} G' _inst_2))) _inst_3))) f g₂))
but is expected to have type
  forall {G : Type.{u2}} {G' : Type.{u3}} {F : Type.{u1}} [_inst_1 : Group.{u2} G] [_inst_2 : Group.{u3} G'] [_inst_3 : MonoidHomClass.{u1, u2, u3} F G G' (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u3} G' (DivInvMonoid.toMonoid.{u3} G' (Group.toDivInvMonoid.{u3} G' _inst_2)))] (f : F) (g₁ : G) (g₂ : G), Eq.{succ u3} ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => G') (Bracket.bracket.{u2, u2} G G (commutatorElement.{u2} G _inst_1) g₁ g₂)) (FunLike.coe.{succ u1, succ u2, succ u3} F G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => G') _x) (MulHomClass.toFunLike.{u1, u2, u3} F G G' (MulOneClass.toMul.{u2} G (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1)))) (MulOneClass.toMul.{u3} G' (Monoid.toMulOneClass.{u3} G' (DivInvMonoid.toMonoid.{u3} G' (Group.toDivInvMonoid.{u3} G' _inst_2)))) (MonoidHomClass.toMulHomClass.{u1, u2, u3} F G G' (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u3} G' (DivInvMonoid.toMonoid.{u3} G' (Group.toDivInvMonoid.{u3} G' _inst_2))) _inst_3)) f (Bracket.bracket.{u2, u2} G G (commutatorElement.{u2} G _inst_1) g₁ g₂)) (Bracket.bracket.{u3, u3} ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => G') g₁) ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => G') g₂) (commutatorElement.{u3} ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => G') g₁) _inst_2) (FunLike.coe.{succ u1, succ u2, succ u3} F G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => G') _x) (MulHomClass.toFunLike.{u1, u2, u3} F G G' (MulOneClass.toMul.{u2} G (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1)))) (MulOneClass.toMul.{u3} G' (Monoid.toMulOneClass.{u3} G' (DivInvMonoid.toMonoid.{u3} G' (Group.toDivInvMonoid.{u3} G' _inst_2)))) (MonoidHomClass.toMulHomClass.{u1, u2, u3} F G G' (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u3} G' (DivInvMonoid.toMonoid.{u3} G' (Group.toDivInvMonoid.{u3} G' _inst_2))) _inst_3)) f g₁) (FunLike.coe.{succ u1, succ u2, succ u3} F G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => G') _x) (MulHomClass.toFunLike.{u1, u2, u3} F G G' (MulOneClass.toMul.{u2} G (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1)))) (MulOneClass.toMul.{u3} G' (Monoid.toMulOneClass.{u3} G' (DivInvMonoid.toMonoid.{u3} G' (Group.toDivInvMonoid.{u3} G' _inst_2)))) (MonoidHomClass.toMulHomClass.{u1, u2, u3} F G G' (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u3} G' (DivInvMonoid.toMonoid.{u3} G' (Group.toDivInvMonoid.{u3} G' _inst_2))) _inst_3)) f g₂))
Case conversion may be inaccurate. Consider using '#align map_commutator_element map_commutatorElementₓ'. -/
theorem map_commutatorElement : (f ⁅g₁, g₂⁆ : G') = ⁅f g₁, f g₂⁆ := by
  simp_rw [commutatorElement_def, map_mul f, map_inv f]
#align map_commutator_element map_commutatorElement

/- warning: conjugate_commutator_element -> conjugate_commutatorElement is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (g₁ : G) (g₂ : G) (g₃ : G), Eq.{succ u1} G (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G (MulOneClass.toHasMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))) (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G (MulOneClass.toHasMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))) g₃ (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂)) (Inv.inv.{u1} G (DivInvMonoid.toHasInv.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)) g₃)) (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G (MulOneClass.toHasMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))) (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G (MulOneClass.toHasMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))) g₃ g₁) (Inv.inv.{u1} G (DivInvMonoid.toHasInv.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)) g₃)) (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G (MulOneClass.toHasMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))) (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G (MulOneClass.toHasMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))) g₃ g₂) (Inv.inv.{u1} G (DivInvMonoid.toHasInv.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)) g₃)))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (g₁ : G) (g₂ : G) (g₃ : G), Eq.{succ u1} G (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G (MulOneClass.toMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))) (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G (MulOneClass.toMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))) g₃ (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂)) (Inv.inv.{u1} G (InvOneClass.toInv.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1)))) g₃)) (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G (MulOneClass.toMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))) (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G (MulOneClass.toMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))) g₃ g₁) (Inv.inv.{u1} G (InvOneClass.toInv.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1)))) g₃)) (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G (MulOneClass.toMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))) (HMul.hMul.{u1, u1, u1} G G G (instHMul.{u1} G (MulOneClass.toMul.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))) g₃ g₂) (Inv.inv.{u1} G (InvOneClass.toInv.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1)))) g₃)))
Case conversion may be inaccurate. Consider using '#align conjugate_commutator_element conjugate_commutatorElementₓ'. -/
theorem conjugate_commutatorElement : g₃ * ⁅g₁, g₂⁆ * g₃⁻¹ = ⁅g₃ * g₁ * g₃⁻¹, g₃ * g₂ * g₃⁻¹⁆ :=
  map_commutatorElement (MulAut.conj g₃).toMonoidHom g₁ g₂
#align conjugate_commutator_element conjugate_commutatorElement

namespace Subgroup

#print Subgroup.commutator /-
/-- The commutator of two subgroups `H₁` and `H₂`. -/
instance commutator : Bracket (Subgroup G) (Subgroup G) :=
  ⟨fun H₁ H₂ => closure { g | ∃ g₁ ∈ H₁, ∃ g₂ ∈ H₂, ⁅g₁, g₂⁆ = g }⟩
#align subgroup.commutator Subgroup.commutator
-/

/- warning: subgroup.commutator_def -> Subgroup.commutator_def is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (H₁ : Subgroup.{u1} G _inst_1) (H₂ : Subgroup.{u1} G _inst_1), Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) (Subgroup.closure.{u1} G _inst_1 (setOf.{u1} G (fun (g : G) => Exists.{succ u1} G (fun (g₁ : G) => Exists.{0} (Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) g₁ H₁) (fun (H : Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) g₁ H₁) => Exists.{succ u1} G (fun (g₂ : G) => Exists.{0} (Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) g₂ H₂) (fun (H : Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) g₂ H₂) => Eq.{succ u1} G (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂) g)))))))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (H₁ : Subgroup.{u1} G _inst_1) (H₂ : Subgroup.{u1} G _inst_1), Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) (Subgroup.closure.{u1} G _inst_1 (setOf.{u1} G (fun (g : G) => Exists.{succ u1} G (fun (g₁ : G) => And (Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) g₁ H₁) (Exists.{succ u1} G (fun (g₂ : G) => And (Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) g₂ H₂) (Eq.{succ u1} G (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂) g)))))))
Case conversion may be inaccurate. Consider using '#align subgroup.commutator_def Subgroup.commutator_defₓ'. -/
theorem commutator_def (H₁ H₂ : Subgroup G) :
    ⁅H₁, H₂⁆ = closure { g | ∃ g₁ ∈ H₁, ∃ g₂ ∈ H₂, ⁅g₁, g₂⁆ = g } :=
  rfl
#align subgroup.commutator_def Subgroup.commutator_def

variable {g₁ g₂ g₃} {H₁ H₂ H₃ K₁ K₂ : Subgroup G}

/- warning: subgroup.commutator_mem_commutator -> Subgroup.commutator_mem_commutator is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {g₁ : G} {g₂ : G} {H₁ : Subgroup.{u1} G _inst_1} {H₂ : Subgroup.{u1} G _inst_1}, (Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) g₁ H₁) -> (Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) g₂ H₂) -> (Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {g₁ : G} {g₂ : G} {H₁ : Subgroup.{u1} G _inst_1} {H₂ : Subgroup.{u1} G _inst_1}, (Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) g₁ H₁) -> (Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) g₂ H₂) -> (Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂))
Case conversion may be inaccurate. Consider using '#align subgroup.commutator_mem_commutator Subgroup.commutator_mem_commutatorₓ'. -/
theorem commutator_mem_commutator (h₁ : g₁ ∈ H₁) (h₂ : g₂ ∈ H₂) : ⁅g₁, g₂⁆ ∈ ⁅H₁, H₂⁆ :=
  subset_closure ⟨g₁, h₁, g₂, h₂, rfl⟩
#align subgroup.commutator_mem_commutator Subgroup.commutator_mem_commutator

/- warning: subgroup.commutator_le -> Subgroup.commutator_le is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {H₁ : Subgroup.{u1} G _inst_1} {H₂ : Subgroup.{u1} G _inst_1} {H₃ : Subgroup.{u1} G _inst_1}, Iff (LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (SetLike.partialOrder.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)))) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) H₃) (forall (g₁ : G), (Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) g₁ H₁) -> (forall (g₂ : G), (Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) g₂ H₂) -> (Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂) H₃)))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {H₁ : Subgroup.{u1} G _inst_1} {H₂ : Subgroup.{u1} G _inst_1} {H₃ : Subgroup.{u1} G _inst_1}, Iff (LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (CompleteSemilatticeInf.toPartialOrder.{u1} (Subgroup.{u1} G _inst_1) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instCompleteLatticeSubgroup.{u1} G _inst_1))))) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) H₃) (forall (g₁ : G), (Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) g₁ H₁) -> (forall (g₂ : G), (Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) g₂ H₂) -> (Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) (Bracket.bracket.{u1, u1} G G (commutatorElement.{u1} G _inst_1) g₁ g₂) H₃)))
Case conversion may be inaccurate. Consider using '#align subgroup.commutator_le Subgroup.commutator_leₓ'. -/
theorem commutator_le : ⁅H₁, H₂⁆ ≤ H₃ ↔ ∀ g₁ ∈ H₁, ∀ g₂ ∈ H₂, ⁅g₁, g₂⁆ ∈ H₃ :=
  H₃.closure_le.trans
    ⟨fun h a b c d => h ⟨a, b, c, d, rfl⟩, fun h g ⟨a, b, c, d, h_eq⟩ => h_eq ▸ h a b c d⟩
#align subgroup.commutator_le Subgroup.commutator_le

/- warning: subgroup.commutator_mono -> Subgroup.commutator_mono is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {H₁ : Subgroup.{u1} G _inst_1} {H₂ : Subgroup.{u1} G _inst_1} {K₁ : Subgroup.{u1} G _inst_1} {K₂ : Subgroup.{u1} G _inst_1}, (LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (SetLike.partialOrder.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)))) H₁ K₁) -> (LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (SetLike.partialOrder.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)))) H₂ K₂) -> (LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (SetLike.partialOrder.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)))) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) K₁ K₂))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {H₁ : Subgroup.{u1} G _inst_1} {H₂ : Subgroup.{u1} G _inst_1} {K₁ : Subgroup.{u1} G _inst_1} {K₂ : Subgroup.{u1} G _inst_1}, (LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (CompleteSemilatticeInf.toPartialOrder.{u1} (Subgroup.{u1} G _inst_1) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instCompleteLatticeSubgroup.{u1} G _inst_1))))) H₁ K₁) -> (LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (CompleteSemilatticeInf.toPartialOrder.{u1} (Subgroup.{u1} G _inst_1) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instCompleteLatticeSubgroup.{u1} G _inst_1))))) H₂ K₂) -> (LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (CompleteSemilatticeInf.toPartialOrder.{u1} (Subgroup.{u1} G _inst_1) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instCompleteLatticeSubgroup.{u1} G _inst_1))))) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) K₁ K₂))
Case conversion may be inaccurate. Consider using '#align subgroup.commutator_mono Subgroup.commutator_monoₓ'. -/
theorem commutator_mono (h₁ : H₁ ≤ K₁) (h₂ : H₂ ≤ K₂) : ⁅H₁, H₂⁆ ≤ ⁅K₁, K₂⁆ :=
  commutator_le.mpr fun g₁ hg₁ g₂ hg₂ => commutator_mem_commutator (h₁ hg₁) (h₂ hg₂)
#align subgroup.commutator_mono Subgroup.commutator_mono

/- warning: subgroup.commutator_eq_bot_iff_le_centralizer -> Subgroup.commutator_eq_bot_iff_le_centralizer is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {H₁ : Subgroup.{u1} G _inst_1} {H₂ : Subgroup.{u1} G _inst_1}, Iff (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.hasBot.{u1} G _inst_1))) (LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (SetLike.partialOrder.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)))) H₁ (Subgroup.centralizer.{u1} G _inst_1 H₂))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {H₁ : Subgroup.{u1} G _inst_1} {H₂ : Subgroup.{u1} G _inst_1}, Iff (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instBotSubgroup.{u1} G _inst_1))) (LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (CompleteSemilatticeInf.toPartialOrder.{u1} (Subgroup.{u1} G _inst_1) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instCompleteLatticeSubgroup.{u1} G _inst_1))))) H₁ (Subgroup.centralizer.{u1} G _inst_1 H₂))
Case conversion may be inaccurate. Consider using '#align subgroup.commutator_eq_bot_iff_le_centralizer Subgroup.commutator_eq_bot_iff_le_centralizerₓ'. -/
theorem commutator_eq_bot_iff_le_centralizer : ⁅H₁, H₂⁆ = ⊥ ↔ H₁ ≤ H₂.centralizer :=
  by
  rw [eq_bot_iff, commutator_le]
  refine'
    forall_congr' fun p => forall_congr' fun hp => forall_congr' fun q => forall_congr' fun hq => _
  rw [mem_bot, commutatorElement_eq_one_iff_mul_comm, eq_comm]
#align subgroup.commutator_eq_bot_iff_le_centralizer Subgroup.commutator_eq_bot_iff_le_centralizer

/- warning: subgroup.commutator_commutator_eq_bot_of_rotate -> Subgroup.commutator_commutator_eq_bot_of_rotate is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {H₁ : Subgroup.{u1} G _inst_1} {H₂ : Subgroup.{u1} G _inst_1} {H₃ : Subgroup.{u1} G _inst_1}, (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₂ H₃) H₁) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.hasBot.{u1} G _inst_1))) -> (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₃ H₁) H₂) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.hasBot.{u1} G _inst_1))) -> (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) H₃) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.hasBot.{u1} G _inst_1)))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {H₁ : Subgroup.{u1} G _inst_1} {H₂ : Subgroup.{u1} G _inst_1} {H₃ : Subgroup.{u1} G _inst_1}, (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₂ H₃) H₁) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instBotSubgroup.{u1} G _inst_1))) -> (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₃ H₁) H₂) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instBotSubgroup.{u1} G _inst_1))) -> (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) H₃) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instBotSubgroup.{u1} G _inst_1)))
Case conversion may be inaccurate. Consider using '#align subgroup.commutator_commutator_eq_bot_of_rotate Subgroup.commutator_commutator_eq_bot_of_rotateₓ'. -/
/-- **The Three Subgroups Lemma** (via the Hall-Witt identity) -/
theorem commutator_commutator_eq_bot_of_rotate (h1 : ⁅⁅H₂, H₃⁆, H₁⁆ = ⊥) (h2 : ⁅⁅H₃, H₁⁆, H₂⁆ = ⊥) :
    ⁅⁅H₁, H₂⁆, H₃⁆ = ⊥ :=
  by
  simp_rw [commutator_eq_bot_iff_le_centralizer, commutator_le,
    mem_centralizer_iff_commutator_eq_one, ← commutatorElement_def] at h1 h2⊢
  intro x hx y hy z hz
  trans x * z * ⁅y, ⁅z⁻¹, x⁻¹⁆⁆⁻¹ * z⁻¹ * y * ⁅x⁻¹, ⁅y⁻¹, z⁆⁆⁻¹ * y⁻¹ * x⁻¹
  · group
  · rw [h1 _ (H₂.inv_mem hy) _ hz _ (H₁.inv_mem hx), h2 _ (H₃.inv_mem hz) _ (H₁.inv_mem hx) _ hy]
    group
#align subgroup.commutator_commutator_eq_bot_of_rotate Subgroup.commutator_commutator_eq_bot_of_rotate

variable (H₁ H₂)

/- warning: subgroup.commutator_comm_le -> Subgroup.commutator_comm_le is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (H₁ : Subgroup.{u1} G _inst_1) (H₂ : Subgroup.{u1} G _inst_1), LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (SetLike.partialOrder.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)))) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₂ H₁)
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (H₁ : Subgroup.{u1} G _inst_1) (H₂ : Subgroup.{u1} G _inst_1), LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (CompleteSemilatticeInf.toPartialOrder.{u1} (Subgroup.{u1} G _inst_1) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instCompleteLatticeSubgroup.{u1} G _inst_1))))) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₂ H₁)
Case conversion may be inaccurate. Consider using '#align subgroup.commutator_comm_le Subgroup.commutator_comm_leₓ'. -/
theorem commutator_comm_le : ⁅H₁, H₂⁆ ≤ ⁅H₂, H₁⁆ :=
  commutator_le.mpr fun g₁ h₁ g₂ h₂ =>
    commutatorElement_inv g₂ g₁ ▸ ⁅H₂, H₁⁆.inv_mem_iff.mpr (commutator_mem_commutator h₂ h₁)
#align subgroup.commutator_comm_le Subgroup.commutator_comm_le

#print Subgroup.commutator_comm /-
theorem commutator_comm : ⁅H₁, H₂⁆ = ⁅H₂, H₁⁆ :=
  le_antisymm (commutator_comm_le H₁ H₂) (commutator_comm_le H₂ H₁)
#align subgroup.commutator_comm Subgroup.commutator_comm
-/

section Normal

#print Subgroup.commutator_normal /-
instance commutator_normal [h₁ : H₁.Normal] [h₂ : H₂.Normal] : Normal ⁅H₁, H₂⁆ :=
  by
  let base : Set G := { x | ∃ g₁ ∈ H₁, ∃ g₂ ∈ H₂, ⁅g₁, g₂⁆ = x }
  change (closure base).Normal
  suffices h_base : base = Group.conjugatesOfSet base
  · rw [h_base]
    exact Subgroup.normalClosure_normal
  refine' Set.Subset.antisymm Group.subset_conjugatesOfSet fun a h => _
  simp_rw [Group.mem_conjugatesOfSet_iff, isConj_iff] at h
  rcases h with ⟨b, ⟨c, hc, e, he, rfl⟩, d, rfl⟩
  exact ⟨_, h₁.conj_mem c hc d, _, h₂.conj_mem e he d, (conjugate_commutatorElement c e d).symm⟩
#align subgroup.commutator_normal Subgroup.commutator_normal
-/

#print Subgroup.commutator_def' /-
theorem commutator_def' [H₁.Normal] [H₂.Normal] :
    ⁅H₁, H₂⁆ = normalClosure { g | ∃ g₁ ∈ H₁, ∃ g₂ ∈ H₂, ⁅g₁, g₂⁆ = g } :=
  le_antisymm closure_le_normalClosure (normalClosure_le_normal subset_closure)
#align subgroup.commutator_def' Subgroup.commutator_def'
-/

/- warning: subgroup.commutator_le_right -> Subgroup.commutator_le_right is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (H₁ : Subgroup.{u1} G _inst_1) (H₂ : Subgroup.{u1} G _inst_1) [h : Subgroup.Normal.{u1} G _inst_1 H₂], LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (SetLike.partialOrder.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)))) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) H₂
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (H₁ : Subgroup.{u1} G _inst_1) (H₂ : Subgroup.{u1} G _inst_1) [h : Subgroup.Normal.{u1} G _inst_1 H₂], LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (CompleteSemilatticeInf.toPartialOrder.{u1} (Subgroup.{u1} G _inst_1) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instCompleteLatticeSubgroup.{u1} G _inst_1))))) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) H₂
Case conversion may be inaccurate. Consider using '#align subgroup.commutator_le_right Subgroup.commutator_le_rightₓ'. -/
theorem commutator_le_right [h : H₂.Normal] : ⁅H₁, H₂⁆ ≤ H₂ :=
  commutator_le.mpr fun g₁ h₁ g₂ h₂ => H₂.mul_mem (h.conj_mem g₂ h₂ g₁) (H₂.inv_mem h₂)
#align subgroup.commutator_le_right Subgroup.commutator_le_right

/- warning: subgroup.commutator_le_left -> Subgroup.commutator_le_left is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (H₁ : Subgroup.{u1} G _inst_1) (H₂ : Subgroup.{u1} G _inst_1) [_inst_4 : Subgroup.Normal.{u1} G _inst_1 H₁], LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (SetLike.partialOrder.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)))) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) H₁
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (H₁ : Subgroup.{u1} G _inst_1) (H₂ : Subgroup.{u1} G _inst_1) [_inst_4 : Subgroup.Normal.{u1} G _inst_1 H₁], LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (CompleteSemilatticeInf.toPartialOrder.{u1} (Subgroup.{u1} G _inst_1) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instCompleteLatticeSubgroup.{u1} G _inst_1))))) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) H₁
Case conversion may be inaccurate. Consider using '#align subgroup.commutator_le_left Subgroup.commutator_le_leftₓ'. -/
theorem commutator_le_left [H₁.Normal] : ⁅H₁, H₂⁆ ≤ H₁ :=
  commutator_comm H₂ H₁ ▸ commutator_le_right H₂ H₁
#align subgroup.commutator_le_left Subgroup.commutator_le_left

/- warning: subgroup.commutator_bot_left -> Subgroup.commutator_bot_left is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (H₁ : Subgroup.{u1} G _inst_1), Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.hasBot.{u1} G _inst_1)) H₁) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.hasBot.{u1} G _inst_1))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (H₁ : Subgroup.{u1} G _inst_1), Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instBotSubgroup.{u1} G _inst_1)) H₁) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instBotSubgroup.{u1} G _inst_1))
Case conversion may be inaccurate. Consider using '#align subgroup.commutator_bot_left Subgroup.commutator_bot_leftₓ'. -/
@[simp]
theorem commutator_bot_left : ⁅(⊥ : Subgroup G), H₁⁆ = ⊥ :=
  le_bot_iff.mp (commutator_le_left ⊥ H₁)
#align subgroup.commutator_bot_left Subgroup.commutator_bot_left

/- warning: subgroup.commutator_bot_right -> Subgroup.commutator_bot_right is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (H₁ : Subgroup.{u1} G _inst_1), Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.hasBot.{u1} G _inst_1))) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.hasBot.{u1} G _inst_1))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (H₁ : Subgroup.{u1} G _inst_1), Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instBotSubgroup.{u1} G _inst_1))) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instBotSubgroup.{u1} G _inst_1))
Case conversion may be inaccurate. Consider using '#align subgroup.commutator_bot_right Subgroup.commutator_bot_rightₓ'. -/
@[simp]
theorem commutator_bot_right : ⁅H₁, ⊥⁆ = (⊥ : Subgroup G) :=
  le_bot_iff.mp (commutator_le_right H₁ ⊥)
#align subgroup.commutator_bot_right Subgroup.commutator_bot_right

/- warning: subgroup.commutator_le_inf -> Subgroup.commutator_le_inf is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (H₁ : Subgroup.{u1} G _inst_1) (H₂ : Subgroup.{u1} G _inst_1) [_inst_4 : Subgroup.Normal.{u1} G _inst_1 H₁] [_inst_5 : Subgroup.Normal.{u1} G _inst_1 H₂], LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (SetLike.partialOrder.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)))) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) (Inf.inf.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.hasInf.{u1} G _inst_1) H₁ H₂)
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (H₁ : Subgroup.{u1} G _inst_1) (H₂ : Subgroup.{u1} G _inst_1) [_inst_4 : Subgroup.Normal.{u1} G _inst_1 H₁] [_inst_5 : Subgroup.Normal.{u1} G _inst_1 H₂], LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (CompleteSemilatticeInf.toPartialOrder.{u1} (Subgroup.{u1} G _inst_1) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instCompleteLatticeSubgroup.{u1} G _inst_1))))) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) (Inf.inf.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instInfSubgroup.{u1} G _inst_1) H₁ H₂)
Case conversion may be inaccurate. Consider using '#align subgroup.commutator_le_inf Subgroup.commutator_le_infₓ'. -/
theorem commutator_le_inf [Normal H₁] [Normal H₂] : ⁅H₁, H₂⁆ ≤ H₁ ⊓ H₂ :=
  le_inf (commutator_le_left H₁ H₂) (commutator_le_right H₁ H₂)
#align subgroup.commutator_le_inf Subgroup.commutator_le_inf

end Normal

/- warning: subgroup.map_commutator -> Subgroup.map_commutator is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} {G' : Type.{u2}} [_inst_1 : Group.{u1} G] [_inst_2 : Group.{u2} G'] (H₁ : Subgroup.{u1} G _inst_1) (H₂ : Subgroup.{u1} G _inst_1) (f : MonoidHom.{u1, u2} G G' (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) (Monoid.toMulOneClass.{u2} G' (DivInvMonoid.toMonoid.{u2} G' (Group.toDivInvMonoid.{u2} G' _inst_2)))), Eq.{succ u2} (Subgroup.{u2} G' _inst_2) (Subgroup.map.{u1, u2} G _inst_1 G' _inst_2 f (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂)) (Bracket.bracket.{u2, u2} (Subgroup.{u2} G' _inst_2) (Subgroup.{u2} G' _inst_2) (Subgroup.commutator.{u2} G' _inst_2) (Subgroup.map.{u1, u2} G _inst_1 G' _inst_2 f H₁) (Subgroup.map.{u1, u2} G _inst_1 G' _inst_2 f H₂))
but is expected to have type
  forall {G : Type.{u2}} {G' : Type.{u1}} [_inst_1 : Group.{u2} G] [_inst_2 : Group.{u1} G'] (H₁ : Subgroup.{u2} G _inst_1) (H₂ : Subgroup.{u2} G _inst_1) (f : MonoidHom.{u2, u1} G G' (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u1} G' (DivInvMonoid.toMonoid.{u1} G' (Group.toDivInvMonoid.{u1} G' _inst_2)))), Eq.{succ u1} (Subgroup.{u1} G' _inst_2) (Subgroup.map.{u2, u1} G _inst_1 G' _inst_2 f (Bracket.bracket.{u2, u2} (Subgroup.{u2} G _inst_1) (Subgroup.{u2} G _inst_1) (Subgroup.commutator.{u2} G _inst_1) H₁ H₂)) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G' _inst_2) (Subgroup.{u1} G' _inst_2) (Subgroup.commutator.{u1} G' _inst_2) (Subgroup.map.{u2, u1} G _inst_1 G' _inst_2 f H₁) (Subgroup.map.{u2, u1} G _inst_1 G' _inst_2 f H₂))
Case conversion may be inaccurate. Consider using '#align subgroup.map_commutator Subgroup.map_commutatorₓ'. -/
theorem map_commutator (f : G →* G') : map f ⁅H₁, H₂⁆ = ⁅map f H₁, map f H₂⁆ :=
  by
  simp_rw [le_antisymm_iff, map_le_iff_le_comap, commutator_le, mem_comap, map_commutatorElement]
  constructor
  · intro p hp q hq
    exact commutator_mem_commutator (mem_map_of_mem _ hp) (mem_map_of_mem _ hq)
  · rintro _ ⟨p, hp, rfl⟩ _ ⟨q, hq, rfl⟩
    rw [← map_commutatorElement]
    exact mem_map_of_mem _ (commutator_mem_commutator hp hq)
#align subgroup.map_commutator Subgroup.map_commutator

variable {H₁ H₂}

/- warning: subgroup.commutator_le_map_commutator -> Subgroup.commutator_le_map_commutator is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} {G' : Type.{u2}} [_inst_1 : Group.{u1} G] [_inst_2 : Group.{u2} G'] {H₁ : Subgroup.{u1} G _inst_1} {H₂ : Subgroup.{u1} G _inst_1} {f : MonoidHom.{u1, u2} G G' (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) (Monoid.toMulOneClass.{u2} G' (DivInvMonoid.toMonoid.{u2} G' (Group.toDivInvMonoid.{u2} G' _inst_2)))} {K₁ : Subgroup.{u2} G' _inst_2} {K₂ : Subgroup.{u2} G' _inst_2}, (LE.le.{u2} (Subgroup.{u2} G' _inst_2) (Preorder.toLE.{u2} (Subgroup.{u2} G' _inst_2) (PartialOrder.toPreorder.{u2} (Subgroup.{u2} G' _inst_2) (SetLike.partialOrder.{u2, u2} (Subgroup.{u2} G' _inst_2) G' (Subgroup.setLike.{u2} G' _inst_2)))) K₁ (Subgroup.map.{u1, u2} G _inst_1 G' _inst_2 f H₁)) -> (LE.le.{u2} (Subgroup.{u2} G' _inst_2) (Preorder.toLE.{u2} (Subgroup.{u2} G' _inst_2) (PartialOrder.toPreorder.{u2} (Subgroup.{u2} G' _inst_2) (SetLike.partialOrder.{u2, u2} (Subgroup.{u2} G' _inst_2) G' (Subgroup.setLike.{u2} G' _inst_2)))) K₂ (Subgroup.map.{u1, u2} G _inst_1 G' _inst_2 f H₂)) -> (LE.le.{u2} (Subgroup.{u2} G' _inst_2) (Preorder.toLE.{u2} (Subgroup.{u2} G' _inst_2) (PartialOrder.toPreorder.{u2} (Subgroup.{u2} G' _inst_2) (SetLike.partialOrder.{u2, u2} (Subgroup.{u2} G' _inst_2) G' (Subgroup.setLike.{u2} G' _inst_2)))) (Bracket.bracket.{u2, u2} (Subgroup.{u2} G' _inst_2) (Subgroup.{u2} G' _inst_2) (Subgroup.commutator.{u2} G' _inst_2) K₁ K₂) (Subgroup.map.{u1, u2} G _inst_1 G' _inst_2 f (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂)))
but is expected to have type
  forall {G : Type.{u2}} {G' : Type.{u1}} [_inst_1 : Group.{u2} G] [_inst_2 : Group.{u1} G'] {H₁ : Subgroup.{u2} G _inst_1} {H₂ : Subgroup.{u2} G _inst_1} {f : MonoidHom.{u2, u1} G G' (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u1} G' (DivInvMonoid.toMonoid.{u1} G' (Group.toDivInvMonoid.{u1} G' _inst_2)))} {K₁ : Subgroup.{u1} G' _inst_2} {K₂ : Subgroup.{u1} G' _inst_2}, (LE.le.{u1} (Subgroup.{u1} G' _inst_2) (Preorder.toLE.{u1} (Subgroup.{u1} G' _inst_2) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G' _inst_2) (CompleteSemilatticeInf.toPartialOrder.{u1} (Subgroup.{u1} G' _inst_2) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Subgroup.{u1} G' _inst_2) (Subgroup.instCompleteLatticeSubgroup.{u1} G' _inst_2))))) K₁ (Subgroup.map.{u2, u1} G _inst_1 G' _inst_2 f H₁)) -> (LE.le.{u1} (Subgroup.{u1} G' _inst_2) (Preorder.toLE.{u1} (Subgroup.{u1} G' _inst_2) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G' _inst_2) (CompleteSemilatticeInf.toPartialOrder.{u1} (Subgroup.{u1} G' _inst_2) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Subgroup.{u1} G' _inst_2) (Subgroup.instCompleteLatticeSubgroup.{u1} G' _inst_2))))) K₂ (Subgroup.map.{u2, u1} G _inst_1 G' _inst_2 f H₂)) -> (LE.le.{u1} (Subgroup.{u1} G' _inst_2) (Preorder.toLE.{u1} (Subgroup.{u1} G' _inst_2) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G' _inst_2) (CompleteSemilatticeInf.toPartialOrder.{u1} (Subgroup.{u1} G' _inst_2) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Subgroup.{u1} G' _inst_2) (Subgroup.instCompleteLatticeSubgroup.{u1} G' _inst_2))))) (Bracket.bracket.{u1, u1} (Subgroup.{u1} G' _inst_2) (Subgroup.{u1} G' _inst_2) (Subgroup.commutator.{u1} G' _inst_2) K₁ K₂) (Subgroup.map.{u2, u1} G _inst_1 G' _inst_2 f (Bracket.bracket.{u2, u2} (Subgroup.{u2} G _inst_1) (Subgroup.{u2} G _inst_1) (Subgroup.commutator.{u2} G _inst_1) H₁ H₂)))
Case conversion may be inaccurate. Consider using '#align subgroup.commutator_le_map_commutator Subgroup.commutator_le_map_commutatorₓ'. -/
theorem commutator_le_map_commutator {f : G →* G'} {K₁ K₂ : Subgroup G'} (h₁ : K₁ ≤ H₁.map f)
    (h₂ : K₂ ≤ H₂.map f) : ⁅K₁, K₂⁆ ≤ ⁅H₁, H₂⁆.map f :=
  (commutator_mono h₁ h₂).trans (ge_of_eq (map_commutator H₁ H₂ f))
#align subgroup.commutator_le_map_commutator Subgroup.commutator_le_map_commutator

variable (H₁ H₂)

#print Subgroup.commutator_characteristic /-
instance commutator_characteristic [h₁ : Characteristic H₁] [h₂ : Characteristic H₂] :
    Characteristic ⁅H₁, H₂⁆ :=
  characteristic_iff_le_map.mpr fun ϕ =>
    commutator_le_map_commutator (characteristic_iff_le_map.mp h₁ ϕ)
      (characteristic_iff_le_map.mp h₂ ϕ)
#align subgroup.commutator_characteristic Subgroup.commutator_characteristic
-/

/- warning: subgroup.commutator_prod_prod -> Subgroup.commutator_prod_prod is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} {G' : Type.{u2}} [_inst_1 : Group.{u1} G] [_inst_2 : Group.{u2} G'] (H₁ : Subgroup.{u1} G _inst_1) (H₂ : Subgroup.{u1} G _inst_1) (K₁ : Subgroup.{u2} G' _inst_2) (K₂ : Subgroup.{u2} G' _inst_2), Eq.{succ (max u1 u2)} (Subgroup.{max u1 u2} (Prod.{u1, u2} G G') (Prod.group.{u1, u2} G G' _inst_1 _inst_2)) (Bracket.bracket.{max u1 u2, max u1 u2} (Subgroup.{max u1 u2} (Prod.{u1, u2} G G') (Prod.group.{u1, u2} G G' _inst_1 _inst_2)) (Subgroup.{max u1 u2} (Prod.{u1, u2} G G') (Prod.group.{u1, u2} G G' _inst_1 _inst_2)) (Subgroup.commutator.{max u1 u2} (Prod.{u1, u2} G G') (Prod.group.{u1, u2} G G' _inst_1 _inst_2)) (Subgroup.prod.{u1, u2} G _inst_1 G' _inst_2 H₁ K₁) (Subgroup.prod.{u1, u2} G _inst_1 G' _inst_2 H₂ K₂)) (Subgroup.prod.{u1, u2} G _inst_1 G' _inst_2 (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) (Bracket.bracket.{u2, u2} (Subgroup.{u2} G' _inst_2) (Subgroup.{u2} G' _inst_2) (Subgroup.commutator.{u2} G' _inst_2) K₁ K₂))
but is expected to have type
  forall {G : Type.{u1}} {G' : Type.{u2}} [_inst_1 : Group.{u1} G] [_inst_2 : Group.{u2} G'] (H₁ : Subgroup.{u1} G _inst_1) (H₂ : Subgroup.{u1} G _inst_1) (K₁ : Subgroup.{u2} G' _inst_2) (K₂ : Subgroup.{u2} G' _inst_2), Eq.{max (succ u1) (succ u2)} (Subgroup.{max u2 u1} (Prod.{u1, u2} G G') (Prod.instGroupProd.{u1, u2} G G' _inst_1 _inst_2)) (Bracket.bracket.{max u1 u2, max u1 u2} (Subgroup.{max u2 u1} (Prod.{u1, u2} G G') (Prod.instGroupProd.{u1, u2} G G' _inst_1 _inst_2)) (Subgroup.{max u2 u1} (Prod.{u1, u2} G G') (Prod.instGroupProd.{u1, u2} G G' _inst_1 _inst_2)) (Subgroup.commutator.{max u1 u2} (Prod.{u1, u2} G G') (Prod.instGroupProd.{u1, u2} G G' _inst_1 _inst_2)) (Subgroup.prod.{u1, u2} G _inst_1 G' _inst_2 H₁ K₁) (Subgroup.prod.{u1, u2} G _inst_1 G' _inst_2 H₂ K₂)) (Subgroup.prod.{u1, u2} G _inst_1 G' _inst_2 (Bracket.bracket.{u1, u1} (Subgroup.{u1} G _inst_1) (Subgroup.{u1} G _inst_1) (Subgroup.commutator.{u1} G _inst_1) H₁ H₂) (Bracket.bracket.{u2, u2} (Subgroup.{u2} G' _inst_2) (Subgroup.{u2} G' _inst_2) (Subgroup.commutator.{u2} G' _inst_2) K₁ K₂))
Case conversion may be inaccurate. Consider using '#align subgroup.commutator_prod_prod Subgroup.commutator_prod_prodₓ'. -/
theorem commutator_prod_prod (K₁ K₂ : Subgroup G') :
    ⁅H₁.Prod K₁, H₂.Prod K₂⁆ = ⁅H₁, H₂⁆.Prod ⁅K₁, K₂⁆ :=
  by
  apply le_antisymm
  · rw [commutator_le]
    rintro ⟨p₁, p₂⟩ ⟨hp₁, hp₂⟩ ⟨q₁, q₂⟩ ⟨hq₁, hq₂⟩
    exact ⟨commutator_mem_commutator hp₁ hq₁, commutator_mem_commutator hp₂ hq₂⟩
  · rw [prod_le_iff]
    constructor <;>
      · rw [map_commutator]
        apply commutator_mono <;>
          simp [le_prod_iff, map_map, MonoidHom.fst_comp_inl, MonoidHom.snd_comp_inl,
            MonoidHom.fst_comp_inr, MonoidHom.snd_comp_inr]
#align subgroup.commutator_prod_prod Subgroup.commutator_prod_prod

/- warning: subgroup.commutator_pi_pi_le -> Subgroup.commutator_pi_pi_le is a dubious translation:
lean 3 declaration is
  forall {η : Type.{u1}} {Gs : η -> Type.{u2}} [_inst_4 : forall (i : η), Group.{u2} (Gs i)] (H : forall (i : η), Subgroup.{u2} (Gs i) (_inst_4 i)) (K : forall (i : η), Subgroup.{u2} (Gs i) (_inst_4 i)), LE.le.{max u1 u2} (Subgroup.{max u1 u2} (forall (i : η), Gs i) (Pi.group.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i))) (Preorder.toLE.{max u1 u2} (Subgroup.{max u1 u2} (forall (i : η), Gs i) (Pi.group.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i))) (PartialOrder.toPreorder.{max u1 u2} (Subgroup.{max u1 u2} (forall (i : η), Gs i) (Pi.group.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i))) (SetLike.partialOrder.{max u1 u2, max u1 u2} (Subgroup.{max u1 u2} (forall (i : η), Gs i) (Pi.group.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i))) (forall (i : η), Gs i) (Subgroup.setLike.{max u1 u2} (forall (i : η), Gs i) (Pi.group.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i)))))) (Bracket.bracket.{max u1 u2, max u1 u2} (Subgroup.{max u1 u2} (forall (i : η), Gs i) (Pi.group.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i))) (Subgroup.{max u1 u2} (forall (i : η), Gs i) (Pi.group.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i))) (Subgroup.commutator.{max u1 u2} (forall (i : η), Gs i) (Pi.group.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i))) (Subgroup.pi.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i) (Set.univ.{u1} η) H) (Subgroup.pi.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i) (Set.univ.{u1} η) K)) (Subgroup.pi.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i) (Set.univ.{u1} η) (fun (i : η) => Bracket.bracket.{u2, u2} (Subgroup.{u2} (Gs i) (_inst_4 i)) (Subgroup.{u2} (Gs i) (_inst_4 i)) (Subgroup.commutator.{u2} (Gs i) (_inst_4 i)) (H i) (K i)))
but is expected to have type
  forall {η : Type.{u2}} {Gs : η -> Type.{u1}} [_inst_4 : forall (i : η), Group.{u1} (Gs i)] (H : forall (i : η), Subgroup.{u1} (Gs i) (_inst_4 i)) (K : forall (i : η), Subgroup.{u1} (Gs i) (_inst_4 i)), LE.le.{max u2 u1} (Subgroup.{max u2 u1} (forall (i : η), Gs i) (Pi.group.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i))) (Preorder.toLE.{max u2 u1} (Subgroup.{max u2 u1} (forall (i : η), Gs i) (Pi.group.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i))) (PartialOrder.toPreorder.{max u2 u1} (Subgroup.{max u2 u1} (forall (i : η), Gs i) (Pi.group.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i))) (CompleteSemilatticeInf.toPartialOrder.{max u2 u1} (Subgroup.{max u2 u1} (forall (i : η), Gs i) (Pi.group.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i))) (CompleteLattice.toCompleteSemilatticeInf.{max u2 u1} (Subgroup.{max u2 u1} (forall (i : η), Gs i) (Pi.group.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i))) (Subgroup.instCompleteLatticeSubgroup.{max u2 u1} (forall (i : η), Gs i) (Pi.group.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i))))))) (Bracket.bracket.{max u1 u2, max u1 u2} (Subgroup.{max u2 u1} (forall (i : η), Gs i) (Pi.group.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i))) (Subgroup.{max u2 u1} (forall (i : η), Gs i) (Pi.group.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i))) (Subgroup.commutator.{max u2 u1} (forall (i : η), Gs i) (Pi.group.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i))) (Subgroup.pi.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i) (Set.univ.{u2} η) H) (Subgroup.pi.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i) (Set.univ.{u2} η) K)) (Subgroup.pi.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_4 i) (Set.univ.{u2} η) (fun (i : η) => Bracket.bracket.{u1, u1} (Subgroup.{u1} (Gs i) (_inst_4 i)) (Subgroup.{u1} (Gs i) (_inst_4 i)) (Subgroup.commutator.{u1} (Gs i) (_inst_4 i)) (H i) (K i)))
Case conversion may be inaccurate. Consider using '#align subgroup.commutator_pi_pi_le Subgroup.commutator_pi_pi_leₓ'. -/
/-- The commutator of direct product is contained in the direct product of the commutators.

See `commutator_pi_pi_of_finite` for equality given `fintype η`.
-/
theorem commutator_pi_pi_le {η : Type _} {Gs : η → Type _} [∀ i, Group (Gs i)]
    (H K : ∀ i, Subgroup (Gs i)) :
    ⁅Subgroup.pi Set.univ H, Subgroup.pi Set.univ K⁆ ≤ Subgroup.pi Set.univ fun i => ⁅H i, K i⁆ :=
  commutator_le.mpr fun p hp q hq i hi => commutator_mem_commutator (hp i hi) (hq i hi)
#align subgroup.commutator_pi_pi_le Subgroup.commutator_pi_pi_le

/- warning: subgroup.commutator_pi_pi_of_finite -> Subgroup.commutator_pi_pi_of_finite is a dubious translation:
lean 3 declaration is
  forall {η : Type.{u1}} [_inst_4 : Finite.{succ u1} η] {Gs : η -> Type.{u2}} [_inst_5 : forall (i : η), Group.{u2} (Gs i)] (H : forall (i : η), Subgroup.{u2} (Gs i) (_inst_5 i)) (K : forall (i : η), Subgroup.{u2} (Gs i) (_inst_5 i)), Eq.{succ (max u1 u2)} (Subgroup.{max u1 u2} (forall (i : η), Gs i) (Pi.group.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_5 i))) (Bracket.bracket.{max u1 u2, max u1 u2} (Subgroup.{max u1 u2} (forall (i : η), Gs i) (Pi.group.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_5 i))) (Subgroup.{max u1 u2} (forall (i : η), Gs i) (Pi.group.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_5 i))) (Subgroup.commutator.{max u1 u2} (forall (i : η), Gs i) (Pi.group.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_5 i))) (Subgroup.pi.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_5 i) (Set.univ.{u1} η) H) (Subgroup.pi.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_5 i) (Set.univ.{u1} η) K)) (Subgroup.pi.{u1, u2} η (fun (i : η) => Gs i) (fun (i : η) => _inst_5 i) (Set.univ.{u1} η) (fun (i : η) => Bracket.bracket.{u2, u2} (Subgroup.{u2} (Gs i) (_inst_5 i)) (Subgroup.{u2} (Gs i) (_inst_5 i)) (Subgroup.commutator.{u2} (Gs i) (_inst_5 i)) (H i) (K i)))
but is expected to have type
  forall {η : Type.{u2}} [_inst_4 : Finite.{succ u2} η] {Gs : η -> Type.{u1}} [_inst_5 : forall (i : η), Group.{u1} (Gs i)] (H : forall (i : η), Subgroup.{u1} (Gs i) (_inst_5 i)) (K : forall (i : η), Subgroup.{u1} (Gs i) (_inst_5 i)), Eq.{max (succ u2) (succ u1)} (Subgroup.{max u2 u1} (forall (i : η), Gs i) (Pi.group.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_5 i))) (Bracket.bracket.{max u1 u2, max u1 u2} (Subgroup.{max u2 u1} (forall (i : η), Gs i) (Pi.group.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_5 i))) (Subgroup.{max u2 u1} (forall (i : η), Gs i) (Pi.group.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_5 i))) (Subgroup.commutator.{max u2 u1} (forall (i : η), Gs i) (Pi.group.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_5 i))) (Subgroup.pi.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_5 i) (Set.univ.{u2} η) H) (Subgroup.pi.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_5 i) (Set.univ.{u2} η) K)) (Subgroup.pi.{u2, u1} η (fun (i : η) => Gs i) (fun (i : η) => _inst_5 i) (Set.univ.{u2} η) (fun (i : η) => Bracket.bracket.{u1, u1} (Subgroup.{u1} (Gs i) (_inst_5 i)) (Subgroup.{u1} (Gs i) (_inst_5 i)) (Subgroup.commutator.{u1} (Gs i) (_inst_5 i)) (H i) (K i)))
Case conversion may be inaccurate. Consider using '#align subgroup.commutator_pi_pi_of_finite Subgroup.commutator_pi_pi_of_finiteₓ'. -/
/-- The commutator of a finite direct product is contained in the direct product of the commutators.
-/
theorem commutator_pi_pi_of_finite {η : Type _} [Finite η] {Gs : η → Type _} [∀ i, Group (Gs i)]
    (H K : ∀ i, Subgroup (Gs i)) :
    ⁅Subgroup.pi Set.univ H, Subgroup.pi Set.univ K⁆ = Subgroup.pi Set.univ fun i => ⁅H i, K i⁆ :=
  by
  classical
    apply le_antisymm (commutator_pi_pi_le H K)
    · rw [pi_le_iff]
      intro i hi
      rw [map_commutator]
      apply commutator_mono <;>
        · rw [le_pi_iff]
          intro j hj
          rintro _ ⟨_, ⟨x, hx, rfl⟩, rfl⟩
          by_cases h : j = i
          · subst h
            simpa using hx
          · simp [h, one_mem]
#align subgroup.commutator_pi_pi_of_finite Subgroup.commutator_pi_pi_of_finite

end Subgroup

variable (G)

#print commutatorSet /-
/-- The set of commutator elements `⁅g₁, g₂⁆` in `G`. -/
def commutatorSet : Set G :=
  { g | ∃ g₁ g₂ : G, ⁅g₁, g₂⁆ = g }
#align commutator_set commutatorSet
-/

#print commutatorSet_def /-
theorem commutatorSet_def : commutatorSet G = { g | ∃ g₁ g₂ : G, ⁅g₁, g₂⁆ = g } :=
  rfl
#align commutator_set_def commutatorSet_def
-/

/- warning: one_mem_commutator_set -> one_mem_commutatorSet is a dubious translation:
lean 3 declaration is
  forall (G : Type.{u1}) [_inst_1 : Group.{u1} G], Membership.Mem.{u1, u1} G (Set.{u1} G) (Set.hasMem.{u1} G) (OfNat.ofNat.{u1} G 1 (OfNat.mk.{u1} G 1 (One.one.{u1} G (MulOneClass.toHasOne.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))))) (commutatorSet.{u1} G _inst_1)
but is expected to have type
  forall (G : Type.{u1}) [_inst_1 : Group.{u1} G], Membership.mem.{u1, u1} G (Set.{u1} G) (Set.instMembershipSet.{u1} G) (OfNat.ofNat.{u1} G 1 (One.toOfNat1.{u1} G (InvOneClass.toOne.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1)))))) (commutatorSet.{u1} G _inst_1)
Case conversion may be inaccurate. Consider using '#align one_mem_commutator_set one_mem_commutatorSetₓ'. -/
theorem one_mem_commutatorSet : (1 : G) ∈ commutatorSet G :=
  ⟨1, 1, commutatorElement_self 1⟩
#align one_mem_commutator_set one_mem_commutatorSet

instance : Nonempty (commutatorSet G) :=
  ⟨⟨1, one_mem_commutatorSet G⟩⟩

variable {G g}

#print mem_commutatorSet_iff /-
theorem mem_commutatorSet_iff : g ∈ commutatorSet G ↔ ∃ g₁ g₂ : G, ⁅g₁, g₂⁆ = g :=
  Iff.rfl
#align mem_commutator_set_iff mem_commutatorSet_iff
-/

#print commutator_mem_commutatorSet /-
theorem commutator_mem_commutatorSet : ⁅g₁, g₂⁆ ∈ commutatorSet G :=
  ⟨g₁, g₂, rfl⟩
#align commutator_mem_commutator_set commutator_mem_commutatorSet
-/


/-
Copyright (c) 2021 Aaron Anderson, Yaël Dillies. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Aaron Anderson, Kevin Buzzard, Yaël Dillies, Eric Wieser
-/
import data.finset.pairwise
import data.finset.powerset
import data.fintype.basic

/-!
# Supremum independence

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.

In this file, we define supremum independence of indexed sets. An indexed family `f : ι → α` is
sup-independent if, for all `a`, `f a` and the supremum of the rest are disjoint.

## Main definitions

* `finset.sup_indep s f`: a family of elements `f` are supremum independent on the finite set `s`.
* `complete_lattice.set_independent s`: a set of elements are supremum independent.
* `complete_lattice.independent f`: a family of elements are supremum independent.

## Main statements

* In a distributive lattice, supremum independence is equivalent to pairwise disjointness:
  * `finset.sup_indep_iff_pairwise_disjoint`
  * `complete_lattice.set_independent_iff_pairwise_disjoint`
  * `complete_lattice.independent_iff_pairwise_disjoint`
* Otherwise, supremum independence is stronger than pairwise disjointness:
  * `finset.sup_indep.pairwise_disjoint`
  * `complete_lattice.set_independent.pairwise_disjoint`
  * `complete_lattice.independent.pairwise_disjoint`

## Implementation notes

For the finite version, we avoid the "obvious" definition
`∀ i ∈ s, disjoint (f i) ((s.erase i).sup f)` because `erase` would require decidable equality on
`ι`.
-/

variables {α β ι ι' : Type*}

/-! ### On lattices with a bottom element, via `finset.sup` -/

namespace finset
section lattice
variables [lattice α] [order_bot α]

/-- Supremum independence of finite sets. We avoid the "obvious" definition using `s.erase i`
because `erase` would require decidable equality on `ι`. -/
def sup_indep (s : finset ι) (f : ι → α) : Prop :=
∀ ⦃t⦄, t ⊆ s → ∀ ⦃i⦄, i ∈ s → i ∉ t → disjoint (f i) (t.sup f)

variables {s t : finset ι} {f : ι → α} {i : ι}

instance [decidable_eq ι] [decidable_eq α] : decidable (sup_indep s f) :=
begin
  apply @finset.decidable_forall_of_decidable_subsets _ _ _ _,
  intros t ht,
  apply @finset.decidable_dforall_finset _ _ _ _,
  exact λ i hi, @implies.decidable _ _ _ (decidable_of_iff' (_ = ⊥) disjoint_iff),
end

lemma sup_indep.subset (ht : t.sup_indep f) (h : s ⊆ t) : s.sup_indep f :=
λ u hu i hi, ht (hu.trans h) (h hi)

lemma sup_indep_empty (f : ι → α) : (∅ : finset ι).sup_indep f := λ _ _ a ha, ha.elim

lemma sup_indep_singleton (i : ι) (f : ι → α) : ({i} : finset ι).sup_indep f :=
λ s hs j hji hj, begin
  rw [eq_empty_of_ssubset_singleton ⟨hs, λ h, hj (h hji)⟩, sup_empty],
  exact disjoint_bot_right,
end

lemma sup_indep.pairwise_disjoint (hs : s.sup_indep f) : (s : set ι).pairwise_disjoint f :=
λ a ha b hb hab, sup_singleton.subst $ hs (singleton_subset_iff.2 hb) ha $ not_mem_singleton.2 hab

/-- The RHS looks like the definition of `complete_lattice.independent`. -/
lemma sup_indep_iff_disjoint_erase [decidable_eq ι] :
  s.sup_indep f ↔ ∀ i ∈ s, disjoint (f i) ((s.erase i).sup f) :=
⟨λ hs i hi, hs (erase_subset _ _) hi (not_mem_erase _ _), λ hs t ht i hi hit,
  (hs i hi).mono_right (sup_mono $ λ j hj, mem_erase.2 ⟨ne_of_mem_of_not_mem hj hit, ht hj⟩)⟩

@[simp] lemma sup_indep_pair [decidable_eq ι] {i j : ι} (hij : i ≠ j) :
  ({i, j} : finset ι).sup_indep f ↔ disjoint (f i) (f j) :=
⟨λ h, h.pairwise_disjoint (by simp) (by simp) hij, λ h, begin
  rw sup_indep_iff_disjoint_erase,
  intros k hk,
  rw [finset.mem_insert, finset.mem_singleton] at hk,
  obtain rfl | rfl := hk,
  { convert h using 1,
    rw [finset.erase_insert, finset.sup_singleton],
    simpa using hij },
  { convert h.symm using 1,
    have : ({i, k} : finset ι).erase k = {i},
    { ext,
      rw [mem_erase, mem_insert, mem_singleton, mem_singleton, and_or_distrib_left,
        ne.def, not_and_self, or_false, and_iff_right_of_imp],
      rintro rfl,
      exact hij },
    rw [this, finset.sup_singleton] }
end⟩

lemma sup_indep_univ_bool (f : bool → α) :
  (finset.univ : finset bool).sup_indep f ↔ disjoint (f ff) (f tt) :=
begin
  have : tt ≠ ff := by simp only [ne.def, not_false_iff],
  exact (sup_indep_pair this).trans disjoint.comm,
end

@[simp] lemma sup_indep_univ_fin_two (f : fin 2 → α) :
  (finset.univ : finset (fin 2)).sup_indep f ↔ disjoint (f 0) (f 1) :=
begin
  have : (0 : fin 2) ≠ 1 := by simp,
  exact sup_indep_pair this,
end

lemma sup_indep.attach (hs : s.sup_indep f) : s.attach.sup_indep (f ∘ subtype.val) :=
begin
  intros t ht i _ hi,
  classical,
  rw ←finset.sup_image,
  refine hs (image_subset_iff.2 $ λ (j : {x // x ∈ s}) _, j.2) i.2 (λ hi', hi _),
  rw mem_image at hi',
  obtain ⟨j, hj, hji⟩ := hi',
  rwa subtype.ext hji at hj,
end

end lattice

section distrib_lattice
variables [distrib_lattice α] [order_bot α] {s : finset ι} {f : ι → α}

lemma sup_indep_iff_pairwise_disjoint : s.sup_indep f ↔ (s : set ι).pairwise_disjoint f :=
⟨sup_indep.pairwise_disjoint, λ hs t ht i hi hit,
  finset.disjoint_sup_right.2 $ λ j hj, hs hi (ht hj) (ne_of_mem_of_not_mem hj hit).symm⟩

alias sup_indep_iff_pairwise_disjoint ↔ sup_indep.pairwise_disjoint
  _root_.set.pairwise_disjoint.sup_indep

/-- Bind operation for `sup_indep`. -/
lemma sup_indep.sup [decidable_eq ι] {s : finset ι'} {g : ι' → finset ι} {f : ι → α}
  (hs : s.sup_indep (λ i, (g i).sup f)) (hg : ∀ i' ∈ s, (g i').sup_indep f) :
  (s.sup g).sup_indep f :=
begin
  simp_rw sup_indep_iff_pairwise_disjoint at ⊢ hs hg,
  rw [sup_eq_bUnion, coe_bUnion],
  exact hs.bUnion_finset hg,
end

/-- Bind operation for `sup_indep`. -/
lemma sup_indep.bUnion [decidable_eq ι] {s : finset ι'} {g : ι' → finset ι} {f : ι → α}
  (hs : s.sup_indep (λ i, (g i).sup f)) (hg : ∀ i' ∈ s, (g i').sup_indep f) :
  (s.bUnion g).sup_indep f :=
by { rw ←sup_eq_bUnion, exact hs.sup hg }

end distrib_lattice
end finset

/-! ### On complete lattices via `has_Sup.Sup` -/

namespace complete_lattice
variables [complete_lattice α]

open set function

/-- An independent set of elements in a complete lattice is one in which every element is disjoint
  from the `Sup` of the rest. -/
def set_independent (s : set α) : Prop := ∀ ⦃a⦄, a ∈ s → disjoint a (Sup (s \ {a}))

variables {s : set α} (hs : set_independent s)

@[simp]
lemma set_independent_empty : set_independent (∅ : set α) :=
λ x hx, (set.not_mem_empty x hx).elim

theorem set_independent.mono {t : set α} (hst : t ⊆ s) :
  set_independent t :=
λ a ha, (hs (hst ha)).mono_right (Sup_le_Sup (diff_subset_diff_left hst))

/-- If the elements of a set are independent, then any pair within that set is disjoint. -/
lemma set_independent.pairwise_disjoint : s.pairwise_disjoint id :=
λ x hx y hy h, disjoint_Sup_right (hs hx) ((mem_diff y).mpr ⟨hy, h.symm⟩)

lemma set_independent_pair {a b : α} (hab : a ≠ b) :
  set_independent ({a, b} : set α) ↔ disjoint a b :=
begin
  split,
  { intro h,
    exact h.pairwise_disjoint (mem_insert _ _) (mem_insert_of_mem _ (mem_singleton _)) hab, },
  { rintros h c ((rfl : c = a) | (rfl : c = b)),
    { convert h using 1,
      simp [hab, Sup_singleton] },
    { convert h.symm using 1,
      simp [hab, Sup_singleton] }, },
end

include hs

/-- If the elements of a set are independent, then any element is disjoint from the `Sup` of some
subset of the rest. -/
lemma set_independent.disjoint_Sup {x : α} {y : set α} (hx : x ∈ s) (hy : y ⊆ s) (hxy : x ∉ y) :
  disjoint x (Sup y) :=
begin
  have := (hs.mono $ insert_subset.mpr ⟨hx, hy⟩) (mem_insert x _),
  rw [insert_diff_of_mem _ (mem_singleton _), diff_singleton_eq_self hxy] at this,
  exact this,
end

omit hs

/-- An independent indexed family of elements in a complete lattice is one in which every element
  is disjoint from the `supr` of the rest.

  Example: an indexed family of non-zero elements in a
  vector space is linearly independent iff the indexed family of subspaces they generate is
  independent in this sense.

  Example: an indexed family of submodules of a module is independent in this sense if
  and only the natural map from the direct sum of the submodules to the module is injective. -/
def independent {ι : Sort*} {α : Type*} [complete_lattice α] (t : ι → α) : Prop :=
∀ i : ι, disjoint (t i) (⨆ (j ≠ i), t j)

lemma set_independent_iff {α : Type*} [complete_lattice α] (s : set α) :
  set_independent s ↔ independent (coe : s → α) :=
begin
  simp_rw [independent, set_independent, set_coe.forall, Sup_eq_supr],
  refine forall₂_congr (λ a ha, _),
  congr' 2,
  convert supr_subtype.symm,
  simp [supr_and],
end

variables {t : ι → α} (ht : independent t)

theorem independent_def : independent t ↔ ∀ i : ι, disjoint (t i) (⨆ (j ≠ i), t j) :=
iff.rfl

theorem independent_def' :
  independent t ↔ ∀ i, disjoint (t i) (Sup (t '' {j | j ≠ i})) :=
by {simp_rw Sup_image, refl}

theorem independent_def'' :
  independent t ↔ ∀ i, disjoint (t i) (Sup {a | ∃ j ≠ i, t j = a}) :=
by {rw independent_def', tidy}

@[simp]
lemma independent_empty (t : empty → α) : independent t.

@[simp]
lemma independent_pempty (t : pempty → α) : independent t.

/-- If the elements of a set are independent, then any pair within that set is disjoint. -/
lemma independent.pairwise_disjoint : pairwise (disjoint on t) :=
λ x y h, disjoint_Sup_right (ht x) ⟨y, supr_pos h.symm⟩

lemma independent.mono
  {s t : ι → α} (hs : independent s) (hst : t ≤ s) :
  independent t :=
λ i, (hs i).mono (hst i) $ supr₂_mono $ λ j _, hst j

/-- Composing an independent indexed family with an injective function on the index results in
another indepedendent indexed family. -/
lemma independent.comp {ι ι' : Sort*}
  {t : ι → α} {f : ι' → ι} (ht : independent t) (hf : injective f) :
  independent (t ∘ f) :=
λ i, (ht (f i)).mono_right $ begin
  refine (supr_mono $ λ i, _).trans (supr_comp_le _ f),
  exact supr_const_mono hf.ne,
end

lemma independent.comp' {ι ι' : Sort*}
  {t : ι → α} {f : ι' → ι} (ht : independent $ t ∘ f) (hf : surjective f) :
  independent t :=
begin
  intros i,
  obtain ⟨i', rfl⟩ := hf i,
  rw ← hf.supr_comp,
  exact (ht i').mono_right (bsupr_mono $ λ j' hij, mt (congr_arg f) hij),
end

lemma independent.set_independent_range (ht : independent t) :
  set_independent $ range t :=
begin
  rw set_independent_iff,
  rw ← coe_comp_range_factorization t at ht,
  exact ht.comp' surjective_onto_range,
end

lemma independent.injective (ht : independent t) (h_ne_bot : ∀ i, t i ≠ ⊥) : injective t :=
begin
  intros i j h,
  by_contra' contra,
  apply h_ne_bot j,
  suffices : t j ≤ ⨆ k (hk : k ≠ i), t k,
  { replace ht := (ht i).mono_right this,
    rwa [h, disjoint_self] at ht, },
  replace contra : j ≠ i, { exact ne.symm contra, },
  exact le_supr₂ j contra,
end

lemma independent_pair {i j : ι} (hij : i ≠ j) (huniv : ∀ k, k = i ∨ k = j):
  independent t ↔ disjoint (t i) (t j) :=
begin
  split,
  { exact λ h, h.pairwise_disjoint hij },
  { rintros h k,
    obtain rfl | rfl := huniv k,
    { refine h.mono_right (supr_le $ λ i, supr_le $ λ hi, eq.le _),
      rw (huniv i).resolve_left hi },
    { refine h.symm.mono_right (supr_le $ λ j, supr_le $ λ hj, eq.le _),
      rw (huniv j).resolve_right hj } },
end

/-- Composing an indepedent indexed family with an order isomorphism on the elements results in
another indepedendent indexed family. -/
lemma independent.map_order_iso {ι : Sort*} {α β : Type*}
  [complete_lattice α] [complete_lattice β] (f : α ≃o β) {a : ι → α} (ha : independent a) :
  independent (f ∘ a) :=
λ i, ((ha i).map_order_iso f).mono_right (f.monotone.le_map_supr₂ _)

@[simp] lemma independent_map_order_iso_iff {ι : Sort*} {α β : Type*}
  [complete_lattice α] [complete_lattice β] (f : α ≃o β) {a : ι → α} :
  independent (f ∘ a) ↔ independent a :=
⟨ λ h, have hf : f.symm ∘ f ∘ a = a := congr_arg (∘ a) f.left_inv.comp_eq_id,
      hf ▸ h.map_order_iso f.symm,
  λ h, h.map_order_iso f⟩

/-- If the elements of a set are independent, then any element is disjoint from the `supr` of some
subset of the rest. -/
lemma independent.disjoint_bsupr {ι : Type*} {α : Type*} [complete_lattice α]
  {t : ι → α} (ht : independent t) {x : ι} {y : set ι} (hx : x ∉ y) :
  disjoint (t x) (⨆ i ∈ y, t i) :=
disjoint.mono_right (bsupr_mono $ λ i hi, (ne_of_mem_of_not_mem hi hx : _)) (ht x)

end complete_lattice

lemma complete_lattice.independent_iff_sup_indep [complete_lattice α] {s : finset ι} {f : ι → α} :
  complete_lattice.independent (f ∘ (coe : s → ι)) ↔ s.sup_indep f :=
begin
  classical,
  rw finset.sup_indep_iff_disjoint_erase,
  refine subtype.forall.trans (forall₂_congr $ λ a b, _),
  rw finset.sup_eq_supr,
  congr' 2,
  refine supr_subtype.trans _,
  congr' 1 with x,
  simp [supr_and, @supr_comm _ (x ∈ s)],
end

alias complete_lattice.independent_iff_sup_indep ↔ complete_lattice.independent.sup_indep
  finset.sup_indep.independent

/-- A variant of `complete_lattice.independent_iff_sup_indep` for `fintype`s. -/
lemma complete_lattice.independent_iff_sup_indep_univ [complete_lattice α] [fintype ι] {f : ι → α} :
  complete_lattice.independent f ↔ finset.univ.sup_indep f :=
begin
  classical,
  simp [finset.sup_indep_iff_disjoint_erase, complete_lattice.independent, finset.sup_eq_supr],
end

alias complete_lattice.independent_iff_sup_indep_univ ↔ complete_lattice.independent.sup_indep_univ
  finset.sup_indep.independent_of_univ

section frame

namespace complete_lattice
variables [order.frame α]

lemma set_independent_iff_pairwise_disjoint {s : set α} :
  set_independent s ↔ s.pairwise_disjoint id :=
⟨set_independent.pairwise_disjoint, λ hs i hi, disjoint_Sup_iff.2 $ λ j hj,
  hs hi hj.1 $ ne.symm hj.2⟩

alias set_independent_iff_pairwise_disjoint ↔ _ _root_.set.pairwise_disjoint.set_independent

lemma independent_iff_pairwise_disjoint {f : ι → α} : independent f ↔ pairwise (disjoint on f) :=
⟨independent.pairwise_disjoint, λ hs i, disjoint_supr_iff.2 $ λ j, disjoint_supr_iff.2 $ λ hij,
  hs hij.symm⟩

end complete_lattice

end frame


def g : List Nat → List Nat → Nat
| [],         y::ys => y
| [],         ys    => 0
| x1::x2::xs, ys    => g xs ys
| x::xs,      y::ys => g xs ys + y
| x::xs,      []    => g xs []

universe u v

inductive Imf {α : Type u} {β : Type v} (f : α → β) : β → Type (max u v)
| mk : (a : α) → Imf f (f a)

def h {α β} {f : α → β} : {b : β} → Imf f b → α
| _, Imf.mk a => a

theorem ex1 {α β} (f : α → β) (a : α) : h (Imf.mk (f := f) a) = a :=
rfl

def v₁ : Imf Nat.succ 1 :=
Imf.mk 0

def v₂ : Imf (fun x => 1 + x) 1 :=
Imf.mk 0

theorem ex2 : h v₁ = 0 :=
rfl

theorem ex3 : h v₂ = 0 :=
rfl

theorem ex4 {α} : {a b : α} → a = b → b = a
| _, _, rfl => rfl

theorem ex5 {α} : {a b : α} → a = b → b = a
| a, .(a), rfl => rfl

theorem ex6 {α} : {a b : α} → a = b → b = a
| a, .(a), Eq.refl .(a) => rfl

theorem ex7 {α} : {a b : α} → a = b → b = a
| .(a), a, Eq.refl .(a) => rfl


import analysis.calculus.mean_value
open polynomial

open set filter

noncomputable theory

@[simp]
def x_sub_dx (p : polynomial ℝ) :=
X * p - p.derivative

lemma x_sub_dx_def (p : polynomial ℝ) : x_sub_dx p = X*p - p.derivative := rfl

lemma x_sub_dx_apply (p : polynomial ℝ) (x : ℝ) :
eval x (x_sub_dx p) = x*(eval x p) - (eval x (derivative p)) := by simp

def hermite (n : ℕ) : polynomial ℝ :=
nat.iterate x_sub_dx n 1

@[simp]
lemma hermite_eq_iter (n : ℕ) : hermite n = nat.iterate x_sub_dx n 1 := rfl

@[simp]
lemma hermite_succ (n : ℕ) : hermite n.succ = x_sub_dx (hermite n) :=
begin
  simp only [hermite],
  rw function.iterate_succ' x_sub_dx n,
end

@[simp]
lemma hermite_zero : hermite 0 = C 1 := rfl

@[simp]
lemma hermite_one : hermite 1 = X :=
begin
  rw [hermite_succ, x_sub_dx_def],
  simp only [hermite_zero, map_one, mul_one, derivative_one, sub_zero],
end


/-
Copyright (c) 2021 OpenAI. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kunhao Zheng, Stanislas Polu, David Renshaw, OpenAI GPT-f
-/
import mathzoo.imports.miniF2F

open_locale nat rat real big_operators topological_space

theorem mathd_algebra_126
  (x y : ℝ)
  (h₀ : 2 * 3 = x - 9)
  (h₁ : 2 * (-5) = y + 1) :
  x = 15 ∧ y = -11 :=
begin
  split; linarith,
end


/-
Copyright (c) 2022 Junyan Xu. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Junyan Xu

! This file was ported from Lean 3 source module data.finsupp.well_founded
! leanprover-community/mathlib commit 5fd3186f1ec30a75d5f65732e3ce5e623382556f
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathlib.Data.Dfinsupp.WellFounded
import Mathlib.Data.Finsupp.Lex

/-!
# Well-foundedness of the lexicographic and product orders on `Finsupp`

`Finsupp.Lex.wellFounded` and the two variants that follow it essentially say that if `(· > ·)` is
a well order on `α`, `(· < ·)` is well-founded on `N`, and `0` is a bottom element in `N`, then the
lexicographic `(· < ·)` is well-founded on `α →₀ N`.

`Finsupp.Lex.wellFoundedLT_of_finite` says that if `α` is finite and equipped with a linear order
and `(· < ·)` is well-founded on `N`, then the lexicographic `(· < ·)` is well-founded on `α →₀ N`.

`Finsupp.wellFoundedLT` and `wellFoundedLT_of_finite` state the same results for the product
order `(· < ·)`, but without the ordering conditions on `α`.

All results are transferred from `Dfinsupp` via `Finsupp.toDfinsupp`.
-/

variable {α N : Type _}

namespace Finsupp

variable [Zero N] {r : α → α → Prop} {s : N → N → Prop} (hbot : ∀ ⦃n⦄, ¬s n 0)
  (hs : WellFounded s)

/-- Transferred from `Dfinsupp.Lex.acc`. See the top of that file for an explanation for the
  appearance of the relation `rᶜ ⊓ (≠)`. -/
theorem Lex.acc (x : α →₀ N) (h : ∀ a ∈ x.support, Acc (rᶜ ⊓ (· ≠ ·)) a) :
    Acc (Finsupp.Lex r s) x := by
  rw [lex_eq_invImage_dfinsupp_lex]
  classical
    refine' InvImage.accessible toDfinsupp (Dfinsupp.Lex.acc (fun _ => hbot) (fun _ => hs) _ _)
    simpa only [toDfinsupp_support] using h
#align finsupp.lex.acc Finsupp.Lex.acc

theorem Lex.wellFounded (hr : WellFounded <| rᶜ ⊓ (· ≠ ·)) : WellFounded (Finsupp.Lex r s) :=
  ⟨fun x => Lex.acc hbot hs x fun a _ => hr.apply a⟩
#align finsupp.lex.well_founded Finsupp.Lex.wellFounded

theorem Lex.wellFounded' [IsTrichotomous α r] (hr : WellFounded (Function.swap r)) :
    WellFounded (Finsupp.Lex r s) :=
  (lex_eq_invImage_dfinsupp_lex r s).symm ▸
    InvImage.wf _ (Dfinsupp.Lex.wellFounded' (fun _ => hbot) (fun _ => hs) hr)
#align finsupp.lex.well_founded' Finsupp.Lex.wellFounded'

instance Lex.wellFoundedLT {α N} [LT α] [IsTrichotomous α (· < ·)] [hα : WellFoundedGT α]
    [CanonicallyOrderedAddMonoid N] [hN : WellFoundedLT N] : WellFoundedLT (Lex (α →₀ N)) :=
  ⟨Lex.wellFounded' (fun n => (zero_le n).not_lt) hN.wf hα.wf⟩
#align finsupp.lex.well_founded_lt Finsupp.Lex.wellFoundedLT

variable (r)

theorem Lex.wellFounded_of_finite [IsStrictTotalOrder α r] [Finite α] [Zero N]
    (hs : WellFounded s) : WellFounded (Finsupp.Lex r s) :=
  InvImage.wf (@equivFunOnFinite α N _ _) (Pi.Lex.wellFounded r fun _ => hs)
#align finsupp.lex.well_founded_of_finite Finsupp.Lex.wellFounded_of_finite

theorem Lex.wellFoundedLT_of_finite [LinearOrder α] [Finite α] [Zero N] [LT N]
    [hwf : WellFoundedLT N] : WellFoundedLT (Lex (α →₀ N)) :=
  ⟨Finsupp.Lex.wellFounded_of_finite (· < ·) hwf.1⟩
#align finsupp.lex.well_founded_lt_of_finite Finsupp.Lex.wellFoundedLT_of_finite

protected theorem wellFoundedLT [Zero N] [Preorder N] [WellFoundedLT N] (hbot : ∀ n : N, ¬n < 0) :
    WellFoundedLT (α →₀ N) :=
  ⟨InvImage.wf toDfinsupp (Dfinsupp.wellFoundedLT fun _ a => hbot a).wf⟩
#align finsupp.well_founded_lt Finsupp.wellFoundedLT

instance wellFoundedLT' {N} [CanonicallyOrderedAddMonoid N] [WellFoundedLT N] :
    WellFoundedLT (α →₀ N) :=
  Finsupp.wellFoundedLT fun a => (zero_le a).not_lt
#align finsupp.well_founded_lt' Finsupp.wellFoundedLT'

instance wellFoundedLT_of_finite [Finite α] [Zero N] [Preorder N] [WellFoundedLT N] :
    WellFoundedLT (α →₀ N) :=
  ⟨InvImage.wf equivFunOnFinite Function.wellFoundedLT.wf⟩
#align finsupp.well_founded_lt_of_finite Finsupp.wellFoundedLT_of_finite

end Finsupp


/-
Copyright (c) 2020 Heather Macbeth. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Heather Macbeth
-/
import analysis.normed_space.hahn_banach
import analysis.normed_space.is_R_or_C

/-!
# The topological dual of a normed space

In this file we define the topological dual `normed_space.dual` of a normed space, and the
continuous linear map `normed_space.inclusion_in_double_dual` from a normed space into its double
dual.

For base field `𝕜 = ℝ` or `𝕜 = ℂ`, this map is actually an isometric embedding; we provide a
version `normed_space.inclusion_in_double_dual_li` of the map which is of type a bundled linear
isometric embedding, `E →ₗᵢ[𝕜] (dual 𝕜 (dual 𝕜 E))`.

Since a lot of elementary properties don't require `eq_of_dist_eq_zero` we start setting up the
theory for `semi_normed_group` and we specialize to `normed_group` when needed.

## Main definitions

* `inclusion_in_double_dual` and `inclusion_in_double_dual_li` are the inclusion of a normed space
  in its double dual, considered as a bounded linear map and as a linear isometry, respectively.
* `polar 𝕜 s` is the subset of `dual 𝕜 E` consisting of those functionals `x'` for which
  `∥x' z∥ ≤ 1` for every `z ∈ s`.

## Tags

dual
-/

noncomputable theory
open_locale classical topological_space
universes u v

namespace normed_space

section general
variables (𝕜 : Type*) [nondiscrete_normed_field 𝕜]
variables (E : Type*) [semi_normed_group E] [normed_space 𝕜 E]
variables (F : Type*) [normed_group F] [normed_space 𝕜 F]

/-- The topological dual of a seminormed space `E`. -/
@[derive [inhabited, semi_normed_group, normed_space 𝕜]] def dual := E →L[𝕜] 𝕜

instance : add_monoid_hom_class (dual 𝕜 E) E 𝕜 := continuous_linear_map.add_monoid_hom_class

instance : has_coe_to_fun (dual 𝕜 E) (λ _, E → 𝕜) := continuous_linear_map.to_fun

instance : normed_group (dual 𝕜 F) := continuous_linear_map.to_normed_group

instance [finite_dimensional 𝕜 E] : finite_dimensional 𝕜 (dual 𝕜 E) :=
continuous_linear_map.finite_dimensional

/-- The inclusion of a normed space in its double (topological) dual, considered
   as a bounded linear map. -/
def inclusion_in_double_dual : E →L[𝕜] (dual 𝕜 (dual 𝕜 E)) :=
continuous_linear_map.apply 𝕜 𝕜

@[simp] lemma dual_def (x : E) (f : dual 𝕜 E) : inclusion_in_double_dual 𝕜 E x f = f x := rfl

lemma inclusion_in_double_dual_norm_eq :
  ∥inclusion_in_double_dual 𝕜 E∥ = ∥(continuous_linear_map.id 𝕜 (dual 𝕜 E))∥ :=
continuous_linear_map.op_norm_flip _

lemma inclusion_in_double_dual_norm_le : ∥inclusion_in_double_dual 𝕜 E∥ ≤ 1 :=
by { rw inclusion_in_double_dual_norm_eq, exact continuous_linear_map.norm_id_le }

lemma double_dual_bound (x : E) : ∥(inclusion_in_double_dual 𝕜 E) x∥ ≤ ∥x∥ :=
by simpa using continuous_linear_map.le_of_op_norm_le _ (inclusion_in_double_dual_norm_le 𝕜 E) x

end general

section bidual_isometry

variables (𝕜 : Type v) [is_R_or_C 𝕜]
  {E : Type u} [normed_group E] [normed_space 𝕜 E]

/-- If one controls the norm of every `f x`, then one controls the norm of `x`.
    Compare `continuous_linear_map.op_norm_le_bound`. -/
lemma norm_le_dual_bound (x : E) {M : ℝ} (hMp: 0 ≤ M) (hM : ∀ (f : dual 𝕜 E), ∥f x∥ ≤ M * ∥f∥) :
  ∥x∥ ≤ M :=
begin
  classical,
  by_cases h : x = 0,
  { simp only [h, hMp, norm_zero] },
  { obtain ⟨f, hf₁, hfx⟩ : ∃ f : E →L[𝕜] 𝕜, ∥f∥ = 1 ∧ f x = ∥x∥ := exists_dual_vector 𝕜 x h,
    calc ∥x∥ = ∥(∥x∥ : 𝕜)∥ : is_R_or_C.norm_coe_norm.symm
    ... = ∥f x∥ : by rw hfx
    ... ≤ M * ∥f∥ : hM f
    ... = M : by rw [hf₁, mul_one] }
end

lemma eq_zero_of_forall_dual_eq_zero {x : E} (h : ∀ f : dual 𝕜 E, f x = (0 : 𝕜)) : x = 0 :=
norm_le_zero_iff.mp (norm_le_dual_bound 𝕜 x le_rfl (λ f, by simp [h f]))

lemma eq_zero_iff_forall_dual_eq_zero (x : E) : x = 0 ↔ ∀ g : dual 𝕜 E, g x = 0 :=
⟨λ hx, by simp [hx], λ h, eq_zero_of_forall_dual_eq_zero 𝕜 h⟩

lemma eq_iff_forall_dual_eq {x y : E} :
  x = y ↔ ∀ g : dual 𝕜 E, g x = g y :=
begin
  rw [← sub_eq_zero, eq_zero_iff_forall_dual_eq_zero 𝕜 (x - y)],
  simp [sub_eq_zero],
end

/-- The inclusion of a normed space in its double dual is an isometry onto its image.-/
def inclusion_in_double_dual_li : E →ₗᵢ[𝕜] (dual 𝕜 (dual 𝕜 E)) :=
{ norm_map' := begin
    intros x,
    apply le_antisymm,
    { exact double_dual_bound 𝕜 E x },
    rw continuous_linear_map.norm_def,
    refine le_cInf continuous_linear_map.bounds_nonempty _,
    rintros c ⟨hc1, hc2⟩,
    exact norm_le_dual_bound 𝕜 x hc1 hc2
  end,
  .. inclusion_in_double_dual 𝕜 E }

end bidual_isometry

end normed_space

section polar_sets

open metric set normed_space

/-- Given a subset `s` in a normed space `E` (over a field `𝕜`), the polar
`polar 𝕜 s` is the subset of `dual 𝕜 E` consisting of those functionals which
evaluate to something of norm at most one at all points `z ∈ s`. -/
def polar (𝕜 : Type*) [nondiscrete_normed_field 𝕜]
  {E : Type*} [normed_group E] [normed_space 𝕜 E] (s : set E) : set (dual 𝕜 E) :=
{x' : dual 𝕜 E | ∀ z ∈ s, ∥ x' z ∥ ≤ 1}

variables (𝕜 : Type*) [nondiscrete_normed_field 𝕜]
variables {E : Type*} [normed_group E] [normed_space 𝕜 E]

@[simp] lemma zero_mem_polar (s : set E) :
  (0 : dual 𝕜 E) ∈ polar 𝕜 s :=
λ _ _, by simp only [zero_le_one, continuous_linear_map.zero_apply, norm_zero]

lemma polar_eq_Inter (s : set E) :
  polar 𝕜 s = ⋂ z ∈ s, {x' : dual 𝕜 E | ∥x' z∥ ≤ 1} :=
by simp only [polar, set_of_forall]

@[simp] lemma polar_univ : polar 𝕜 (univ : set E) = {(0 : dual 𝕜 E)} :=
begin
  refine eq_singleton_iff_unique_mem.2 ⟨zero_mem_polar _ _, λ x' hx', _⟩,
  ext x,
  refine norm_le_zero_iff.1 (le_of_forall_le_of_dense $ λ ε hε, _),
  rcases normed_field.exists_norm_lt 𝕜 hε with ⟨c, hc, hcε⟩,
  calc ∥x' x∥ = ∥c∥ * ∥x' (c⁻¹ • x)∥ :
    by rw [x'.map_smul, norm_smul, normed_field.norm_inv,
      mul_inv_cancel_left₀ hc.ne']
  ... ≤ ε * 1 : mul_le_mul hcε.le (hx' _ trivial) (norm_nonneg _) hε.le
  ... = ε : mul_one _
end

lemma is_closed_polar (s : set E) : is_closed (polar 𝕜 s) :=
begin
  simp only [polar_eq_Inter, ← continuous_linear_map.apply_apply _ (_ : dual 𝕜 E)],
  refine is_closed_bInter (λ z hz, _),
  exact is_closed_Iic.preimage (continuous_linear_map.apply 𝕜 𝕜 z).continuous.norm
end

variable (E)

/-- `polar 𝕜 : set E → set (normed_space.dual 𝕜 E)` forms an order-reversing Galois connection with
a similarly defined map `set (normed_space.dual 𝕜 E) → set E`. We use `order_dual.to_dual` and
`order_dual.of_dual` to express that `polar` is order-reversing. Instead of defining the dual
operation `unpolar s := {x : E | ∀ x' ∈ s, ∥x' x∥ ≤ 1}` we apply `polar 𝕜` again, then pull the set
from the double dual space to the original space using `normed_space.inclusion_in_double_dual`. -/
lemma polar_gc :
  galois_connection (order_dual.to_dual ∘ polar 𝕜)
    (λ s, inclusion_in_double_dual 𝕜 E ⁻¹' (polar 𝕜 $ order_dual.of_dual s)) :=
λ s t, ⟨λ H x hx x' hx', H hx' x hx, λ H x' hx' x hx, H hx x' hx'⟩

variable {E}

@[simp] lemma polar_Union {ι} (s : ι → set E) : polar 𝕜 (⋃ i, s i) = ⋂ i, polar 𝕜 (s i) :=
(polar_gc 𝕜 E).l_supr

@[simp] lemma polar_union (s t : set E) : polar 𝕜 (s ∪ t) = polar 𝕜 s ∩ polar 𝕜 t :=
(polar_gc 𝕜 E).l_sup

lemma polar_antitone : antitone (polar 𝕜 : set E → set (dual 𝕜 E)) := (polar_gc 𝕜 E).monotone_l

@[simp] lemma polar_empty : polar 𝕜 (∅ : set E) = univ := (polar_gc 𝕜 E).l_bot

@[simp] lemma polar_zero : polar 𝕜 ({0} : set E) = univ :=
eq_univ_of_forall $ λ x', forall_eq.2 $ by { rw [map_zero, norm_zero], exact zero_le_one }

@[simp] lemma polar_closure (s : set E) : polar 𝕜 (closure s) = polar 𝕜 s :=
(polar_antitone 𝕜 subset_closure).antisymm $ (polar_gc 𝕜 E).l_le $
  closure_minimal ((polar_gc 𝕜 E).le_u_l s) $
  (is_closed_polar _ _).preimage (inclusion_in_double_dual 𝕜 E).continuous

variables {𝕜}

/-- If `x'` is a dual element such that the norms `∥x' z∥` are bounded for `z ∈ s`, then a
small scalar multiple of `x'` is in `polar 𝕜 s`. -/
lemma smul_mem_polar {s : set E} {x' : dual 𝕜 E} {c : 𝕜}
  (hc : ∀ z, z ∈ s → ∥ x' z ∥ ≤ ∥c∥) : c⁻¹ • x' ∈ polar 𝕜 s :=
begin
  by_cases c_zero : c = 0, { simp [c_zero] },
  have eq : ∀ z, ∥ c⁻¹ • (x' z) ∥ = ∥ c⁻¹ ∥ * ∥ x' z ∥ := λ z, norm_smul c⁻¹ _,
  have le : ∀ z, z ∈ s → ∥ c⁻¹ • (x' z) ∥ ≤ ∥ c⁻¹ ∥ * ∥ c ∥,
  { intros z hzs,
    rw eq z,
    apply mul_le_mul (le_of_eq rfl) (hc z hzs) (norm_nonneg _) (norm_nonneg _), },
  have cancel : ∥ c⁻¹ ∥ * ∥ c ∥ = 1,
  by simp only [c_zero, norm_eq_zero, ne.def, not_false_iff,
                inv_mul_cancel, normed_field.norm_inv],
  rwa cancel at le,
end

lemma polar_ball_subset_closed_ball_div {c : 𝕜} (hc : 1 < ∥c∥) {r : ℝ} (hr : 0 < r) :
  polar 𝕜 (ball (0 : E) r) ⊆ closed_ball (0 : dual 𝕜 E) (∥c∥ / r) :=
begin
  intros x' hx',
  simp only [polar, mem_set_of_eq, mem_closed_ball_zero_iff, mem_ball_zero_iff] at *,
  have hcr : 0 < ∥c∥ / r, from div_pos (zero_lt_one.trans hc) hr,
  refine continuous_linear_map.op_norm_le_of_shell hr hcr.le hc (λ x h₁ h₂, _),
  calc ∥x' x∥ ≤ 1 : hx' _ h₂
  ... ≤ (∥c∥ / r) * ∥x∥ : (inv_pos_le_iff_one_le_mul' hcr).1 (by rwa inv_div)
end

variables (𝕜)

lemma closed_ball_inv_subset_polar_closed_ball {r : ℝ} :
  closed_ball (0 : dual 𝕜 E) r⁻¹ ⊆ polar 𝕜 (closed_ball (0 : E) r) :=
λ x' hx' x hx,
calc ∥x' x∥ ≤ ∥x'∥ * ∥x∥ : x'.le_op_norm x
... ≤ r⁻¹ * r :
  mul_le_mul (mem_closed_ball_zero_iff.1 hx') (mem_closed_ball_zero_iff.1 hx)
    (norm_nonneg _) (dist_nonneg.trans hx')
... = r / r : div_eq_inv_mul.symm
... ≤ 1 : div_self_le_one r

/-- The `polar` of closed ball in a normed space `E` is the closed ball of the dual with
inverse radius. -/
lemma polar_closed_ball
  {𝕜 : Type*} [is_R_or_C 𝕜] {E : Type*} [normed_group E] [normed_space 𝕜 E] {r : ℝ} (hr : 0 < r) :
  polar 𝕜 (closed_ball (0 : E) r) = closed_ball (0 : dual 𝕜 E) r⁻¹ :=
begin
  refine subset.antisymm _ (closed_ball_inv_subset_polar_closed_ball _),
  intros x' h,
  simp only [mem_closed_ball_zero_iff],
  refine continuous_linear_map.op_norm_le_of_ball hr (inv_nonneg.mpr hr.le) (λ z hz, _),
  simpa only [one_div] using linear_map.bound_of_ball_bound' hr 1 x'.to_linear_map h z
end

/-- Given a neighborhood `s` of the origin in a normed space `E`, the dual norms
of all elements of the polar `polar 𝕜 s` are bounded by a constant. -/
lemma bounded_polar_of_mem_nhds_zero {s : set E} (s_nhd : s ∈ 𝓝 (0 : E)) :
  bounded (polar 𝕜 s) :=
begin
  obtain ⟨a, ha⟩ : ∃ a : 𝕜, 1 < ∥a∥ := normed_field.exists_one_lt_norm 𝕜,
  obtain ⟨r, r_pos, r_ball⟩ : ∃ (r : ℝ) (hr : 0 < r), ball 0 r ⊆ s :=
    metric.mem_nhds_iff.1 s_nhd,
  exact bounded_closed_ball.mono ((polar_antitone 𝕜 r_ball).trans $
    polar_ball_subset_closed_ball_div ha r_pos)
end

end polar_sets