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

Proof steps:
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: 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)! = ↑(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
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: 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) * if (↑a * ↑x✝¹).val ≤ p / 2 then ↑a * ↑x✝¹ else -(↑a * ↑x✝¹)
state_after: no goals
tactic: split_ifs <;> simp
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: 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
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: rw [prod_mul_distrib, this, prod_const]
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
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]