l3lab/ntp-mathlib huggingface dataset:
open List Perm in
/-- We establish the bijection from `ℕ × smoothNumbers p` to `smoothNumbers (p+1)`
given by `(e, n) ↦ p^e * n` when `p` is a prime. See `Nat.smoothNumbers_succ` for
when `p` is not prime. -/
def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) :
    ℕ × smoothNumbers p ≃ smoothNumbers p.succ where
  toFun := fun ⟨e, n⟩ ↦ ⟨p ^ e * n, pow_mul_mem_smoothNumbers hp.ne_zero e n.2⟩
  invFun := fun ⟨m, _⟩  ↦ (m.factorization p,
                            ⟨(m.factors.filter (· < p)).prod, prod_mem_smoothNumbers ..⟩)
  left_inv := by
    rintro ⟨e, m, hm₀, hm⟩
    simp (config := { etaStruct := .all }) only
      [Set.coe_setOf, Set.mem_setOf_eq, Prod.mk.injEq, Subtype.mk.injEq]
    constructor
    · rw [factorization_mul (pos_iff_ne_zero.mp <| pos_pow_of_pos e hp.pos) hm₀]
      simp only [factorization_pow, Finsupp.coe_add, Finsupp.coe_smul, nsmul_eq_mul,
        Pi.coe_nat, cast_id, Pi.add_apply, Pi.mul_apply, hp.factorization_self,
        mul_one, add_right_eq_self]
      

Proof state:
case mk.mk.intro.left
p : ℕ
hp : Prime p
e m : ℕ
hm₀ : m ≠ 0
hm : ∀ p_1 ∈ factors m, p_1 < p
⊢ (factorization m) p = 0

Next tactic:
rw [← factors_count_eq, count_eq_zero]
open List Perm in
/-- We establish the bijection from `ℕ × smoothNumbers p` to `smoothNumbers (p+1)`
given by `(e, n) ↦ p^e * n` when `p` is a prime. See `Nat.smoothNumbers_succ` for
when `p` is not prime. -/
def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) :
    ℕ × smoothNumbers p ≃ smoothNumbers p.succ where
  toFun := fun ⟨e, n⟩ ↦ ⟨p ^ e * n, pow_mul_mem_smoothNumbers hp.ne_zero e n.2⟩
  invFun := fun ⟨m, _⟩  ↦ (m.factorization p,
                            ⟨(m.factors.filter (· < p)).prod, prod_mem_smoothNumbers ..⟩)
  left_inv := by
    rintro ⟨e, m, hm₀, hm⟩
    simp (config := { etaStruct := .all }) only
      [Set.coe_setOf, Set.mem_setOf_eq, Prod.mk.injEq, Subtype.mk.injEq]
    constructor
    · rw [factorization_mul (pos_iff_ne_zero.mp <| pos_pow_of_pos e hp.pos) hm₀]
      simp only [factorization_pow, Finsupp.coe_add, Finsupp.coe_smul, nsmul_eq_mul,
        Pi.coe_nat, cast_id, Pi.add_apply, Pi.mul_apply, hp.factorization_self,
        mul_one, add_right_eq_self]
      rw [← factors_count_eq, count_eq_zero]
      

Proof state:
case mk.mk.intro.left
p : ℕ
hp : Prime p
e m : ℕ
hm₀ : m ≠ 0
hm : ∀ p_1 ∈ factors m, p_1 < p
⊢ p ∉ factors m

Next tactic:
exact fun H ↦ (hm p H).false
open List Perm in
/-- We establish the bijection from `ℕ × smoothNumbers p` to `smoothNumbers (p+1)`
given by `(e, n) ↦ p^e * n` when `p` is a prime. See `Nat.smoothNumbers_succ` for
when `p` is not prime. -/
def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) :
    ℕ × smoothNumbers p ≃ smoothNumbers p.succ where
  toFun := fun ⟨e, n⟩ ↦ ⟨p ^ e * n, pow_mul_mem_smoothNumbers hp.ne_zero e n.2⟩
  invFun := fun ⟨m, _⟩  ↦ (m.factorization p,
                            ⟨(m.factors.filter (· < p)).prod, prod_mem_smoothNumbers ..⟩)
  left_inv := by
    rintro ⟨e, m, hm₀, hm⟩
    simp (config := { etaStruct := .all }) only
      [Set.coe_setOf, Set.mem_setOf_eq, Prod.mk.injEq, Subtype.mk.injEq]
    constructor
    · rw [factorization_mul (pos_iff_ne_zero.mp <| pos_pow_of_pos e hp.pos) hm₀]
      simp only [factorization_pow, Finsupp.coe_add, Finsupp.coe_smul, nsmul_eq_mul,
        Pi.coe_nat, cast_id, Pi.add_apply, Pi.mul_apply, hp.factorization_self,
        mul_one, add_right_eq_self]
      rw [← factors_count_eq, count_eq_zero]
      exact fun H ↦ (hm p H).false
    · 

Proof state:
case mk.mk.intro.right
p : ℕ
hp : Prime p
e m : ℕ
hm₀ : m ≠ 0
hm : ∀ p_1 ∈ factors m, p_1 < p
⊢ prod (List.filter (fun x => decide (x < p)) (factors (p ^ e * m))) = m

Next tactic:
nth_rw 2 [← prod_factors hm₀]
open List Perm in
/-- We establish the bijection from `ℕ × smoothNumbers p` to `smoothNumbers (p+1)`
given by `(e, n) ↦ p^e * n` when `p` is a prime. See `Nat.smoothNumbers_succ` for
when `p` is not prime. -/
def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) :
    ℕ × smoothNumbers p ≃ smoothNumbers p.succ where
  toFun := fun ⟨e, n⟩ ↦ ⟨p ^ e * n, pow_mul_mem_smoothNumbers hp.ne_zero e n.2⟩
  invFun := fun ⟨m, _⟩  ↦ (m.factorization p,
                            ⟨(m.factors.filter (· < p)).prod, prod_mem_smoothNumbers ..⟩)
  left_inv := by
    rintro ⟨e, m, hm₀, hm⟩
    simp (config := { etaStruct := .all }) only
      [Set.coe_setOf, Set.mem_setOf_eq, Prod.mk.injEq, Subtype.mk.injEq]
    constructor
    · rw [factorization_mul (pos_iff_ne_zero.mp <| pos_pow_of_pos e hp.pos) hm₀]
      simp only [factorization_pow, Finsupp.coe_add, Finsupp.coe_smul, nsmul_eq_mul,
        Pi.coe_nat, cast_id, Pi.add_apply, Pi.mul_apply, hp.factorization_self,
        mul_one, add_right_eq_self]
      rw [← factors_count_eq, count_eq_zero]
      exact fun H ↦ (hm p H).false
    · nth_rw 2 [← prod_factors hm₀]
      

Proof state:
case mk.mk.intro.right
p : ℕ
hp : Prime p
e m : ℕ
hm₀ : m ≠ 0
hm : ∀ p_1 ∈ factors m, p_1 < p
⊢ prod (List.filter (fun x => decide (x < p)) (factors (p ^ e * m))) = prod (factors m)

Next tactic:
refine prod_eq <| (filter _ <| perm_factors_mul (pow_ne_zero e hp.ne_zero) hm₀).trans ?_
open List Perm in
/-- We establish the bijection from `ℕ × smoothNumbers p` to `smoothNumbers (p+1)`
given by `(e, n) ↦ p^e * n` when `p` is a prime. See `Nat.smoothNumbers_succ` for
when `p` is not prime. -/
def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) :
    ℕ × smoothNumbers p ≃ smoothNumbers p.succ where
  toFun := fun ⟨e, n⟩ ↦ ⟨p ^ e * n, pow_mul_mem_smoothNumbers hp.ne_zero e n.2⟩
  invFun := fun ⟨m, _⟩  ↦ (m.factorization p,
                            ⟨(m.factors.filter (· < p)).prod, prod_mem_smoothNumbers ..⟩)
  left_inv := by
    rintro ⟨e, m, hm₀, hm⟩
    simp (config := { etaStruct := .all }) only
      [Set.coe_setOf, Set.mem_setOf_eq, Prod.mk.injEq, Subtype.mk.injEq]
    constructor
    · rw [factorization_mul (pos_iff_ne_zero.mp <| pos_pow_of_pos e hp.pos) hm₀]
      simp only [factorization_pow, Finsupp.coe_add, Finsupp.coe_smul, nsmul_eq_mul,
        Pi.coe_nat, cast_id, Pi.add_apply, Pi.mul_apply, hp.factorization_self,
        mul_one, add_right_eq_self]
      rw [← factors_count_eq, count_eq_zero]
      exact fun H ↦ (hm p H).false
    · nth_rw 2 [← prod_factors hm₀]
      refine prod_eq <| (filter _ <| perm_factors_mul (pow_ne_zero e hp.ne_zero) hm₀).trans ?_
      

Proof state:
case mk.mk.intro.right
p : ℕ
hp : Prime p
e m : ℕ
hm₀ : m ≠ 0
hm : ∀ p_1 ∈ factors m, p_1 < p
⊢ List.filter (fun x => decide (x < p)) (factors (p ^ e) ++ factors m) ~ factors m

Next tactic:
rw [filter_append, hp.factors_pow,
          filter_eq_nil.mpr <| fun q hq ↦ by rw [mem_replicate] at hq; simp [hq.2],
          nil_append, filter_eq_self.mpr <| fun q hq ↦ by simp [hm q hq]]
open List Perm in
/-- We establish the bijection from `ℕ × smoothNumbers p` to `smoothNumbers (p+1)`
given by `(e, n) ↦ p^e * n` when `p` is a prime. See `Nat.smoothNumbers_succ` for
when `p` is not prime. -/
def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) :
    ℕ × smoothNumbers p ≃ smoothNumbers p.succ where
  toFun := fun ⟨e, n⟩ ↦ ⟨p ^ e * n, pow_mul_mem_smoothNumbers hp.ne_zero e n.2⟩
  invFun := fun ⟨m, _⟩  ↦ (m.factorization p,
                            ⟨(m.factors.filter (· < p)).prod, prod_mem_smoothNumbers ..⟩)
  left_inv := by
    rintro ⟨e, m, hm₀, hm⟩
    simp (config := { etaStruct := .all }) only
      [Set.coe_setOf, Set.mem_setOf_eq, Prod.mk.injEq, Subtype.mk.injEq]
    constructor
    · rw [factorization_mul (pos_iff_ne_zero.mp <| pos_pow_of_pos e hp.pos) hm₀]
      simp only [factorization_pow, Finsupp.coe_add, Finsupp.coe_smul, nsmul_eq_mul,
        Pi.coe_nat, cast_id, Pi.add_apply, Pi.mul_apply, hp.factorization_self,
        mul_one, add_right_eq_self]
      rw [← factors_count_eq, count_eq_zero]
      exact fun H ↦ (hm p H).false
    · nth_rw 2 [← prod_factors hm₀]
      refine prod_eq <| (filter _ <| perm_factors_mul (pow_ne_zero e hp.ne_zero) hm₀).trans ?_
      rw [filter_append, hp.factors_pow,
          filter_eq_nil.mpr <| fun q hq ↦ by 

Proof state:
p : ℕ
hp : Prime p
e m : ℕ
hm₀ : m ≠ 0
hm : ∀ p_1 ∈ factors m, p_1 < p
q : ℕ
hq : q ∈ replicate e p
⊢ ¬decide (q < p) = true

Next tactic:
rw [mem_replicate] at hq
open List Perm in
/-- We establish the bijection from `ℕ × smoothNumbers p` to `smoothNumbers (p+1)`
given by `(e, n) ↦ p^e * n` when `p` is a prime. See `Nat.smoothNumbers_succ` for
when `p` is not prime. -/
def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) :
    ℕ × smoothNumbers p ≃ smoothNumbers p.succ where
  toFun := fun ⟨e, n⟩ ↦ ⟨p ^ e * n, pow_mul_mem_smoothNumbers hp.ne_zero e n.2⟩
  invFun := fun ⟨m, _⟩  ↦ (m.factorization p,
                            ⟨(m.factors.filter (· < p)).prod, prod_mem_smoothNumbers ..⟩)
  left_inv := by
    rintro ⟨e, m, hm₀, hm⟩
    simp (config := { etaStruct := .all }) only
      [Set.coe_setOf, Set.mem_setOf_eq, Prod.mk.injEq, Subtype.mk.injEq]
    constructor
    · rw [factorization_mul (pos_iff_ne_zero.mp <| pos_pow_of_pos e hp.pos) hm₀]
      simp only [factorization_pow, Finsupp.coe_add, Finsupp.coe_smul, nsmul_eq_mul,
        Pi.coe_nat, cast_id, Pi.add_apply, Pi.mul_apply, hp.factorization_self,
        mul_one, add_right_eq_self]
      rw [← factors_count_eq, count_eq_zero]
      exact fun H ↦ (hm p H).false
    · nth_rw 2 [← prod_factors hm₀]
      refine prod_eq <| (filter _ <| perm_factors_mul (pow_ne_zero e hp.ne_zero) hm₀).trans ?_
      rw [filter_append, hp.factors_pow,
          filter_eq_nil.mpr <| fun q hq ↦ by rw [mem_replicate] at hq; 

Proof state:
p : ℕ
hp : Prime p
e m : ℕ
hm₀ : m ≠ 0
hm : ∀ p_1 ∈ factors m, p_1 < p
q : ℕ
hq : e ≠ 0 ∧ q = p
⊢ ¬decide (q < p) = true

Next tactic:
simp [hq.2]
open List Perm in
/-- We establish the bijection from `ℕ × smoothNumbers p` to `smoothNumbers (p+1)`
given by `(e, n) ↦ p^e * n` when `p` is a prime. See `Nat.smoothNumbers_succ` for
when `p` is not prime. -/
def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) :
    ℕ × smoothNumbers p ≃ smoothNumbers p.succ where
  toFun := fun ⟨e, n⟩ ↦ ⟨p ^ e * n, pow_mul_mem_smoothNumbers hp.ne_zero e n.2⟩
  invFun := fun ⟨m, _⟩  ↦ (m.factorization p,
                            ⟨(m.factors.filter (· < p)).prod, prod_mem_smoothNumbers ..⟩)
  left_inv := by
    rintro ⟨e, m, hm₀, hm⟩
    simp (config := { etaStruct := .all }) only
      [Set.coe_setOf, Set.mem_setOf_eq, Prod.mk.injEq, Subtype.mk.injEq]
    constructor
    · rw [factorization_mul (pos_iff_ne_zero.mp <| pos_pow_of_pos e hp.pos) hm₀]
      simp only [factorization_pow, Finsupp.coe_add, Finsupp.coe_smul, nsmul_eq_mul,
        Pi.coe_nat, cast_id, Pi.add_apply, Pi.mul_apply, hp.factorization_self,
        mul_one, add_right_eq_self]
      rw [← factors_count_eq, count_eq_zero]
      exact fun H ↦ (hm p H).false
    · nth_rw 2 [← prod_factors hm₀]
      refine prod_eq <| (filter _ <| perm_factors_mul (pow_ne_zero e hp.ne_zero) hm₀).trans ?_
      rw [filter_append, hp.factors_pow,
          filter_eq_nil.mpr <| fun q hq ↦ by rw [mem_replicate] at hq; simp [hq.2],
          nil_append, filter_eq_self.mpr <| fun q hq ↦ by 

Proof state:
p : ℕ
hp : Prime p
e m : ℕ
hm₀ : m ≠ 0
hm : ∀ p_1 ∈ factors m, p_1 < p
q : ℕ
hq : q ∈ factors m
⊢ decide (q < p) = true

Next tactic:
simp [hm q hq]
open List Perm in
/-- We establish the bijection from `ℕ × smoothNumbers p` to `smoothNumbers (p+1)`
given by `(e, n) ↦ p^e * n` when `p` is a prime. See `Nat.smoothNumbers_succ` for
when `p` is not prime. -/
def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) :
    ℕ × smoothNumbers p ≃ smoothNumbers p.succ where
  toFun := fun ⟨e, n⟩ ↦ ⟨p ^ e * n, pow_mul_mem_smoothNumbers hp.ne_zero e n.2⟩
  invFun := fun ⟨m, _⟩  ↦ (m.factorization p,
                            ⟨(m.factors.filter (· < p)).prod, prod_mem_smoothNumbers ..⟩)
  left_inv := by
    rintro ⟨e, m, hm₀, hm⟩
    simp (config := { etaStruct := .all }) only
      [Set.coe_setOf, Set.mem_setOf_eq, Prod.mk.injEq, Subtype.mk.injEq]
    constructor
    · rw [factorization_mul (pos_iff_ne_zero.mp <| pos_pow_of_pos e hp.pos) hm₀]
      simp only [factorization_pow, Finsupp.coe_add, Finsupp.coe_smul, nsmul_eq_mul,
        Pi.coe_nat, cast_id, Pi.add_apply, Pi.mul_apply, hp.factorization_self,
        mul_one, add_right_eq_self]
      rw [← factors_count_eq, count_eq_zero]
      exact fun H ↦ (hm p H).false
    · nth_rw 2 [← prod_factors hm₀]
      refine prod_eq <| (filter _ <| perm_factors_mul (pow_ne_zero e hp.ne_zero) hm₀).trans ?_
      rw [filter_append, hp.factors_pow,
          filter_eq_nil.mpr <| fun q hq ↦ by rw [mem_replicate] at hq; simp [hq.2],
          nil_append, filter_eq_self.mpr <| fun q hq ↦ by simp [hm q hq]]
  right_inv := by
    

Proof state:
p : ℕ
hp : Prime p
⊢ Function.RightInverse
    (fun x =>
      match x with
      | { val := m, property := property } =>
        ((factorization m) p,
          { val := prod (List.filter (fun x => decide (x < p)) (factors m)),
            property := (_ : prod (List.filter (fun x => decide (x < p)) (factors m)) ∈ smoothNumbers p) }))
    fun x =>
    match x with
    | (e, n) => { val := p ^ e * ↑n, property := (_ : p ^ e * ↑n ∈ smoothNumbers (succ p)) }

Next tactic:
rintro ⟨m, hm₀, hm⟩
open List Perm in
/-- We establish the bijection from `ℕ × smoothNumbers p` to `smoothNumbers (p+1)`
given by `(e, n) ↦ p^e * n` when `p` is a prime. See `Nat.smoothNumbers_succ` for
when `p` is not prime. -/
def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) :
    ℕ × smoothNumbers p ≃ smoothNumbers p.succ where
  toFun := fun ⟨e, n⟩ ↦ ⟨p ^ e * n, pow_mul_mem_smoothNumbers hp.ne_zero e n.2⟩
  invFun := fun ⟨m, _⟩  ↦ (m.factorization p,
                            ⟨(m.factors.filter (· < p)).prod, prod_mem_smoothNumbers ..⟩)
  left_inv := by
    rintro ⟨e, m, hm₀, hm⟩
    simp (config := { etaStruct := .all }) only
      [Set.coe_setOf, Set.mem_setOf_eq, Prod.mk.injEq, Subtype.mk.injEq]
    constructor
    · rw [factorization_mul (pos_iff_ne_zero.mp <| pos_pow_of_pos e hp.pos) hm₀]
      simp only [factorization_pow, Finsupp.coe_add, Finsupp.coe_smul, nsmul_eq_mul,
        Pi.coe_nat, cast_id, Pi.add_apply, Pi.mul_apply, hp.factorization_self,
        mul_one, add_right_eq_self]
      rw [← factors_count_eq, count_eq_zero]
      exact fun H ↦ (hm p H).false
    · nth_rw 2 [← prod_factors hm₀]
      refine prod_eq <| (filter _ <| perm_factors_mul (pow_ne_zero e hp.ne_zero) hm₀).trans ?_
      rw [filter_append, hp.factors_pow,
          filter_eq_nil.mpr <| fun q hq ↦ by rw [mem_replicate] at hq; simp [hq.2],
          nil_append, filter_eq_self.mpr <| fun q hq ↦ by simp [hm q hq]]
  right_inv := by
    rintro ⟨m, hm₀, hm⟩
    

Proof state:
case mk.intro
p : ℕ
hp : Prime p
m : ℕ
hm₀ : m ≠ 0
hm : ∀ p_1 ∈ factors m, p_1 < succ p
⊢ (fun x =>
        match x with
        | (e, n) => { val := p ^ e * ↑n, property := (_ : p ^ e * ↑n ∈ smoothNumbers (succ p)) })
      ((fun x =>
          match x with
          | { val := m, property := property } =>
            ((factorization m) p,
              { val := prod (List.filter (fun x => decide (x < p)) (factors m)),
                property := (_ : prod (List.filter (fun x => decide (x < p)) (factors m)) ∈ smoothNumbers p) }))
        { val := m, property := (_ : m ≠ 0 ∧ ∀ p_1 ∈ factors m, p_1 < succ p) }) =
    { val := m, property := (_ : m ≠ 0 ∧ ∀ p_1 ∈ factors m, p_1 < succ p) }

Next tactic:
simp only [Set.coe_setOf, Set.mem_setOf_eq, Subtype.mk.injEq]
open List Perm in
/-- We establish the bijection from `ℕ × smoothNumbers p` to `smoothNumbers (p+1)`
given by `(e, n) ↦ p^e * n` when `p` is a prime. See `Nat.smoothNumbers_succ` for
when `p` is not prime. -/
def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) :
    ℕ × smoothNumbers p ≃ smoothNumbers p.succ where
  toFun := fun ⟨e, n⟩ ↦ ⟨p ^ e * n, pow_mul_mem_smoothNumbers hp.ne_zero e n.2⟩
  invFun := fun ⟨m, _⟩  ↦ (m.factorization p,
                            ⟨(m.factors.filter (· < p)).prod, prod_mem_smoothNumbers ..⟩)
  left_inv := by
    rintro ⟨e, m, hm₀, hm⟩
    simp (config := { etaStruct := .all }) only
      [Set.coe_setOf, Set.mem_setOf_eq, Prod.mk.injEq, Subtype.mk.injEq]
    constructor
    · rw [factorization_mul (pos_iff_ne_zero.mp <| pos_pow_of_pos e hp.pos) hm₀]
      simp only [factorization_pow, Finsupp.coe_add, Finsupp.coe_smul, nsmul_eq_mul,
        Pi.coe_nat, cast_id, Pi.add_apply, Pi.mul_apply, hp.factorization_self,
        mul_one, add_right_eq_self]
      rw [← factors_count_eq, count_eq_zero]
      exact fun H ↦ (hm p H).false
    · nth_rw 2 [← prod_factors hm₀]
      refine prod_eq <| (filter _ <| perm_factors_mul (pow_ne_zero e hp.ne_zero) hm₀).trans ?_
      rw [filter_append, hp.factors_pow,
          filter_eq_nil.mpr <| fun q hq ↦ by rw [mem_replicate] at hq; simp [hq.2],
          nil_append, filter_eq_self.mpr <| fun q hq ↦ by simp [hm q hq]]
  right_inv := by
    rintro ⟨m, hm₀, hm⟩
    simp only [Set.coe_setOf, Set.mem_setOf_eq, Subtype.mk.injEq]
    

Proof state:
case mk.intro
p : ℕ
hp : Prime p
m : ℕ
hm₀ : m ≠ 0
hm : ∀ p_1 ∈ factors m, p_1 < succ p
⊢ p ^ (factorization m) p * prod (List.filter (fun x => decide (x < p)) (factors m)) = m

Next tactic:
rw [← factors_count_eq, ← prod_replicate, ← prod_append]
open List Perm in
/-- We establish the bijection from `ℕ × smoothNumbers p` to `smoothNumbers (p+1)`
given by `(e, n) ↦ p^e * n` when `p` is a prime. See `Nat.smoothNumbers_succ` for
when `p` is not prime. -/
def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) :
    ℕ × smoothNumbers p ≃ smoothNumbers p.succ where
  toFun := fun ⟨e, n⟩ ↦ ⟨p ^ e * n, pow_mul_mem_smoothNumbers hp.ne_zero e n.2⟩
  invFun := fun ⟨m, _⟩  ↦ (m.factorization p,
                            ⟨(m.factors.filter (· < p)).prod, prod_mem_smoothNumbers ..⟩)
  left_inv := by
    rintro ⟨e, m, hm₀, hm⟩
    simp (config := { etaStruct := .all }) only
      [Set.coe_setOf, Set.mem_setOf_eq, Prod.mk.injEq, Subtype.mk.injEq]
    constructor
    · rw [factorization_mul (pos_iff_ne_zero.mp <| pos_pow_of_pos e hp.pos) hm₀]
      simp only [factorization_pow, Finsupp.coe_add, Finsupp.coe_smul, nsmul_eq_mul,
        Pi.coe_nat, cast_id, Pi.add_apply, Pi.mul_apply, hp.factorization_self,
        mul_one, add_right_eq_self]
      rw [← factors_count_eq, count_eq_zero]
      exact fun H ↦ (hm p H).false
    · nth_rw 2 [← prod_factors hm₀]
      refine prod_eq <| (filter _ <| perm_factors_mul (pow_ne_zero e hp.ne_zero) hm₀).trans ?_
      rw [filter_append, hp.factors_pow,
          filter_eq_nil.mpr <| fun q hq ↦ by rw [mem_replicate] at hq; simp [hq.2],
          nil_append, filter_eq_self.mpr <| fun q hq ↦ by simp [hm q hq]]
  right_inv := by
    rintro ⟨m, hm₀, hm⟩
    simp only [Set.coe_setOf, Set.mem_setOf_eq, Subtype.mk.injEq]
    rw [← factors_count_eq, ← prod_replicate, ← prod_append]
    

Proof state:
case mk.intro
p : ℕ
hp : Prime p
m : ℕ
hm₀ : m ≠ 0
hm : ∀ p_1 ∈ factors m, p_1 < succ p
⊢ prod (replicate (count p (factors m)) p ++ List.filter (fun x => decide (x < p)) (factors m)) = m

Next tactic:
nth_rw 3 [← prod_factors hm₀]
open List Perm in
/-- We establish the bijection from `ℕ × smoothNumbers p` to `smoothNumbers (p+1)`
given by `(e, n) ↦ p^e * n` when `p` is a prime. See `Nat.smoothNumbers_succ` for
when `p` is not prime. -/
def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) :
    ℕ × smoothNumbers p ≃ smoothNumbers p.succ where
  toFun := fun ⟨e, n⟩ ↦ ⟨p ^ e * n, pow_mul_mem_smoothNumbers hp.ne_zero e n.2⟩
  invFun := fun ⟨m, _⟩  ↦ (m.factorization p,
                            ⟨(m.factors.filter (· < p)).prod, prod_mem_smoothNumbers ..⟩)
  left_inv := by
    rintro ⟨e, m, hm₀, hm⟩
    simp (config := { etaStruct := .all }) only
      [Set.coe_setOf, Set.mem_setOf_eq, Prod.mk.injEq, Subtype.mk.injEq]
    constructor
    · rw [factorization_mul (pos_iff_ne_zero.mp <| pos_pow_of_pos e hp.pos) hm₀]
      simp only [factorization_pow, Finsupp.coe_add, Finsupp.coe_smul, nsmul_eq_mul,
        Pi.coe_nat, cast_id, Pi.add_apply, Pi.mul_apply, hp.factorization_self,
        mul_one, add_right_eq_self]
      rw [← factors_count_eq, count_eq_zero]
      exact fun H ↦ (hm p H).false
    · nth_rw 2 [← prod_factors hm₀]
      refine prod_eq <| (filter _ <| perm_factors_mul (pow_ne_zero e hp.ne_zero) hm₀).trans ?_
      rw [filter_append, hp.factors_pow,
          filter_eq_nil.mpr <| fun q hq ↦ by rw [mem_replicate] at hq; simp [hq.2],
          nil_append, filter_eq_self.mpr <| fun q hq ↦ by simp [hm q hq]]
  right_inv := by
    rintro ⟨m, hm₀, hm⟩
    simp only [Set.coe_setOf, Set.mem_setOf_eq, Subtype.mk.injEq]
    rw [← factors_count_eq, ← prod_replicate, ← prod_append]
    nth_rw 3 [← prod_factors hm₀]
    

Proof state:
case mk.intro
p : ℕ
hp : Prime p
m : ℕ
hm₀ : m ≠ 0
hm : ∀ p_1 ∈ factors m, p_1 < succ p
⊢ prod (replicate (count p (factors m)) p ++ List.filter (fun x => decide (x < p)) (factors m)) = prod (factors m)

Next tactic:
have : m.factors.filter (· = p) = m.factors.filter (¬ · < p)
open List Perm in
/-- We establish the bijection from `ℕ × smoothNumbers p` to `smoothNumbers (p+1)`
given by `(e, n) ↦ p^e * n` when `p` is a prime. See `Nat.smoothNumbers_succ` for
when `p` is not prime. -/
def equivProdNatSmoothNumbers {p : ℕ} (hp: p.Prime) :
    ℕ × smoothNumbers p ≃ smoothNumbers p.succ where
  toFun := fun ⟨e, n⟩ ↦ ⟨p ^ e * n, pow_mul_mem_smoothNumbers hp.ne_zero e n.2⟩
  invFun := fun ⟨m, _⟩  ↦ (m.factorization p,
                            ⟨(m.factors.filter (· < p)).prod, prod_mem_smoothNumbers ..⟩)
  left_inv := by
    rintro ⟨e, m, hm₀, hm⟩
    simp (config := { etaStruct := .all }) only
      [Set.coe_setOf, Set.mem_setOf_eq, Prod.mk.injEq, Subtype.mk.injEq]
    constructor
    · rw [factorization_mul (pos_iff_ne_zero.mp <| pos_pow_of_pos e hp.pos) hm₀]
      simp only [factorization_pow, Finsupp.coe_add, Finsupp.coe_smul, nsmul_eq_mul,
        Pi.coe_nat, cast_id, Pi.add_apply, Pi.mul_apply, hp.factorization_self,
        mul_one, add_right_eq_self]
      rw [← factors_count_eq, count_eq_zero]
      exact fun H ↦ (hm p H).false
    · nth_rw 2 [← prod_factors hm₀]
      refine prod_eq <| (filter _ <| perm_factors_mul (pow_ne_zero e hp.ne_zero) hm₀).trans ?_
      rw [filter_append, hp.factors_pow,
          filter_eq_nil.mpr <| fun q hq ↦ by rw [mem_replicate] at hq; simp [hq.2],
          nil_append, filter_eq_self.mpr <| fun q hq ↦ by simp [hm q hq]]
  right_inv := by
    rintro ⟨m, hm₀, hm⟩
    simp only [Set.coe_setOf, Set.mem_setOf_eq, Subtype.mk.injEq]
    rw [← factors_count_eq, ← prod_replicate, ← prod_append]
    nth_rw 3 [← prod_factors hm₀]
    have : m.factors.filter (· = p) = m.factors.filter (¬ · < p)
    · 

Proof state:
case this
p : ℕ
hp : Prime p
m : ℕ
hm₀ : m ≠ 0
hm : ∀ p_1 ∈ factors m, p_1 < succ p
⊢ List.filter (fun x => decide (x = p)) (factors m) = List.filter (fun x => decide ¬x < p) (factors m)

Next tactic:
refine (filter_congr' <| fun q hq ↦ ?_).symm