l3lab/ntp-mathlib huggingface dataset:
/-- A subgroup has index two if and only if there exists `a` such that for all `b`, exactly one
of `b * a` and `b` belong to `H`. -/
@[to_additive "An additive subgroup has index two if and only if there exists `a` such that
for all `b`, exactly one of `b + a` and `b` belong to `H`."]
theorem index_eq_two_iff : H.index = 2 ↔ ∃ a, ∀ b, Xor' (b * a ∈ H) (b ∈ H) := by
  simp only [index, Nat.card_eq_two_iff' ((1 : G) : G ⧸ H), ExistsUnique, inv_mem_iff,
    QuotientGroup.exists_mk, QuotientGroup.forall_mk, Ne.def, QuotientGroup.eq, mul_one,
    xor_iff_iff_not]
  refine'
    exists_congr fun a => ⟨fun ha b => ⟨fun hba hb => _, fun hb => _⟩, fun ha => ⟨_, fun b hb => _⟩⟩
  · exact ha.1 ((mul_mem_cancel_left hb).1 hba)
  · exact inv_inv b ▸ ha.2 _ (mt (inv_mem_iff (x := b)).1 hb)
  · rw [← inv_mem_iff (x := a), ← ha, inv_mul_self]
    exact one_mem _
  · 

Proof state:
case refine'_4
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
a : G
ha : ∀ (b : G), b * a ∈ H ↔ b ∉ H
b : G
hb : b ∉ H
⊢ b⁻¹ * a ∈ H

Next tactic:
rwa [ha, inv_mem_iff (x := b)]
@[to_additive]
theorem mul_mem_iff_of_index_two (h : H.index = 2) {a b : G} : a * b ∈ H ↔ (a ∈ H ↔ b ∈ H) := by
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
h : index H = 2
a b : G
⊢ a * b ∈ H ↔ (a ∈ H ↔ b ∈ H)

Next tactic:
by_cases ha : a ∈ H
@[to_additive]
theorem mul_mem_iff_of_index_two (h : H.index = 2) {a b : G} : a * b ∈ H ↔ (a ∈ H ↔ b ∈ H) := by
  by_cases ha : a ∈ H; · 

Proof state:
case pos
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
h : index H = 2
a b : G
ha : a ∈ H
⊢ a * b ∈ H ↔ (a ∈ H ↔ b ∈ H)

Next tactic:
simp only [ha, true_iff_iff, mul_mem_cancel_left ha]
@[to_additive]
theorem mul_mem_iff_of_index_two (h : H.index = 2) {a b : G} : a * b ∈ H ↔ (a ∈ H ↔ b ∈ H) := by
  by_cases ha : a ∈ H; · simp only [ha, true_iff_iff, mul_mem_cancel_left ha]
  

Proof state:
case neg
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
h : index H = 2
a b : G
ha : a ∉ H
⊢ a * b ∈ H ↔ (a ∈ H ↔ b ∈ H)

Next tactic:
by_cases hb : b ∈ H
@[to_additive]
theorem mul_mem_iff_of_index_two (h : H.index = 2) {a b : G} : a * b ∈ H ↔ (a ∈ H ↔ b ∈ H) := by
  by_cases ha : a ∈ H; · simp only [ha, true_iff_iff, mul_mem_cancel_left ha]
  by_cases hb : b ∈ H; · 

Proof state:
case pos
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
h : index H = 2
a b : G
ha : a ∉ H
hb : b ∈ H
⊢ a * b ∈ H ↔ (a ∈ H ↔ b ∈ H)

Next tactic:
simp only [hb, iff_true_iff, mul_mem_cancel_right hb]
@[to_additive]
theorem mul_mem_iff_of_index_two (h : H.index = 2) {a b : G} : a * b ∈ H ↔ (a ∈ H ↔ b ∈ H) := by
  by_cases ha : a ∈ H; · simp only [ha, true_iff_iff, mul_mem_cancel_left ha]
  by_cases hb : b ∈ H; · simp only [hb, iff_true_iff, mul_mem_cancel_right hb]
  

Proof state:
case neg
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
h : index H = 2
a b : G
ha : a ∉ H
hb : b ∉ H
⊢ a * b ∈ H ↔ (a ∈ H ↔ b ∈ H)

Next tactic:
simp only [ha, hb, iff_self_iff, iff_true_iff]
@[to_additive]
theorem mul_mem_iff_of_index_two (h : H.index = 2) {a b : G} : a * b ∈ H ↔ (a ∈ H ↔ b ∈ H) := by
  by_cases ha : a ∈ H; · simp only [ha, true_iff_iff, mul_mem_cancel_left ha]
  by_cases hb : b ∈ H; · simp only [hb, iff_true_iff, mul_mem_cancel_right hb]
  simp only [ha, hb, iff_self_iff, iff_true_iff]
  

Proof state:
case neg
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
h : index H = 2
a b : G
ha : a ∉ H
hb : b ∉ H
⊢ a * b ∈ H

Next tactic:
rcases index_eq_two_iff.1 h with ⟨c, hc⟩
@[to_additive]
theorem mul_mem_iff_of_index_two (h : H.index = 2) {a b : G} : a * b ∈ H ↔ (a ∈ H ↔ b ∈ H) := by
  by_cases ha : a ∈ H; · simp only [ha, true_iff_iff, mul_mem_cancel_left ha]
  by_cases hb : b ∈ H; · simp only [hb, iff_true_iff, mul_mem_cancel_right hb]
  simp only [ha, hb, iff_self_iff, iff_true_iff]
  rcases index_eq_two_iff.1 h with ⟨c, hc⟩
  

Proof state:
case neg.intro
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
h : index H = 2
a b : G
ha : a ∉ H
hb : b ∉ H
c : G
hc : ∀ (b : G), Xor' (b * c ∈ H) (b ∈ H)
⊢ a * b ∈ H

Next tactic:
refine' (hc _).or.resolve_left _
@[to_additive]
theorem mul_mem_iff_of_index_two (h : H.index = 2) {a b : G} : a * b ∈ H ↔ (a ∈ H ↔ b ∈ H) := by
  by_cases ha : a ∈ H; · simp only [ha, true_iff_iff, mul_mem_cancel_left ha]
  by_cases hb : b ∈ H; · simp only [hb, iff_true_iff, mul_mem_cancel_right hb]
  simp only [ha, hb, iff_self_iff, iff_true_iff]
  rcases index_eq_two_iff.1 h with ⟨c, hc⟩
  refine' (hc _).or.resolve_left _
  

Proof state:
case neg.intro
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
h : index H = 2
a b : G
ha : a ∉ H
hb : b ∉ H
c : G
hc : ∀ (b : G), Xor' (b * c ∈ H) (b ∈ H)
⊢ a * b * c ∉ H

Next tactic:
rwa [mul_assoc, mul_mem_cancel_right ((hc _).or.resolve_right hb)]
@[to_additive]
theorem mul_self_mem_of_index_two (h : H.index = 2) (a : G) : a * a ∈ H := by
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
h : index H = 2
a : G
⊢ a * a ∈ H

Next tactic:
rw [mul_mem_iff_of_index_two h]
@[to_additive (attr := simp)]
theorem relindex_top_right : H.relindex ⊤ = H.index := by
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
⊢ relindex H ⊤ = index H

Next tactic:
rw [← relindex_mul_index (show H ≤ ⊤ from le_top), index_top, mul_one]
@[to_additive (attr := simp)]
theorem relindex_bot_left : (⊥ : Subgroup G).relindex H = Nat.card H := by
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
⊢ relindex ⊥ H = Nat.card ↥H

Next tactic:
rw [relindex, bot_subgroupOf, index_bot]
@[to_additive (attr := simp)]
theorem relindex_bot_right : H.relindex ⊥ = 1 := by 

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
⊢ relindex H ⊥ = 1

Next tactic:
rw [relindex, subgroupOf_bot_eq_top, index_top]
@[to_additive (attr := simp)]
theorem relindex_self : H.relindex H = 1 := by 

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
⊢ relindex H H = 1

Next tactic:
rw [relindex, subgroupOf_self, index_top]
@[to_additive]
theorem index_ker {H} [Group H] (f : G →* H) : f.ker.index = Nat.card (Set.range f) := by
  

Proof state:
G : Type u_1
inst✝¹ : Group G
H✝ K L : Subgroup G
H : Type u_2
inst✝ : Group H
f : G →* H
⊢ index (MonoidHom.ker f) = Nat.card ↑(Set.range ⇑f)

Next tactic:
rw [← MonoidHom.comap_bot, index_comap, relindex_bot_left]
@[to_additive]
theorem index_ker {H} [Group H] (f : G →* H) : f.ker.index = Nat.card (Set.range f) := by
  rw [← MonoidHom.comap_bot, index_comap, relindex_bot_left]
  

Proof state:
G : Type u_1
inst✝¹ : Group G
H✝ K L : Subgroup G
H : Type u_2
inst✝ : Group H
f : G →* H
⊢ Nat.card ↥(MonoidHom.range f) = Nat.card ↑(Set.range ⇑f)

Next tactic:
rfl
@[to_additive]
theorem relindex_ker {H} [Group H] (f : G →* H) (K : Subgroup G) :
    f.ker.relindex K = Nat.card (f '' K) := by
  

Proof state:
G : Type u_1
inst✝¹ : Group G
H✝ K✝ L : Subgroup G
H : Type u_2
inst✝ : Group H
f : G →* H
K : Subgroup G
⊢ relindex (MonoidHom.ker f) K = Nat.card ↑(⇑f '' ↑K)

Next tactic:
rw [← MonoidHom.comap_bot, relindex_comap, relindex_bot_left]
@[to_additive]
theorem relindex_ker {H} [Group H] (f : G →* H) (K : Subgroup G) :
    f.ker.relindex K = Nat.card (f '' K) := by
  rw [← MonoidHom.comap_bot, relindex_comap, relindex_bot_left]
  

Proof state:
G : Type u_1
inst✝¹ : Group G
H✝ K✝ L : Subgroup G
H : Type u_2
inst✝ : Group H
f : G →* H
K : Subgroup G
⊢ Nat.card ↥(map f K) = Nat.card ↑(⇑f '' ↑K)

Next tactic:
rfl
@[to_additive (attr := simp) card_mul_index]
theorem card_mul_index : Nat.card H * H.index = Nat.card G := by
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
⊢ Nat.card ↥H * index H = Nat.card G

Next tactic:
rw [← relindex_bot_left, ← index_bot]
@[to_additive (attr := simp) card_mul_index]
theorem card_mul_index : Nat.card H * H.index = Nat.card G := by
  rw [← relindex_bot_left, ← index_bot]
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
⊢ relindex ⊥ H * index H = index ⊥

Next tactic:
exact relindex_mul_index bot_le
@[to_additive]
theorem nat_card_dvd_of_injective {G H : Type*} [Group G] [Group H] (f : G →* H)
    (hf : Function.Injective f) : Nat.card G ∣ Nat.card H := by
  

Proof state:
G✝ : Type u_1
inst✝² : Group G✝
H✝ K L : Subgroup G✝
G : Type u_2
H : Type u_3
inst✝¹ : Group G
inst✝ : Group H
f : G →* H
hf : Function.Injective ⇑f
⊢ Nat.card G ∣ Nat.card H

Next tactic:
rw [Nat.card_congr (MonoidHom.ofInjective hf).toEquiv]
@[to_additive]
theorem nat_card_dvd_of_injective {G H : Type*} [Group G] [Group H] (f : G →* H)
    (hf : Function.Injective f) : Nat.card G ∣ Nat.card H := by
  rw [Nat.card_congr (MonoidHom.ofInjective hf).toEquiv]
  

Proof state:
G✝ : Type u_1
inst✝² : Group G✝
H✝ K L : Subgroup G✝
G : Type u_2
H : Type u_3
inst✝¹ : Group G
inst✝ : Group H
f : G →* H
hf : Function.Injective ⇑f
⊢ Nat.card ↥(MonoidHom.range f) ∣ Nat.card H

Next tactic:
exact Dvd.intro f.range.index f.range.card_mul_index
@[to_additive]
theorem nat_card_dvd_of_surjective {G H : Type*} [Group G] [Group H] (f : G →* H)
    (hf : Function.Surjective f) : Nat.card H ∣ Nat.card G := by
  

Proof state:
G✝ : Type u_1
inst✝² : Group G✝
H✝ K L : Subgroup G✝
G : Type u_2
H : Type u_3
inst✝¹ : Group G
inst✝ : Group H
f : G →* H
hf : Function.Surjective ⇑f
⊢ Nat.card H ∣ Nat.card G

Next tactic:
rw [← Nat.card_congr (QuotientGroup.quotientKerEquivOfSurjective f hf).toEquiv]
@[to_additive]
theorem nat_card_dvd_of_surjective {G H : Type*} [Group G] [Group H] (f : G →* H)
    (hf : Function.Surjective f) : Nat.card H ∣ Nat.card G := by
  rw [← Nat.card_congr (QuotientGroup.quotientKerEquivOfSurjective f hf).toEquiv]
  

Proof state:
G✝ : Type u_1
inst✝² : Group G✝
H✝ K L : Subgroup G✝
G : Type u_2
H : Type u_3
inst✝¹ : Group G
inst✝ : Group H
f : G →* H
hf : Function.Surjective ⇑f
⊢ Nat.card (G ⧸ MonoidHom.ker f) ∣ Nat.card G

Next tactic:
exact Dvd.intro_left (Nat.card f.ker) f.ker.card_mul_index
@[to_additive]
theorem card_dvd_of_surjective {G H : Type*} [Group G] [Group H] [Fintype G] [Fintype H]
    (f : G →* H) (hf : Function.Surjective f) : Fintype.card H ∣ Fintype.card G := by
  

Proof state:
G✝ : Type u_1
inst✝⁴ : Group G✝
H✝ K L : Subgroup G✝
G : Type u_2
H : Type u_3
inst✝³ : Group G
inst✝² : Group H
inst✝¹ : Fintype G
inst✝ : Fintype H
f : G →* H
hf : Function.Surjective ⇑f
⊢ Fintype.card H ∣ Fintype.card G

Next tactic:
simp only [← Nat.card_eq_fintype_card, nat_card_dvd_of_surjective f hf]
@[to_additive]
theorem index_map {G' : Type*} [Group G'] (f : G →* G') :
    (H.map f).index = (H ⊔ f.ker).index * f.range.index := by
  

Proof state:
G : Type u_1
inst✝¹ : Group G
H K L : Subgroup G
G' : Type u_2
inst✝ : Group G'
f : G →* G'
⊢ index (map f H) = index (H ⊔ MonoidHom.ker f) * index (MonoidHom.range f)

Next tactic:
rw [← comap_map_eq, index_comap, relindex_mul_index (H.map_le_range f)]
@[to_additive]
theorem index_map_dvd {G' : Type*} [Group G'] {f : G →* G'} (hf : Function.Surjective f) :
    (H.map f).index ∣ H.index := by
  

Proof state:
G : Type u_1
inst✝¹ : Group G
H K L : Subgroup G
G' : Type u_2
inst✝ : Group G'
f : G →* G'
hf : Function.Surjective ⇑f
⊢ index (map f H) ∣ index H

Next tactic:
rw [index_map, f.range_top_of_surjective hf, index_top, mul_one]
@[to_additive]
theorem index_map_dvd {G' : Type*} [Group G'] {f : G →* G'} (hf : Function.Surjective f) :
    (H.map f).index ∣ H.index := by
  rw [index_map, f.range_top_of_surjective hf, index_top, mul_one]
  

Proof state:
G : Type u_1
inst✝¹ : Group G
H K L : Subgroup G
G' : Type u_2
inst✝ : Group G'
f : G →* G'
hf : Function.Surjective ⇑f
⊢ index (H ⊔ MonoidHom.ker f) ∣ index H

Next tactic:
exact index_dvd_of_le le_sup_left
@[to_additive]
theorem dvd_index_map {G' : Type*} [Group G'] {f : G →* G'} (hf : f.ker ≤ H) :
    H.index ∣ (H.map f).index := by
  

Proof state:
G : Type u_1
inst✝¹ : Group G
H K L : Subgroup G
G' : Type u_2
inst✝ : Group G'
f : G →* G'
hf : MonoidHom.ker f ≤ H
⊢ index H ∣ index (map f H)

Next tactic:
rw [index_map, sup_of_le_left hf]
@[to_additive]
theorem dvd_index_map {G' : Type*} [Group G'] {f : G →* G'} (hf : f.ker ≤ H) :
    H.index ∣ (H.map f).index := by
  rw [index_map, sup_of_le_left hf]
  

Proof state:
G : Type u_1
inst✝¹ : Group G
H K L : Subgroup G
G' : Type u_2
inst✝ : Group G'
f : G →* G'
hf : MonoidHom.ker f ≤ H
⊢ index H ∣ index H * index (MonoidHom.range f)

Next tactic:
apply dvd_mul_right
@[to_additive index_mul_card]
theorem index_mul_card [Fintype G] [hH : Fintype H] :
    H.index * Fintype.card H = Fintype.card G := by
  

Proof state:
G : Type u_1
inst✝¹ : Group G
H K L : Subgroup G
inst✝ : Fintype G
hH : Fintype ↥H
⊢ index H * Fintype.card ↥H = Fintype.card G

Next tactic:
rw [← relindex_bot_left_eq_card, ← index_bot_eq_card, mul_comm]
@[to_additive index_mul_card]
theorem index_mul_card [Fintype G] [hH : Fintype H] :
    H.index * Fintype.card H = Fintype.card G := by
  rw [← relindex_bot_left_eq_card, ← index_bot_eq_card, mul_comm];
    

Proof state:
G : Type u_1
inst✝¹ : Group G
H K L : Subgroup G
inst✝ : Fintype G
hH : Fintype ↥H
⊢ relindex ⊥ H * index H = index ⊥

Next tactic:
exact relindex_mul_index bot_le
@[to_additive]
theorem index_dvd_card [Fintype G] : H.index ∣ Fintype.card G := by
  

Proof state:
G : Type u_1
inst✝¹ : Group G
H K L : Subgroup G
inst✝ : Fintype G
⊢ index H ∣ Fintype.card G

Next tactic:
classical exact ⟨Fintype.card H, H.index_mul_card.symm⟩
@[to_additive]
theorem index_dvd_card [Fintype G] : H.index ∣ Fintype.card G := by
  classical 

Proof state:
G : Type u_1
inst✝¹ : Group G
H K L : Subgroup G
inst✝ : Fintype G
⊢ index H ∣ Fintype.card G

Next tactic:
exact ⟨Fintype.card H, H.index_mul_card.symm⟩
@[to_additive]
theorem relindex_inf_ne_zero (hH : H.relindex L ≠ 0) (hK : K.relindex L ≠ 0) :
    (H ⊓ K).relindex L ≠ 0 := by
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
hH : relindex H L ≠ 0
hK : relindex K L ≠ 0
⊢ relindex (H ⊓ K) L ≠ 0

Next tactic:
replace hH : H.relindex (K ⊓ L) ≠ 0 := mt (relindex_eq_zero_of_le_right inf_le_right) hH
@[to_additive]
theorem relindex_inf_ne_zero (hH : H.relindex L ≠ 0) (hK : K.relindex L ≠ 0) :
    (H ⊓ K).relindex L ≠ 0 := by
  replace hH : H.relindex (K ⊓ L) ≠ 0 := mt (relindex_eq_zero_of_le_right inf_le_right) hH
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
hK : relindex K L ≠ 0
hH : relindex H (K ⊓ L) ≠ 0
⊢ relindex (H ⊓ K) L ≠ 0

Next tactic:
rw [← inf_relindex_right] at hH hK ⊢
@[to_additive]
theorem relindex_inf_ne_zero (hH : H.relindex L ≠ 0) (hK : K.relindex L ≠ 0) :
    (H ⊓ K).relindex L ≠ 0 := by
  replace hH : H.relindex (K ⊓ L) ≠ 0 := mt (relindex_eq_zero_of_le_right inf_le_right) hH
  rw [← inf_relindex_right] at hH hK ⊢
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
hK : relindex (K ⊓ L) L ≠ 0
hH : relindex (H ⊓ (K ⊓ L)) (K ⊓ L) ≠ 0
⊢ relindex (H ⊓ K ⊓ L) L ≠ 0

Next tactic:
rw [inf_assoc]
@[to_additive]
theorem relindex_inf_ne_zero (hH : H.relindex L ≠ 0) (hK : K.relindex L ≠ 0) :
    (H ⊓ K).relindex L ≠ 0 := by
  replace hH : H.relindex (K ⊓ L) ≠ 0 := mt (relindex_eq_zero_of_le_right inf_le_right) hH
  rw [← inf_relindex_right] at hH hK ⊢
  rw [inf_assoc]
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
hK : relindex (K ⊓ L) L ≠ 0
hH : relindex (H ⊓ (K ⊓ L)) (K ⊓ L) ≠ 0
⊢ relindex (H ⊓ (K ⊓ L)) L ≠ 0

Next tactic:
exact relindex_ne_zero_trans hH hK
@[to_additive]
theorem index_inf_ne_zero (hH : H.index ≠ 0) (hK : K.index ≠ 0) : (H ⊓ K).index ≠ 0 := by
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
hH : index H ≠ 0
hK : index K ≠ 0
⊢ index (H ⊓ K) ≠ 0

Next tactic:
rw [← relindex_top_right] at hH hK ⊢
@[to_additive]
theorem index_inf_ne_zero (hH : H.index ≠ 0) (hK : K.index ≠ 0) : (H ⊓ K).index ≠ 0 := by
  rw [← relindex_top_right] at hH hK ⊢
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
hH : relindex H ⊤ ≠ 0
hK : relindex K ⊤ ≠ 0
⊢ relindex (H ⊓ K) ⊤ ≠ 0

Next tactic:
exact relindex_inf_ne_zero hH hK
@[to_additive]
theorem relindex_inf_le : (H ⊓ K).relindex L ≤ H.relindex L * K.relindex L := by
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
⊢ relindex (H ⊓ K) L ≤ relindex H L * relindex K L

Next tactic:
by_cases h : H.relindex L = 0
@[to_additive]
theorem relindex_inf_le : (H ⊓ K).relindex L ≤ H.relindex L * K.relindex L := by
  by_cases h : H.relindex L = 0
  · 

Proof state:
case pos
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
h : relindex H L = 0
⊢ relindex (H ⊓ K) L ≤ relindex H L * relindex K L

Next tactic:
exact (le_of_eq (relindex_eq_zero_of_le_left inf_le_left h)).trans (zero_le _)
@[to_additive]
theorem relindex_inf_le : (H ⊓ K).relindex L ≤ H.relindex L * K.relindex L := by
  by_cases h : H.relindex L = 0
  · exact (le_of_eq (relindex_eq_zero_of_le_left inf_le_left h)).trans (zero_le _)
  

Proof state:
case neg
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
h : ¬relindex H L = 0
⊢ relindex (H ⊓ K) L ≤ relindex H L * relindex K L

Next tactic:
rw [← inf_relindex_right, inf_assoc, ← relindex_mul_relindex _ _ L inf_le_right inf_le_right,
    inf_relindex_right, inf_relindex_right]
@[to_additive]
theorem relindex_inf_le : (H ⊓ K).relindex L ≤ H.relindex L * K.relindex L := by
  by_cases h : H.relindex L = 0
  · exact (le_of_eq (relindex_eq_zero_of_le_left inf_le_left h)).trans (zero_le _)
  rw [← inf_relindex_right, inf_assoc, ← relindex_mul_relindex _ _ L inf_le_right inf_le_right,
    inf_relindex_right, inf_relindex_right]
  

Proof state:
case neg
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
h : ¬relindex H L = 0
⊢ relindex H (K ⊓ L) * relindex K L ≤ relindex H L * relindex K L

Next tactic:
exact mul_le_mul_right' (relindex_le_of_le_right inf_le_right h) (K.relindex L)
@[to_additive]
theorem index_inf_le : (H ⊓ K).index ≤ H.index * K.index := by
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
⊢ index (H ⊓ K) ≤ index H * index K

Next tactic:
simp_rw [← relindex_top_right, relindex_inf_le]
@[to_additive]
theorem index_iInf_ne_zero {ι : Type*} [Finite ι] {f : ι → Subgroup G}
    (hf : ∀ i, (f i).index ≠ 0) : (⨅ i, f i).index ≠ 0 := by
  

Proof state:
G : Type u_1
inst✝¹ : Group G
H K L : Subgroup G
ι : Type u_2
inst✝ : Finite ι
f : ι → Subgroup G
hf : ∀ (i : ι), index (f i) ≠ 0
⊢ index (⨅ i, f i) ≠ 0

Next tactic:
simp_rw [← relindex_top_right] at hf ⊢
@[to_additive]
theorem index_iInf_ne_zero {ι : Type*} [Finite ι] {f : ι → Subgroup G}
    (hf : ∀ i, (f i).index ≠ 0) : (⨅ i, f i).index ≠ 0 := by
  simp_rw [← relindex_top_right] at hf ⊢
  

Proof state:
G : Type u_1
inst✝¹ : Group G
H K L : Subgroup G
ι : Type u_2
inst✝ : Finite ι
f : ι → Subgroup G
hf : ∀ (i : ι), relindex (f i) ⊤ ≠ 0
⊢ relindex (⨅ i, f i) ⊤ ≠ 0

Next tactic:
exact relindex_iInf_ne_zero hf
@[to_additive]
theorem index_iInf_le {ι : Type*} [Fintype ι] (f : ι → Subgroup G) :
    (⨅ i, f i).index ≤ ∏ i, (f i).index := by 

Proof state:
G : Type u_1
inst✝¹ : Group G
H K L : Subgroup G
ι : Type u_2
inst✝ : Fintype ι
f : ι → Subgroup G
⊢ index (⨅ i, f i) ≤ ∏ i : ι, index (f i)

Next tactic:
simp_rw [← relindex_top_right, relindex_iInf_le]
@[to_additive]
theorem index_ne_zero_of_finite [hH : Finite (G ⧸ H)] : H.index ≠ 0 := by
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
hH : Finite (G ⧸ H)
⊢ index H ≠ 0

Next tactic:
cases nonempty_fintype (G ⧸ H)
@[to_additive]
theorem index_ne_zero_of_finite [hH : Finite (G ⧸ H)] : H.index ≠ 0 := by
  cases nonempty_fintype (G ⧸ H)
  

Proof state:
case intro
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
hH : Finite (G ⧸ H)
val✝ : Fintype (G ⧸ H)
⊢ index H ≠ 0

Next tactic:
rw [index_eq_card]
@[to_additive]
theorem index_ne_zero_of_finite [hH : Finite (G ⧸ H)] : H.index ≠ 0 := by
  cases nonempty_fintype (G ⧸ H)
  rw [index_eq_card]
  

Proof state:
case intro
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
hH : Finite (G ⧸ H)
val✝ : Fintype (G ⧸ H)
⊢ Fintype.card (G ⧸ H) ≠ 0

Next tactic:
exact Fintype.card_ne_zero
instance finiteIndex_normalCore [H.FiniteIndex] : H.normalCore.FiniteIndex := by
  

Proof state:
G : Type u_1
inst✝¹ : Group G
H K L : Subgroup G
inst✝ : FiniteIndex H
⊢ FiniteIndex (normalCore H)

Next tactic:
rw [normalCore_eq_ker]
instance finiteIndex_normalCore [H.FiniteIndex] : H.normalCore.FiniteIndex := by
  rw [normalCore_eq_ker]
  

Proof state:
G : Type u_1
inst✝¹ : Group G
H K L : Subgroup G
inst✝ : FiniteIndex H
⊢ FiniteIndex (MonoidHom.ker (MulAction.toPermHom G (G ⧸ H)))

Next tactic:
infer_instance
instance finiteIndex_center [Finite (commutatorSet G)] [Group.FG G] : FiniteIndex (center G) := by
  

Proof state:
G : Type u_1
inst✝² : Group G
H K L : Subgroup G
inst✝¹ : Finite ↑(commutatorSet G)
inst✝ : Group.FG G
⊢ FiniteIndex (center G)

Next tactic:
obtain ⟨S, -, hS⟩ := Group.rank_spec G
instance finiteIndex_center [Finite (commutatorSet G)] [Group.FG G] : FiniteIndex (center G) := by
  obtain ⟨S, -, hS⟩ := Group.rank_spec G
  

Proof state:
case intro.intro
G : Type u_1
inst✝² : Group G
H K L : Subgroup G
inst✝¹ : Finite ↑(commutatorSet G)
inst✝ : Group.FG G
S : Finset G
hS : closure ↑S = ⊤
⊢ FiniteIndex (center G)

Next tactic:
exact ⟨mt (Finite.card_eq_zero_of_embedding (quotientCenterEmbedding hS)) Finite.card_pos.ne'⟩
theorem index_center_le_pow [Finite (commutatorSet G)] [Group.FG G] :
    (center G).index ≤ Nat.card (commutatorSet G) ^ Group.rank G := by
  

Proof state:
G : Type u_1
inst✝² : Group G
H K L : Subgroup G
inst✝¹ : Finite ↑(commutatorSet G)
inst✝ : Group.FG G
⊢ index (center G) ≤ Nat.card ↑(commutatorSet G) ^ Group.rank G

Next tactic:
obtain ⟨S, hS1, hS2⟩ := Group.rank_spec G
theorem index_center_le_pow [Finite (commutatorSet G)] [Group.FG G] :
    (center G).index ≤ Nat.card (commutatorSet G) ^ Group.rank G := by
  obtain ⟨S, hS1, hS2⟩ := Group.rank_spec G
  

Proof state:
case intro.intro
G : Type u_1
inst✝² : Group G
H K L : Subgroup G
inst✝¹ : Finite ↑(commutatorSet G)
inst✝ : Group.FG G
S : Finset G
hS1 : Finset.card S = Group.rank G
hS2 : closure ↑S = ⊤
⊢ index (center G) ≤ Nat.card ↑(commutatorSet G) ^ Group.rank G

Next tactic:
rw [← hS1, ← Fintype.card_coe, ← Nat.card_eq_fintype_card, ← Finset.coe_sort_coe, ← Nat.card_fun]
theorem index_center_le_pow [Finite (commutatorSet G)] [Group.FG G] :
    (center G).index ≤ Nat.card (commutatorSet G) ^ Group.rank G := by
  obtain ⟨S, hS1, hS2⟩ := Group.rank_spec G
  rw [← hS1, ← Fintype.card_coe, ← Nat.card_eq_fintype_card, ← Finset.coe_sort_coe, ← Nat.card_fun]
  

Proof state:
case intro.intro
G : Type u_1
inst✝² : Group G
H K L : Subgroup G
inst✝¹ : Finite ↑(commutatorSet G)
inst✝ : Group.FG G
S : Finset G
hS1 : Finset.card S = Group.rank G
hS2 : closure ↑S = ⊤
⊢ index (center G) ≤ Nat.card (↑↑S → ↑(commutatorSet G))

Next tactic:
exact Finite.card_le_of_embedding (quotientCenterEmbedding hS2)
instance (priority := 100) reflectsIsomorphisms_of_full_and_faithful
    (F : C ⥤ D) [Full F] [Faithful F] :
    ReflectsIsomorphisms F where
  reflects f i :=
    ⟨⟨F.preimage (inv (F.map f)), ⟨F.map_injective (by 

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
E : Type u₃
inst✝² : Category.{v₃, u₃} E
F : C ⥤ D
inst✝¹ : Full F
inst✝ : Faithful F
A✝ B✝ : C
f : A✝ ⟶ B✝
i : IsIso (F.map f)
⊢ F.map (f ≫ F.preimage (inv (F.map f))) = F.map (𝟙 A✝)

Next tactic:
simp
instance (priority := 100) reflectsIsomorphisms_of_full_and_faithful
    (F : C ⥤ D) [Full F] [Faithful F] :
    ReflectsIsomorphisms F where
  reflects f i :=
    ⟨⟨F.preimage (inv (F.map f)), ⟨F.map_injective (by simp), F.map_injective (by 

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
E : Type u₃
inst✝² : Category.{v₃, u₃} E
F : C ⥤ D
inst✝¹ : Full F
inst✝ : Faithful F
A✝ B✝ : C
f : A✝ ⟶ B✝
i : IsIso (F.map f)
⊢ F.map (F.preimage (inv (F.map f)) ≫ f) = F.map (𝟙 B✝)

Next tactic:
simp
instance reflectsIsomorphisms_of_comp (F : C ⥤ D) (G : D ⥤ E)
    [ReflectsIsomorphisms F] [ReflectsIsomorphisms G] :
    ReflectsIsomorphisms (F ⋙ G) :=
  ⟨fun f (hf : IsIso (G.map _)) => by
    

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
E : Type u₃
inst✝² : Category.{v₃, u₃} E
F : C ⥤ D
G : D ⥤ E
inst✝¹ : ReflectsIsomorphisms F
inst✝ : ReflectsIsomorphisms G
A✝ B✝ : C
f : A✝ ⟶ B✝
hf : IsIso (G.map (F.map f))
⊢ IsIso f

Next tactic:
haveI := isIso_of_reflects_iso (F.map f) G