l3lab/ntp-mathlib huggingface dataset:
/-- The isomorphism between `n ⊗ X` and `normalize X n` is natural (in both `X` and `n`, but
    naturality in `n` is trivial and was "proved" in `normalizeIsoAux`). This is the real heart
    of our proof of the coherence theorem. -/
def normalizeIso : tensorFunc C ≅ normalize' C :=
  NatIso.ofComponents (normalizeIsoAux C)
    (by -- porting note: the proof has been mostly rewritten
      rintro X Y f
      induction' f using Quotient.recOn with f; swap; rfl
      induction' f with _ X₁ X₂ X₃ _ _ _ _ _ _ _ _ _ _ _ _ h₁ h₂ X₁ X₂ Y₁ Y₂ f g h₁ h₂
      · simp only [mk_id, Functor.map_id, Category.comp_id, Category.id_comp]
      · ext n
        dsimp
        rw [mk_α_hom, NatTrans.comp_app, NatTrans.comp_app]
        dsimp [NatIso.ofComponents, normalizeMapAux, whiskeringRight, whiskerRight, Functor.comp]
        simp only [comp_tensor_id, associator_conjugation, tensor_id,
          Category.comp_id]
        simp only [← Category.assoc]
        congr 4
        simp only [Category.assoc, ← cancel_epi (𝟙 (inclusionObj n.as) ⊗ (α_ X₁ X₂ X₃).inv),
          pentagon_inv_assoc (inclusionObj n.as) X₁ X₂ X₃,
          tensor_inv_hom_id_assoc, tensor_id, Category.id_comp, Iso.inv_hom_id,
          Category.comp_id]
      · ext n
        dsimp
        rw [mk_α_inv, NatTrans.comp_app, NatTrans.comp_app]
        dsimp [NatIso.ofComponents, normalizeMapAux, whiskeringRight, whiskerRight, Functor.comp]
        simp only [Category.assoc, comp_tensor_id, tensor_id, Category.comp_id,
          pentagon_inv_assoc, ← associator_inv_naturality_assoc]
        rfl
      · ext n
        dsimp [Functor.comp]
        rw [mk_l_hom, NatTrans.comp_app, NatTrans.comp_app]
        dsimp [NatIso.ofComponents, normalizeMapAux, whiskeringRight, whiskerRight, Functor.comp]
        simp only [triangle_assoc_comp_right_assoc, Category.assoc, Category.comp_id]
        rfl
      · ext n
        dsimp [Functor.comp]
        rw [mk_l_inv, NatTrans.comp_app, NatTrans.comp_app]
        dsimp [NatIso.ofComponents, normalizeMapAux, whiskeringRight, whiskerRight, Functor.comp]
        simp only [triangle_assoc_comp_left_inv_assoc, inv_hom_id_tensor_assoc, tensor_id,
          Category.id_comp, Category.comp_id]
        rfl
      · ext n
        dsimp
        rw [mk_ρ_hom, NatTrans.comp_app, NatTrans.comp_app]
        dsimp [NatIso.ofComponents, normalizeMapAux, whiskeringRight, whiskerRight, Functor.comp]
        simp only [← (Iso.inv_comp_eq _).2 (rightUnitor_tensor _ _), Category.assoc,
          ← rightUnitor_naturality, Category.comp_id]; 

Proof state:
case f.ρ_hom.w.h
C : Type u
X Y X✝ : F C
n : (Discrete ∘ NormalMonoidalObject) C
⊢ (α_ (inclusionObj n.as) X✝ (𝟙_ (F C))).inv ≫
      ((normalizeIsoApp C X✝ n).hom ⊗ 𝟙 (𝟙_ (F C))) ≫
        (ρ_ (inclusionObj ((Discrete.functor (normalizeObj X✝)).obj n).as)).hom =
    (α_ (inclusionObj n.as) X✝ (𝟙_ (F C))).inv ≫
      ((normalizeIsoApp C X✝ n).hom ⊗ 𝟙 (𝟙_ (F C))) ≫ (ρ_ (inclusionObj (normalizeObj X✝ n.as).as)).hom

Next tactic:
rfl
/-- The isomorphism between `n ⊗ X` and `normalize X n` is natural (in both `X` and `n`, but
    naturality in `n` is trivial and was "proved" in `normalizeIsoAux`). This is the real heart
    of our proof of the coherence theorem. -/
def normalizeIso : tensorFunc C ≅ normalize' C :=
  NatIso.ofComponents (normalizeIsoAux C)
    (by -- porting note: the proof has been mostly rewritten
      rintro X Y f
      induction' f using Quotient.recOn with f; swap; rfl
      induction' f with _ X₁ X₂ X₃ _ _ _ _ _ _ _ _ _ _ _ _ h₁ h₂ X₁ X₂ Y₁ Y₂ f g h₁ h₂
      · simp only [mk_id, Functor.map_id, Category.comp_id, Category.id_comp]
      · ext n
        dsimp
        rw [mk_α_hom, NatTrans.comp_app, NatTrans.comp_app]
        dsimp [NatIso.ofComponents, normalizeMapAux, whiskeringRight, whiskerRight, Functor.comp]
        simp only [comp_tensor_id, associator_conjugation, tensor_id,
          Category.comp_id]
        simp only [← Category.assoc]
        congr 4
        simp only [Category.assoc, ← cancel_epi (𝟙 (inclusionObj n.as) ⊗ (α_ X₁ X₂ X₃).inv),
          pentagon_inv_assoc (inclusionObj n.as) X₁ X₂ X₃,
          tensor_inv_hom_id_assoc, tensor_id, Category.id_comp, Iso.inv_hom_id,
          Category.comp_id]
      · ext n
        dsimp
        rw [mk_α_inv, NatTrans.comp_app, NatTrans.comp_app]
        dsimp [NatIso.ofComponents, normalizeMapAux, whiskeringRight, whiskerRight, Functor.comp]
        simp only [Category.assoc, comp_tensor_id, tensor_id, Category.comp_id,
          pentagon_inv_assoc, ← associator_inv_naturality_assoc]
        rfl
      · ext n
        dsimp [Functor.comp]
        rw [mk_l_hom, NatTrans.comp_app, NatTrans.comp_app]
        dsimp [NatIso.ofComponents, normalizeMapAux, whiskeringRight, whiskerRight, Functor.comp]
        simp only [triangle_assoc_comp_right_assoc, Category.assoc, Category.comp_id]
        rfl
      · ext n
        dsimp [Functor.comp]
        rw [mk_l_inv, NatTrans.comp_app, NatTrans.comp_app]
        dsimp [NatIso.ofComponents, normalizeMapAux, whiskeringRight, whiskerRight, Functor.comp]
        simp only [triangle_assoc_comp_left_inv_assoc, inv_hom_id_tensor_assoc, tensor_id,
          Category.id_comp, Category.comp_id]
        rfl
      · ext n
        dsimp
        rw [mk_ρ_hom, NatTrans.comp_app, NatTrans.comp_app]
        dsimp [NatIso.ofComponents, normalizeMapAux, whiskeringRight, whiskerRight, Functor.comp]
        simp only [← (Iso.inv_comp_eq _).2 (rightUnitor_tensor _ _), Category.assoc,
          ← rightUnitor_naturality, Category.comp_id]; rfl
      · 

Proof state:
case f.ρ_inv
C : Type u
X Y X✝ : F C
⊢ (tensorFunc C).map ⟦Hom.ρ_inv X✝⟧ ≫ (normalizeIsoAux C (tensor X✝ unit)).hom =
    (normalizeIsoAux C X✝).hom ≫ (normalize' C).map ⟦Hom.ρ_inv X✝⟧

Next tactic:
ext n
/-- The isomorphism between `n ⊗ X` and `normalize X n` is natural (in both `X` and `n`, but
    naturality in `n` is trivial and was "proved" in `normalizeIsoAux`). This is the real heart
    of our proof of the coherence theorem. -/
def normalizeIso : tensorFunc C ≅ normalize' C :=
  NatIso.ofComponents (normalizeIsoAux C)
    (by -- porting note: the proof has been mostly rewritten
      rintro X Y f
      induction' f using Quotient.recOn with f; swap; rfl
      induction' f with _ X₁ X₂ X₃ _ _ _ _ _ _ _ _ _ _ _ _ h₁ h₂ X₁ X₂ Y₁ Y₂ f g h₁ h₂
      · simp only [mk_id, Functor.map_id, Category.comp_id, Category.id_comp]
      · ext n
        dsimp
        rw [mk_α_hom, NatTrans.comp_app, NatTrans.comp_app]
        dsimp [NatIso.ofComponents, normalizeMapAux, whiskeringRight, whiskerRight, Functor.comp]
        simp only [comp_tensor_id, associator_conjugation, tensor_id,
          Category.comp_id]
        simp only [← Category.assoc]
        congr 4
        simp only [Category.assoc, ← cancel_epi (𝟙 (inclusionObj n.as) ⊗ (α_ X₁ X₂ X₃).inv),
          pentagon_inv_assoc (inclusionObj n.as) X₁ X₂ X₃,
          tensor_inv_hom_id_assoc, tensor_id, Category.id_comp, Iso.inv_hom_id,
          Category.comp_id]
      · ext n
        dsimp
        rw [mk_α_inv, NatTrans.comp_app, NatTrans.comp_app]
        dsimp [NatIso.ofComponents, normalizeMapAux, whiskeringRight, whiskerRight, Functor.comp]
        simp only [Category.assoc, comp_tensor_id, tensor_id, Category.comp_id,
          pentagon_inv_assoc, ← associator_inv_naturality_assoc]
        rfl
      · ext n
        dsimp [Functor.comp]
        rw [mk_l_hom, NatTrans.comp_app, NatTrans.comp_app]
        dsimp [NatIso.ofComponents, normalizeMapAux, whiskeringRight, whiskerRight, Functor.comp]
        simp only [triangle_assoc_comp_right_assoc, Category.assoc, Category.comp_id]
        rfl
      · ext n
        dsimp [Functor.comp]
        rw [mk_l_inv, NatTrans.comp_app, NatTrans.comp_app]
        dsimp [NatIso.ofComponents, normalizeMapAux, whiskeringRight, whiskerRight, Functor.comp]
        simp only [triangle_assoc_comp_left_inv_assoc, inv_hom_id_tensor_assoc, tensor_id,
          Category.id_comp, Category.comp_id]
        rfl
      · ext n
        dsimp
        rw [mk_ρ_hom, NatTrans.comp_app, NatTrans.comp_app]
        dsimp [NatIso.ofComponents, normalizeMapAux, whiskeringRight, whiskerRight, Functor.comp]
        simp only [← (Iso.inv_comp_eq _).2 (rightUnitor_tensor _ _), Category.assoc,
          ← rightUnitor_naturality, Category.comp_id]; rfl
      · ext n
        

Proof state:
case f.ρ_inv.w.h
C : Type u
X Y X✝ : F C
n : (Discrete ∘ NormalMonoidalObject) C
⊢ ((tensorFunc C).map ⟦Hom.ρ_inv X✝⟧ ≫ (normalizeIsoAux C (tensor X✝ unit)).hom).app n =
    ((normalizeIsoAux C X✝).hom ≫ (normalize' C).map ⟦Hom.ρ_inv X✝⟧).app n

Next tactic:
dsimp
/-- The isomorphism between an object and its normal form is natural. -/
def fullNormalizeIso : 𝟭 (F C) ≅ fullNormalize C ⋙ inclusion :=
  NatIso.ofComponents
  (fun X => (λ_ X).symm ≪≫ ((normalizeIso C).app X).app ⟨NormalMonoidalObject.unit⟩)
    (by
      

Proof state:
C : Type u
⊢ ∀ {X Y : F C} (f : X ⟶ Y),
    (𝟭 (F C)).map f ≫
        ((fun X => (λ_ X).symm ≪≫ ((normalizeIso C).app X).app { as := NormalMonoidalObject.unit }) Y).hom =
      ((fun X => (λ_ X).symm ≪≫ ((normalizeIso C).app X).app { as := NormalMonoidalObject.unit }) X).hom ≫
        (fullNormalize C ⋙ inclusion).map f

Next tactic:
intro X Y f
/-- The isomorphism between an object and its normal form is natural. -/
def fullNormalizeIso : 𝟭 (F C) ≅ fullNormalize C ⋙ inclusion :=
  NatIso.ofComponents
  (fun X => (λ_ X).symm ≪≫ ((normalizeIso C).app X).app ⟨NormalMonoidalObject.unit⟩)
    (by
      intro X Y f
      

Proof state:
C : Type u
X Y : F C
f : X ⟶ Y
⊢ (𝟭 (F C)).map f ≫ ((fun X => (λ_ X).symm ≪≫ ((normalizeIso C).app X).app { as := NormalMonoidalObject.unit }) Y).hom =
    ((fun X => (λ_ X).symm ≪≫ ((normalizeIso C).app X).app { as := NormalMonoidalObject.unit }) X).hom ≫
      (fullNormalize C ⋙ inclusion).map f

Next tactic:
dsimp
/-- The isomorphism between an object and its normal form is natural. -/
def fullNormalizeIso : 𝟭 (F C) ≅ fullNormalize C ⋙ inclusion :=
  NatIso.ofComponents
  (fun X => (λ_ X).symm ≪≫ ((normalizeIso C).app X).app ⟨NormalMonoidalObject.unit⟩)
    (by
      intro X Y f
      dsimp
      

Proof state:
C : Type u
X Y : F C
f : X ⟶ Y
⊢ f ≫ (λ_ Y).inv ≫ (((normalizeIso C).app Y).app { as := NormalMonoidalObject.unit }).hom =
    ((λ_ X).inv ≫ (((normalizeIso C).app X).app { as := NormalMonoidalObject.unit }).hom) ≫
      (fullNormalize C ⋙ Discrete.functor inclusionObj).map f

Next tactic:
rw [leftUnitor_inv_naturality_assoc, Category.assoc, Iso.cancel_iso_inv_left]
/-- The isomorphism between an object and its normal form is natural. -/
def fullNormalizeIso : 𝟭 (F C) ≅ fullNormalize C ⋙ inclusion :=
  NatIso.ofComponents
  (fun X => (λ_ X).symm ≪≫ ((normalizeIso C).app X).app ⟨NormalMonoidalObject.unit⟩)
    (by
      intro X Y f
      dsimp
      rw [leftUnitor_inv_naturality_assoc, Category.assoc, Iso.cancel_iso_inv_left]
      

Proof state:
C : Type u
X Y : F C
f : X ⟶ Y
⊢ (𝟙 (𝟙_ (F C)) ⊗ f) ≫ (((normalizeIso C).app Y).app { as := NormalMonoidalObject.unit }).hom =
    (((normalizeIso C).app X).app { as := NormalMonoidalObject.unit }).hom ≫
      (fullNormalize C ⋙ Discrete.functor inclusionObj).map f

Next tactic:
exact
        congr_arg (fun f => NatTrans.app f (Discrete.mk NormalMonoidalObject.unit))
          ((normalizeIso.{u} C).hom.naturality f)
/-- The monoidal coherence theorem. -/
instance subsingleton_hom : Quiver.IsThin (F C) := fun X Y =>
  ⟨fun f g => by
    

Proof state:
C : Type u
X Y : F C
f g : X ⟶ Y
⊢ f = g

Next tactic:
have hfg : (fullNormalize C).map f = (fullNormalize C).map g := Subsingleton.elim _ _
/-- The monoidal coherence theorem. -/
instance subsingleton_hom : Quiver.IsThin (F C) := fun X Y =>
  ⟨fun f g => by
    have hfg : (fullNormalize C).map f = (fullNormalize C).map g := Subsingleton.elim _ _
    

Proof state:
C : Type u
X Y : F C
f g : X ⟶ Y
hfg : (fullNormalize C).map f = (fullNormalize C).map g
⊢ f = g

Next tactic:
have hf := NatIso.naturality_2 (fullNormalizeIso.{u} C) f
/-- The monoidal coherence theorem. -/
instance subsingleton_hom : Quiver.IsThin (F C) := fun X Y =>
  ⟨fun f g => by
    have hfg : (fullNormalize C).map f = (fullNormalize C).map g := Subsingleton.elim _ _
    have hf := NatIso.naturality_2 (fullNormalizeIso.{u} C) f
    

Proof state:
C : Type u
X Y : F C
f g : X ⟶ Y
hfg : (fullNormalize C).map f = (fullNormalize C).map g
hf :
  (fullNormalizeIso C).hom.app X ≫ (fullNormalize C ⋙ inclusion).map f ≫ (fullNormalizeIso C).inv.app Y =
    (𝟭 (F C)).map f
⊢ f = g

Next tactic:
have hg := NatIso.naturality_2 (fullNormalizeIso.{u} C) g
/-- The monoidal coherence theorem. -/
instance subsingleton_hom : Quiver.IsThin (F C) := fun X Y =>
  ⟨fun f g => by
    have hfg : (fullNormalize C).map f = (fullNormalize C).map g := Subsingleton.elim _ _
    have hf := NatIso.naturality_2 (fullNormalizeIso.{u} C) f
    have hg := NatIso.naturality_2 (fullNormalizeIso.{u} C) g
    

Proof state:
C : Type u
X Y : F C
f g : X ⟶ Y
hfg : (fullNormalize C).map f = (fullNormalize C).map g
hf :
  (fullNormalizeIso C).hom.app X ≫ (fullNormalize C ⋙ inclusion).map f ≫ (fullNormalizeIso C).inv.app Y =
    (𝟭 (F C)).map f
hg :
  (fullNormalizeIso C).hom.app X ≫ (fullNormalize C ⋙ inclusion).map g ≫ (fullNormalizeIso C).inv.app Y =
    (𝟭 (F C)).map g
⊢ f = g

Next tactic:
exact hf.symm.trans (Eq.trans (by simp only [Functor.comp_map, hfg]) hg)
/-- The monoidal coherence theorem. -/
instance subsingleton_hom : Quiver.IsThin (F C) := fun X Y =>
  ⟨fun f g => by
    have hfg : (fullNormalize C).map f = (fullNormalize C).map g := Subsingleton.elim _ _
    have hf := NatIso.naturality_2 (fullNormalizeIso.{u} C) f
    have hg := NatIso.naturality_2 (fullNormalizeIso.{u} C) g
    exact hf.symm.trans (Eq.trans (by 

Proof state:
C : Type u
X Y : F C
f g : X ⟶ Y
hfg : (fullNormalize C).map f = (fullNormalize C).map g
hf :
  (fullNormalizeIso C).hom.app X ≫ (fullNormalize C ⋙ inclusion).map f ≫ (fullNormalizeIso C).inv.app Y =
    (𝟭 (F C)).map f
hg :
  (fullNormalizeIso C).hom.app X ≫ (fullNormalize C ⋙ inclusion).map g ≫ (fullNormalizeIso C).inv.app Y =
    (𝟭 (F C)).map g
⊢ (fullNormalizeIso C).hom.app X ≫ (fullNormalize C ⋙ inclusion).map f ≫ (fullNormalizeIso C).inv.app Y =
    (fullNormalizeIso C).hom.app X ≫ (fullNormalize C ⋙ inclusion).map g ≫ (fullNormalizeIso C).inv.app Y

Next tactic:
simp only [Functor.comp_map, hfg]
instance : Groupoid.{u} (F C) :=
  { (inferInstance : Category (F C)) with
    inv := Quotient.lift (fun f => ⟦inverseAux f⟧) (by 

Proof state:
C : Type u
src✝ : Category.{u, u} (F C) := inferInstance
X✝ Y✝ : F C
⊢ ∀ (a b : X✝ ⟶ᵐ Y✝), a ≈ b → (fun f => ⟦inverseAux f⟧) a = (fun f => ⟦inverseAux f⟧) b

Next tactic:
aesop_cat
instance : NoncompactSpace ℍ := by
  

Proof state:
⊢ NoncompactSpace ℍ

Next tactic:
refine' ⟨fun h => _⟩
instance : NoncompactSpace ℍ := by
  refine' ⟨fun h => _⟩
  

Proof state:
h : IsCompact univ
⊢ False

Next tactic:
have : IsCompact (Complex.im ⁻¹' Ioi 0) := isCompact_iff_isCompact_univ.2 h
instance : NoncompactSpace ℍ := by
  refine' ⟨fun h => _⟩
  have : IsCompact (Complex.im ⁻¹' Ioi 0) := isCompact_iff_isCompact_univ.2 h
  

Proof state:
h : IsCompact univ
this : IsCompact (Complex.im ⁻¹' Ioi 0)
⊢ False

Next tactic:
replace := this.isClosed.closure_eq
instance : NoncompactSpace ℍ := by
  refine' ⟨fun h => _⟩
  have : IsCompact (Complex.im ⁻¹' Ioi 0) := isCompact_iff_isCompact_univ.2 h
  replace := this.isClosed.closure_eq
  

Proof state:
h : IsCompact univ
this : closure (Complex.im ⁻¹' Ioi 0) = Complex.im ⁻¹' Ioi 0
⊢ False

Next tactic:
rw [closure_preimage_im, closure_Ioi, Set.ext_iff] at this
instance : NoncompactSpace ℍ := by
  refine' ⟨fun h => _⟩
  have : IsCompact (Complex.im ⁻¹' Ioi 0) := isCompact_iff_isCompact_univ.2 h
  replace := this.isClosed.closure_eq
  rw [closure_preimage_im, closure_Ioi, Set.ext_iff] at this
  

Proof state:
h : IsCompact univ
this : ∀ (x : ℂ), x ∈ Complex.im ⁻¹' Ici 0 ↔ x ∈ Complex.im ⁻¹' Ioi 0
⊢ False

Next tactic:
exact absurd ((this 0).1 (@left_mem_Ici ℝ _ 0)) (@lt_irrefl ℝ _ 0)
theorem primorial_succ {n : ℕ} (hn1 : n ≠ 1) (hn : Odd n) : (n + 1)# = n# := by
  

Proof state:
n : ℕ
hn1 : n ≠ 1
hn : Odd n
⊢ (n + 1)# = n#

Next tactic:
refine prod_congr ?_ fun _ _ ↦ rfl
theorem primorial_succ {n : ℕ} (hn1 : n ≠ 1) (hn : Odd n) : (n + 1)# = n# := by
  refine prod_congr ?_ fun _ _ ↦ rfl
  

Proof state:
n : ℕ
hn1 : n ≠ 1
hn : Odd n
⊢ filter Nat.Prime (range (n + 1 + 1)) = filter Nat.Prime (range (n + 1))

Next tactic:
rw [range_succ, filter_insert, if_neg fun h ↦ odd_iff_not_even.mp hn _]
theorem primorial_succ {n : ℕ} (hn1 : n ≠ 1) (hn : Odd n) : (n + 1)# = n# := by
  refine prod_congr ?_ fun _ _ ↦ rfl
  rw [range_succ, filter_insert, if_neg fun h ↦ odd_iff_not_even.mp hn _]
  

Proof state:
n : ℕ
hn1 : n ≠ 1
hn : Odd n
⊢ Nat.Prime (n + 1) → Even n

Next tactic:
exact fun h ↦ h.even_sub_one <| mt succ.inj hn1
theorem primorial_add (m n : ℕ) :
    (m + n)# = m# * ∏ p in filter Nat.Prime (Ico (m + 1) (m + n + 1)), p := by
  

Proof state:
m n : ℕ
⊢ (m + n)# = m# * ∏ p in filter Nat.Prime (Ico (m + 1) (m + n + 1)), p

Next tactic:
rw [primorial, primorial, ← Ico_zero_eq_range, ← prod_union, ← filter_union, Ico_union_Ico_eq_Ico]
theorem primorial_add (m n : ℕ) :
    (m + n)# = m# * ∏ p in filter Nat.Prime (Ico (m + 1) (m + n + 1)), p := by
  rw [primorial, primorial, ← Ico_zero_eq_range, ← prod_union, ← filter_union, Ico_union_Ico_eq_Ico]
  

Proof state:
case hab
m n : ℕ
⊢ 0 ≤ m + 1
case hbc
m n : ℕ
⊢ m + 1 ≤ m + n + 1
m n : ℕ ⊢ Disjoint (filter Nat.Prime (Ico 0 (m + 1))) (filter Nat.Prime (Ico (m + 1) (m + n + 1)))

Next tactic:
exacts [Nat.zero_le _, add_le_add_right (Nat.le_add_right _ _) _,
    disjoint_filter_filter <| Ico_disjoint_Ico_consecutive _ _ _]
theorem primorial_add_dvd {m n : ℕ} (h : n ≤ m) : (m + n)# ∣ m# * choose (m + n) m :=
  calc
    (m + n)# = m# * ∏ p in filter Nat.Prime (Ico (m + 1) (m + n + 1)), p := primorial_add _ _
    _ ∣ m# * choose (m + n) m :=
      mul_dvd_mul_left _ <|
        prod_primes_dvd _ (fun k hk ↦ (mem_filter.1 hk).2.prime) fun p hp ↦ by
          

Proof state:
m n : ℕ
h : n ≤ m
p : ℕ
hp : p ∈ filter Nat.Prime (Ico (m + 1) (m + n + 1))
⊢ p ∣ Nat.choose (m + n) m

Next tactic:
rw [mem_filter, mem_Ico] at hp
theorem primorial_add_dvd {m n : ℕ} (h : n ≤ m) : (m + n)# ∣ m# * choose (m + n) m :=
  calc
    (m + n)# = m# * ∏ p in filter Nat.Prime (Ico (m + 1) (m + n + 1)), p := primorial_add _ _
    _ ∣ m# * choose (m + n) m :=
      mul_dvd_mul_left _ <|
        prod_primes_dvd _ (fun k hk ↦ (mem_filter.1 hk).2.prime) fun p hp ↦ by
          rw [mem_filter, mem_Ico] at hp
          

Proof state:
m n : ℕ
h : n ≤ m
p : ℕ
hp : (m + 1 ≤ p ∧ p < m + n + 1) ∧ Nat.Prime p
⊢ p ∣ Nat.choose (m + n) m

Next tactic:
exact hp.2.dvd_choose_add hp.1.1 (h.trans_lt (m.lt_succ_self.trans_le hp.1.1))
              (Nat.lt_succ_iff.1 hp.1.2)
theorem primorial_le_4_pow (n : ℕ) : n# ≤ 4 ^ n := by
  

Proof state:
n : ℕ
⊢ n# ≤ 4 ^ n

Next tactic:
induction' n using Nat.strong_induction_on with n ihn
theorem primorial_le_4_pow (n : ℕ) : n# ≤ 4 ^ n := by
  induction' n using Nat.strong_induction_on with n ihn
  

Proof state:
case h
n : ℕ
ihn : ∀ m < n, m# ≤ 4 ^ m
⊢ n# ≤ 4 ^ n

Next tactic:
cases' n with n
theorem primorial_le_4_pow (n : ℕ) : n# ≤ 4 ^ n := by
  induction' n using Nat.strong_induction_on with n ihn
  cases' n with n; · 

Proof state:
case h.zero
ihn : ∀ m < zero, m# ≤ 4 ^ m
⊢ zero# ≤ 4 ^ zero

Next tactic:
rfl
theorem primorial_le_4_pow (n : ℕ) : n# ≤ 4 ^ n := by
  induction' n using Nat.strong_induction_on with n ihn
  cases' n with n; · rfl
  

Proof state:
case h.succ
n : ℕ
ihn : ∀ m < succ n, m# ≤ 4 ^ m
⊢ succ n# ≤ 4 ^ succ n

Next tactic:
rcases n.even_or_odd with (⟨m, rfl⟩ | ho)
theorem primorial_le_4_pow (n : ℕ) : n# ≤ 4 ^ n := by
  induction' n using Nat.strong_induction_on with n ihn
  cases' n with n; · rfl
  rcases n.even_or_odd with (⟨m, rfl⟩ | ho)
  · 

Proof state:
case h.succ.inl.intro
m : ℕ
ihn : ∀ m_1 < succ (m + m), m_1# ≤ 4 ^ m_1
⊢ succ (m + m)# ≤ 4 ^ succ (m + m)

Next tactic:
rcases m.eq_zero_or_pos with (rfl | hm)
theorem primorial_le_4_pow (n : ℕ) : n# ≤ 4 ^ n := by
  induction' n using Nat.strong_induction_on with n ihn
  cases' n with n; · rfl
  rcases n.even_or_odd with (⟨m, rfl⟩ | ho)
  · rcases m.eq_zero_or_pos with (rfl | hm)
    · 

Proof state:
case h.succ.inl.intro.inl
ihn : ∀ m < succ (0 + 0), m# ≤ 4 ^ m
⊢ succ (0 + 0)# ≤ 4 ^ succ (0 + 0)

Next tactic:
decide
theorem primorial_le_4_pow (n : ℕ) : n# ≤ 4 ^ n := by
  induction' n using Nat.strong_induction_on with n ihn
  cases' n with n; · rfl
  rcases n.even_or_odd with (⟨m, rfl⟩ | ho)
  · rcases m.eq_zero_or_pos with (rfl | hm)
    · decide
    

Proof state:
case h.succ.inl.intro.inr
m : ℕ
ihn : ∀ m_1 < succ (m + m), m_1# ≤ 4 ^ m_1
hm : m > 0
⊢ succ (m + m)# ≤ 4 ^ succ (m + m)

Next tactic:
calc
      (m + m + 1)# = (m + 1 + m)# := by rw [add_right_comm]
      _ ≤ (m + 1)# * choose (m + 1 + m) (m + 1) := primorial_add_le m.le_succ
      _ = (m + 1)# * choose (2 * m + 1) m := by rw [choose_symm_add, two_mul, add_right_comm]
      _ ≤ 4 ^ (m + 1) * 4 ^ m :=
        mul_le_mul' (ihn _ <| succ_lt_succ <| (lt_add_iff_pos_left _).2 hm) (choose_middle_le_pow _)
      _ ≤ 4 ^ (m + m + 1) := by rw [← pow_add, add_right_comm]
theorem primorial_le_4_pow (n : ℕ) : n# ≤ 4 ^ n := by
  induction' n using Nat.strong_induction_on with n ihn
  cases' n with n; · rfl
  rcases n.even_or_odd with (⟨m, rfl⟩ | ho)
  · rcases m.eq_zero_or_pos with (rfl | hm)
    · decide
    calc
      (m + m + 1)# = (m + 1 + m)# := by 

Proof state:
m : ℕ
ihn : ∀ m_1 < succ (m + m), m_1# ≤ 4 ^ m_1
hm : m > 0
⊢ (m + m + 1)# = (m + 1 + m)#

Next tactic:
rw [add_right_comm]
theorem primorial_le_4_pow (n : ℕ) : n# ≤ 4 ^ n := by
  induction' n using Nat.strong_induction_on with n ihn
  cases' n with n; · rfl
  rcases n.even_or_odd with (⟨m, rfl⟩ | ho)
  · rcases m.eq_zero_or_pos with (rfl | hm)
    · decide
    calc
      (m + m + 1)# = (m + 1 + m)# := by rw [add_right_comm]
      _ ≤ (m + 1)# * choose (m + 1 + m) (m + 1) := primorial_add_le m.le_succ
      _ = (m + 1)# * choose (2 * m + 1) m := by 

Proof state:
m : ℕ
ihn : ∀ m_1 < succ (m + m), m_1# ≤ 4 ^ m_1
hm : m > 0
⊢ (m + 1)# * Nat.choose (m + 1 + m) (m + 1) = (m + 1)# * Nat.choose (2 * m + 1) m

Next tactic:
rw [choose_symm_add, two_mul, add_right_comm]
theorem primorial_le_4_pow (n : ℕ) : n# ≤ 4 ^ n := by
  induction' n using Nat.strong_induction_on with n ihn
  cases' n with n; · rfl
  rcases n.even_or_odd with (⟨m, rfl⟩ | ho)
  · rcases m.eq_zero_or_pos with (rfl | hm)
    · decide
    calc
      (m + m + 1)# = (m + 1 + m)# := by rw [add_right_comm]
      _ ≤ (m + 1)# * choose (m + 1 + m) (m + 1) := primorial_add_le m.le_succ
      _ = (m + 1)# * choose (2 * m + 1) m := by rw [choose_symm_add, two_mul, add_right_comm]
      _ ≤ 4 ^ (m + 1) * 4 ^ m :=
        mul_le_mul' (ihn _ <| succ_lt_succ <| (lt_add_iff_pos_left _).2 hm) (choose_middle_le_pow _)
      _ ≤ 4 ^ (m + m + 1) := by 

Proof state:
m : ℕ
ihn : ∀ m_1 < succ (m + m), m_1# ≤ 4 ^ m_1
hm : m > 0
⊢ 4 ^ (m + 1) * 4 ^ m ≤ 4 ^ (m + m + 1)

Next tactic:
rw [← pow_add, add_right_comm]
theorem primorial_le_4_pow (n : ℕ) : n# ≤ 4 ^ n := by
  induction' n using Nat.strong_induction_on with n ihn
  cases' n with n; · rfl
  rcases n.even_or_odd with (⟨m, rfl⟩ | ho)
  · rcases m.eq_zero_or_pos with (rfl | hm)
    · decide
    calc
      (m + m + 1)# = (m + 1 + m)# := by rw [add_right_comm]
      _ ≤ (m + 1)# * choose (m + 1 + m) (m + 1) := primorial_add_le m.le_succ
      _ = (m + 1)# * choose (2 * m + 1) m := by rw [choose_symm_add, two_mul, add_right_comm]
      _ ≤ 4 ^ (m + 1) * 4 ^ m :=
        mul_le_mul' (ihn _ <| succ_lt_succ <| (lt_add_iff_pos_left _).2 hm) (choose_middle_le_pow _)
      _ ≤ 4 ^ (m + m + 1) := by rw [← pow_add, add_right_comm]
  · 

Proof state:
case h.succ.inr
n : ℕ
ihn : ∀ m < succ n, m# ≤ 4 ^ m
ho : Odd n
⊢ succ n# ≤ 4 ^ succ n

Next tactic:
rcases Decidable.eq_or_ne n 1 with (rfl | hn)