l3lab/ntp-mathlib huggingface dataset:
/-- Construction of the homotopy from `PInfty` to the identity using eventually
(termwise) constant homotopies from `P q` to the identity for all `q` -/
@[simps]
def homotopyPInftyToId : Homotopy (PInfty : K[X] ⟶ _) (𝟙 _) where
  hom i j := (homotopyPToId X (j + 1)).hom i j
  zero i j hij := Homotopy.zero _ i j hij
  comm n := by
    rcases n with _|n
    · simpa only [Homotopy.dNext_zero_chainComplex, Homotopy.prevD_chainComplex,
        PInfty_f, Nat.zero_eq, P_f_0_eq, zero_add] using (homotopyPToId X 2).comm 0
    · -- Porting note: this branch had been:
      -- simpa only [Homotopy.dNext_succ_chainComplex, Homotopy.prevD_chainComplex,
      --   HomologicalComplex.id_f, PInfty_f, ← P_is_eventually_constant (rfl.le : n + 1 ≤ n + 1),
      --   homotopyPToId_eventually_constant X (lt_add_one (n + 1))] using
      --   (homotopyPToId X (n + 2)).comm (n + 1)
      -- which fails on leanprover/lean4:nightly-2023-05-16 due to
      -- https://github.com/leanprover/lean4/pull/2146
      -- The `erw` below clunkily works around this.
      

Proof state:
case succ
C : Type u_1
inst✝¹ : Category.{?u.44331, u_1} C
inst✝ : Preadditive C
X : SimplicialObject C
n : ℕ
⊢ HomologicalComplex.Hom.f PInfty (Nat.succ n) =
    (((dNext (Nat.succ n)) fun i j => Homotopy.hom (homotopyPToId X (j + 1)) i j) +
        (prevD (Nat.succ n)) fun i j => Homotopy.hom (homotopyPToId X (j + 1)) i j) +
      HomologicalComplex.Hom.f (𝟙 K[X]) (Nat.succ n)

Next tactic:
rw [Homotopy.dNext_succ_chainComplex, Homotopy.prevD_chainComplex, PInfty_f,
        ← P_is_eventually_constant (rfl.le : n + 1 ≤ n + 1)]
/-- Construction of the homotopy from `PInfty` to the identity using eventually
(termwise) constant homotopies from `P q` to the identity for all `q` -/
@[simps]
def homotopyPInftyToId : Homotopy (PInfty : K[X] ⟶ _) (𝟙 _) where
  hom i j := (homotopyPToId X (j + 1)).hom i j
  zero i j hij := Homotopy.zero _ i j hij
  comm n := by
    rcases n with _|n
    · simpa only [Homotopy.dNext_zero_chainComplex, Homotopy.prevD_chainComplex,
        PInfty_f, Nat.zero_eq, P_f_0_eq, zero_add] using (homotopyPToId X 2).comm 0
    · -- Porting note: this branch had been:
      -- simpa only [Homotopy.dNext_succ_chainComplex, Homotopy.prevD_chainComplex,
      --   HomologicalComplex.id_f, PInfty_f, ← P_is_eventually_constant (rfl.le : n + 1 ≤ n + 1),
      --   homotopyPToId_eventually_constant X (lt_add_one (n + 1))] using
      --   (homotopyPToId X (n + 2)).comm (n + 1)
      -- which fails on leanprover/lean4:nightly-2023-05-16 due to
      -- https://github.com/leanprover/lean4/pull/2146
      -- The `erw` below clunkily works around this.
      rw [Homotopy.dNext_succ_chainComplex, Homotopy.prevD_chainComplex, PInfty_f,
        ← P_is_eventually_constant (rfl.le : n + 1 ≤ n + 1)]
      

Proof state:
case succ
C : Type u_1
inst✝¹ : Category.{?u.44331, u_1} C
inst✝ : Preadditive C
X : SimplicialObject C
n : ℕ
⊢ HomologicalComplex.Hom.f (P (n + 1 + 1)) (n + 1) =
    HomologicalComplex.d K[X] (n + 1) n ≫ Homotopy.hom (homotopyPToId X (n + 1 + 1)) n (n + 1) +
        Homotopy.hom (homotopyPToId X (Nat.succ n + 1 + 1)) (Nat.succ n) (Nat.succ n + 1) ≫
          HomologicalComplex.d K[X] (Nat.succ n + 1) (Nat.succ n) +
      HomologicalComplex.Hom.f (𝟙 K[X]) (Nat.succ n)

Next tactic:
erw [homotopyPToId_eventually_constant X (lt_add_one (Nat.succ n))]
/-- Construction of the homotopy from `PInfty` to the identity using eventually
(termwise) constant homotopies from `P q` to the identity for all `q` -/
@[simps]
def homotopyPInftyToId : Homotopy (PInfty : K[X] ⟶ _) (𝟙 _) where
  hom i j := (homotopyPToId X (j + 1)).hom i j
  zero i j hij := Homotopy.zero _ i j hij
  comm n := by
    rcases n with _|n
    · simpa only [Homotopy.dNext_zero_chainComplex, Homotopy.prevD_chainComplex,
        PInfty_f, Nat.zero_eq, P_f_0_eq, zero_add] using (homotopyPToId X 2).comm 0
    · -- Porting note: this branch had been:
      -- simpa only [Homotopy.dNext_succ_chainComplex, Homotopy.prevD_chainComplex,
      --   HomologicalComplex.id_f, PInfty_f, ← P_is_eventually_constant (rfl.le : n + 1 ≤ n + 1),
      --   homotopyPToId_eventually_constant X (lt_add_one (n + 1))] using
      --   (homotopyPToId X (n + 2)).comm (n + 1)
      -- which fails on leanprover/lean4:nightly-2023-05-16 due to
      -- https://github.com/leanprover/lean4/pull/2146
      -- The `erw` below clunkily works around this.
      rw [Homotopy.dNext_succ_chainComplex, Homotopy.prevD_chainComplex, PInfty_f,
        ← P_is_eventually_constant (rfl.le : n + 1 ≤ n + 1)]
      erw [homotopyPToId_eventually_constant X (lt_add_one (Nat.succ n))]
      

Proof state:
case succ
C : Type u_1
inst✝¹ : Category.{?u.44331, u_1} C
inst✝ : Preadditive C
X : SimplicialObject C
n : ℕ
⊢ HomologicalComplex.Hom.f (P (n + 1 + 1)) (n + 1) =
    HomologicalComplex.d K[X] (n + 1) n ≫ Homotopy.hom (homotopyPToId X (n + 1 + 1)) n (n + 1) +
        Homotopy.hom (homotopyPToId X (Nat.succ n + 1)) (Nat.succ n) (Nat.succ n + 1) ≫
          HomologicalComplex.d K[X] (Nat.succ n + 1) (Nat.succ n) +
      HomologicalComplex.Hom.f (𝟙 K[X]) (Nat.succ n)

Next tactic:
have := (homotopyPToId X (n + 2)).comm (n + 1)
/-- Construction of the homotopy from `PInfty` to the identity using eventually
(termwise) constant homotopies from `P q` to the identity for all `q` -/
@[simps]
def homotopyPInftyToId : Homotopy (PInfty : K[X] ⟶ _) (𝟙 _) where
  hom i j := (homotopyPToId X (j + 1)).hom i j
  zero i j hij := Homotopy.zero _ i j hij
  comm n := by
    rcases n with _|n
    · simpa only [Homotopy.dNext_zero_chainComplex, Homotopy.prevD_chainComplex,
        PInfty_f, Nat.zero_eq, P_f_0_eq, zero_add] using (homotopyPToId X 2).comm 0
    · -- Porting note: this branch had been:
      -- simpa only [Homotopy.dNext_succ_chainComplex, Homotopy.prevD_chainComplex,
      --   HomologicalComplex.id_f, PInfty_f, ← P_is_eventually_constant (rfl.le : n + 1 ≤ n + 1),
      --   homotopyPToId_eventually_constant X (lt_add_one (n + 1))] using
      --   (homotopyPToId X (n + 2)).comm (n + 1)
      -- which fails on leanprover/lean4:nightly-2023-05-16 due to
      -- https://github.com/leanprover/lean4/pull/2146
      -- The `erw` below clunkily works around this.
      rw [Homotopy.dNext_succ_chainComplex, Homotopy.prevD_chainComplex, PInfty_f,
        ← P_is_eventually_constant (rfl.le : n + 1 ≤ n + 1)]
      erw [homotopyPToId_eventually_constant X (lt_add_one (Nat.succ n))]
      have := (homotopyPToId X (n + 2)).comm (n + 1)
      

Proof state:
case succ
C : Type u_1
inst✝¹ : Category.{?u.44331, u_1} C
inst✝ : Preadditive C
X : SimplicialObject C
n : ℕ
this :
  HomologicalComplex.Hom.f (P (n + 2)) (n + 1) =
    (dNext (n + 1)) (homotopyPToId X (n + 2)).hom + (prevD (n + 1)) (homotopyPToId X (n + 2)).hom +
      HomologicalComplex.Hom.f (𝟙 K[X]) (n + 1)
⊢ HomologicalComplex.Hom.f (P (n + 1 + 1)) (n + 1) =
    HomologicalComplex.d K[X] (n + 1) n ≫ Homotopy.hom (homotopyPToId X (n + 1 + 1)) n (n + 1) +
        Homotopy.hom (homotopyPToId X (Nat.succ n + 1)) (Nat.succ n) (Nat.succ n + 1) ≫
          HomologicalComplex.d K[X] (Nat.succ n + 1) (Nat.succ n) +
      HomologicalComplex.Hom.f (𝟙 K[X]) (Nat.succ n)

Next tactic:
rw [Homotopy.dNext_succ_chainComplex, Homotopy.prevD_chainComplex] at this
/-- Construction of the homotopy from `PInfty` to the identity using eventually
(termwise) constant homotopies from `P q` to the identity for all `q` -/
@[simps]
def homotopyPInftyToId : Homotopy (PInfty : K[X] ⟶ _) (𝟙 _) where
  hom i j := (homotopyPToId X (j + 1)).hom i j
  zero i j hij := Homotopy.zero _ i j hij
  comm n := by
    rcases n with _|n
    · simpa only [Homotopy.dNext_zero_chainComplex, Homotopy.prevD_chainComplex,
        PInfty_f, Nat.zero_eq, P_f_0_eq, zero_add] using (homotopyPToId X 2).comm 0
    · -- Porting note: this branch had been:
      -- simpa only [Homotopy.dNext_succ_chainComplex, Homotopy.prevD_chainComplex,
      --   HomologicalComplex.id_f, PInfty_f, ← P_is_eventually_constant (rfl.le : n + 1 ≤ n + 1),
      --   homotopyPToId_eventually_constant X (lt_add_one (n + 1))] using
      --   (homotopyPToId X (n + 2)).comm (n + 1)
      -- which fails on leanprover/lean4:nightly-2023-05-16 due to
      -- https://github.com/leanprover/lean4/pull/2146
      -- The `erw` below clunkily works around this.
      rw [Homotopy.dNext_succ_chainComplex, Homotopy.prevD_chainComplex, PInfty_f,
        ← P_is_eventually_constant (rfl.le : n + 1 ≤ n + 1)]
      erw [homotopyPToId_eventually_constant X (lt_add_one (Nat.succ n))]
      have := (homotopyPToId X (n + 2)).comm (n + 1)
      rw [Homotopy.dNext_succ_chainComplex, Homotopy.prevD_chainComplex] at this
      

Proof state:
case succ
C : Type u_1
inst✝¹ : Category.{?u.44331, u_1} C
inst✝ : Preadditive C
X : SimplicialObject C
n : ℕ
this :
  HomologicalComplex.Hom.f (P (n + 2)) (n + 1) =
    HomologicalComplex.d K[X] (n + 1) n ≫ Homotopy.hom (homotopyPToId X (n + 2)) n (n + 1) +
        Homotopy.hom (homotopyPToId X (n + 2)) (n + 1) (n + 1 + 1) ≫ HomologicalComplex.d K[X] (n + 1 + 1) (n + 1) +
      HomologicalComplex.Hom.f (𝟙 K[X]) (n + 1)
⊢ HomologicalComplex.Hom.f (P (n + 1 + 1)) (n + 1) =
    HomologicalComplex.d K[X] (n + 1) n ≫ Homotopy.hom (homotopyPToId X (n + 1 + 1)) n (n + 1) +
        Homotopy.hom (homotopyPToId X (Nat.succ n + 1)) (Nat.succ n) (Nat.succ n + 1) ≫
          HomologicalComplex.d K[X] (Nat.succ n + 1) (Nat.succ n) +
      HomologicalComplex.Hom.f (𝟙 K[X]) (Nat.succ n)

Next tactic:
exact this
/-- The cardinality of the finset `primesBelow n` equals the counting function
`primeCounting'` at `n`. -/
lemma primesBelow_card_eq_primeCounting' (n : ℕ) : n.primesBelow.card = primeCounting' n := by
  

Proof state:
n : ℕ
⊢ card (primesBelow n) = π' n

Next tactic:
simp only [primesBelow, primeCounting']
/-- The cardinality of the finset `primesBelow n` equals the counting function
`primeCounting'` at `n`. -/
lemma primesBelow_card_eq_primeCounting' (n : ℕ) : n.primesBelow.card = primeCounting' n := by
  simp only [primesBelow, primeCounting']
  

Proof state:
n : ℕ
⊢ card (filter (fun p => Prime p) (range n)) = count Prime n

Next tactic:
exact (count_eq_card_filter_range Prime n).symm
/-- A linear upper bound on the size of the `primeCounting'` function -/
theorem primeCounting'_add_le {a k : ℕ} (h0 : 0 < a) (h1 : a < k) (n : ℕ) :
    π' (k + n) ≤ π' k + Nat.totient a * (n / a + 1) :=
  calc
    π' (k + n) ≤ ((range k).filter Prime).card + ((Ico k (k + n)).filter Prime).card := by
      

Proof state:
a k : ℕ
h0 : 0 < a
h1 : a < k
n : ℕ
⊢ π' (k + n) ≤ card (filter Prime (range k)) + card (filter Prime (Ico k (k + n)))

Next tactic:
rw [primeCounting', count_eq_card_filter_range, range_eq_Ico, ←
        Ico_union_Ico_eq_Ico (zero_le k) le_self_add, filter_union]
/-- A linear upper bound on the size of the `primeCounting'` function -/
theorem primeCounting'_add_le {a k : ℕ} (h0 : 0 < a) (h1 : a < k) (n : ℕ) :
    π' (k + n) ≤ π' k + Nat.totient a * (n / a + 1) :=
  calc
    π' (k + n) ≤ ((range k).filter Prime).card + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range, range_eq_Ico, ←
        Ico_union_Ico_eq_Ico (zero_le k) le_self_add, filter_union]
      

Proof state:
a k : ℕ
h0 : 0 < a
h1 : a < k
n : ℕ
⊢ card (filter Prime (Ico 0 k) ∪ filter Prime (Ico k (k + n))) ≤
    card (filter Prime (Ico 0 k)) + card (filter Prime (Ico k (k + n)))

Next tactic:
apply card_union_le
/-- A linear upper bound on the size of the `primeCounting'` function -/
theorem primeCounting'_add_le {a k : ℕ} (h0 : 0 < a) (h1 : a < k) (n : ℕ) :
    π' (k + n) ≤ π' k + Nat.totient a * (n / a + 1) :=
  calc
    π' (k + n) ≤ ((range k).filter Prime).card + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range, range_eq_Ico, ←
        Ico_union_Ico_eq_Ico (zero_le k) le_self_add, filter_union]
      apply card_union_le
    _ ≤ π' k + ((Ico k (k + n)).filter Prime).card := by
      

Proof state:
a k : ℕ
h0 : 0 < a
h1 : a < k
n : ℕ
⊢ card (filter Prime (range k)) + card (filter Prime (Ico k (k + n))) ≤ π' k + card (filter Prime (Ico k (k + n)))

Next tactic:
rw [primeCounting', count_eq_card_filter_range]
/-- A linear upper bound on the size of the `primeCounting'` function -/
theorem primeCounting'_add_le {a k : ℕ} (h0 : 0 < a) (h1 : a < k) (n : ℕ) :
    π' (k + n) ≤ π' k + Nat.totient a * (n / a + 1) :=
  calc
    π' (k + n) ≤ ((range k).filter Prime).card + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range, range_eq_Ico, ←
        Ico_union_Ico_eq_Ico (zero_le k) le_self_add, filter_union]
      apply card_union_le
    _ ≤ π' k + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range]
    _ ≤ π' k + ((Ico k (k + n)).filter (Coprime a)).card := by
      

Proof state:
a k : ℕ
h0 : 0 < a
h1 : a < k
n : ℕ
⊢ π' k + card (filter Prime (Ico k (k + n))) ≤ π' k + card (filter (Coprime a) (Ico k (k + n)))

Next tactic:
refine' add_le_add_left (card_le_of_subset _) k.primeCounting'
/-- A linear upper bound on the size of the `primeCounting'` function -/
theorem primeCounting'_add_le {a k : ℕ} (h0 : 0 < a) (h1 : a < k) (n : ℕ) :
    π' (k + n) ≤ π' k + Nat.totient a * (n / a + 1) :=
  calc
    π' (k + n) ≤ ((range k).filter Prime).card + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range, range_eq_Ico, ←
        Ico_union_Ico_eq_Ico (zero_le k) le_self_add, filter_union]
      apply card_union_le
    _ ≤ π' k + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range]
    _ ≤ π' k + ((Ico k (k + n)).filter (Coprime a)).card := by
      refine' add_le_add_left (card_le_of_subset _) k.primeCounting'
      

Proof state:
a k : ℕ
h0 : 0 < a
h1 : a < k
n : ℕ
⊢ filter Prime (Ico k (k + n)) ⊆ filter (Coprime a) (Ico k (k + n))

Next tactic:
simp only [subset_iff, and_imp, mem_filter, mem_Ico]
/-- A linear upper bound on the size of the `primeCounting'` function -/
theorem primeCounting'_add_le {a k : ℕ} (h0 : 0 < a) (h1 : a < k) (n : ℕ) :
    π' (k + n) ≤ π' k + Nat.totient a * (n / a + 1) :=
  calc
    π' (k + n) ≤ ((range k).filter Prime).card + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range, range_eq_Ico, ←
        Ico_union_Ico_eq_Ico (zero_le k) le_self_add, filter_union]
      apply card_union_le
    _ ≤ π' k + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range]
    _ ≤ π' k + ((Ico k (k + n)).filter (Coprime a)).card := by
      refine' add_le_add_left (card_le_of_subset _) k.primeCounting'
      simp only [subset_iff, and_imp, mem_filter, mem_Ico]
      

Proof state:
a k : ℕ
h0 : 0 < a
h1 : a < k
n : ℕ
⊢ ∀ ⦃x : ℕ⦄, k ≤ x → x < k + n → Prime x → (k ≤ x ∧ x < k + n) ∧ Coprime a x

Next tactic:
intro p succ_k_le_p p_lt_n p_prime
/-- A linear upper bound on the size of the `primeCounting'` function -/
theorem primeCounting'_add_le {a k : ℕ} (h0 : 0 < a) (h1 : a < k) (n : ℕ) :
    π' (k + n) ≤ π' k + Nat.totient a * (n / a + 1) :=
  calc
    π' (k + n) ≤ ((range k).filter Prime).card + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range, range_eq_Ico, ←
        Ico_union_Ico_eq_Ico (zero_le k) le_self_add, filter_union]
      apply card_union_le
    _ ≤ π' k + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range]
    _ ≤ π' k + ((Ico k (k + n)).filter (Coprime a)).card := by
      refine' add_le_add_left (card_le_of_subset _) k.primeCounting'
      simp only [subset_iff, and_imp, mem_filter, mem_Ico]
      intro p succ_k_le_p p_lt_n p_prime
      

Proof state:
a k : ℕ
h0 : 0 < a
h1 : a < k
n p : ℕ
succ_k_le_p : k ≤ p
p_lt_n : p < k + n
p_prime : Prime p
⊢ (k ≤ p ∧ p < k + n) ∧ Coprime a p

Next tactic:
constructor
/-- A linear upper bound on the size of the `primeCounting'` function -/
theorem primeCounting'_add_le {a k : ℕ} (h0 : 0 < a) (h1 : a < k) (n : ℕ) :
    π' (k + n) ≤ π' k + Nat.totient a * (n / a + 1) :=
  calc
    π' (k + n) ≤ ((range k).filter Prime).card + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range, range_eq_Ico, ←
        Ico_union_Ico_eq_Ico (zero_le k) le_self_add, filter_union]
      apply card_union_le
    _ ≤ π' k + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range]
    _ ≤ π' k + ((Ico k (k + n)).filter (Coprime a)).card := by
      refine' add_le_add_left (card_le_of_subset _) k.primeCounting'
      simp only [subset_iff, and_imp, mem_filter, mem_Ico]
      intro p succ_k_le_p p_lt_n p_prime
      constructor
      · 

Proof state:
case left
a k : ℕ
h0 : 0 < a
h1 : a < k
n p : ℕ
succ_k_le_p : k ≤ p
p_lt_n : p < k + n
p_prime : Prime p
⊢ k ≤ p ∧ p < k + n

Next tactic:
exact ⟨succ_k_le_p, p_lt_n⟩
/-- A linear upper bound on the size of the `primeCounting'` function -/
theorem primeCounting'_add_le {a k : ℕ} (h0 : 0 < a) (h1 : a < k) (n : ℕ) :
    π' (k + n) ≤ π' k + Nat.totient a * (n / a + 1) :=
  calc
    π' (k + n) ≤ ((range k).filter Prime).card + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range, range_eq_Ico, ←
        Ico_union_Ico_eq_Ico (zero_le k) le_self_add, filter_union]
      apply card_union_le
    _ ≤ π' k + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range]
    _ ≤ π' k + ((Ico k (k + n)).filter (Coprime a)).card := by
      refine' add_le_add_left (card_le_of_subset _) k.primeCounting'
      simp only [subset_iff, and_imp, mem_filter, mem_Ico]
      intro p succ_k_le_p p_lt_n p_prime
      constructor
      · exact ⟨succ_k_le_p, p_lt_n⟩
      · 

Proof state:
case right
a k : ℕ
h0 : 0 < a
h1 : a < k
n p : ℕ
succ_k_le_p : k ≤ p
p_lt_n : p < k + n
p_prime : Prime p
⊢ Coprime a p

Next tactic:
rw [coprime_comm]
/-- A linear upper bound on the size of the `primeCounting'` function -/
theorem primeCounting'_add_le {a k : ℕ} (h0 : 0 < a) (h1 : a < k) (n : ℕ) :
    π' (k + n) ≤ π' k + Nat.totient a * (n / a + 1) :=
  calc
    π' (k + n) ≤ ((range k).filter Prime).card + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range, range_eq_Ico, ←
        Ico_union_Ico_eq_Ico (zero_le k) le_self_add, filter_union]
      apply card_union_le
    _ ≤ π' k + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range]
    _ ≤ π' k + ((Ico k (k + n)).filter (Coprime a)).card := by
      refine' add_le_add_left (card_le_of_subset _) k.primeCounting'
      simp only [subset_iff, and_imp, mem_filter, mem_Ico]
      intro p succ_k_le_p p_lt_n p_prime
      constructor
      · exact ⟨succ_k_le_p, p_lt_n⟩
      · rw [coprime_comm]
        

Proof state:
case right
a k : ℕ
h0 : 0 < a
h1 : a < k
n p : ℕ
succ_k_le_p : k ≤ p
p_lt_n : p < k + n
p_prime : Prime p
⊢ Coprime p a

Next tactic:
exact coprime_of_lt_prime h0 (gt_of_ge_of_gt succ_k_le_p h1) p_prime
/-- A linear upper bound on the size of the `primeCounting'` function -/
theorem primeCounting'_add_le {a k : ℕ} (h0 : 0 < a) (h1 : a < k) (n : ℕ) :
    π' (k + n) ≤ π' k + Nat.totient a * (n / a + 1) :=
  calc
    π' (k + n) ≤ ((range k).filter Prime).card + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range, range_eq_Ico, ←
        Ico_union_Ico_eq_Ico (zero_le k) le_self_add, filter_union]
      apply card_union_le
    _ ≤ π' k + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range]
    _ ≤ π' k + ((Ico k (k + n)).filter (Coprime a)).card := by
      refine' add_le_add_left (card_le_of_subset _) k.primeCounting'
      simp only [subset_iff, and_imp, mem_filter, mem_Ico]
      intro p succ_k_le_p p_lt_n p_prime
      constructor
      · exact ⟨succ_k_le_p, p_lt_n⟩
      · rw [coprime_comm]
        exact coprime_of_lt_prime h0 (gt_of_ge_of_gt succ_k_le_p h1) p_prime
    _ ≤ π' k + totient a * (n / a + 1) := by
      

Proof state:
a k : ℕ
h0 : 0 < a
h1 : a < k
n : ℕ
⊢ π' k + card (filter (Coprime a) (Ico k (k + n))) ≤ π' k + φ a * (n / a + 1)

Next tactic:
rw [add_le_add_iff_left]
/-- A linear upper bound on the size of the `primeCounting'` function -/
theorem primeCounting'_add_le {a k : ℕ} (h0 : 0 < a) (h1 : a < k) (n : ℕ) :
    π' (k + n) ≤ π' k + Nat.totient a * (n / a + 1) :=
  calc
    π' (k + n) ≤ ((range k).filter Prime).card + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range, range_eq_Ico, ←
        Ico_union_Ico_eq_Ico (zero_le k) le_self_add, filter_union]
      apply card_union_le
    _ ≤ π' k + ((Ico k (k + n)).filter Prime).card := by
      rw [primeCounting', count_eq_card_filter_range]
    _ ≤ π' k + ((Ico k (k + n)).filter (Coprime a)).card := by
      refine' add_le_add_left (card_le_of_subset _) k.primeCounting'
      simp only [subset_iff, and_imp, mem_filter, mem_Ico]
      intro p succ_k_le_p p_lt_n p_prime
      constructor
      · exact ⟨succ_k_le_p, p_lt_n⟩
      · rw [coprime_comm]
        exact coprime_of_lt_prime h0 (gt_of_ge_of_gt succ_k_le_p h1) p_prime
    _ ≤ π' k + totient a * (n / a + 1) := by
      rw [add_le_add_iff_left]
      

Proof state:
a k : ℕ
h0 : 0 < a
h1 : a < k
n : ℕ
⊢ card (filter (Coprime a) (Ico k (k + n))) ≤ φ a * (n / a + 1)

Next tactic:
exact Ico_filter_coprime_le k n h0
theorem finite_coe_iff {s : Set α} : Finite s ↔ s.Finite := by
  

Proof state:
α : Type u
β : Type v
ι : Sort w
γ : Type x
s : Set α
⊢ Finite ↑s ↔ Set.Finite s

Next tactic:
rw [finite_iff_nonempty_fintype, finite_def]
theorem Finite.toFinset_eq_toFinset {s : Set α} [Fintype s] (h : s.Finite) :
    h.toFinset = s.toFinset := by
  -- porting note: was `rw [Finite.toFinset]; congr`
  -- in Lean 4, a goal is left after `congr`
  

Proof state:
α : Type u
β : Type v
ι : Sort w
γ : Type x
s : Set α
inst✝ : Fintype ↑s
h : Set.Finite s
⊢ Finite.toFinset h = toFinset s

Next tactic:
have : h.fintype = ‹_› := Subsingleton.elim _ _
theorem Finite.toFinset_eq_toFinset {s : Set α} [Fintype s] (h : s.Finite) :
    h.toFinset = s.toFinset := by
  -- porting note: was `rw [Finite.toFinset]; congr`
  -- in Lean 4, a goal is left after `congr`
  have : h.fintype = ‹_› := Subsingleton.elim _ _
  

Proof state:
α : Type u
β : Type v
ι : Sort w
γ : Type x
s : Set α
inst✝ : Fintype ↑s
h : Set.Finite s
this : Finite.fintype h = inst✝
⊢ Finite.toFinset h = toFinset s

Next tactic:
rw [Finite.toFinset, this]
theorem Finite.exists_finset {s : Set α} (h : s.Finite) :
    ∃ s' : Finset α, ∀ a : α, a ∈ s' ↔ a ∈ s := by
  

Proof state:
α : Type u
β : Type v
ι : Sort w
γ : Type x
s : Set α
h : Set.Finite s
⊢ ∃ s', ∀ (a : α), a ∈ s' ↔ a ∈ s

Next tactic:
cases h
theorem Finite.exists_finset {s : Set α} (h : s.Finite) :
    ∃ s' : Finset α, ∀ a : α, a ∈ s' ↔ a ∈ s := by
  cases h
  

Proof state:
case intro
α : Type u
β : Type v
ι : Sort w
γ : Type x
s : Set α
a✝ : Fintype ↑s
⊢ ∃ s', ∀ (a : α), a ∈ s' ↔ a ∈ s

Next tactic:
exact ⟨s.toFinset, fun _ => mem_toFinset⟩
theorem Finite.exists_finset_coe {s : Set α} (h : s.Finite) : ∃ s' : Finset α, ↑s' = s := by
  

Proof state:
α : Type u
β : Type v
ι : Sort w
γ : Type x
s : Set α
h : Set.Finite s
⊢ ∃ s', ↑s' = s

Next tactic:
cases h
theorem Finite.exists_finset_coe {s : Set α} (h : s.Finite) : ∃ s' : Finset α, ↑s' = s := by
  cases h
  

Proof state:
case intro
α : Type u
β : Type v
ι : Sort w
γ : Type x
s : Set α
a✝ : Fintype ↑s
⊢ ∃ s', ↑s' = s

Next tactic:
exact ⟨s.toFinset, s.coe_toFinset⟩
@[simp]
protected theorem toFinset_nonempty : hs.toFinset.Nonempty ↔ s.Nonempty := by
  

Proof state:
α : Type u
β : Type v
ι : Sort w
γ : Type x
s t : Set α
a : α
hs : Set.Finite s
ht : Set.Finite t
⊢ Finset.Nonempty (Finite.toFinset hs) ↔ Set.Nonempty s

Next tactic:
rw [← Finset.coe_nonempty, Finite.coe_toFinset]
/-- Note that this is an equality of types not holding definitionally. Use wisely. -/
theorem coeSort_toFinset : ↥hs.toFinset = ↥s := by
  

Proof state:
α : Type u
β : Type v
ι : Sort w
γ : Type x
s t : Set α
a : α
hs : Set.Finite s
ht : Set.Finite t
⊢ { x // x ∈ Finite.toFinset hs } = ↑s

Next tactic:
rw [← Finset.coe_sort_coe _, hs.coe_toFinset]