l3lab/ntp-mathlib huggingface dataset:
/-- The following diagram is a pullback, i.e. `Vᵢⱼ` is the intersection of `Uᵢ` and `Uⱼ` in `X`.

Vᵢⱼ ⟶ Uᵢ
 |      |
 ↓      ↓
 Uⱼ ⟶ X
-/
def vPullbackConeIsLimit (i j : D.J) : IsLimit (𝖣.vPullbackCone i j) :=
  PullbackCone.isLimitAux' _ fun s => by
    refine' ⟨_, _, _, _⟩
    · refine' PresheafedSpace.IsOpenImmersion.lift (D.f i j) s.fst _
      erw [← D.toTopGlueData.preimage_range j i]
      have :
        s.fst.base ≫ D.toTopGlueData.ι i =
          s.snd.base ≫ D.toTopGlueData.ι j := by
        rw [← 𝖣.ι_gluedIso_hom (PresheafedSpace.forget _) _, ←
          𝖣.ι_gluedIso_hom (PresheafedSpace.forget _) _]
        have := congr_arg PresheafedSpace.Hom.base s.condition
        rw [comp_base, comp_base] at this
        replace this := reassoc_of% this
        exact this _
      rw [← Set.image_subset_iff, ← Set.image_univ, ← Set.image_comp, Set.image_univ]
      -- Porting note : change `rw` to `erw`
      erw [← coe_comp]
      rw [this, coe_comp, ← Set.image_univ, Set.image_comp]
      exact Set.image_subset_range _ _
    · apply IsOpenImmersion.lift_fac
    · rw [← cancel_mono (𝖣.ι j), Category.assoc, ← (𝖣.vPullbackCone i j).condition]
      conv_rhs => 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
D : GlueData C
inst✝ : HasLimits C
i j : D.J
s : PullbackCone (ι D.toGlueData i) (ι D.toGlueData j)
| PullbackCone.snd s ≫ ι D.toGlueData j

Next tactic:
rw [← s.condition]
/-- The following diagram is a pullback, i.e. `Vᵢⱼ` is the intersection of `Uᵢ` and `Uⱼ` in `X`.

Vᵢⱼ ⟶ Uᵢ
 |      |
 ↓      ↓
 Uⱼ ⟶ X
-/
def vPullbackConeIsLimit (i j : D.J) : IsLimit (𝖣.vPullbackCone i j) :=
  PullbackCone.isLimitAux' _ fun s => by
    refine' ⟨_, _, _, _⟩
    · refine' PresheafedSpace.IsOpenImmersion.lift (D.f i j) s.fst _
      erw [← D.toTopGlueData.preimage_range j i]
      have :
        s.fst.base ≫ D.toTopGlueData.ι i =
          s.snd.base ≫ D.toTopGlueData.ι j := by
        rw [← 𝖣.ι_gluedIso_hom (PresheafedSpace.forget _) _, ←
          𝖣.ι_gluedIso_hom (PresheafedSpace.forget _) _]
        have := congr_arg PresheafedSpace.Hom.base s.condition
        rw [comp_base, comp_base] at this
        replace this := reassoc_of% this
        exact this _
      rw [← Set.image_subset_iff, ← Set.image_univ, ← Set.image_comp, Set.image_univ]
      -- Porting note : change `rw` to `erw`
      erw [← coe_comp]
      rw [this, coe_comp, ← Set.image_univ, Set.image_comp]
      exact Set.image_subset_range _ _
    · apply IsOpenImmersion.lift_fac
    · rw [← cancel_mono (𝖣.ι j), Category.assoc, ← (𝖣.vPullbackCone i j).condition]
      conv_rhs => rw [← s.condition]
      

Proof state:
case refine'_3
C : Type u
inst✝¹ : Category.{v, u} C
D : GlueData C
inst✝ : HasLimits C
i j : D.J
s : PullbackCone (ι D.toGlueData i) (ι D.toGlueData j)
⊢ IsOpenImmersion.lift (f D.toGlueData i j) (PullbackCone.fst s)
        (_ : Set.range ⇑(PullbackCone.fst s).base ⊆ Set.range ⇑(f D.toGlueData i j).base) ≫
      PullbackCone.fst (vPullbackCone D.toGlueData i j) ≫ ι D.toGlueData i =
    PullbackCone.fst s ≫ ι D.toGlueData i

Next tactic:
erw [IsOpenImmersion.lift_fac_assoc]
/-- The following diagram is a pullback, i.e. `Vᵢⱼ` is the intersection of `Uᵢ` and `Uⱼ` in `X`.

Vᵢⱼ ⟶ Uᵢ
 |      |
 ↓      ↓
 Uⱼ ⟶ X
-/
def vPullbackConeIsLimit (i j : D.J) : IsLimit (𝖣.vPullbackCone i j) :=
  PullbackCone.isLimitAux' _ fun s => by
    refine' ⟨_, _, _, _⟩
    · refine' PresheafedSpace.IsOpenImmersion.lift (D.f i j) s.fst _
      erw [← D.toTopGlueData.preimage_range j i]
      have :
        s.fst.base ≫ D.toTopGlueData.ι i =
          s.snd.base ≫ D.toTopGlueData.ι j := by
        rw [← 𝖣.ι_gluedIso_hom (PresheafedSpace.forget _) _, ←
          𝖣.ι_gluedIso_hom (PresheafedSpace.forget _) _]
        have := congr_arg PresheafedSpace.Hom.base s.condition
        rw [comp_base, comp_base] at this
        replace this := reassoc_of% this
        exact this _
      rw [← Set.image_subset_iff, ← Set.image_univ, ← Set.image_comp, Set.image_univ]
      -- Porting note : change `rw` to `erw`
      erw [← coe_comp]
      rw [this, coe_comp, ← Set.image_univ, Set.image_comp]
      exact Set.image_subset_range _ _
    · apply IsOpenImmersion.lift_fac
    · rw [← cancel_mono (𝖣.ι j), Category.assoc, ← (𝖣.vPullbackCone i j).condition]
      conv_rhs => rw [← s.condition]
      erw [IsOpenImmersion.lift_fac_assoc]
    · 

Proof state:
case refine'_4
C : Type u
inst✝¹ : Category.{v, u} C
D : GlueData C
inst✝ : HasLimits C
i j : D.J
s : PullbackCone (ι D.toGlueData i) (ι D.toGlueData j)
⊢ ∀ {m : s.pt ⟶ (vPullbackCone D.toGlueData i j).pt},
    m ≫ PullbackCone.fst (vPullbackCone D.toGlueData i j) = PullbackCone.fst s →
      m ≫ PullbackCone.snd (vPullbackCone D.toGlueData i j) = PullbackCone.snd s →
        m =
          IsOpenImmersion.lift (f D.toGlueData i j) (PullbackCone.fst s)
            (_ : Set.range ⇑(PullbackCone.fst s).base ⊆ Set.range ⇑(f D.toGlueData i j).base)

Next tactic:
intro m e₁ _
/-- The following diagram is a pullback, i.e. `Vᵢⱼ` is the intersection of `Uᵢ` and `Uⱼ` in `X`.

Vᵢⱼ ⟶ Uᵢ
 |      |
 ↓      ↓
 Uⱼ ⟶ X
-/
def vPullbackConeIsLimit (i j : D.J) : IsLimit (𝖣.vPullbackCone i j) :=
  PullbackCone.isLimitAux' _ fun s => by
    refine' ⟨_, _, _, _⟩
    · refine' PresheafedSpace.IsOpenImmersion.lift (D.f i j) s.fst _
      erw [← D.toTopGlueData.preimage_range j i]
      have :
        s.fst.base ≫ D.toTopGlueData.ι i =
          s.snd.base ≫ D.toTopGlueData.ι j := by
        rw [← 𝖣.ι_gluedIso_hom (PresheafedSpace.forget _) _, ←
          𝖣.ι_gluedIso_hom (PresheafedSpace.forget _) _]
        have := congr_arg PresheafedSpace.Hom.base s.condition
        rw [comp_base, comp_base] at this
        replace this := reassoc_of% this
        exact this _
      rw [← Set.image_subset_iff, ← Set.image_univ, ← Set.image_comp, Set.image_univ]
      -- Porting note : change `rw` to `erw`
      erw [← coe_comp]
      rw [this, coe_comp, ← Set.image_univ, Set.image_comp]
      exact Set.image_subset_range _ _
    · apply IsOpenImmersion.lift_fac
    · rw [← cancel_mono (𝖣.ι j), Category.assoc, ← (𝖣.vPullbackCone i j).condition]
      conv_rhs => rw [← s.condition]
      erw [IsOpenImmersion.lift_fac_assoc]
    · intro m e₁ _; 

Proof state:
case refine'_4
C : Type u
inst✝¹ : Category.{v, u} C
D : GlueData C
inst✝ : HasLimits C
i j : D.J
s : PullbackCone (ι D.toGlueData i) (ι D.toGlueData j)
m : s.pt ⟶ (vPullbackCone D.toGlueData i j).pt
e₁ : m ≫ PullbackCone.fst (vPullbackCone D.toGlueData i j) = PullbackCone.fst s
a✝ : m ≫ PullbackCone.snd (vPullbackCone D.toGlueData i j) = PullbackCone.snd s
⊢ m =
    IsOpenImmersion.lift (f D.toGlueData i j) (PullbackCone.fst s)
      (_ : Set.range ⇑(PullbackCone.fst s).base ⊆ Set.range ⇑(f D.toGlueData i j).base)

Next tactic:
rw [← cancel_mono (D.f i j)]
/-- The following diagram is a pullback, i.e. `Vᵢⱼ` is the intersection of `Uᵢ` and `Uⱼ` in `X`.

Vᵢⱼ ⟶ Uᵢ
 |      |
 ↓      ↓
 Uⱼ ⟶ X
-/
def vPullbackConeIsLimit (i j : D.J) : IsLimit (𝖣.vPullbackCone i j) :=
  PullbackCone.isLimitAux' _ fun s => by
    refine' ⟨_, _, _, _⟩
    · refine' PresheafedSpace.IsOpenImmersion.lift (D.f i j) s.fst _
      erw [← D.toTopGlueData.preimage_range j i]
      have :
        s.fst.base ≫ D.toTopGlueData.ι i =
          s.snd.base ≫ D.toTopGlueData.ι j := by
        rw [← 𝖣.ι_gluedIso_hom (PresheafedSpace.forget _) _, ←
          𝖣.ι_gluedIso_hom (PresheafedSpace.forget _) _]
        have := congr_arg PresheafedSpace.Hom.base s.condition
        rw [comp_base, comp_base] at this
        replace this := reassoc_of% this
        exact this _
      rw [← Set.image_subset_iff, ← Set.image_univ, ← Set.image_comp, Set.image_univ]
      -- Porting note : change `rw` to `erw`
      erw [← coe_comp]
      rw [this, coe_comp, ← Set.image_univ, Set.image_comp]
      exact Set.image_subset_range _ _
    · apply IsOpenImmersion.lift_fac
    · rw [← cancel_mono (𝖣.ι j), Category.assoc, ← (𝖣.vPullbackCone i j).condition]
      conv_rhs => rw [← s.condition]
      erw [IsOpenImmersion.lift_fac_assoc]
    · intro m e₁ _; rw [← cancel_mono (D.f i j)]; 

Proof state:
case refine'_4
C : Type u
inst✝¹ : Category.{v, u} C
D : GlueData C
inst✝ : HasLimits C
i j : D.J
s : PullbackCone (ι D.toGlueData i) (ι D.toGlueData j)
m : s.pt ⟶ (vPullbackCone D.toGlueData i j).pt
e₁ : m ≫ PullbackCone.fst (vPullbackCone D.toGlueData i j) = PullbackCone.fst s
a✝ : m ≫ PullbackCone.snd (vPullbackCone D.toGlueData i j) = PullbackCone.snd s
⊢ m ≫ f D.toGlueData i j =
    IsOpenImmersion.lift (f D.toGlueData i j) (PullbackCone.fst s)
        (_ : Set.range ⇑(PullbackCone.fst s).base ⊆ Set.range ⇑(f D.toGlueData i j).base) ≫
      f D.toGlueData i j

Next tactic:
erw [e₁]
/-- The following diagram is a pullback, i.e. `Vᵢⱼ` is the intersection of `Uᵢ` and `Uⱼ` in `X`.

Vᵢⱼ ⟶ Uᵢ
 |      |
 ↓      ↓
 Uⱼ ⟶ X
-/
def vPullbackConeIsLimit (i j : D.J) : IsLimit (𝖣.vPullbackCone i j) :=
  PullbackCone.isLimitAux' _ fun s => by
    refine' ⟨_, _, _, _⟩
    · refine' PresheafedSpace.IsOpenImmersion.lift (D.f i j) s.fst _
      erw [← D.toTopGlueData.preimage_range j i]
      have :
        s.fst.base ≫ D.toTopGlueData.ι i =
          s.snd.base ≫ D.toTopGlueData.ι j := by
        rw [← 𝖣.ι_gluedIso_hom (PresheafedSpace.forget _) _, ←
          𝖣.ι_gluedIso_hom (PresheafedSpace.forget _) _]
        have := congr_arg PresheafedSpace.Hom.base s.condition
        rw [comp_base, comp_base] at this
        replace this := reassoc_of% this
        exact this _
      rw [← Set.image_subset_iff, ← Set.image_univ, ← Set.image_comp, Set.image_univ]
      -- Porting note : change `rw` to `erw`
      erw [← coe_comp]
      rw [this, coe_comp, ← Set.image_univ, Set.image_comp]
      exact Set.image_subset_range _ _
    · apply IsOpenImmersion.lift_fac
    · rw [← cancel_mono (𝖣.ι j), Category.assoc, ← (𝖣.vPullbackCone i j).condition]
      conv_rhs => rw [← s.condition]
      erw [IsOpenImmersion.lift_fac_assoc]
    · intro m e₁ _; rw [← cancel_mono (D.f i j)]; erw [e₁]; 

Proof state:
case refine'_4
C : Type u
inst✝¹ : Category.{v, u} C
D : GlueData C
inst✝ : HasLimits C
i j : D.J
s : PullbackCone (ι D.toGlueData i) (ι D.toGlueData j)
m : s.pt ⟶ (vPullbackCone D.toGlueData i j).pt
e₁ : m ≫ PullbackCone.fst (vPullbackCone D.toGlueData i j) = PullbackCone.fst s
a✝ : m ≫ PullbackCone.snd (vPullbackCone D.toGlueData i j) = PullbackCone.snd s
⊢ PullbackCone.fst s =
    IsOpenImmersion.lift (f D.toGlueData i j) (PullbackCone.fst s)
        (_ : Set.range ⇑(PullbackCone.fst s).base ⊆ Set.range ⇑(f D.toGlueData i j).base) ≫
      f D.toGlueData i j

Next tactic:
rw [IsOpenImmersion.lift_fac]
instance ιIsOpenImmersion (i : D.J) : IsOpenImmersion (𝖣.ι i) := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasProducts C
D : GlueData C
inst✝ : HasLimits C
i : D.J
⊢ IsOpenImmersion (ι D.toGlueData i)

Next tactic:
rw [← D.ι_isoPresheafedSpace_inv]
instance ιIsOpenImmersion (i : D.J) : IsOpenImmersion (𝖣.ι i) := by
  rw [← D.ι_isoPresheafedSpace_inv]
  -- Porting note : was `inferInstance`
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasProducts C
D : GlueData C
inst✝ : HasLimits C
i : D.J
⊢ IsOpenImmersion (ι (toPresheafedSpaceGlueData D).toGlueData i ≫ (isoPresheafedSpace D).inv)

Next tactic:
refine PresheafedSpace.IsOpenImmersion.comp (hf := ?_) (hg := inferInstance)
instance ιIsOpenImmersion (i : D.J) : IsOpenImmersion (𝖣.ι i) := by
  rw [← D.ι_isoPresheafedSpace_inv]
  -- Porting note : was `inferInstance`
  refine PresheafedSpace.IsOpenImmersion.comp (hf := ?_) (hg := inferInstance)
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasProducts C
D : GlueData C
inst✝ : HasLimits C
i : D.J
⊢ PresheafedSpace.IsOpenImmersion (ι (toPresheafedSpaceGlueData D).toGlueData i)

Next tactic:
apply PresheafedSpace.GlueData.ιIsOpenImmersion
instance ι_isOpenImmersion (i : D.J) : IsOpenImmersion (𝖣.ι i) := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
D : GlueData
i : D.J
⊢ IsOpenImmersion (ι D.toGlueData i)

Next tactic:
delta IsOpenImmersion
instance ι_isOpenImmersion (i : D.J) : IsOpenImmersion (𝖣.ι i) := by
  delta IsOpenImmersion; 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
D : GlueData
i : D.J
⊢ SheafedSpace.IsOpenImmersion (ι D.toGlueData i).val

Next tactic:
rw [← D.ι_isoSheafedSpace_inv]
instance ι_isOpenImmersion (i : D.J) : IsOpenImmersion (𝖣.ι i) := by
  delta IsOpenImmersion; rw [← D.ι_isoSheafedSpace_inv]
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
D : GlueData
i : D.J
⊢ SheafedSpace.IsOpenImmersion (ι (toSheafedSpaceGlueData D).toGlueData i ≫ (isoSheafedSpace D).inv)

Next tactic:
apply (config := { allowSynthFailures := true }) PresheafedSpace.IsOpenImmersion.comp
instance ι_isOpenImmersion (i : D.J) : IsOpenImmersion (𝖣.ι i) := by
  delta IsOpenImmersion; rw [← D.ι_isoSheafedSpace_inv]
  apply (config := { allowSynthFailures := true }) PresheafedSpace.IsOpenImmersion.comp
  -- Porting note : this was automatic
  

Proof state:
case hf
C : Type u
inst✝ : Category.{v, u} C
D : GlueData
i : D.J
⊢ PresheafedSpace.IsOpenImmersion (ι (toSheafedSpaceGlueData D).toGlueData i)

Next tactic:
exact (D.toSheafedSpaceGlueData).ιIsOpenImmersion i
@[to_additive]
theorem IsSquare.map [MulOneClass α] [MulOneClass β] [MonoidHomClass F α β] {m : α} (f : F) :
    IsSquare m → IsSquare (f m) := by
  

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝² : MulOneClass α
inst✝¹ : MulOneClass β
inst✝ : MonoidHomClass F α β
m : α
f : F
⊢ IsSquare m → IsSquare (f m)

Next tactic:
rintro ⟨m, rfl⟩
@[to_additive]
theorem IsSquare.map [MulOneClass α] [MulOneClass β] [MonoidHomClass F α β] {m : α} (f : F) :
    IsSquare m → IsSquare (f m) := by
  rintro ⟨m, rfl⟩
  

Proof state:
case intro
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝² : MulOneClass α
inst✝¹ : MulOneClass β
inst✝ : MonoidHomClass F α β
f : F
m : α
⊢ IsSquare (f (m * m))

Next tactic:
exact ⟨f m, by simp⟩
@[to_additive]
theorem IsSquare.map [MulOneClass α] [MulOneClass β] [MonoidHomClass F α β] {m : α} (f : F) :
    IsSquare m → IsSquare (f m) := by
  rintro ⟨m, rfl⟩
  exact ⟨f m, by 

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝² : MulOneClass α
inst✝¹ : MulOneClass β
inst✝ : MonoidHomClass F α β
f : F
m : α
⊢ f (m * m) = f m * f m

Next tactic:
simp
@[to_additive even_iff_exists_two_nsmul]
theorem isSquare_iff_exists_sq (m : α) : IsSquare m ↔ ∃ c, m = c ^ 2 := by 

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : Monoid α
n : ℕ
a m : α
⊢ IsSquare m ↔ ∃ c, m = c ^ 2

Next tactic:
simp [IsSquare, pow_two]
@[to_additive]
theorem IsSquare.pow (n : ℕ) : IsSquare a → IsSquare (a ^ n) := by
  

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : Monoid α
n✝ : ℕ
a : α
n : ℕ
⊢ IsSquare a → IsSquare (a ^ n)

Next tactic:
rintro ⟨a, rfl⟩
@[to_additive]
theorem IsSquare.pow (n : ℕ) : IsSquare a → IsSquare (a ^ n) := by
  rintro ⟨a, rfl⟩
  

Proof state:
case intro
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : Monoid α
n✝ n : ℕ
a : α
⊢ IsSquare ((a * a) ^ n)

Next tactic:
exact ⟨a ^ n, (Commute.refl _).mul_pow _⟩
@[to_additive Even.nsmul']
theorem Even.isSquare_pow : Even n → ∀ a : α, IsSquare (a ^ n) := by
  

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : Monoid α
n : ℕ
a : α
⊢ Even n → ∀ (a : α), IsSquare (a ^ n)

Next tactic:
rintro ⟨n, rfl⟩ a
@[to_additive Even.nsmul']
theorem Even.isSquare_pow : Even n → ∀ a : α, IsSquare (a ^ n) := by
  rintro ⟨n, rfl⟩ a
  

Proof state:
case intro
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : Monoid α
a✝ : α
n : ℕ
a : α
⊢ IsSquare (a ^ (n + n))

Next tactic:
exact ⟨a ^ n, pow_add _ _ _⟩
@[simp]
theorem Even.neg_pow : Even n → ∀ a : α, (-a) ^ n = a ^ n := by
  

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝¹ : Monoid α
n : ℕ
a : α
inst✝ : HasDistribNeg α
⊢ Even n → ∀ (a : α), (-a) ^ n = a ^ n

Next tactic:
rintro ⟨c, rfl⟩ a
@[simp]
theorem Even.neg_pow : Even n → ∀ a : α, (-a) ^ n = a ^ n := by
  rintro ⟨c, rfl⟩ a
  

Proof state:
case intro
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝¹ : Monoid α
a✝ : α
inst✝ : HasDistribNeg α
c : ℕ
a : α
⊢ (-a) ^ (c + c) = a ^ (c + c)

Next tactic:
simp_rw [← two_mul, pow_mul, neg_sq]
theorem Even.neg_one_pow (h : Even n) : (-1 : α) ^ n = 1 := by 

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝¹ : Monoid α
n : ℕ
a : α
inst✝ : HasDistribNeg α
h : Even n
⊢ (-1) ^ n = 1

Next tactic:
rw [h.neg_pow, one_pow]
@[to_additive]
theorem IsSquare.mul [CommSemigroup α] {a b : α} : IsSquare a → IsSquare b → IsSquare (a * b) := by
  

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : CommSemigroup α
a b : α
⊢ IsSquare a → IsSquare b → IsSquare (a * b)

Next tactic:
rintro ⟨a, rfl⟩ ⟨b, rfl⟩
@[to_additive]
theorem IsSquare.mul [CommSemigroup α] {a b : α} : IsSquare a → IsSquare b → IsSquare (a * b) := by
  rintro ⟨a, rfl⟩ ⟨b, rfl⟩
  

Proof state:
case intro.intro
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : CommSemigroup α
a b : α
⊢ IsSquare (a * a * (b * b))

Next tactic:
exact ⟨a * b, mul_mul_mul_comm _ _ _ _⟩
@[to_additive (attr := simp)]
theorem isSquare_inv : IsSquare a⁻¹ ↔ IsSquare a := by
  

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : DivisionMonoid α
a : α
⊢ IsSquare a⁻¹ ↔ IsSquare a

Next tactic:
refine' ⟨fun h => _, fun h => _⟩
@[to_additive (attr := simp)]
theorem isSquare_inv : IsSquare a⁻¹ ↔ IsSquare a := by
  refine' ⟨fun h => _, fun h => _⟩
  · 

Proof state:
case refine'_1
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : DivisionMonoid α
a : α
h : IsSquare a⁻¹
⊢ IsSquare a

Next tactic:
rw [← isSquare_op_iff, ← inv_inv a]
@[to_additive (attr := simp)]
theorem isSquare_inv : IsSquare a⁻¹ ↔ IsSquare a := by
  refine' ⟨fun h => _, fun h => _⟩
  · rw [← isSquare_op_iff, ← inv_inv a]
    

Proof state:
case refine'_1
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : DivisionMonoid α
a : α
h : IsSquare a⁻¹
⊢ IsSquare (op a⁻¹⁻¹)

Next tactic:
exact h.map (MulEquiv.inv' α)
@[to_additive (attr := simp)]
theorem isSquare_inv : IsSquare a⁻¹ ↔ IsSquare a := by
  refine' ⟨fun h => _, fun h => _⟩
  · rw [← isSquare_op_iff, ← inv_inv a]
    exact h.map (MulEquiv.inv' α)
  · 

Proof state:
case refine'_2
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : DivisionMonoid α
a : α
h : IsSquare a
⊢ IsSquare a⁻¹

Next tactic:
exact (isSquare_op_iff.mpr h).map (MulEquiv.inv' α).symm
@[to_additive]
theorem IsSquare.zpow (n : ℤ) : IsSquare a → IsSquare (a ^ n) := by
  

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : DivisionMonoid α
a : α
n : ℤ
⊢ IsSquare a → IsSquare (a ^ n)

Next tactic:
rintro ⟨a, rfl⟩
@[to_additive]
theorem IsSquare.zpow (n : ℤ) : IsSquare a → IsSquare (a ^ n) := by
  rintro ⟨a, rfl⟩
  

Proof state:
case intro
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : DivisionMonoid α
n : ℤ
a : α
⊢ IsSquare ((a * a) ^ n)

Next tactic:
exact ⟨a ^ n, (Commute.refl _).mul_zpow _⟩
theorem Even.neg_zpow : Even n → ∀ a : α, (-a) ^ n = a ^ n := by
  

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝¹ : DivisionMonoid α
a : α
inst✝ : HasDistribNeg α
n : ℤ
⊢ Even n → ∀ (a : α), (-a) ^ n = a ^ n

Next tactic:
rintro ⟨c, rfl⟩ a
theorem Even.neg_zpow : Even n → ∀ a : α, (-a) ^ n = a ^ n := by
  rintro ⟨c, rfl⟩ a
  

Proof state:
case intro
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝¹ : DivisionMonoid α
a✝ : α
inst✝ : HasDistribNeg α
c : ℤ
a : α
⊢ (-a) ^ (c + c) = a ^ (c + c)

Next tactic:
exact zpow_bit0_neg _ _
theorem Even.neg_one_zpow (h : Even n) : (-1 : α) ^ n = 1 := by 

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝¹ : DivisionMonoid α
a : α
inst✝ : HasDistribNeg α
n : ℤ
h : Even n
⊢ (-1) ^ n = 1

Next tactic:
rw [h.neg_zpow, one_zpow]
theorem even_abs [SubtractionMonoid α] [LinearOrder α] {a : α} : Even |a| ↔ Even a := by
  

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝¹ : SubtractionMonoid α
inst✝ : LinearOrder α
a : α
⊢ Even |a| ↔ Even a

Next tactic:
cases abs_choice a
theorem even_abs [SubtractionMonoid α] [LinearOrder α] {a : α} : Even |a| ↔ Even a := by
  cases abs_choice a
  · 

Proof state:
case inl
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝¹ : SubtractionMonoid α
inst✝ : LinearOrder α
a : α
h✝ : |a| = a
⊢ Even |a| ↔ Even a

Next tactic:
have h : abs a = a := by assumption
theorem even_abs [SubtractionMonoid α] [LinearOrder α] {a : α} : Even |a| ↔ Even a := by
  cases abs_choice a
  · have h : abs a = a := by 

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝¹ : SubtractionMonoid α
inst✝ : LinearOrder α
a : α
h✝ : |a| = a
⊢ |a| = a

Next tactic:
assumption
theorem even_abs [SubtractionMonoid α] [LinearOrder α] {a : α} : Even |a| ↔ Even a := by
  cases abs_choice a
  · have h : abs a = a := by assumption
    

Proof state:
case inl
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝¹ : SubtractionMonoid α
inst✝ : LinearOrder α
a : α
h✝ h : |a| = a
⊢ Even |a| ↔ Even a

Next tactic:
simp only [h, even_neg]
theorem even_abs [SubtractionMonoid α] [LinearOrder α] {a : α} : Even |a| ↔ Even a := by
  cases abs_choice a
  · have h : abs a = a := by assumption
    simp only [h, even_neg]
  · 

Proof state:
case inr
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝¹ : SubtractionMonoid α
inst✝ : LinearOrder α
a : α
h✝ : |a| = -a
⊢ Even |a| ↔ Even a

Next tactic:
have h : abs a = -a := by assumption
theorem even_abs [SubtractionMonoid α] [LinearOrder α] {a : α} : Even |a| ↔ Even a := by
  cases abs_choice a
  · have h : abs a = a := by assumption
    simp only [h, even_neg]
  · have h : abs a = -a := by 

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝¹ : SubtractionMonoid α
inst✝ : LinearOrder α
a : α
h✝ : |a| = -a
⊢ |a| = -a

Next tactic:
assumption
theorem even_abs [SubtractionMonoid α] [LinearOrder α] {a : α} : Even |a| ↔ Even a := by
  cases abs_choice a
  · have h : abs a = a := by assumption
    simp only [h, even_neg]
  · have h : abs a = -a := by assumption
    

Proof state:
case inr
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝¹ : SubtractionMonoid α
inst✝ : LinearOrder α
a : α
h✝ h : |a| = -a
⊢ Even |a| ↔ Even a

Next tactic:
simp only [h, even_neg]
@[to_additive]
theorem IsSquare.div [DivisionCommMonoid α] {a b : α} (ha : IsSquare a) (hb : IsSquare b) :
    IsSquare (a / b) := by
  

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : DivisionCommMonoid α
a b : α
ha : IsSquare a
hb : IsSquare b
⊢ IsSquare (a / b)

Next tactic:
rw [div_eq_mul_inv]
@[to_additive]
theorem IsSquare.div [DivisionCommMonoid α] {a b : α} (ha : IsSquare a) (hb : IsSquare b) :
    IsSquare (a / b) := by
  rw [div_eq_mul_inv]
  

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : DivisionCommMonoid α
a b : α
ha : IsSquare a
hb : IsSquare b
⊢ IsSquare (a * b⁻¹)

Next tactic:
exact ha.mul hb.inv
@[to_additive (attr := simp) Even.zsmul']
theorem Even.isSquare_zpow [Group α] {n : ℤ} : Even n → ∀ a : α, IsSquare (a ^ n) := by
  

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : Group α
n : ℤ
⊢ Even n → ∀ (a : α), IsSquare (a ^ n)

Next tactic:
rintro ⟨n, rfl⟩ a
@[to_additive (attr := simp) Even.zsmul']
theorem Even.isSquare_zpow [Group α] {n : ℤ} : Even n → ∀ a : α, IsSquare (a ^ n) := by
  rintro ⟨n, rfl⟩ a
  

Proof state:
case intro
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝ : Group α
n : ℤ
a : α
⊢ IsSquare (a ^ (n + n))

Next tactic:
exact ⟨a ^ n, zpow_add _ _ _⟩
theorem Even.tsub [CanonicallyLinearOrderedAddCommMonoid α] [Sub α] [OrderedSub α]
    [ContravariantClass α α (· + ·) (· ≤ ·)] {m n : α} (hm : Even m) (hn : Even n) :
    Even (m - n) := by
  

Proof state:
F : Type u_1
α : Type u_2
β : Type u_3
R : Type u_4
inst✝³ : CanonicallyLinearOrderedAddCommMonoid α
inst✝² : Sub α
inst✝¹ : OrderedSub α
inst✝ : ContravariantClass α α (fun x x_1 => x + x_1) fun x x_1 => x ≤ x_1
m n : α
hm : Even m
hn : Even n
⊢ Even (m - n)

Next tactic:
obtain ⟨a, rfl⟩ := hm