l3lab/ntp-mathlib huggingface dataset:
/-- The canonical isomorphism `S.opcycles ≅ cokernel S.f`. -/
@[simps]
noncomputable def opcyclesIsoCokernel [HasCokernel S.f] : S.opcycles ≅ cokernel S.f where
  hom := S.descOpcycles (cokernel.π S.f) (by 

Proof state:
C : Type u_1
inst✝³ : Category.{?u.257993, u_1} C
inst✝² : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
h : RightHomologyData S
A : C
k : S.X₂ ⟶ A
hk : S.f ≫ k = 0
inst✝¹ : HasRightHomology S
inst✝ : HasCokernel S.f
⊢ S.f ≫ cokernel.π S.f = 0

Next tactic:
simp
/-- The canonical isomorphism `S.opcycles ≅ cokernel S.f`. -/
@[simps]
noncomputable def opcyclesIsoCokernel [HasCokernel S.f] : S.opcycles ≅ cokernel S.f where
  hom := S.descOpcycles (cokernel.π S.f) (by simp)
  inv := cokernel.desc S.f S.pOpcycles (by 

Proof state:
C : Type u_1
inst✝³ : Category.{?u.257993, u_1} C
inst✝² : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
h : RightHomologyData S
A : C
k : S.X₂ ⟶ A
hk : S.f ≫ k = 0
inst✝¹ : HasRightHomology S
inst✝ : HasCokernel S.f
⊢ S.f ≫ pOpcycles S = 0

Next tactic:
simp
@[reassoc]
lemma rightHomologyι_descOpcycles_π_eq_zero_of_boundary (x : S.X₃ ⟶ A) (hx : k = S.g ≫ x) :
    S.rightHomologyι ≫ S.descOpcycles k (by 

Proof state:
C : Type u_1
inst✝² : Category.{?u.262567, u_1} C
inst✝¹ : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
h : RightHomologyData S
A : C
k : S.X₂ ⟶ A
hk : S.f ≫ k = 0
inst✝ : HasRightHomology S
x : S.X₃ ⟶ A
hx : k = S.g ≫ x
⊢ S.f ≫ k = 0

Next tactic:
rw [hx, S.zero_assoc, zero_comp]
@[reassoc (attr := simp)]
lemma rightHomologyι_comp_fromOpcycles :
    S.rightHomologyι ≫ S.fromOpcycles = 0 :=
  S.rightHomologyι_descOpcycles_π_eq_zero_of_boundary S.g (𝟙 _) (by 

Proof state:
C : Type u_1
inst✝² : Category.{u_2, u_1} C
inst✝¹ : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
h : RightHomologyData S
A : C
k : S.X₂ ⟶ A
hk : S.f ≫ k = 0
inst✝ : HasRightHomology S
⊢ S.g = S.g ≫ 𝟙 S.X₃

Next tactic:
rw [comp_id]
@[reassoc (attr := simp)]
lemma opcyclesMap_comp_descOpcycles (φ : S₁ ⟶ S) [S₁.HasRightHomology] :
    opcyclesMap φ ≫ S.descOpcycles k hk =
      S₁.descOpcycles (φ.τ₂ ≫ k) (by 

Proof state:
C : Type u_1
inst✝³ : Category.{?u.267262, u_1} C
inst✝² : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
h : RightHomologyData S
A : C
k : S.X₂ ⟶ A
hk : S.f ≫ k = 0
inst✝¹ : HasRightHomology S
φ : S₁ ⟶ S
inst✝ : HasRightHomology S₁
⊢ S₁.f ≫ φ.τ₂ ≫ k = 0

Next tactic:
rw [← φ.comm₁₂_assoc, hk, comp_zero]
@[reassoc (attr := simp)]
lemma opcyclesMap_comp_descOpcycles (φ : S₁ ⟶ S) [S₁.HasRightHomology] :
    opcyclesMap φ ≫ S.descOpcycles k hk =
      S₁.descOpcycles (φ.τ₂ ≫ k) (by rw [← φ.comm₁₂_assoc, hk, comp_zero]) := by
  

Proof state:
C : Type u_1
inst✝³ : Category.{u_2, u_1} C
inst✝² : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
h : RightHomologyData S
A : C
k : S.X₂ ⟶ A
hk : S.f ≫ k = 0
inst✝¹ : HasRightHomology S
φ : S₁ ⟶ S
inst✝ : HasRightHomology S₁
⊢ opcyclesMap φ ≫ descOpcycles S k hk = descOpcycles S₁ (φ.τ₂ ≫ k) (_ : S₁.f ≫ φ.τ₂ ≫ k = 0)

Next tactic:
simp only [← cancel_epi (S₁.pOpcycles), p_opcyclesMap_assoc, p_descOpcycles]
@[reassoc (attr := simp)]
lemma RightHomologyData.opcyclesIso_inv_comp_descOpcycles :
    h.opcyclesIso.inv ≫ S.descOpcycles k hk = h.descQ k hk := by
  

Proof state:
C : Type u_1
inst✝² : Category.{u_2, u_1} C
inst✝¹ : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
h : RightHomologyData S
A : C
k : S.X₂ ⟶ A
hk : S.f ≫ k = 0
inst✝ : HasRightHomology S
⊢ (opcyclesIso h).inv ≫ descOpcycles S k hk = descQ h k hk

Next tactic:
simp only [← cancel_epi h.p, p_comp_opcyclesIso_inv_assoc, p_descOpcycles, p_descQ]
@[simp]
lemma RightHomologyData.opcyclesIso_hom_comp_descQ :
    h.opcyclesIso.hom ≫ h.descQ k hk = S.descOpcycles k hk := by
  

Proof state:
C : Type u_1
inst✝² : Category.{u_2, u_1} C
inst✝¹ : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
h : RightHomologyData S
A : C
k : S.X₂ ⟶ A
hk : S.f ≫ k = 0
inst✝ : HasRightHomology S
⊢ (opcyclesIso h).hom ≫ descQ h k hk = descOpcycles S k hk

Next tactic:
rw [← h.opcyclesIso_inv_comp_descOpcycles, Iso.hom_inv_id_assoc]
lemma hasKernel [S.HasRightHomology] [HasCokernel S.f] :
    HasKernel (cokernel.desc S.f S.g S.zero) := by
  

Proof state:
C : Type u_1
inst✝³ : Category.{u_2, u_1} C
inst✝² : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
inst✝¹ : HasRightHomology S
inst✝ : HasCokernel S.f
⊢ HasKernel (cokernel.desc S.f S.g (_ : S.f ≫ S.g = 0))

Next tactic:
let h := S.rightHomologyData
lemma hasKernel [S.HasRightHomology] [HasCokernel S.f] :
    HasKernel (cokernel.desc S.f S.g S.zero) := by
  let h := S.rightHomologyData
  

Proof state:
C : Type u_1
inst✝³ : Category.{u_2, u_1} C
inst✝² : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
inst✝¹ : HasRightHomology S
inst✝ : HasCokernel S.f
h : RightHomologyData S := rightHomologyData S
⊢ HasKernel (cokernel.desc S.f S.g (_ : S.f ≫ S.g = 0))

Next tactic:
haveI : HasLimit (parallelPair h.g' 0) := ⟨⟨⟨_, h.hι'⟩⟩⟩
lemma hasKernel [S.HasRightHomology] [HasCokernel S.f] :
    HasKernel (cokernel.desc S.f S.g S.zero) := by
  let h := S.rightHomologyData
  haveI : HasLimit (parallelPair h.g' 0) := ⟨⟨⟨_, h.hι'⟩⟩⟩
  

Proof state:
C : Type u_1
inst✝³ : Category.{u_2, u_1} C
inst✝² : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
inst✝¹ : HasRightHomology S
inst✝ : HasCokernel S.f
h : RightHomologyData S := rightHomologyData S
this : HasLimit (parallelPair (RightHomologyData.g' h) 0)
⊢ HasKernel (cokernel.desc S.f S.g (_ : S.f ≫ S.g = 0))

Next tactic:
let e : parallelPair (cokernel.desc S.f S.g S.zero) 0 ≅ parallelPair h.g' 0 :=
    parallelPair.ext (IsColimit.coconePointUniqueUpToIso (colimit.isColimit _) h.hp)
      (Iso.refl _) (coequalizer.hom_ext (by simp)) (by aesop_cat)
lemma hasKernel [S.HasRightHomology] [HasCokernel S.f] :
    HasKernel (cokernel.desc S.f S.g S.zero) := by
  let h := S.rightHomologyData
  haveI : HasLimit (parallelPair h.g' 0) := ⟨⟨⟨_, h.hι'⟩⟩⟩
  let e : parallelPair (cokernel.desc S.f S.g S.zero) 0 ≅ parallelPair h.g' 0 :=
    parallelPair.ext (IsColimit.coconePointUniqueUpToIso (colimit.isColimit _) h.hp)
      (Iso.refl _) (coequalizer.hom_ext (by 

Proof state:
C : Type u_1
inst✝³ : Category.{u_2, u_1} C
inst✝² : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
inst✝¹ : HasRightHomology S
inst✝ : HasCokernel S.f
h : RightHomologyData S := rightHomologyData S
this : HasLimit (parallelPair (RightHomologyData.g' h) 0)
⊢ coequalizer.π S.f 0 ≫
      (parallelPair (cokernel.desc S.f S.g (_ : S.f ≫ S.g = 0)) 0).map WalkingParallelPairHom.left ≫
        (Iso.refl ((parallelPair (cokernel.desc S.f S.g (_ : S.f ≫ S.g = 0)) 0).obj WalkingParallelPair.one)).hom =
    coequalizer.π S.f 0 ≫
      (IsColimit.coconePointUniqueUpToIso (colimit.isColimit (parallelPair S.f 0)) h.hp).hom ≫
        (parallelPair (RightHomologyData.g' h) 0).map WalkingParallelPairHom.left

Next tactic:
simp
lemma hasKernel [S.HasRightHomology] [HasCokernel S.f] :
    HasKernel (cokernel.desc S.f S.g S.zero) := by
  let h := S.rightHomologyData
  haveI : HasLimit (parallelPair h.g' 0) := ⟨⟨⟨_, h.hι'⟩⟩⟩
  let e : parallelPair (cokernel.desc S.f S.g S.zero) 0 ≅ parallelPair h.g' 0 :=
    parallelPair.ext (IsColimit.coconePointUniqueUpToIso (colimit.isColimit _) h.hp)
      (Iso.refl _) (coequalizer.hom_ext (by simp)) (by 

Proof state:
C : Type u_1
inst✝³ : Category.{u_2, u_1} C
inst✝² : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
inst✝¹ : HasRightHomology S
inst✝ : HasCokernel S.f
h : RightHomologyData S := rightHomologyData S
this : HasLimit (parallelPair (RightHomologyData.g' h) 0)
⊢ (parallelPair (cokernel.desc S.f S.g (_ : S.f ≫ S.g = 0)) 0).map WalkingParallelPairHom.right ≫
      (Iso.refl ((parallelPair (cokernel.desc S.f S.g (_ : S.f ≫ S.g = 0)) 0).obj WalkingParallelPair.one)).hom =
    (IsColimit.coconePointUniqueUpToIso (colimit.isColimit (parallelPair S.f 0)) h.hp).hom ≫
      (parallelPair (RightHomologyData.g' h) 0).map WalkingParallelPairHom.right

Next tactic:
aesop_cat
lemma hasKernel [S.HasRightHomology] [HasCokernel S.f] :
    HasKernel (cokernel.desc S.f S.g S.zero) := by
  let h := S.rightHomologyData
  haveI : HasLimit (parallelPair h.g' 0) := ⟨⟨⟨_, h.hι'⟩⟩⟩
  let e : parallelPair (cokernel.desc S.f S.g S.zero) 0 ≅ parallelPair h.g' 0 :=
    parallelPair.ext (IsColimit.coconePointUniqueUpToIso (colimit.isColimit _) h.hp)
      (Iso.refl _) (coequalizer.hom_ext (by simp)) (by aesop_cat)
  

Proof state:
C : Type u_1
inst✝³ : Category.{u_2, u_1} C
inst✝² : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
inst✝¹ : HasRightHomology S
inst✝ : HasCokernel S.f
h : RightHomologyData S := rightHomologyData S
this : HasLimit (parallelPair (RightHomologyData.g' h) 0)
e : parallelPair (cokernel.desc S.f S.g (_ : S.f ≫ S.g = 0)) 0 ≅ parallelPair (RightHomologyData.g' h) 0 :=
  parallelPair.ext (IsColimit.coconePointUniqueUpToIso (colimit.isColimit (parallelPair S.f 0)) h.hp)
    (Iso.refl ((parallelPair (cokernel.desc S.f S.g (_ : S.f ≫ S.g = 0)) 0).obj WalkingParallelPair.one))
    (_ :
      (parallelPair (cokernel.desc S.f S.g (_ : S.f ≫ S.g = 0)) 0).map WalkingParallelPairHom.left ≫
          (Iso.refl ((parallelPair (cokernel.desc S.f S.g (_ : S.f ≫ S.g = 0)) 0).obj WalkingParallelPair.one)).hom =
        (IsColimit.coconePointUniqueUpToIso (colimit.isColimit (parallelPair S.f 0)) h.hp).hom ≫
          (parallelPair (RightHomologyData.g' h) 0).map WalkingParallelPairHom.left)
    (_ :
      0 ≫ 𝟙 S.X₃ =
        (IsColimit.coconePointUniqueUpToIso (colimit.isColimit (parallelPair S.f 0)) (rightHomologyData S).hp).hom ≫ 0)
⊢ HasKernel (cokernel.desc S.f S.g (_ : S.f ≫ S.g = 0))

Next tactic:
exact hasLimitOfIso e.symm
lemma isIso_opcyclesMap'_of_isIso_of_epi (φ : S₁ ⟶ S₂) (h₂ : IsIso φ.τ₂) (h₁ : Epi φ.τ₁)
    (h₁ : S₁.RightHomologyData) (h₂ : S₂.RightHomologyData) :
    IsIso (opcyclesMap' φ h₁ h₂) := by
  

Proof state:
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
φ : S₁ ⟶ S₂
h₂✝ : IsIso φ.τ₂
h₁✝ : Epi φ.τ₁
h₁ : RightHomologyData S₁
h₂ : RightHomologyData S₂
⊢ IsIso (opcyclesMap' φ h₁ h₂)

Next tactic:
refine' ⟨h₂.descQ (inv φ.τ₂ ≫ h₁.p) _, _, _⟩
lemma isIso_opcyclesMap'_of_isIso_of_epi (φ : S₁ ⟶ S₂) (h₂ : IsIso φ.τ₂) (h₁ : Epi φ.τ₁)
    (h₁ : S₁.RightHomologyData) (h₂ : S₂.RightHomologyData) :
    IsIso (opcyclesMap' φ h₁ h₂) := by
  refine' ⟨h₂.descQ (inv φ.τ₂ ≫ h₁.p) _, _, _⟩
  · 

Proof state:
case refine'_1
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
φ : S₁ ⟶ S₂
h₂✝ : IsIso φ.τ₂
h₁✝ : Epi φ.τ₁
h₁ : RightHomologyData S₁
h₂ : RightHomologyData S₂
⊢ S₂.f ≫ inv φ.τ₂ ≫ h₁.p = 0

Next tactic:
simp only [← cancel_epi φ.τ₁, comp_zero, φ.comm₁₂_assoc, IsIso.hom_inv_id_assoc, h₁.wp]
lemma isIso_opcyclesMap'_of_isIso_of_epi (φ : S₁ ⟶ S₂) (h₂ : IsIso φ.τ₂) (h₁ : Epi φ.τ₁)
    (h₁ : S₁.RightHomologyData) (h₂ : S₂.RightHomologyData) :
    IsIso (opcyclesMap' φ h₁ h₂) := by
  refine' ⟨h₂.descQ (inv φ.τ₂ ≫ h₁.p) _, _, _⟩
  · simp only [← cancel_epi φ.τ₁, comp_zero, φ.comm₁₂_assoc, IsIso.hom_inv_id_assoc, h₁.wp]
  · 

Proof state:
case refine'_2
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
φ : S₁ ⟶ S₂
h₂✝ : IsIso φ.τ₂
h₁✝ : Epi φ.τ₁
h₁ : RightHomologyData S₁
h₂ : RightHomologyData S₂
⊢ opcyclesMap' φ h₁ h₂ ≫ RightHomologyData.descQ h₂ (inv φ.τ₂ ≫ h₁.p) (_ : S₂.f ≫ inv φ.τ₂ ≫ h₁.p = 0) = 𝟙 h₁.Q

Next tactic:
simp only [← cancel_epi h₁.p, p_opcyclesMap'_assoc, h₂.p_descQ,
      IsIso.hom_inv_id_assoc, comp_id]
lemma isIso_opcyclesMap'_of_isIso_of_epi (φ : S₁ ⟶ S₂) (h₂ : IsIso φ.τ₂) (h₁ : Epi φ.τ₁)
    (h₁ : S₁.RightHomologyData) (h₂ : S₂.RightHomologyData) :
    IsIso (opcyclesMap' φ h₁ h₂) := by
  refine' ⟨h₂.descQ (inv φ.τ₂ ≫ h₁.p) _, _, _⟩
  · simp only [← cancel_epi φ.τ₁, comp_zero, φ.comm₁₂_assoc, IsIso.hom_inv_id_assoc, h₁.wp]
  · simp only [← cancel_epi h₁.p, p_opcyclesMap'_assoc, h₂.p_descQ,
      IsIso.hom_inv_id_assoc, comp_id]
  · 

Proof state:
case refine'_3
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasZeroMorphisms C
S S₁ S₂ S₃ : ShortComplex C
φ : S₁ ⟶ S₂
h₂✝ : IsIso φ.τ₂
h₁✝ : Epi φ.τ₁
h₁ : RightHomologyData S₁
h₂ : RightHomologyData S₂
⊢ RightHomologyData.descQ h₂ (inv φ.τ₂ ≫ h₁.p) (_ : S₂.f ≫ inv φ.τ₂ ≫ h₁.p = 0) ≫ opcyclesMap' φ h₁ h₂ = 𝟙 h₂.Q

Next tactic:
simp only [← cancel_epi h₂.p, h₂.p_descQ_assoc, assoc, p_opcyclesMap',
      IsIso.inv_hom_id_assoc, comp_id]
theorem periodic_gcd (a : ℕ) : Periodic (gcd a) a := by
  

Proof state:
a : ℕ
⊢ Periodic (gcd a) a

Next tactic:
simp only [forall_const, gcd_add_self_right, eq_self_iff_true, Periodic]
theorem periodic_coprime (a : ℕ) : Periodic (Coprime a) a := by
  

Proof state:
a : ℕ
⊢ Periodic (Coprime a) a

Next tactic:
simp only [coprime_add_self_right, forall_const, iff_self_iff, eq_iff_iff, Periodic]
theorem periodic_mod (a : ℕ) : Periodic (fun n => n % a) a := by
  

Proof state:
a : ℕ
⊢ Periodic (fun n => n % a) a

Next tactic:
simp only [forall_const, eq_self_iff_true, add_mod_right, Periodic]
theorem _root_.Function.Periodic.map_mod_nat {α : Type*} {f : ℕ → α} {a : ℕ} (hf : Periodic f a) :
    ∀ n, f (n % a) = f n := fun n => by
  

Proof state:
α : Type u_1
f : ℕ → α
a : ℕ
hf : Periodic f a
n : ℕ
⊢ f (n % a) = f n

Next tactic:
conv_rhs => rw [← Nat.mod_add_div n a, mul_comm, ← Nat.nsmul_eq_mul, hf.nsmul]
theorem _root_.Function.Periodic.map_mod_nat {α : Type*} {f : ℕ → α} {a : ℕ} (hf : Periodic f a) :
    ∀ n, f (n % a) = f n := fun n => by
  conv_rhs => 

Proof state:
α : Type u_1
f : ℕ → α
a : ℕ
hf : Periodic f a
n : ℕ
| f n

Next tactic:
rw [← Nat.mod_add_div n a, mul_comm, ← Nat.nsmul_eq_mul, hf.nsmul]
/-- An interval of length `a` filtered over a periodic predicate of period `a` has cardinality
equal to the number naturals below `a` for which `p a` is true. -/
theorem filter_multiset_Ico_card_eq_of_periodic (n a : ℕ) (p : ℕ → Prop) [DecidablePred p]
    (pp : Periodic p a) : card (filter p (Ico n (n + a))) = a.count p := by
  

Proof state:
n a : ℕ
p : ℕ → Prop
inst✝ : DecidablePred p
pp : Periodic p a
⊢ card (filter p (Ico n (n + a))) = count p a

Next tactic:
rw [count_eq_card_filter_range, Finset.card, Finset.filter_val, Finset.range_val, ←
    multiset_Ico_map_mod n, ← map_count_True_eq_filter_card, ← map_count_True_eq_filter_card,
    map_map]
/-- An interval of length `a` filtered over a periodic predicate of period `a` has cardinality
equal to the number naturals below `a` for which `p a` is true. -/
theorem filter_multiset_Ico_card_eq_of_periodic (n a : ℕ) (p : ℕ → Prop) [DecidablePred p]
    (pp : Periodic p a) : card (filter p (Ico n (n + a))) = a.count p := by
  rw [count_eq_card_filter_range, Finset.card, Finset.filter_val, Finset.range_val, ←
    multiset_Ico_map_mod n, ← map_count_True_eq_filter_card, ← map_count_True_eq_filter_card,
    map_map]
  

Proof state:
n a : ℕ
p : ℕ → Prop
inst✝ : DecidablePred p
pp : Periodic p a
⊢ Multiset.count True (map p (Ico n (n + a))) = Multiset.count True (map (p ∘ fun x => x % a) (Ico n (n + a)))

Next tactic:
congr
/-- An interval of length `a` filtered over a periodic predicate of period `a` has cardinality
equal to the number naturals below `a` for which `p a` is true. -/
theorem filter_multiset_Ico_card_eq_of_periodic (n a : ℕ) (p : ℕ → Prop) [DecidablePred p]
    (pp : Periodic p a) : card (filter p (Ico n (n + a))) = a.count p := by
  rw [count_eq_card_filter_range, Finset.card, Finset.filter_val, Finset.range_val, ←
    multiset_Ico_map_mod n, ← map_count_True_eq_filter_card, ← map_count_True_eq_filter_card,
    map_map]
  congr; 

Proof state:
case e_a.e_f
n a : ℕ
p : ℕ → Prop
inst✝ : DecidablePred p
pp : Periodic p a
⊢ p = p ∘ fun x => x % a

Next tactic:
funext n
/-- An interval of length `a` filtered over a periodic predicate of period `a` has cardinality
equal to the number naturals below `a` for which `p a` is true. -/
theorem filter_multiset_Ico_card_eq_of_periodic (n a : ℕ) (p : ℕ → Prop) [DecidablePred p]
    (pp : Periodic p a) : card (filter p (Ico n (n + a))) = a.count p := by
  rw [count_eq_card_filter_range, Finset.card, Finset.filter_val, Finset.range_val, ←
    multiset_Ico_map_mod n, ← map_count_True_eq_filter_card, ← map_count_True_eq_filter_card,
    map_map]
  congr; funext n
  

Proof state:
case e_a.e_f.h
n✝ a : ℕ
p : ℕ → Prop
inst✝ : DecidablePred p
pp : Periodic p a
n : ℕ
⊢ p n = (p ∘ fun x => x % a) n

Next tactic:
exact (Function.Periodic.map_mod_nat pp n).symm
/-- The set of natural number powers of an element of a monoid is closed under multiplication. -/
@[to_additive
      "The set of natural number multiples of an element of an `AddMonoid` is closed under
      addition."]
theorem powers.mul_mem {x y z : M} : y ∈ powers x → z ∈ powers x → y * z ∈ powers x :=
  fun ⟨n₁, h₁⟩ ⟨n₂, h₂⟩ => ⟨n₁ + n₂, by 

Proof state:
M : Type u_1
inst✝¹ : Monoid M
s : Set M
A : Type u_2
inst✝ : AddMonoid A
t : Set A
x y z : M
x✝¹ : y ∈ powers x
x✝ : z ∈ powers x
n₁ : ℕ
h₁ : x ^ n₁ = y
n₂ : ℕ
h₂ : x ^ n₂ = z
⊢ x ^ (n₁ + n₂) = y * z

Next tactic:
simp only [pow_add, *]
/-- A monoid is a submonoid of itself. -/
@[to_additive "An `AddMonoid` is an `AddSubmonoid` of itself."]
theorem Univ.isSubmonoid : IsSubmonoid (@Set.univ M) := by 

Proof state:
M : Type u_1
inst✝¹ : Monoid M
s : Set M
A : Type u_2
inst✝ : AddMonoid A
t : Set A
⊢ IsSubmonoid Set.univ

Next tactic:
constructor
/-- A monoid is a submonoid of itself. -/
@[to_additive "An `AddMonoid` is an `AddSubmonoid` of itself."]
theorem Univ.isSubmonoid : IsSubmonoid (@Set.univ M) := by constructor <;> 

Proof state:
case one_mem
M : Type u_1
inst✝¹ : Monoid M
s : Set M
A : Type u_2
inst✝ : AddMonoid A
t : Set A
⊢ 1 ∈ Set.univ

Next tactic:
simp
/-- A monoid is a submonoid of itself. -/
@[to_additive "An `AddMonoid` is an `AddSubmonoid` of itself."]
theorem Univ.isSubmonoid : IsSubmonoid (@Set.univ M) := by constructor <;> 

Proof state:
case mul_mem
M : Type u_1
inst✝¹ : Monoid M
s : Set M
A : Type u_2
inst✝ : AddMonoid A
t : Set A
⊢ ∀ {a b : M}, a ∈ Set.univ → b ∈ Set.univ → a * b ∈ Set.univ

Next tactic:
simp
/-- The preimage of a submonoid under a monoid hom is a submonoid of the domain. -/
@[to_additive
      "The preimage of an `AddSubmonoid` under an `AddMonoid` hom is
      an `AddSubmonoid` of the domain."]
theorem IsSubmonoid.preimage {N : Type*} [Monoid N] {f : M → N} (hf : IsMonoidHom f) {s : Set N}
    (hs : IsSubmonoid s) : IsSubmonoid (f ⁻¹' s) :=
  { one_mem := show f 1 ∈ s by (

Proof state:
M : Type u_1
inst✝² : Monoid M
s✝ : Set M
A : Type u_2
inst✝¹ : AddMonoid A
t : Set A
N : Type u_3
inst✝ : Monoid N
f : M → N
hf : IsMonoidHom f
s : Set N
hs : IsSubmonoid s
⊢ f 1 ∈ s

Next tactic:
rw [IsMonoidHom.map_one hf]
/-- The preimage of a submonoid under a monoid hom is a submonoid of the domain. -/
@[to_additive
      "The preimage of an `AddSubmonoid` under an `AddMonoid` hom is
      an `AddSubmonoid` of the domain."]
theorem IsSubmonoid.preimage {N : Type*} [Monoid N] {f : M → N} (hf : IsMonoidHom f) {s : Set N}
    (hs : IsSubmonoid s) : IsSubmonoid (f ⁻¹' s) :=
  { one_mem := show f 1 ∈ s by (rw [IsMonoidHom.map_one hf]; 

Proof state:
M : Type u_1
inst✝² : Monoid M
s✝ : Set M
A : Type u_2
inst✝¹ : AddMonoid A
t : Set A
N : Type u_3
inst✝ : Monoid N
f : M → N
hf : IsMonoidHom f
s : Set N
hs : IsSubmonoid s
⊢ 1 ∈ s

Next tactic:
exact hs.one_mem
/-- The preimage of a submonoid under a monoid hom is a submonoid of the domain. -/
@[to_additive
      "The preimage of an `AddSubmonoid` under an `AddMonoid` hom is
      an `AddSubmonoid` of the domain."]
theorem IsSubmonoid.preimage {N : Type*} [Monoid N] {f : M → N} (hf : IsMonoidHom f) {s : Set N}
    (hs : IsSubmonoid s) : IsSubmonoid (f ⁻¹' s) :=
  { one_mem := show f 1 ∈ s by (rw [IsMonoidHom.map_one hf]; exact hs.one_mem)
    mul_mem := fun {a b} (ha : f a ∈ s) (hb : f b ∈ s) =>
      show f (a * b) ∈ s by (

Proof state:
M : Type u_1
inst✝² : Monoid M
s✝ : Set M
A : Type u_2
inst✝¹ : AddMonoid A
t : Set A
N : Type u_3
inst✝ : Monoid N
f : M → N
hf : IsMonoidHom f
s : Set N
hs : IsSubmonoid s
a b : M
ha : f a ∈ s
hb : f b ∈ s
⊢ f (a * b) ∈ s

Next tactic:
rw [IsMonoidHom.map_mul' hf]
/-- The preimage of a submonoid under a monoid hom is a submonoid of the domain. -/
@[to_additive
      "The preimage of an `AddSubmonoid` under an `AddMonoid` hom is
      an `AddSubmonoid` of the domain."]
theorem IsSubmonoid.preimage {N : Type*} [Monoid N] {f : M → N} (hf : IsMonoidHom f) {s : Set N}
    (hs : IsSubmonoid s) : IsSubmonoid (f ⁻¹' s) :=
  { one_mem := show f 1 ∈ s by (rw [IsMonoidHom.map_one hf]; exact hs.one_mem)
    mul_mem := fun {a b} (ha : f a ∈ s) (hb : f b ∈ s) =>
      show f (a * b) ∈ s by (rw [IsMonoidHom.map_mul' hf]; 

Proof state:
M : Type u_1
inst✝² : Monoid M
s✝ : Set M
A : Type u_2
inst✝¹ : AddMonoid A
t : Set A
N : Type u_3
inst✝ : Monoid N
f : M → N
hf : IsMonoidHom f
s : Set N
hs : IsSubmonoid s
a b : M
ha : f a ∈ s
hb : f b ∈ s
⊢ f a * f b ∈ s

Next tactic:
exact hs.mul_mem ha hb
/-- The image of a submonoid under a monoid hom is a submonoid of the codomain. -/
@[to_additive
      "The image of an `AddSubmonoid` under an `AddMonoid` hom is an `AddSubmonoid` of the
      codomain."]
theorem IsSubmonoid.image {γ : Type*} [Monoid γ] {f : M → γ} (hf : IsMonoidHom f) {s : Set M}
    (hs : IsSubmonoid s) : IsSubmonoid (f '' s) :=
  { one_mem := ⟨1, hs.one_mem, hf.map_one⟩
    mul_mem := @fun a b ⟨x, hx⟩ ⟨y, hy⟩ =>
      ⟨x * y, hs.mul_mem hx.1 hy.1, by 

Proof state:
M : Type u_1
inst✝² : Monoid M
s✝ : Set M
A : Type u_2
inst✝¹ : AddMonoid A
t : Set A
γ : Type u_3
inst✝ : Monoid γ
f : M → γ
hf : IsMonoidHom f
s : Set M
hs : IsSubmonoid s
a b : γ
x✝¹ : a ∈ f '' s
x✝ : b ∈ f '' s
x : M
hx : x ∈ s ∧ f x = a
y : M
hy : y ∈ s ∧ f y = b
⊢ f (x * y) = a * b

Next tactic:
rw [hf.map_mul, hx.2, hy.2]
/-- The image of a monoid hom is a submonoid of the codomain. -/
@[to_additive "The image of an `AddMonoid` hom is an `AddSubmonoid` of the codomain."]
theorem Range.isSubmonoid {γ : Type*} [Monoid γ] {f : M → γ} (hf : IsMonoidHom f) :
    IsSubmonoid (Set.range f) := by
  

Proof state:
M : Type u_1
inst✝² : Monoid M
s : Set M
A : Type u_2
inst✝¹ : AddMonoid A
t : Set A
γ : Type u_3
inst✝ : Monoid γ
f : M → γ
hf : IsMonoidHom f
⊢ IsSubmonoid (Set.range f)

Next tactic:
rw [← Set.image_univ]
/-- The image of a monoid hom is a submonoid of the codomain. -/
@[to_additive "The image of an `AddMonoid` hom is an `AddSubmonoid` of the codomain."]
theorem Range.isSubmonoid {γ : Type*} [Monoid γ] {f : M → γ} (hf : IsMonoidHom f) :
    IsSubmonoid (Set.range f) := by
  rw [← Set.image_univ]
  

Proof state:
M : Type u_1
inst✝² : Monoid M
s : Set M
A : Type u_2
inst✝¹ : AddMonoid A
t : Set A
γ : Type u_3
inst✝ : Monoid γ
f : M → γ
hf : IsMonoidHom f
⊢ IsSubmonoid (f '' Set.univ)

Next tactic:
exact Univ.isSubmonoid.image hf
/-- Submonoids are closed under natural powers. -/
@[to_additive
      "An `AddSubmonoid` is closed under multiplication by naturals."]
theorem IsSubmonoid.pow_mem {a : M} (hs : IsSubmonoid s) (h : a ∈ s) : ∀ {n : ℕ}, a ^ n ∈ s
  | 0 => by
    

Proof state:
M : Type u_1
inst✝¹ : Monoid M
s : Set M
A : Type u_2
inst✝ : AddMonoid A
t : Set A
a : M
hs : IsSubmonoid s
h : a ∈ s
⊢ a ^ 0 ∈ s

Next tactic:
rw [pow_zero]
/-- Submonoids are closed under natural powers. -/
@[to_additive
      "An `AddSubmonoid` is closed under multiplication by naturals."]
theorem IsSubmonoid.pow_mem {a : M} (hs : IsSubmonoid s) (h : a ∈ s) : ∀ {n : ℕ}, a ^ n ∈ s
  | 0 => by
    rw [pow_zero]
    

Proof state:
M : Type u_1
inst✝¹ : Monoid M
s : Set M
A : Type u_2
inst✝ : AddMonoid A
t : Set A
a : M
hs : IsSubmonoid s
h : a ∈ s
⊢ 1 ∈ s

Next tactic:
exact hs.one_mem
/-- Submonoids are closed under natural powers. -/
@[to_additive
      "An `AddSubmonoid` is closed under multiplication by naturals."]
theorem IsSubmonoid.pow_mem {a : M} (hs : IsSubmonoid s) (h : a ∈ s) : ∀ {n : ℕ}, a ^ n ∈ s
  | 0 => by
    rw [pow_zero]
    exact hs.one_mem
  | n + 1 => by
    

Proof state:
M : Type u_1
inst✝¹ : Monoid M
s : Set M
A : Type u_2
inst✝ : AddMonoid A
t : Set A
a : M
hs : IsSubmonoid s
h : a ∈ s
n : ℕ
⊢ a ^ (n + 1) ∈ s

Next tactic:
rw [pow_succ]