Theorem: ZMod.gauss_lemma_aux₁
File: Mathlib/NumberTheory/LegendreSymbol/GaussEisensteinLemmas.lean

tactic: rw [prod_mul_distrib, ← prod_natCast, prod_Ico_id_eq_factorial, prod_const, card_Ico,
  Nat.add_one_sub_one]
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ ↑a ^ (p / 2) * ↑(p / 2)! = ↑(∏ x ∈ Ico 1 (p / 2).succ, a * ↑x)
state_after: p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ ↑a ^ (p / 2) * ↑(p / 2)! = ↑(a ^ (p / 2) * ↑(p / 2)!)

tactic: simp
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ ↑a ^ (p / 2) * ↑(p / 2)! = ↑(a ^ (p / 2) * ↑(p / 2)!)
state_after: no goals

tactic: simp
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ ↑(∏ x ∈ Ico 1 (p / 2).succ, a * ↑x) = ∏ x ∈ Ico 1 (p / 2).succ, ↑(↑a * ↑x).val
state_after: no goals

tactic: simp only [natCast_natAbs_valMinAbs]
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
x✝¹ : ℕ
x✝ : x✝¹ ∈ Ico 1 (p / 2).succ
⊢ ↑(↑a * ↑x✝¹).val = (if (↑a * ↑x✝¹).val ≤ p / 2 then 1 else -1) * ↑(↑a * ↑x✝¹).valMinAbs.natAbs
state_after: p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
x✝¹ : ℕ
x✝ : x✝¹ ∈ Ico 1 (p / 2).succ
⊢ ↑(↑a * ↑x✝¹).val =
    (if (↑a * ↑x✝¹).val ≤ p / 2 then 1 else -1) * if (↑a * ↑x✝¹).val ≤ p / 2 then ↑a * ↑x✝¹ else -(↑a * ↑x✝¹)

tactic: split_ifs <;> simp
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
x✝¹ : ℕ
x✝ : x✝¹ ∈ Ico 1 (p / 2).succ
⊢ ↑(↑a * ↑x✝¹).val =
    (if (↑a * ↑x✝¹).val ≤ p / 2 then 1 else -1) * if (↑a * ↑x✝¹).val ≤ p / 2 then ↑a * ↑x✝¹ else -(↑a * ↑x✝¹)
state_after: no goals

tactic: have :
    (∏ x ∈ Ico 1 (p / 2).succ, if (a * x : ZMod p).val ≤ p / 2 then (1 : ZMod p) else -1) =
    ∏ x ∈ (Ico 1 (p / 2).succ).filter fun x : ℕ => ¬(a * x : ZMod p).val ≤ p / 2, -1 :=
  prod_bij_ne_one (fun x _ _ => x)
    (fun x => by split_ifs <;> (dsimp; simp_all))
    (fun _ _ _ _ _ _ => id) (fun b h _ => ⟨b, by simp_all [-not_le]⟩)
    (by intros; split_ifs at * <;> simp_all)
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ ∏ x ∈ Ico 1 (p / 2).succ, (if (↑a * ↑x).val ≤ p / 2 then 1 else -1) * ↑(↑a * ↑x).valMinAbs.natAbs =
    (-1) ^ (filter (fun x => ¬(↑a * ↑x).val ≤ p / 2) (Ico 1 (p / 2).succ)).card *
      ∏ x ∈ Ico 1 (p / 2).succ, ↑(↑a * ↑x).valMinAbs.natAbs
state_after: p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
this :
  (∏ x ∈ Ico 1 (p / 2).succ, if (↑a * ↑x).val ≤ p / 2 then 1 else -1) =
    ∏ x ∈ filter (fun x => ¬(↑a * ↑x).val ≤ p / 2) (Ico 1 (p / 2).succ), -1
⊢ ∏ x ∈ Ico 1 (p / 2).succ, (if (↑a * ↑x).val ≤ p / 2 then 1 else -1) * ↑(↑a * ↑x).valMinAbs.natAbs =
    (-1) ^ (filter (fun x => ¬(↑a * ↑x).val ≤ p / 2) (Ico 1 (p / 2).succ)).card *
      ∏ x ∈ Ico 1 (p / 2).succ, ↑(↑a * ↑x).valMinAbs.natAbs

tactic: rw [prod_mul_distrib, this, prod_const]
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
this :
  (∏ x ∈ Ico 1 (p / 2).succ, if (↑a * ↑x).val ≤ p / 2 then 1 else -1) =
    ∏ x ∈ filter (fun x => ¬(↑a * ↑x).val ≤ p / 2) (Ico 1 (p / 2).succ), -1
⊢ ∏ x ∈ Ico 1 (p / 2).succ, (if (↑a * ↑x).val ≤ p / 2 then 1 else -1) * ↑(↑a * ↑x).valMinAbs.natAbs =
    (-1) ^ (filter (fun x => ¬(↑a * ↑x).val ≤ p / 2) (Ico 1 (p / 2).succ)).card *
      ∏ x ∈ Ico 1 (p / 2).succ, ↑(↑a * ↑x).valMinAbs.natAbs
state_after: no goals

tactic: split_ifs <;> (dsimp; simp_all)
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
x : ℕ
⊢ ∀ (h₁ : x ∈ Ico 1 (p / 2).succ) (h₂ : (if (↑a * ↑x).val ≤ p / 2 then 1 else -1) ≠ 1),
    (fun x x_1 x_2 => x) x h₁ h₂ ∈ filter (fun x => ¬(↑a * ↑x).val ≤ p / 2) (Ico 1 (p / 2).succ)
state_after: no goals

tactic: dsimp
state_before: case neg
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
x : ℕ
h✝ : ¬(↑a * ↑x).val ≤ p / 2
⊢ ∀ (h₁ : x ∈ Ico 1 (p / 2).succ) (h₂ : -1 ≠ 1),
    (fun x x_1 x_2 => x) x h₁ ⋯ ∈ filter (fun x => ¬(↑a * ↑x).val ≤ p / 2) (Ico 1 (p / 2).succ)
state_after: case neg
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
x : ℕ
h✝ : ¬(↑a * ↑x).val ≤ p / 2
⊢ x ∈ Ico 1 (p / 2 + 1) → ¬-1 = 1 → x ∈ filter (fun x => ¬(↑a * ↑x).val ≤ p / 2) (Ico 1 (p / 2 + 1))

tactic: simp_all
state_before: case neg
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
x : ℕ
h✝ : ¬(↑a * ↑x).val ≤ p / 2
⊢ x ∈ Ico 1 (p / 2 + 1) → ¬-1 = 1 → x ∈ filter (fun x => ¬(↑a * ↑x).val ≤ p / 2) (Ico 1 (p / 2 + 1))
state_after: no goals

tactic: simp_all [-not_le]
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
b : ℕ
h : b ∈ filter (fun x => ¬(↑a * ↑x).val ≤ p / 2) (Ico 1 (p / 2).succ)
x✝ : -1 ≠ 1
⊢ ∃ (h₁ : b ∈ Ico 1 (p / 2).succ) (h₂ : (if (↑a * ↑b).val ≤ p / 2 then 1 else -1) ≠ 1), (fun x x_1 x_2 => x) b h₁ h₂ = b
state_after: no goals

tactic: intros
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ ∀ a_1 ∈ Ico 1 (p / 2).succ,
    (if (↑a * ↑a_1).val ≤ p / 2 then 1 else -1) ≠ 1 → (if (↑a * ↑a_1).val ≤ p / 2 then 1 else -1) = -1
state_after: p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
a✝ : ℕ
h₁✝ : a✝ ∈ Ico 1 (p / 2).succ
h₂✝ : (if (↑a * ↑a✝).val ≤ p / 2 then 1 else -1) ≠ 1
⊢ (if (↑a * ↑a✝).val ≤ p / 2 then 1 else -1) = -1

tactic: split_ifs at * <;> simp_all
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
a✝ : ℕ
h₁✝ : a✝ ∈ Ico 1 (p / 2).succ
h₂✝ : (if (↑a * ↑a✝).val ≤ p / 2 then 1 else -1) ≠ 1
⊢ (if (↑a * ↑a✝).val ≤ p / 2 then 1 else -1) = -1
state_after: no goals

tactic: rw [← prod_natCast, Finset.prod_eq_multiset_prod,
  Ico_map_valMinAbs_natAbs_eq_Ico_map_id p a hap, ← Finset.prod_eq_multiset_prod,
  prod_Ico_id_eq_factorial]
state_before: p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ (-1) ^ (filter (fun x => ¬(↑a * ↑x).val ≤ p / 2) (Ico 1 (p / 2).succ)).card *
      ∏ x ∈ Ico 1 (p / 2).succ, ↑(↑a * ↑x).valMinAbs.natAbs =
    (-1) ^ (filter (fun x => ¬(↑a * ↑x).val ≤ p / 2) (Ico 1 (p / 2).succ)).card * ↑(p / 2)!
state_after: no goals