l3lab/ntp-mathlib huggingface dataset:
/-- Given an object `X : C`, the Čech nerve of the hom to the terminal object `X ⟶ ⊤_ C` is
naturally isomorphic to a simplicial object sending `[n]` to `Xⁿ⁺¹` (when `C` is `G-Set`, this is
`EG`, the universal cover of the classifying space of `G`. -/
def iso (X : C) : (Arrow.mk (terminal.from X)).cechNerve ≅ cechNerveTerminalFrom X :=
  NatIso.ofComponents (fun m => wideCospan.limitIsoPi _ _) (fun {m n} f => by
    dsimp only [cechNerveTerminalFrom, Arrow.cechNerve]
    ext ⟨j⟩
    simp only [Category.assoc, limit.lift_π, Fan.mk_π_app]
    

Proof state:
case h.mk
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasTerminal C
ι : Type w
inst✝ : HasFiniteProducts C
X : C
m n : SimplexCategoryᵒᵖ
f : m ⟶ n
j : ℕ
isLt✝ : j < SimplexCategory.len n.unop + 1
⊢ WidePullback.lift (WidePullback.base fun x => (Arrow.mk (terminal.from X)).hom)
        (fun i =>
          WidePullback.π (fun x => (Arrow.mk (terminal.from X)).hom) ((SimplexCategory.Hom.toOrderHom f.unop) i))
        (_ :
          ∀ (j : Fin (SimplexCategory.len n.unop + 1)),
            WidePullback.π (fun x => (Arrow.mk (terminal.from X)).hom) ((SimplexCategory.Hom.toOrderHom f.unop) j) ≫
                (Arrow.mk (terminal.from X)).hom =
              WidePullback.base fun x => (Arrow.mk (terminal.from X)).hom) ≫
      (wideCospan.limitIsoPi (Fin (SimplexCategory.len n.unop + 1)) (Arrow.mk (terminal.from X)).left).hom ≫
        Pi.π (fun x => X) { val := j, isLt := isLt✝ } =
    (wideCospan.limitIsoPi (Fin (SimplexCategory.len m.unop + 1)) (Arrow.mk (terminal.from X)).left).hom ≫
      Pi.π (fun x => X) ((SimplexCategory.Hom.toOrderHom f.unop) { val := j, isLt := isLt✝ })

Next tactic:
erw [wideCospan.limitIsoPi_hom_comp_pi,
      wideCospan.limitIsoPi_hom_comp_pi, limit.lift_π]
/-- Given an object `X : C`, the Čech nerve of the hom to the terminal object `X ⟶ ⊤_ C` is
naturally isomorphic to a simplicial object sending `[n]` to `Xⁿ⁺¹` (when `C` is `G-Set`, this is
`EG`, the universal cover of the classifying space of `G`. -/
def iso (X : C) : (Arrow.mk (terminal.from X)).cechNerve ≅ cechNerveTerminalFrom X :=
  NatIso.ofComponents (fun m => wideCospan.limitIsoPi _ _) (fun {m n} f => by
    dsimp only [cechNerveTerminalFrom, Arrow.cechNerve]
    ext ⟨j⟩
    simp only [Category.assoc, limit.lift_π, Fan.mk_π_app]
    erw [wideCospan.limitIsoPi_hom_comp_pi,
      wideCospan.limitIsoPi_hom_comp_pi, limit.lift_π]
    

Proof state:
case h.mk
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasTerminal C
ι : Type w
inst✝ : HasFiniteProducts C
X : C
m n : SimplexCategoryᵒᵖ
f : m ⟶ n
j : ℕ
isLt✝ : j < SimplexCategory.len n.unop + 1
⊢ (WidePullbackShape.mkCone (WidePullback.base fun x => (Arrow.mk (terminal.from X)).hom)
            (fun i =>
              WidePullback.π (fun x => (Arrow.mk (terminal.from X)).hom) ((SimplexCategory.Hom.toOrderHom f.unop) i))
            (_ :
              ∀ (j : Fin (SimplexCategory.len n.unop + 1)),
                WidePullback.π (fun x => (Arrow.mk (terminal.from X)).hom) ((SimplexCategory.Hom.toOrderHom f.unop) j) ≫
                    (Arrow.mk (terminal.from X)).hom =
                  WidePullback.base fun x => (Arrow.mk (terminal.from X)).hom)).π.app
      (some { val := j, isLt := isLt✝ }) =
    WidePullback.π (fun x => terminal.from X) ((SimplexCategory.Hom.toOrderHom f.unop) { val := j, isLt := isLt✝ })

Next tactic:
rfl
@[to_additive]
theorem index_comap_of_surjective {G' : Type*} [Group G'] {f : G' →* G}
    (hf : Function.Surjective f) : (H.comap 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 (comap f H) = index H

Next tactic:
letI := QuotientGroup.leftRel H
@[to_additive]
theorem index_comap_of_surjective {G' : Type*} [Group G'] {f : G' →* G}
    (hf : Function.Surjective f) : (H.comap f).index = H.index := by
  letI := QuotientGroup.leftRel H
  

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
this : Setoid G := QuotientGroup.leftRel H
⊢ index (comap f H) = index H

Next tactic:
letI := QuotientGroup.leftRel (H.comap f)
@[to_additive]
theorem index_comap_of_surjective {G' : Type*} [Group G'] {f : G' →* G}
    (hf : Function.Surjective f) : (H.comap f).index = H.index := by
  letI := QuotientGroup.leftRel H
  letI := QuotientGroup.leftRel (H.comap f)
  

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
this✝ : Setoid G := QuotientGroup.leftRel H
this : Setoid G' := QuotientGroup.leftRel (comap f H)
⊢ index (comap f H) = index H

Next tactic:
have key : ∀ x y : G', Setoid.r x y ↔ Setoid.r (f x) (f y) := by
    simp only [QuotientGroup.leftRel_apply]
    exact fun x y => iff_of_eq (congr_arg (· ∈ H) (by rw [f.map_mul, f.map_inv]))
@[to_additive]
theorem index_comap_of_surjective {G' : Type*} [Group G'] {f : G' →* G}
    (hf : Function.Surjective f) : (H.comap f).index = H.index := by
  letI := QuotientGroup.leftRel H
  letI := QuotientGroup.leftRel (H.comap f)
  have key : ∀ x y : G', Setoid.r x y ↔ Setoid.r (f x) (f y) := 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
this✝ : Setoid G := QuotientGroup.leftRel H
this : Setoid G' := QuotientGroup.leftRel (comap f H)
⊢ ∀ (x y : G'), Setoid.r x y ↔ Setoid.r (f x) (f y)

Next tactic:
simp only [QuotientGroup.leftRel_apply]
@[to_additive]
theorem index_comap_of_surjective {G' : Type*} [Group G'] {f : G' →* G}
    (hf : Function.Surjective f) : (H.comap f).index = H.index := by
  letI := QuotientGroup.leftRel H
  letI := QuotientGroup.leftRel (H.comap f)
  have key : ∀ x y : G', Setoid.r x y ↔ Setoid.r (f x) (f y) := by
    simp only [QuotientGroup.leftRel_apply]
    

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
this✝ : Setoid G := QuotientGroup.leftRel H
this : Setoid G' := QuotientGroup.leftRel (comap f H)
⊢ ∀ (x y : G'), x⁻¹ * y ∈ comap f H ↔ (f x)⁻¹ * f y ∈ H

Next tactic:
exact fun x y => iff_of_eq (congr_arg (· ∈ H) (by rw [f.map_mul, f.map_inv]))
@[to_additive]
theorem index_comap_of_surjective {G' : Type*} [Group G'] {f : G' →* G}
    (hf : Function.Surjective f) : (H.comap f).index = H.index := by
  letI := QuotientGroup.leftRel H
  letI := QuotientGroup.leftRel (H.comap f)
  have key : ∀ x y : G', Setoid.r x y ↔ Setoid.r (f x) (f y) := by
    simp only [QuotientGroup.leftRel_apply]
    exact fun x y => iff_of_eq (congr_arg (· ∈ H) (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
this✝ : Setoid G := QuotientGroup.leftRel H
this : Setoid G' := QuotientGroup.leftRel (comap f H)
x y : G'
⊢ f (x⁻¹ * y) = (f x)⁻¹ * f y

Next tactic:
rw [f.map_mul, f.map_inv]
@[to_additive]
theorem index_comap_of_surjective {G' : Type*} [Group G'] {f : G' →* G}
    (hf : Function.Surjective f) : (H.comap f).index = H.index := by
  letI := QuotientGroup.leftRel H
  letI := QuotientGroup.leftRel (H.comap f)
  have key : ∀ x y : G', Setoid.r x y ↔ Setoid.r (f x) (f y) := by
    simp only [QuotientGroup.leftRel_apply]
    exact fun x y => iff_of_eq (congr_arg (· ∈ H) (by rw [f.map_mul, f.map_inv]))
  

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
this✝ : Setoid G := QuotientGroup.leftRel H
this : Setoid G' := QuotientGroup.leftRel (comap f H)
key : ∀ (x y : G'), Setoid.r x y ↔ Setoid.r (f x) (f y)
⊢ index (comap f H) = index H

Next tactic:
refine' Cardinal.toNat_congr (Equiv.ofBijective (Quotient.map' f fun x y => (key x y).mp) ⟨_, _⟩)
@[to_additive]
theorem index_comap_of_surjective {G' : Type*} [Group G'] {f : G' →* G}
    (hf : Function.Surjective f) : (H.comap f).index = H.index := by
  letI := QuotientGroup.leftRel H
  letI := QuotientGroup.leftRel (H.comap f)
  have key : ∀ x y : G', Setoid.r x y ↔ Setoid.r (f x) (f y) := by
    simp only [QuotientGroup.leftRel_apply]
    exact fun x y => iff_of_eq (congr_arg (· ∈ H) (by rw [f.map_mul, f.map_inv]))
  refine' Cardinal.toNat_congr (Equiv.ofBijective (Quotient.map' f fun x y => (key x y).mp) ⟨_, _⟩)
  · 

Proof state:
case refine'_1
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
this✝ : Setoid G := QuotientGroup.leftRel H
this : Setoid G' := QuotientGroup.leftRel (comap f H)
key : ∀ (x y : G'), Setoid.r x y ↔ Setoid.r (f x) (f y)
⊢ Function.Injective (Quotient.map' ⇑f (_ : ∀ (x y : G'), Setoid.r x y → Setoid.r (f x) (f y)))

Next tactic:
simp_rw [← Quotient.eq''] at key
@[to_additive]
theorem index_comap_of_surjective {G' : Type*} [Group G'] {f : G' →* G}
    (hf : Function.Surjective f) : (H.comap f).index = H.index := by
  letI := QuotientGroup.leftRel H
  letI := QuotientGroup.leftRel (H.comap f)
  have key : ∀ x y : G', Setoid.r x y ↔ Setoid.r (f x) (f y) := by
    simp only [QuotientGroup.leftRel_apply]
    exact fun x y => iff_of_eq (congr_arg (· ∈ H) (by rw [f.map_mul, f.map_inv]))
  refine' Cardinal.toNat_congr (Equiv.ofBijective (Quotient.map' f fun x y => (key x y).mp) ⟨_, _⟩)
  · simp_rw [← Quotient.eq''] at key
    

Proof state:
case refine'_1
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
this✝ : Setoid G := QuotientGroup.leftRel H
this : Setoid G' := QuotientGroup.leftRel (comap f H)
key✝ : ∀ (x y : G'), Setoid.r x y ↔ Setoid.r (f x) (f y)
key : ∀ (x y : G'), Quotient.mk'' x = Quotient.mk'' y ↔ Quotient.mk'' (f x) = Quotient.mk'' (f y)
⊢ Function.Injective (Quotient.map' ⇑f (_ : ∀ (x y : G'), Setoid.r x y → Setoid.r (f x) (f y)))

Next tactic:
refine' Quotient.ind' fun x => _
@[to_additive]
theorem index_comap_of_surjective {G' : Type*} [Group G'] {f : G' →* G}
    (hf : Function.Surjective f) : (H.comap f).index = H.index := by
  letI := QuotientGroup.leftRel H
  letI := QuotientGroup.leftRel (H.comap f)
  have key : ∀ x y : G', Setoid.r x y ↔ Setoid.r (f x) (f y) := by
    simp only [QuotientGroup.leftRel_apply]
    exact fun x y => iff_of_eq (congr_arg (· ∈ H) (by rw [f.map_mul, f.map_inv]))
  refine' Cardinal.toNat_congr (Equiv.ofBijective (Quotient.map' f fun x y => (key x y).mp) ⟨_, _⟩)
  · simp_rw [← Quotient.eq''] at key
    refine' Quotient.ind' fun x => _
    

Proof state:
case refine'_1
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
this✝ : Setoid G := QuotientGroup.leftRel H
this : Setoid G' := QuotientGroup.leftRel (comap f H)
key✝ : ∀ (x y : G'), Setoid.r x y ↔ Setoid.r (f x) (f y)
key : ∀ (x y : G'), Quotient.mk'' x = Quotient.mk'' y ↔ Quotient.mk'' (f x) = Quotient.mk'' (f y)
x : G'
⊢ ∀ ⦃a₂ : G' ⧸ comap f H⦄,
    Quotient.map' ⇑f (_ : ∀ (x y : G'), Setoid.r x y → Setoid.r (f x) (f y)) (Quotient.mk'' x) =
        Quotient.map' ⇑f (_ : ∀ (x y : G'), Setoid.r x y → Setoid.r (f x) (f y)) a₂ →
      Quotient.mk'' x = a₂

Next tactic:
refine' Quotient.ind' fun y => _
@[to_additive]
theorem index_comap_of_surjective {G' : Type*} [Group G'] {f : G' →* G}
    (hf : Function.Surjective f) : (H.comap f).index = H.index := by
  letI := QuotientGroup.leftRel H
  letI := QuotientGroup.leftRel (H.comap f)
  have key : ∀ x y : G', Setoid.r x y ↔ Setoid.r (f x) (f y) := by
    simp only [QuotientGroup.leftRel_apply]
    exact fun x y => iff_of_eq (congr_arg (· ∈ H) (by rw [f.map_mul, f.map_inv]))
  refine' Cardinal.toNat_congr (Equiv.ofBijective (Quotient.map' f fun x y => (key x y).mp) ⟨_, _⟩)
  · simp_rw [← Quotient.eq''] at key
    refine' Quotient.ind' fun x => _
    refine' Quotient.ind' fun y => _
    

Proof state:
case refine'_1
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
this✝ : Setoid G := QuotientGroup.leftRel H
this : Setoid G' := QuotientGroup.leftRel (comap f H)
key✝ : ∀ (x y : G'), Setoid.r x y ↔ Setoid.r (f x) (f y)
key : ∀ (x y : G'), Quotient.mk'' x = Quotient.mk'' y ↔ Quotient.mk'' (f x) = Quotient.mk'' (f y)
x y : G'
⊢ Quotient.map' ⇑f (_ : ∀ (x y : G'), Setoid.r x y → Setoid.r (f x) (f y)) (Quotient.mk'' x) =
      Quotient.map' ⇑f (_ : ∀ (x y : G'), Setoid.r x y → Setoid.r (f x) (f y)) (Quotient.mk'' y) →
    Quotient.mk'' x = Quotient.mk'' y

Next tactic:
exact (key x y).mpr
@[to_additive]
theorem index_comap_of_surjective {G' : Type*} [Group G'] {f : G' →* G}
    (hf : Function.Surjective f) : (H.comap f).index = H.index := by
  letI := QuotientGroup.leftRel H
  letI := QuotientGroup.leftRel (H.comap f)
  have key : ∀ x y : G', Setoid.r x y ↔ Setoid.r (f x) (f y) := by
    simp only [QuotientGroup.leftRel_apply]
    exact fun x y => iff_of_eq (congr_arg (· ∈ H) (by rw [f.map_mul, f.map_inv]))
  refine' Cardinal.toNat_congr (Equiv.ofBijective (Quotient.map' f fun x y => (key x y).mp) ⟨_, _⟩)
  · simp_rw [← Quotient.eq''] at key
    refine' Quotient.ind' fun x => _
    refine' Quotient.ind' fun y => _
    exact (key x y).mpr
  · 

Proof state:
case refine'_2
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
this✝ : Setoid G := QuotientGroup.leftRel H
this : Setoid G' := QuotientGroup.leftRel (comap f H)
key : ∀ (x y : G'), Setoid.r x y ↔ Setoid.r (f x) (f y)
⊢ Function.Surjective (Quotient.map' ⇑f (_ : ∀ (x y : G'), Setoid.r x y → Setoid.r (f x) (f y)))

Next tactic:
refine' Quotient.ind' fun x => _
@[to_additive]
theorem index_comap_of_surjective {G' : Type*} [Group G'] {f : G' →* G}
    (hf : Function.Surjective f) : (H.comap f).index = H.index := by
  letI := QuotientGroup.leftRel H
  letI := QuotientGroup.leftRel (H.comap f)
  have key : ∀ x y : G', Setoid.r x y ↔ Setoid.r (f x) (f y) := by
    simp only [QuotientGroup.leftRel_apply]
    exact fun x y => iff_of_eq (congr_arg (· ∈ H) (by rw [f.map_mul, f.map_inv]))
  refine' Cardinal.toNat_congr (Equiv.ofBijective (Quotient.map' f fun x y => (key x y).mp) ⟨_, _⟩)
  · simp_rw [← Quotient.eq''] at key
    refine' Quotient.ind' fun x => _
    refine' Quotient.ind' fun y => _
    exact (key x y).mpr
  · refine' Quotient.ind' fun x => _
    

Proof state:
case refine'_2
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
this✝ : Setoid G := QuotientGroup.leftRel H
this : Setoid G' := QuotientGroup.leftRel (comap f H)
key : ∀ (x y : G'), Setoid.r x y ↔ Setoid.r (f x) (f y)
x : G
⊢ ∃ a, Quotient.map' ⇑f (_ : ∀ (x y : G'), Setoid.r x y → Setoid.r (f x) (f y)) a = Quotient.mk'' x

Next tactic:
obtain ⟨y, hy⟩ := hf x
@[to_additive]
theorem index_comap_of_surjective {G' : Type*} [Group G'] {f : G' →* G}
    (hf : Function.Surjective f) : (H.comap f).index = H.index := by
  letI := QuotientGroup.leftRel H
  letI := QuotientGroup.leftRel (H.comap f)
  have key : ∀ x y : G', Setoid.r x y ↔ Setoid.r (f x) (f y) := by
    simp only [QuotientGroup.leftRel_apply]
    exact fun x y => iff_of_eq (congr_arg (· ∈ H) (by rw [f.map_mul, f.map_inv]))
  refine' Cardinal.toNat_congr (Equiv.ofBijective (Quotient.map' f fun x y => (key x y).mp) ⟨_, _⟩)
  · simp_rw [← Quotient.eq''] at key
    refine' Quotient.ind' fun x => _
    refine' Quotient.ind' fun y => _
    exact (key x y).mpr
  · refine' Quotient.ind' fun x => _
    obtain ⟨y, hy⟩ := hf x
    

Proof state:
case refine'_2.intro
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
this✝ : Setoid G := QuotientGroup.leftRel H
this : Setoid G' := QuotientGroup.leftRel (comap f H)
key : ∀ (x y : G'), Setoid.r x y ↔ Setoid.r (f x) (f y)
x : G
y : G'
hy : f y = x
⊢ ∃ a, Quotient.map' ⇑f (_ : ∀ (x y : G'), Setoid.r x y → Setoid.r (f x) (f y)) a = Quotient.mk'' x

Next tactic:
exact ⟨y, (Quotient.map'_mk'' f _ y).trans (congr_arg Quotient.mk'' hy)⟩
@[to_additive]
theorem index_comap {G' : Type*} [Group G'] (f : G' →* G) :
    (H.comap f).index = H.relindex f.range :=
  Eq.trans (congr_arg 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
⊢ comap f H = comap (MonoidHom.rangeRestrict f) (subgroupOf H (MonoidHom.range f))

Next tactic:
rfl
@[to_additive]
theorem relindex_comap {G' : Type*} [Group G'] (f : G' →* G) (K : Subgroup G') :
    relindex (comap f H) K = relindex H (map f K) := 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
K : Subgroup G'
⊢ relindex (comap f H) K = relindex H (map f K)

Next tactic:
rw [relindex, subgroupOf, comap_comap, index_comap, ← f.map_range, K.subtype_range]
@[to_additive relindex_mul_relindex]
theorem relindex_mul_relindex (hHK : H ≤ K) (hKL : K ≤ L) :
    H.relindex K * K.relindex L = H.relindex L := by
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
hHK : H ≤ K
hKL : K ≤ L
⊢ relindex H K * relindex K L = relindex H L

Next tactic:
rw [← relindex_subgroupOf hKL]
@[to_additive relindex_mul_relindex]
theorem relindex_mul_relindex (hHK : H ≤ K) (hKL : K ≤ L) :
    H.relindex K * K.relindex L = H.relindex L := by
  rw [← relindex_subgroupOf hKL]
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
hHK : H ≤ K
hKL : K ≤ L
⊢ relindex (subgroupOf H L) (subgroupOf K L) * relindex K L = relindex H L

Next tactic:
exact relindex_mul_index fun x hx => hHK hx
@[to_additive]
theorem inf_relindex_right : (H ⊓ K).relindex K = H.relindex K := by
  

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

Next tactic:
rw [relindex, relindex, inf_subgroupOf_right]
@[to_additive]
theorem inf_relindex_left : (H ⊓ K).relindex H = K.relindex H := by
  

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

Next tactic:
rw [inf_comm, inf_relindex_right]
@[to_additive relindex_inf_mul_relindex]
theorem relindex_inf_mul_relindex : H.relindex (K ⊓ L) * K.relindex L = (H ⊓ K).relindex L := by
  

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

Next tactic:
rw [← inf_relindex_right H (K ⊓ L), ← inf_relindex_right K L, ← inf_relindex_right (H ⊓ K) L,
    inf_assoc, relindex_mul_relindex (H ⊓ (K ⊓ L)) (K ⊓ L) L inf_le_right inf_le_right]
@[to_additive (attr := simp)]
theorem relindex_sup_left [K.Normal] : K.relindex (K ⊔ H) = K.relindex H := by
  

Proof state:
G : Type u_1
inst✝¹ : Group G
H K L : Subgroup G
inst✝ : Normal K
⊢ relindex K (K ⊔ H) = relindex K H

Next tactic:
rw [sup_comm, relindex_sup_right]
/-- 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
  

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

Next tactic:
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]
/-- 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]
  

Proof state:
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
⊢ (∃ x ∉ H, ∀ x_1 ∉ H, x_1⁻¹ * x ∈ H) ↔ ∃ a, ∀ (b : G), b * a ∈ H ↔ b ∉ H

Next tactic:
refine'
    exists_congr fun a => ⟨fun ha b => ⟨fun hba hb => _, fun hb => _⟩, fun ha => ⟨_, fun b hb => _⟩⟩
/-- 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 => _⟩⟩
  · 

Proof state:
case refine'_1
G : Type u_1
inst✝ : Group G
H K L : Subgroup G
a : G
ha : a ∉ H ∧ ∀ x ∉ H, x⁻¹ * a ∈ H
b : G
hba : b * a ∈ H
hb : b ∈ H
⊢ False

Next tactic:
exact ha.1 ((mul_mem_cancel_left hb).1 hba)
/-- 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)
  · 

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

Next tactic:
exact inv_inv b ▸ ha.2 _ (mt (inv_mem_iff (x := b)).1 hb)
/-- 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)
  · 

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

Next tactic:
rw [← inv_mem_iff (x := a), ← ha, inv_mul_self]
/-- 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]
    

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

Next tactic:
exact one_mem _