l3lab/ntp-mathlib huggingface dataset:
theorem mirror_eval_one : p.mirror.eval 1 = p.eval 1 := by
  simp_rw [eval_eq_sum_range, one_pow, mul_one, mirror_natDegree]
  refine' Finset.sum_bij_ne_zero _ _ _ _ _
  · exact fun n _ _ => revAt (p.natDegree + p.natTrailingDegree) n
  · intro n hn hp
    rw [Finset.mem_range_succ_iff] at *
    rw [revAt_le (hn.trans (Nat.le_add_right _ _))]
    rw [tsub_le_iff_tsub_le, add_comm, add_tsub_cancel_right, ← mirror_natTrailingDegree]
    exact natTrailingDegree_le_of_ne_zero hp
  · exact fun n₁ n₂ _ _ _ _ h => by rw [← @revAt_invol _ n₁, h, revAt_invol]
  · intro n hn hp
    use revAt (p.natDegree + p.natTrailingDegree) n
    refine' ⟨_, _, revAt_invol.symm⟩
    · rw [Finset.mem_range_succ_iff] at *
      rw [revAt_le (hn.trans (Nat.le_add_right _ _))]
      rw [tsub_le_iff_tsub_le, add_comm, add_tsub_cancel_right]
      exact natTrailingDegree_le_of_ne_zero hp
    · change p.mirror.coeff _ ≠ 0
      

Proof state:
case h.refine'_2
R : Type u_1
inst✝ : Semiring R
p q : R[X]
n : ℕ
hn : n ∈ Finset.range (natDegree p + 1)
hp : coeff p n ≠ 0
⊢ coeff (mirror p) ((revAt (natDegree p + natTrailingDegree p)) n) ≠ 0

Next tactic:
rwa [coeff_mirror, revAt_invol]
theorem mirror_eval_one : p.mirror.eval 1 = p.eval 1 := by
  simp_rw [eval_eq_sum_range, one_pow, mul_one, mirror_natDegree]
  refine' Finset.sum_bij_ne_zero _ _ _ _ _
  · exact fun n _ _ => revAt (p.natDegree + p.natTrailingDegree) n
  · intro n hn hp
    rw [Finset.mem_range_succ_iff] at *
    rw [revAt_le (hn.trans (Nat.le_add_right _ _))]
    rw [tsub_le_iff_tsub_le, add_comm, add_tsub_cancel_right, ← mirror_natTrailingDegree]
    exact natTrailingDegree_le_of_ne_zero hp
  · exact fun n₁ n₂ _ _ _ _ h => by rw [← @revAt_invol _ n₁, h, revAt_invol]
  · intro n hn hp
    use revAt (p.natDegree + p.natTrailingDegree) n
    refine' ⟨_, _, revAt_invol.symm⟩
    · rw [Finset.mem_range_succ_iff] at *
      rw [revAt_le (hn.trans (Nat.le_add_right _ _))]
      rw [tsub_le_iff_tsub_le, add_comm, add_tsub_cancel_right]
      exact natTrailingDegree_le_of_ne_zero hp
    · change p.mirror.coeff _ ≠ 0
      rwa [coeff_mirror, revAt_invol]
  · 

Proof state:
case refine'_5
R : Type u_1
inst✝ : Semiring R
p q : R[X]
⊢ ∀ a ∈ Finset.range (natDegree p + 1),
    coeff (mirror p) a ≠ 0 → coeff (mirror p) a = coeff p ((revAt (natDegree p + natTrailingDegree p)) a)

Next tactic:
exact fun n _ _ => p.coeff_mirror n
theorem mirror_mirror : p.mirror.mirror = p :=
  Polynomial.ext fun n => by
    

Proof state:
R : Type u_1
inst✝ : Semiring R
p q : R[X]
n : ℕ
⊢ coeff (mirror (mirror p)) n = coeff p n

Next tactic:
rw [coeff_mirror, coeff_mirror, mirror_natDegree, mirror_natTrailingDegree, revAt_invol]
@[simp]
theorem mirror_eq_zero : p.mirror = 0 ↔ p = 0 :=
  ⟨fun h => by 

Proof state:
R : Type u_1
inst✝ : Semiring R
p q : R[X]
h : mirror p = 0
⊢ p = 0

Next tactic:
rw [← p.mirror_mirror, h, mirror_zero]
@[simp]
theorem mirror_eq_zero : p.mirror = 0 ↔ p = 0 :=
  ⟨fun h => by rw [← p.mirror_mirror, h, mirror_zero], fun h => by 

Proof state:
R : Type u_1
inst✝ : Semiring R
p q : R[X]
h : p = 0
⊢ mirror p = 0

Next tactic:
rw [h, mirror_zero]
@[simp]
theorem mirror_trailingCoeff : p.mirror.trailingCoeff = p.leadingCoeff := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
p q : R[X]
⊢ trailingCoeff (mirror p) = leadingCoeff p

Next tactic:
rw [leadingCoeff, trailingCoeff, mirror_natTrailingDegree, coeff_mirror,
    revAt_le (Nat.le_add_left _ _), add_tsub_cancel_right]
@[simp]
theorem mirror_leadingCoeff : p.mirror.leadingCoeff = p.trailingCoeff := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
p q : R[X]
⊢ leadingCoeff (mirror p) = trailingCoeff p

Next tactic:
rw [← p.mirror_mirror, mirror_trailingCoeff, p.mirror_mirror]
theorem coeff_mul_mirror :
    (p * p.mirror).coeff (p.natDegree + p.natTrailingDegree) = p.sum fun n => (· ^ 2) := by
  

Proof state:
R : Type u_1
inst✝ : Semiring R
p q : R[X]
⊢ coeff (p * mirror p) (natDegree p + natTrailingDegree p) = sum p fun n x => x ^ 2

Next tactic:
rw [coeff_mul, Finset.Nat.sum_antidiagonal_eq_sum_range_succ_mk]
theorem coeff_mul_mirror :
    (p * p.mirror).coeff (p.natDegree + p.natTrailingDegree) = p.sum fun n => (· ^ 2) := by
  rw [coeff_mul, Finset.Nat.sum_antidiagonal_eq_sum_range_succ_mk]
  

Proof state:
R : Type u_1
inst✝ : Semiring R
p q : R[X]
⊢ (Finset.sum (Finset.range (Nat.succ (natDegree p + natTrailingDegree p))) fun k =>
      coeff p (k, natDegree p + natTrailingDegree p - k).1 *
        coeff (mirror p) (k, natDegree p + natTrailingDegree p - k).2) =
    sum p fun n x => x ^ 2

Next tactic:
refine'
    (Finset.sum_congr rfl fun n hn => _).trans
      (p.sum_eq_of_subset (fun _ => (· ^ 2)) (fun _ => zero_pow zero_lt_two) fun n hn =>
          Finset.mem_range_succ_iff.mpr
            ((le_natDegree_of_mem_supp n hn).trans (Nat.le_add_right _ _))).symm
theorem coeff_mul_mirror :
    (p * p.mirror).coeff (p.natDegree + p.natTrailingDegree) = p.sum fun n => (· ^ 2) := by
  rw [coeff_mul, Finset.Nat.sum_antidiagonal_eq_sum_range_succ_mk]
  refine'
    (Finset.sum_congr rfl fun n hn => _).trans
      (p.sum_eq_of_subset (fun _ => (· ^ 2)) (fun _ => zero_pow zero_lt_two) fun n hn =>
          Finset.mem_range_succ_iff.mpr
            ((le_natDegree_of_mem_supp n hn).trans (Nat.le_add_right _ _))).symm
  

Proof state:
R : Type u_1
inst✝ : Semiring R
p q : R[X]
n : ℕ
hn : n ∈ Finset.range (Nat.succ (natDegree p + natTrailingDegree p))
⊢ coeff p (n, natDegree p + natTrailingDegree p - n).1 * coeff (mirror p) (n, natDegree p + natTrailingDegree p - n).2 =
    coeff p n ^ 2

Next tactic:
rw [coeff_mirror, ← revAt_le (Finset.mem_range_succ_iff.mp hn), revAt_invol, ← sq]
theorem natDegree_mul_mirror : (p * p.mirror).natDegree = 2 * p.natDegree := by
  

Proof state:
R : Type u_1
inst✝¹ : Semiring R
p q : R[X]
inst✝ : NoZeroDivisors R
⊢ natDegree (p * mirror p) = 2 * natDegree p

Next tactic:
by_cases hp : p = 0
theorem natDegree_mul_mirror : (p * p.mirror).natDegree = 2 * p.natDegree := by
  by_cases hp : p = 0
  · 

Proof state:
case pos
R : Type u_1
inst✝¹ : Semiring R
p q : R[X]
inst✝ : NoZeroDivisors R
hp : p = 0
⊢ natDegree (p * mirror p) = 2 * natDegree p

Next tactic:
rw [hp, zero_mul, natDegree_zero, mul_zero]
theorem natDegree_mul_mirror : (p * p.mirror).natDegree = 2 * p.natDegree := by
  by_cases hp : p = 0
  · rw [hp, zero_mul, natDegree_zero, mul_zero]
  

Proof state:
case neg
R : Type u_1
inst✝¹ : Semiring R
p q : R[X]
inst✝ : NoZeroDivisors R
hp : ¬p = 0
⊢ natDegree (p * mirror p) = 2 * natDegree p

Next tactic:
rw [natDegree_mul hp (mt mirror_eq_zero.mp hp), mirror_natDegree, two_mul]
theorem natTrailingDegree_mul_mirror :
    (p * p.mirror).natTrailingDegree = 2 * p.natTrailingDegree := by
  

Proof state:
R : Type u_1
inst✝¹ : Semiring R
p q : R[X]
inst✝ : NoZeroDivisors R
⊢ natTrailingDegree (p * mirror p) = 2 * natTrailingDegree p

Next tactic:
by_cases hp : p = 0
theorem natTrailingDegree_mul_mirror :
    (p * p.mirror).natTrailingDegree = 2 * p.natTrailingDegree := by
  by_cases hp : p = 0
  · 

Proof state:
case pos
R : Type u_1
inst✝¹ : Semiring R
p q : R[X]
inst✝ : NoZeroDivisors R
hp : p = 0
⊢ natTrailingDegree (p * mirror p) = 2 * natTrailingDegree p

Next tactic:
rw [hp, zero_mul, natTrailingDegree_zero, mul_zero]
theorem natTrailingDegree_mul_mirror :
    (p * p.mirror).natTrailingDegree = 2 * p.natTrailingDegree := by
  by_cases hp : p = 0
  · rw [hp, zero_mul, natTrailingDegree_zero, mul_zero]
  

Proof state:
case neg
R : Type u_1
inst✝¹ : Semiring R
p q : R[X]
inst✝ : NoZeroDivisors R
hp : ¬p = 0
⊢ natTrailingDegree (p * mirror p) = 2 * natTrailingDegree p

Next tactic:
rw [natTrailingDegree_mul hp (mt mirror_eq_zero.mp hp), mirror_natTrailingDegree, two_mul]
theorem mirror_neg : (-p).mirror = -p.mirror := by
  

Proof state:
R : Type u_1
inst✝ : Ring R
p q : R[X]
⊢ mirror (-p) = -mirror p

Next tactic:
rw [mirror, mirror, reverse_neg, natTrailingDegree_neg, neg_mul_eq_neg_mul]
theorem mirror_mul_of_domain : (p * q).mirror = p.mirror * q.mirror := by
  

Proof state:
R : Type u_1
inst✝¹ : Ring R
p q : R[X]
inst✝ : NoZeroDivisors R
⊢ mirror (p * q) = mirror p * mirror q

Next tactic:
by_cases hp : p = 0
theorem mirror_mul_of_domain : (p * q).mirror = p.mirror * q.mirror := by
  by_cases hp : p = 0
  · 

Proof state:
case pos
R : Type u_1
inst✝¹ : Ring R
p q : R[X]
inst✝ : NoZeroDivisors R
hp : p = 0
⊢ mirror (p * q) = mirror p * mirror q

Next tactic:
rw [hp, zero_mul, mirror_zero, zero_mul]
theorem mirror_mul_of_domain : (p * q).mirror = p.mirror * q.mirror := by
  by_cases hp : p = 0
  · rw [hp, zero_mul, mirror_zero, zero_mul]
  

Proof state:
case neg
R : Type u_1
inst✝¹ : Ring R
p q : R[X]
inst✝ : NoZeroDivisors R
hp : ¬p = 0
⊢ mirror (p * q) = mirror p * mirror q

Next tactic:
by_cases hq : q = 0
theorem mirror_mul_of_domain : (p * q).mirror = p.mirror * q.mirror := by
  by_cases hp : p = 0
  · rw [hp, zero_mul, mirror_zero, zero_mul]
  by_cases hq : q = 0
  · 

Proof state:
case pos
R : Type u_1
inst✝¹ : Ring R
p q : R[X]
inst✝ : NoZeroDivisors R
hp : ¬p = 0
hq : q = 0
⊢ mirror (p * q) = mirror p * mirror q

Next tactic:
rw [hq, mul_zero, mirror_zero, mul_zero]
theorem mirror_mul_of_domain : (p * q).mirror = p.mirror * q.mirror := by
  by_cases hp : p = 0
  · rw [hp, zero_mul, mirror_zero, zero_mul]
  by_cases hq : q = 0
  · rw [hq, mul_zero, mirror_zero, mul_zero]
  

Proof state:
case neg
R : Type u_1
inst✝¹ : Ring R
p q : R[X]
inst✝ : NoZeroDivisors R
hp : ¬p = 0
hq : ¬q = 0
⊢ mirror (p * q) = mirror p * mirror q

Next tactic:
rw [mirror, mirror, mirror, reverse_mul_of_domain, natTrailingDegree_mul hp hq, pow_add]
theorem mirror_mul_of_domain : (p * q).mirror = p.mirror * q.mirror := by
  by_cases hp : p = 0
  · rw [hp, zero_mul, mirror_zero, zero_mul]
  by_cases hq : q = 0
  · rw [hq, mul_zero, mirror_zero, mul_zero]
  rw [mirror, mirror, mirror, reverse_mul_of_domain, natTrailingDegree_mul hp hq, pow_add]
  

Proof state:
case neg
R : Type u_1
inst✝¹ : Ring R
p q : R[X]
inst✝ : NoZeroDivisors R
hp : ¬p = 0
hq : ¬q = 0
⊢ reverse p * reverse q * (X ^ natTrailingDegree p * X ^ natTrailingDegree q) =
    reverse p * X ^ natTrailingDegree p * (reverse q * X ^ natTrailingDegree q)

Next tactic:
rw [mul_assoc, ← mul_assoc q.reverse, ← X_pow_mul (p := reverse q)]
theorem mirror_mul_of_domain : (p * q).mirror = p.mirror * q.mirror := by
  by_cases hp : p = 0
  · rw [hp, zero_mul, mirror_zero, zero_mul]
  by_cases hq : q = 0
  · rw [hq, mul_zero, mirror_zero, mul_zero]
  rw [mirror, mirror, mirror, reverse_mul_of_domain, natTrailingDegree_mul hp hq, pow_add]
  rw [mul_assoc, ← mul_assoc q.reverse, ← X_pow_mul (p := reverse q)]
  

Proof state:
case neg
R : Type u_1
inst✝¹ : Ring R
p q : R[X]
inst✝ : NoZeroDivisors R
hp : ¬p = 0
hq : ¬q = 0
⊢ reverse p * (X ^ natTrailingDegree p * reverse q * X ^ natTrailingDegree q) =
    reverse p * X ^ natTrailingDegree p * (reverse q * X ^ natTrailingDegree q)

Next tactic:
repeat' rw [mul_assoc]
theorem mirror_mul_of_domain : (p * q).mirror = p.mirror * q.mirror := by
  by_cases hp : p = 0
  · rw [hp, zero_mul, mirror_zero, zero_mul]
  by_cases hq : q = 0
  · rw [hq, mul_zero, mirror_zero, mul_zero]
  rw [mirror, mirror, mirror, reverse_mul_of_domain, natTrailingDegree_mul hp hq, pow_add]
  rw [mul_assoc, ← mul_assoc q.reverse, ← X_pow_mul (p := reverse q)]
  repeat' 

Proof state:
case neg
R : Type u_1
inst✝¹ : Ring R
p q : R[X]
inst✝ : NoZeroDivisors R
hp : ¬p = 0
hq : ¬q = 0
⊢ reverse p * (X ^ natTrailingDegree p * reverse q * X ^ natTrailingDegree q) =
    reverse p * X ^ natTrailingDegree p * (reverse q * X ^ natTrailingDegree q)

Next tactic:
rw [mul_assoc]
theorem mirror_mul_of_domain : (p * q).mirror = p.mirror * q.mirror := by
  by_cases hp : p = 0
  · rw [hp, zero_mul, mirror_zero, zero_mul]
  by_cases hq : q = 0
  · rw [hq, mul_zero, mirror_zero, mul_zero]
  rw [mirror, mirror, mirror, reverse_mul_of_domain, natTrailingDegree_mul hp hq, pow_add]
  rw [mul_assoc, ← mul_assoc q.reverse, ← X_pow_mul (p := reverse q)]
  repeat' 

Proof state:
case neg
R : Type u_1
inst✝¹ : Ring R
p q : R[X]
inst✝ : NoZeroDivisors R
hp : ¬p = 0
hq : ¬q = 0
⊢ reverse p * (X ^ natTrailingDegree p * (reverse q * X ^ natTrailingDegree q)) =
    reverse p * X ^ natTrailingDegree p * (reverse q * X ^ natTrailingDegree q)

Next tactic:
rw [mul_assoc]
theorem mirror_smul (a : R) : (a • p).mirror = a • p.mirror := by
  

Proof state:
R : Type u_1
inst✝¹ : Ring R
p q : R[X]
inst✝ : NoZeroDivisors R
a : R
⊢ mirror (a • p) = a • mirror p

Next tactic:
rw [← C_mul', ← C_mul', mirror_mul_of_domain, mirror_C]
theorem irreducible_of_mirror (h1 : ¬IsUnit f)
    (h2 : ∀ k, f * f.mirror = k * k.mirror → k = f ∨ k = -f ∨ k = f.mirror ∨ k = -f.mirror)
    (h3 : ∀ g, g ∣ f → g ∣ f.mirror → IsUnit g) : Irreducible f := by
  

Proof state:
R : Type u_1
inst✝¹ : CommRing R
inst✝ : NoZeroDivisors R
f : R[X]
h1 : ¬IsUnit f
h2 : ∀ (k : R[X]), f * mirror f = k * mirror k → k = f ∨ k = -f ∨ k = mirror f ∨ k = -mirror f
h3 : ∀ (g : R[X]), g ∣ f → g ∣ mirror f → IsUnit g
⊢ Irreducible f

Next tactic:
constructor
theorem irreducible_of_mirror (h1 : ¬IsUnit f)
    (h2 : ∀ k, f * f.mirror = k * k.mirror → k = f ∨ k = -f ∨ k = f.mirror ∨ k = -f.mirror)
    (h3 : ∀ g, g ∣ f → g ∣ f.mirror → IsUnit g) : Irreducible f := by
  constructor
  · 

Proof state:
case not_unit
R : Type u_1
inst✝¹ : CommRing R
inst✝ : NoZeroDivisors R
f : R[X]
h1 : ¬IsUnit f
h2 : ∀ (k : R[X]), f * mirror f = k * mirror k → k = f ∨ k = -f ∨ k = mirror f ∨ k = -mirror f
h3 : ∀ (g : R[X]), g ∣ f → g ∣ mirror f → IsUnit g
⊢ ¬IsUnit f

Next tactic:
exact h1
theorem irreducible_of_mirror (h1 : ¬IsUnit f)
    (h2 : ∀ k, f * f.mirror = k * k.mirror → k = f ∨ k = -f ∨ k = f.mirror ∨ k = -f.mirror)
    (h3 : ∀ g, g ∣ f → g ∣ f.mirror → IsUnit g) : Irreducible f := by
  constructor
  · exact h1
  · 

Proof state:
case isUnit_or_isUnit'
R : Type u_1
inst✝¹ : CommRing R
inst✝ : NoZeroDivisors R
f : R[X]
h1 : ¬IsUnit f
h2 : ∀ (k : R[X]), f * mirror f = k * mirror k → k = f ∨ k = -f ∨ k = mirror f ∨ k = -mirror f
h3 : ∀ (g : R[X]), g ∣ f → g ∣ mirror f → IsUnit g
⊢ ∀ (a b : R[X]), f = a * b → IsUnit a ∨ IsUnit b

Next tactic:
intro g h fgh
theorem irreducible_of_mirror (h1 : ¬IsUnit f)
    (h2 : ∀ k, f * f.mirror = k * k.mirror → k = f ∨ k = -f ∨ k = f.mirror ∨ k = -f.mirror)
    (h3 : ∀ g, g ∣ f → g ∣ f.mirror → IsUnit g) : Irreducible f := by
  constructor
  · exact h1
  · intro g h fgh
    

Proof state:
case isUnit_or_isUnit'
R : Type u_1
inst✝¹ : CommRing R
inst✝ : NoZeroDivisors R
f : R[X]
h1 : ¬IsUnit f
h2 : ∀ (k : R[X]), f * mirror f = k * mirror k → k = f ∨ k = -f ∨ k = mirror f ∨ k = -mirror f
h3 : ∀ (g : R[X]), g ∣ f → g ∣ mirror f → IsUnit g
g h : R[X]
fgh : f = g * h
⊢ IsUnit g ∨ IsUnit h

Next tactic:
let k := g * h.mirror
theorem irreducible_of_mirror (h1 : ¬IsUnit f)
    (h2 : ∀ k, f * f.mirror = k * k.mirror → k = f ∨ k = -f ∨ k = f.mirror ∨ k = -f.mirror)
    (h3 : ∀ g, g ∣ f → g ∣ f.mirror → IsUnit g) : Irreducible f := by
  constructor
  · exact h1
  · intro g h fgh
    let k := g * h.mirror
    

Proof state:
case isUnit_or_isUnit'
R : Type u_1
inst✝¹ : CommRing R
inst✝ : NoZeroDivisors R
f : R[X]
h1 : ¬IsUnit f
h2 : ∀ (k : R[X]), f * mirror f = k * mirror k → k = f ∨ k = -f ∨ k = mirror f ∨ k = -mirror f
h3 : ∀ (g : R[X]), g ∣ f → g ∣ mirror f → IsUnit g
g h : R[X]
fgh : f = g * h
k : R[X] := g * mirror h
⊢ IsUnit g ∨ IsUnit h

Next tactic:
have key : f * f.mirror = k * k.mirror := by
      rw [fgh, mirror_mul_of_domain, mirror_mul_of_domain, mirror_mirror, mul_assoc, mul_comm h,
        mul_comm g.mirror, mul_assoc, ← mul_assoc]
theorem irreducible_of_mirror (h1 : ¬IsUnit f)
    (h2 : ∀ k, f * f.mirror = k * k.mirror → k = f ∨ k = -f ∨ k = f.mirror ∨ k = -f.mirror)
    (h3 : ∀ g, g ∣ f → g ∣ f.mirror → IsUnit g) : Irreducible f := by
  constructor
  · exact h1
  · intro g h fgh
    let k := g * h.mirror
    have key : f * f.mirror = k * k.mirror := by
      

Proof state:
R : Type u_1
inst✝¹ : CommRing R
inst✝ : NoZeroDivisors R
f : R[X]
h1 : ¬IsUnit f
h2 : ∀ (k : R[X]), f * mirror f = k * mirror k → k = f ∨ k = -f ∨ k = mirror f ∨ k = -mirror f
h3 : ∀ (g : R[X]), g ∣ f → g ∣ mirror f → IsUnit g
g h : R[X]
fgh : f = g * h
k : R[X] := g * mirror h
⊢ f * mirror f = k * mirror k

Next tactic:
rw [fgh, mirror_mul_of_domain, mirror_mul_of_domain, mirror_mirror, mul_assoc, mul_comm h,
        mul_comm g.mirror, mul_assoc, ← mul_assoc]
theorem irreducible_of_mirror (h1 : ¬IsUnit f)
    (h2 : ∀ k, f * f.mirror = k * k.mirror → k = f ∨ k = -f ∨ k = f.mirror ∨ k = -f.mirror)
    (h3 : ∀ g, g ∣ f → g ∣ f.mirror → IsUnit g) : Irreducible f := by
  constructor
  · exact h1
  · intro g h fgh
    let k := g * h.mirror
    have key : f * f.mirror = k * k.mirror := by
      rw [fgh, mirror_mul_of_domain, mirror_mul_of_domain, mirror_mirror, mul_assoc, mul_comm h,
        mul_comm g.mirror, mul_assoc, ← mul_assoc]
    

Proof state:
case isUnit_or_isUnit'
R : Type u_1
inst✝¹ : CommRing R
inst✝ : NoZeroDivisors R
f : R[X]
h1 : ¬IsUnit f
h2 : ∀ (k : R[X]), f * mirror f = k * mirror k → k = f ∨ k = -f ∨ k = mirror f ∨ k = -mirror f
h3 : ∀ (g : R[X]), g ∣ f → g ∣ mirror f → IsUnit g
g h : R[X]
fgh : f = g * h
k : R[X] := g * mirror h
key : f * mirror f = k * mirror k
⊢ IsUnit g ∨ IsUnit h

Next tactic:
have g_dvd_f : g ∣ f := by
      rw [fgh]
      exact dvd_mul_right g h
theorem irreducible_of_mirror (h1 : ¬IsUnit f)
    (h2 : ∀ k, f * f.mirror = k * k.mirror → k = f ∨ k = -f ∨ k = f.mirror ∨ k = -f.mirror)
    (h3 : ∀ g, g ∣ f → g ∣ f.mirror → IsUnit g) : Irreducible f := by
  constructor
  · exact h1
  · intro g h fgh
    let k := g * h.mirror
    have key : f * f.mirror = k * k.mirror := by
      rw [fgh, mirror_mul_of_domain, mirror_mul_of_domain, mirror_mirror, mul_assoc, mul_comm h,
        mul_comm g.mirror, mul_assoc, ← mul_assoc]
    have g_dvd_f : g ∣ f := by
      

Proof state:
R : Type u_1
inst✝¹ : CommRing R
inst✝ : NoZeroDivisors R
f : R[X]
h1 : ¬IsUnit f
h2 : ∀ (k : R[X]), f * mirror f = k * mirror k → k = f ∨ k = -f ∨ k = mirror f ∨ k = -mirror f
h3 : ∀ (g : R[X]), g ∣ f → g ∣ mirror f → IsUnit g
g h : R[X]
fgh : f = g * h
k : R[X] := g * mirror h
key : f * mirror f = k * mirror k
⊢ g ∣ f

Next tactic:
rw [fgh]
theorem irreducible_of_mirror (h1 : ¬IsUnit f)
    (h2 : ∀ k, f * f.mirror = k * k.mirror → k = f ∨ k = -f ∨ k = f.mirror ∨ k = -f.mirror)
    (h3 : ∀ g, g ∣ f → g ∣ f.mirror → IsUnit g) : Irreducible f := by
  constructor
  · exact h1
  · intro g h fgh
    let k := g * h.mirror
    have key : f * f.mirror = k * k.mirror := by
      rw [fgh, mirror_mul_of_domain, mirror_mul_of_domain, mirror_mirror, mul_assoc, mul_comm h,
        mul_comm g.mirror, mul_assoc, ← mul_assoc]
    have g_dvd_f : g ∣ f := by
      rw [fgh]
      

Proof state:
R : Type u_1
inst✝¹ : CommRing R
inst✝ : NoZeroDivisors R
f : R[X]
h1 : ¬IsUnit f
h2 : ∀ (k : R[X]), f * mirror f = k * mirror k → k = f ∨ k = -f ∨ k = mirror f ∨ k = -mirror f
h3 : ∀ (g : R[X]), g ∣ f → g ∣ mirror f → IsUnit g
g h : R[X]
fgh : f = g * h
k : R[X] := g * mirror h
key : f * mirror f = k * mirror k
⊢ g ∣ g * h

Next tactic:
exact dvd_mul_right g h
theorem irreducible_of_mirror (h1 : ¬IsUnit f)
    (h2 : ∀ k, f * f.mirror = k * k.mirror → k = f ∨ k = -f ∨ k = f.mirror ∨ k = -f.mirror)
    (h3 : ∀ g, g ∣ f → g ∣ f.mirror → IsUnit g) : Irreducible f := by
  constructor
  · exact h1
  · intro g h fgh
    let k := g * h.mirror
    have key : f * f.mirror = k * k.mirror := by
      rw [fgh, mirror_mul_of_domain, mirror_mul_of_domain, mirror_mirror, mul_assoc, mul_comm h,
        mul_comm g.mirror, mul_assoc, ← mul_assoc]
    have g_dvd_f : g ∣ f := by
      rw [fgh]
      exact dvd_mul_right g h
    

Proof state:
case isUnit_or_isUnit'
R : Type u_1
inst✝¹ : CommRing R
inst✝ : NoZeroDivisors R
f : R[X]
h1 : ¬IsUnit f
h2 : ∀ (k : R[X]), f * mirror f = k * mirror k → k = f ∨ k = -f ∨ k = mirror f ∨ k = -mirror f
h3 : ∀ (g : R[X]), g ∣ f → g ∣ mirror f → IsUnit g
g h : R[X]
fgh : f = g * h
k : R[X] := g * mirror h
key : f * mirror f = k * mirror k
g_dvd_f : g ∣ f
⊢ IsUnit g ∨ IsUnit h

Next tactic:
have h_dvd_f : h ∣ f := by
      rw [fgh]
      exact dvd_mul_left h g
theorem irreducible_of_mirror (h1 : ¬IsUnit f)
    (h2 : ∀ k, f * f.mirror = k * k.mirror → k = f ∨ k = -f ∨ k = f.mirror ∨ k = -f.mirror)
    (h3 : ∀ g, g ∣ f → g ∣ f.mirror → IsUnit g) : Irreducible f := by
  constructor
  · exact h1
  · intro g h fgh
    let k := g * h.mirror
    have key : f * f.mirror = k * k.mirror := by
      rw [fgh, mirror_mul_of_domain, mirror_mul_of_domain, mirror_mirror, mul_assoc, mul_comm h,
        mul_comm g.mirror, mul_assoc, ← mul_assoc]
    have g_dvd_f : g ∣ f := by
      rw [fgh]
      exact dvd_mul_right g h
    have h_dvd_f : h ∣ f := by
      

Proof state:
R : Type u_1
inst✝¹ : CommRing R
inst✝ : NoZeroDivisors R
f : R[X]
h1 : ¬IsUnit f
h2 : ∀ (k : R[X]), f * mirror f = k * mirror k → k = f ∨ k = -f ∨ k = mirror f ∨ k = -mirror f
h3 : ∀ (g : R[X]), g ∣ f → g ∣ mirror f → IsUnit g
g h : R[X]
fgh : f = g * h
k : R[X] := g * mirror h
key : f * mirror f = k * mirror k
g_dvd_f : g ∣ f
⊢ h ∣ f

Next tactic:
rw [fgh]
theorem irreducible_of_mirror (h1 : ¬IsUnit f)
    (h2 : ∀ k, f * f.mirror = k * k.mirror → k = f ∨ k = -f ∨ k = f.mirror ∨ k = -f.mirror)
    (h3 : ∀ g, g ∣ f → g ∣ f.mirror → IsUnit g) : Irreducible f := by
  constructor
  · exact h1
  · intro g h fgh
    let k := g * h.mirror
    have key : f * f.mirror = k * k.mirror := by
      rw [fgh, mirror_mul_of_domain, mirror_mul_of_domain, mirror_mirror, mul_assoc, mul_comm h,
        mul_comm g.mirror, mul_assoc, ← mul_assoc]
    have g_dvd_f : g ∣ f := by
      rw [fgh]
      exact dvd_mul_right g h
    have h_dvd_f : h ∣ f := by
      rw [fgh]
      

Proof state:
R : Type u_1
inst✝¹ : CommRing R
inst✝ : NoZeroDivisors R
f : R[X]
h1 : ¬IsUnit f
h2 : ∀ (k : R[X]), f * mirror f = k * mirror k → k = f ∨ k = -f ∨ k = mirror f ∨ k = -mirror f
h3 : ∀ (g : R[X]), g ∣ f → g ∣ mirror f → IsUnit g
g h : R[X]
fgh : f = g * h
k : R[X] := g * mirror h
key : f * mirror f = k * mirror k
g_dvd_f : g ∣ f
⊢ h ∣ g * h

Next tactic:
exact dvd_mul_left h g
theorem irreducible_of_mirror (h1 : ¬IsUnit f)
    (h2 : ∀ k, f * f.mirror = k * k.mirror → k = f ∨ k = -f ∨ k = f.mirror ∨ k = -f.mirror)
    (h3 : ∀ g, g ∣ f → g ∣ f.mirror → IsUnit g) : Irreducible f := by
  constructor
  · exact h1
  · intro g h fgh
    let k := g * h.mirror
    have key : f * f.mirror = k * k.mirror := by
      rw [fgh, mirror_mul_of_domain, mirror_mul_of_domain, mirror_mirror, mul_assoc, mul_comm h,
        mul_comm g.mirror, mul_assoc, ← mul_assoc]
    have g_dvd_f : g ∣ f := by
      rw [fgh]
      exact dvd_mul_right g h
    have h_dvd_f : h ∣ f := by
      rw [fgh]
      exact dvd_mul_left h g
    

Proof state:
case isUnit_or_isUnit'
R : Type u_1
inst✝¹ : CommRing R
inst✝ : NoZeroDivisors R
f : R[X]
h1 : ¬IsUnit f
h2 : ∀ (k : R[X]), f * mirror f = k * mirror k → k = f ∨ k = -f ∨ k = mirror f ∨ k = -mirror f
h3 : ∀ (g : R[X]), g ∣ f → g ∣ mirror f → IsUnit g
g h : R[X]
fgh : f = g * h
k : R[X] := g * mirror h
key : f * mirror f = k * mirror k
g_dvd_f : g ∣ f
h_dvd_f : h ∣ f
⊢ IsUnit g ∨ IsUnit h

Next tactic:
have g_dvd_k : g ∣ k := dvd_mul_right g h.mirror