Theorem: ZMod.wilsons_lemma
File: Mathlib/NumberTheory/Wilson.lean

tactic: refine
  calc
    ((p - 1)! : ZMod p) = ∏ x ∈ Ico 1 (succ (p - 1)), (x : ZMod p) := by
      rw [← Finset.prod_Ico_id_eq_factorial, prod_natCast]
    _ = ∏ x : (ZMod p)ˣ, (x : ZMod p) := ?_
    _ = -1 := by
      simp_rw [← Units.coeHom_apply]
      rw [← map_prod (Units.coeHom (ZMod p))]
      simp_rw [prod_univ_units_id_eq_neg_one, Units.coeHom_apply, Units.val_neg, Units.val_one]
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
⊢ ↑(p - 1)! = -1
state_after: p : ℕ
inst✝ : Fact (Nat.Prime p)
⊢ ∏ x ∈ Ico 1 (p - 1).succ, ↑x = ∏ x : (ZMod p)ˣ, ↑x

tactic: have hp : 0 < p := (Fact.out (p := p.Prime)).pos
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
⊢ ∏ x ∈ Ico 1 (p - 1).succ, ↑x = ∏ x : (ZMod p)ˣ, ↑x
state_after: p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
⊢ ∏ x ∈ Ico 1 (p - 1).succ, ↑x = ∏ x : (ZMod p)ˣ, ↑x

tactic: symm
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
⊢ ∏ x ∈ Ico 1 (p - 1).succ, ↑x = ∏ x : (ZMod p)ˣ, ↑x
state_after: p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
⊢ ∏ x : (ZMod p)ˣ, ↑x = ∏ x ∈ Ico 1 (p - 1).succ, ↑x

tactic: refine prod_bij (fun a _ => (a : ZMod p).val) ?_ ?_ ?_ ?_
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
⊢ ∏ x : (ZMod p)ˣ, ↑x = ∏ x ∈ Ico 1 (p - 1).succ, ↑x
state_after: case refine_1
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
⊢ ∀ (a : (ZMod p)ˣ) (ha : a ∈ univ), (fun a x => (↑a).val) a ha ∈ Ico 1 (p - 1).succ

case refine_2
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
⊢ ∀ (a₁ : (ZMod p)ˣ) (ha₁ : a₁ ∈ univ) (a₂ : (ZMod p)ˣ) (ha₂ : a₂ ∈ univ),
    (fun a x => (↑a).val) a₁ ha₁ = (fun a x => (↑a).val) a₂ ha₂ → a₁ = a₂

case refine_3
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
⊢ ∀ b ∈ Ico 1 (p - 1).succ, ∃ a, ∃ (ha : a ∈ univ), (fun a x => (↑a).val) a ha = b

case refine_4
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
⊢ ∀ (a : (ZMod p)ˣ) (ha : a ∈ univ), ↑a = ↑((fun a x => (↑a).val) a ha)

tactic: rw [← Finset.prod_Ico_id_eq_factorial, prod_natCast]
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
⊢ ↑(p - 1)! = ∏ x ∈ Ico 1 (p - 1).succ, ↑x
state_after: no goals

tactic: simp_rw [← Units.coeHom_apply]
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
⊢ ∏ x : (ZMod p)ˣ, ↑x = -1
state_after: p : ℕ
inst✝ : Fact (Nat.Prime p)
⊢ ∏ x : (ZMod p)ˣ, (Units.coeHom (ZMod p)) x = -1

tactic: rw [← map_prod (Units.coeHom (ZMod p))]
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
⊢ ∏ x : (ZMod p)ˣ, (Units.coeHom (ZMod p)) x = -1
state_after: p : ℕ
inst✝ : Fact (Nat.Prime p)
⊢ (Units.coeHom (ZMod p)) (∏ x : (ZMod p)ˣ, x) = -1

tactic: simp_rw [prod_univ_units_id_eq_neg_one, Units.coeHom_apply, Units.val_neg, Units.val_one]
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
⊢ (Units.coeHom (ZMod p)) (∏ x : (ZMod p)ˣ, x) = -1
state_after: no goals

tactic: intro a ha
state_before: case refine_1
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
⊢ ∀ (a : (ZMod p)ˣ) (ha : a ∈ univ), (fun a x => (↑a).val) a ha ∈ Ico 1 (p - 1).succ
state_after: case refine_1
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a : (ZMod p)ˣ
ha : a ∈ univ
⊢ (fun a x => (↑a).val) a ha ∈ Ico 1 (p - 1).succ

tactic: rw [mem_Ico, ← Nat.succ_sub hp, Nat.add_one_sub_one]
state_before: case refine_1
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a : (ZMod p)ˣ
ha : a ∈ univ
⊢ (fun a x => (↑a).val) a ha ∈ Ico 1 (p - 1).succ
state_after: case refine_1
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a : (ZMod p)ˣ
ha : a ∈ univ
⊢ 1 ≤ (fun a x => (↑a).val) a ha ∧ (fun a x => (↑a).val) a ha < p

tactic: constructor
state_before: case refine_1
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a : (ZMod p)ˣ
ha : a ∈ univ
⊢ 1 ≤ (fun a x => (↑a).val) a ha ∧ (fun a x => (↑a).val) a ha < p
state_after: case refine_1.left
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a : (ZMod p)ˣ
ha : a ∈ univ
⊢ 1 ≤ (fun a x => (↑a).val) a ha

case refine_1.right
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a : (ZMod p)ˣ
ha : a ∈ univ
⊢ (fun a x => (↑a).val) a ha < p

tactic: apply Nat.pos_of_ne_zero
state_before: case refine_1.left
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a : (ZMod p)ˣ
ha : a ∈ univ
⊢ 1 ≤ (fun a x => (↑a).val) a ha
state_after: case refine_1.left.a
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a : (ZMod p)ˣ
ha : a ∈ univ
⊢ (fun a x => (↑a).val) a ha ≠ 0

tactic: rw [← @val_zero p]
state_before: case refine_1.left.a
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a : (ZMod p)ˣ
ha : a ∈ univ
⊢ (fun a x => (↑a).val) a ha ≠ 0
state_after: case refine_1.left.a
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a : (ZMod p)ˣ
ha : a ∈ univ
⊢ (fun a x => (↑a).val) a ha ≠ val 0

tactic: intro h
state_before: case refine_1.left.a
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a : (ZMod p)ˣ
ha : a ∈ univ
⊢ (fun a x => (↑a).val) a ha ≠ val 0
state_after: case refine_1.left.a
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a : (ZMod p)ˣ
ha : a ∈ univ
h : (fun a x => (↑a).val) a ha = val 0
⊢ False

tactic: apply Units.ne_zero a (val_injective p h)
state_before: case refine_1.left.a
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a : (ZMod p)ˣ
ha : a ∈ univ
h : (fun a x => (↑a).val) a ha = val 0
⊢ False
state_after: no goals

tactic: exact val_lt _
state_before: case refine_1.right
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a : (ZMod p)ˣ
ha : a ∈ univ
⊢ (fun a x => (↑a).val) a ha < p
state_after: no goals

tactic: intro _ _ _ _ h
state_before: case refine_2
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
⊢ ∀ (a₁ : (ZMod p)ˣ) (ha₁ : a₁ ∈ univ) (a₂ : (ZMod p)ˣ) (ha₂ : a₂ ∈ univ),
    (fun a x => (↑a).val) a₁ ha₁ = (fun a x => (↑a).val) a₂ ha₂ → a₁ = a₂
state_after: case refine_2
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a₁✝ : (ZMod p)ˣ
ha₁✝ : a₁✝ ∈ univ
a₂✝ : (ZMod p)ˣ
ha₂✝ : a₂✝ ∈ univ
h : (fun a x => (↑a).val) a₁✝ ha₁✝ = (fun a x => (↑a).val) a₂✝ ha₂✝
⊢ a₁✝ = a₂✝

tactic: rw [Units.ext_iff]
state_before: case refine_2
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a₁✝ : (ZMod p)ˣ
ha₁✝ : a₁✝ ∈ univ
a₂✝ : (ZMod p)ˣ
ha₂✝ : a₂✝ ∈ univ
h : (fun a x => (↑a).val) a₁✝ ha₁✝ = (fun a x => (↑a).val) a₂✝ ha₂✝
⊢ a₁✝ = a₂✝
state_after: case refine_2
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a₁✝ : (ZMod p)ˣ
ha₁✝ : a₁✝ ∈ univ
a₂✝ : (ZMod p)ˣ
ha₂✝ : a₂✝ ∈ univ
h : (fun a x => (↑a).val) a₁✝ ha₁✝ = (fun a x => (↑a).val) a₂✝ ha₂✝
⊢ ↑a₁✝ = ↑a₂✝

tactic: exact val_injective p h
state_before: case refine_2
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a₁✝ : (ZMod p)ˣ
ha₁✝ : a₁✝ ∈ univ
a₂✝ : (ZMod p)ˣ
ha₂✝ : a₂✝ ∈ univ
h : (fun a x => (↑a).val) a₁✝ ha₁✝ = (fun a x => (↑a).val) a₂✝ ha₂✝
⊢ ↑a₁✝ = ↑a₂✝
state_after: no goals

tactic: intro b hb
state_before: case refine_3
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
⊢ ∀ b ∈ Ico 1 (p - 1).succ, ∃ a, ∃ (ha : a ∈ univ), (fun a x => (↑a).val) a ha = b
state_after: case refine_3
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
b : ℕ
hb : b ∈ Ico 1 (p - 1).succ
⊢ ∃ a, ∃ (ha : a ∈ univ), (fun a x => (↑a).val) a ha = b

tactic: rw [mem_Ico, Nat.succ_le_iff, ← succ_sub hp, Nat.add_one_sub_one, pos_iff_ne_zero] at hb
state_before: case refine_3
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
b : ℕ
hb : b ∈ Ico 1 (p - 1).succ
⊢ ∃ a, ∃ (ha : a ∈ univ), (fun a x => (↑a).val) a ha = b
state_after: case refine_3
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
b : ℕ
hb : b ≠ 0 ∧ b < p
⊢ ∃ a, ∃ (ha : a ∈ univ), (fun a x => (↑a).val) a ha = b

tactic: refine ⟨Units.mk0 b ?_, Finset.mem_univ _, ?_⟩
state_before: case refine_3
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
b : ℕ
hb : b ≠ 0 ∧ b < p
⊢ ∃ a, ∃ (ha : a ∈ univ), (fun a x => (↑a).val) a ha = b
state_after: case refine_3.refine_1
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
b : ℕ
hb : b ≠ 0 ∧ b < p
⊢ ↑b ≠ 0

case refine_3.refine_2
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
b : ℕ
hb : b ≠ 0 ∧ b < p
⊢ (fun a x => (↑a).val) (Units.mk0 ↑b ?refine_3.refine_1) ⋯ = b

tactic: intro h
state_before: case refine_3.refine_1
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
b : ℕ
hb : b ≠ 0 ∧ b < p
⊢ ↑b ≠ 0
state_after: case refine_3.refine_1
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
b : ℕ
hb : b ≠ 0 ∧ b < p
h : ↑b = 0
⊢ False

tactic: apply hb.1
state_before: case refine_3.refine_1
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
b : ℕ
hb : b ≠ 0 ∧ b < p
h : ↑b = 0
⊢ False
state_after: case refine_3.refine_1
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
b : ℕ
hb : b ≠ 0 ∧ b < p
h : ↑b = 0
⊢ b = 0

tactic: apply_fun val at h
state_before: case refine_3.refine_1
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
b : ℕ
hb : b ≠ 0 ∧ b < p
h : ↑b = 0
⊢ b = 0
state_after: case refine_3.refine_1
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
b : ℕ
hb : b ≠ 0 ∧ b < p
h : (↑b).val = val 0
⊢ b = 0

tactic: simpa only [val_cast_of_lt hb.right, val_zero] using h
state_before: case refine_3.refine_1
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
b : ℕ
hb : b ≠ 0 ∧ b < p
h : (↑b).val = val 0
⊢ b = 0
state_after: no goals

tactic: simp only [val_cast_of_lt hb.right, Units.val_mk0]
state_before: case refine_3.refine_2
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
b : ℕ
hb : b ≠ 0 ∧ b < p
⊢ (fun a x => (↑a).val) (Units.mk0 ↑b ⋯) ⋯ = b
state_after: no goals

tactic: rintro a -
state_before: case refine_4
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
⊢ ∀ (a : (ZMod p)ˣ) (ha : a ∈ univ), ↑a = ↑((fun a x => (↑a).val) a ha)
state_after: case refine_4
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a : (ZMod p)ˣ
ha✝ : a ∈ univ
⊢ ↑a = ↑((fun a x => (↑a).val) a ha✝)

tactic: simp only [cast_id, natCast_val]
state_before: case refine_4
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : 0 < p
a : (ZMod p)ˣ
ha✝ : a ∈ univ
⊢ ↑a = ↑((fun a x => (↑a).val) a ha✝)
state_after: no goals