Skip to content

Commit 6e96221

Browse files
committed
feat: port Data.Polynomial.Mirror (#3130)
1 parent 87a0508 commit 6e96221

File tree

2 files changed

+256
-0
lines changed

2 files changed

+256
-0
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,7 @@ import Mathlib.Data.Polynomial.Induction
895895
import Mathlib.Data.Polynomial.Inductions
896896
import Mathlib.Data.Polynomial.IntegralNormalization
897897
import Mathlib.Data.Polynomial.Lifts
898+
import Mathlib.Data.Polynomial.Mirror
898899
import Mathlib.Data.Polynomial.Monic
899900
import Mathlib.Data.Polynomial.Monomial
900901
import Mathlib.Data.Polynomial.Reverse

Mathlib/Data/Polynomial/Mirror.lean

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
/-
2+
Copyright (c) 2020 Thomas Browning. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Thomas Browning
5+
6+
! This file was ported from Lean 3 source module data.polynomial.mirror
7+
! leanprover-community/mathlib commit 2196ab363eb097c008d4497125e0dde23fb36db2
8+
! Please do not edit these lines, except to modify the commit id
9+
! if you have ported upstream changes.
10+
-/
11+
import Mathlib.Algebra.BigOperators.NatAntidiagonal
12+
import Mathlib.Data.Polynomial.RingDivision
13+
14+
/-!
15+
# "Mirror" of a univariate polynomial
16+
17+
In this file we define `Polynomial.mirror`, a variant of `Polynomial.reverse`. The difference
18+
between `reverse` and `mirror` is that `reverse` will decrease the degree if the polynomial is
19+
divisible by `X`.
20+
21+
## Main definitions
22+
23+
- `Polynomial.mirror`
24+
25+
## Main results
26+
27+
- `Polynomial.mirror_mul_of_domain`: `mirror` preserves multiplication.
28+
- `Polynomial.irreducible_of_mirror`: an irreducibility criterion involving `mirror`
29+
30+
-/
31+
32+
33+
namespace Polynomial
34+
35+
open Polynomial
36+
37+
section Semiring
38+
39+
variable {R : Type _} [Semiring R] (p q : R[X])
40+
41+
/-- mirror of a polynomial: reverses the coefficients while preserving `Polynomial.natDegree` -/
42+
noncomputable def mirror :=
43+
p.reverse * X ^ p.natTrailingDegree
44+
#align polynomial.mirror Polynomial.mirror
45+
46+
@[simp]
47+
theorem mirror_zero : (0 : R[X]).mirror = 0 := by simp [mirror]
48+
#align polynomial.mirror_zero Polynomial.mirror_zero
49+
50+
theorem mirror_monomial (n : ℕ) (a : R) : (monomial n a).mirror = monomial n a := by
51+
classical
52+
by_cases ha : a = 0
53+
· rw [ha, monomial_zero_right, mirror_zero]
54+
· rw [mirror, reverse, natDegree_monomial n a, if_neg ha, natTrailingDegree_monomial ha, ←
55+
C_mul_X_pow_eq_monomial, reflect_C_mul_X_pow, revAt_le (le_refl n), tsub_self, pow_zero,
56+
mul_one]
57+
#align polynomial.mirror_monomial Polynomial.mirror_monomial
58+
59+
theorem mirror_C (a : R) : (C a).mirror = C a :=
60+
mirror_monomial 0 a
61+
set_option linter.uppercaseLean3 false in
62+
#align polynomial.mirror_C Polynomial.mirror_C
63+
64+
theorem mirror_X : X.mirror = (X : R[X]) :=
65+
mirror_monomial 1 (1 : R)
66+
set_option linter.uppercaseLean3 false in
67+
#align polynomial.mirror_X Polynomial.mirror_X
68+
69+
theorem mirror_natDegree : p.mirror.natDegree = p.natDegree := by
70+
by_cases hp : p = 0
71+
· rw [hp, mirror_zero]
72+
--Porting note: below two lines were `nontriviality R` in Lean3
73+
have : p.leadingCoeff ≠ 0 := by simpa
74+
let _ : Nontrivial R := nontrivial_of_ne _ _ this
75+
rw [mirror, natDegree_mul', reverse_natDegree, natDegree_X_pow,
76+
tsub_add_cancel_of_le p.natTrailingDegree_le_natDegree]
77+
rwa [leadingCoeff_X_pow, mul_one, reverse_leadingCoeff, Ne, trailingCoeff_eq_zero]
78+
#align polynomial.mirror_nat_degree Polynomial.mirror_natDegree
79+
80+
theorem mirror_natTrailingDegree : p.mirror.natTrailingDegree = p.natTrailingDegree := by
81+
by_cases hp : p = 0
82+
· rw [hp, mirror_zero]
83+
·
84+
rw [mirror, natTrailingDegree_mul_X_pow ((mt reverse_eq_zero.mp) hp),
85+
reverse_natTrailingDegree, zero_add]
86+
#align polynomial.mirror_nat_trailing_degree Polynomial.mirror_natTrailingDegree
87+
88+
theorem coeff_mirror (n : ℕ) :
89+
p.mirror.coeff n = p.coeff (revAt (p.natDegree + p.natTrailingDegree) n) := by
90+
by_cases h2 : p.natDegree < n
91+
· rw [coeff_eq_zero_of_natDegree_lt (by rwa [mirror_natDegree])]
92+
by_cases h1 : n ≤ p.natDegree + p.natTrailingDegree
93+
· rw [revAt_le h1, coeff_eq_zero_of_lt_natTrailingDegree]
94+
exact (tsub_lt_iff_left h1).mpr (Nat.add_lt_add_right h2 _)
95+
· rw [← revAtFun_eq, revAtFun, if_neg h1, coeff_eq_zero_of_natDegree_lt h2]
96+
rw [not_lt] at h2
97+
rw [revAt_le (h2.trans (Nat.le_add_right _ _))]
98+
by_cases h3 : p.natTrailingDegree ≤ n
99+
· rw [← tsub_add_eq_add_tsub h2, ← tsub_tsub_assoc h2 h3, mirror, coeff_mul_X_pow', if_pos h3,
100+
coeff_reverse, revAt_le (tsub_le_self.trans h2)]
101+
rw [not_le] at h3
102+
rw [coeff_eq_zero_of_natDegree_lt (lt_tsub_iff_right.mpr (Nat.add_lt_add_left h3 _))]
103+
exact coeff_eq_zero_of_lt_natTrailingDegree (by rwa [mirror_natTrailingDegree])
104+
#align polynomial.coeff_mirror Polynomial.coeff_mirror
105+
106+
--TODO: Extract `finset.sum_range_rev_at` lemma.
107+
theorem mirror_eval_one : p.mirror.eval 1 = p.eval 1 := by
108+
simp_rw [eval_eq_sum_range, one_pow, mul_one, mirror_natDegree]
109+
refine' Finset.sum_bij_ne_zero _ _ _ _ _
110+
· exact fun n _ _ => revAt (p.natDegree + p.natTrailingDegree) n
111+
· intro n hn hp
112+
rw [Finset.mem_range_succ_iff] at *
113+
rw [revAt_le (hn.trans (Nat.le_add_right _ _))]
114+
rw [tsub_le_iff_tsub_le, add_comm, add_tsub_cancel_right, ← mirror_natTrailingDegree]
115+
exact natTrailingDegree_le_of_ne_zero hp
116+
· exact fun n₁ n₂ _ _ _ _ h => by rw [← @revAt_invol _ n₁, h, revAt_invol]
117+
· intro n hn hp
118+
use revAt (p.natDegree + p.natTrailingDegree) n
119+
refine' ⟨_, _, revAt_invol.symm⟩
120+
· rw [Finset.mem_range_succ_iff] at *
121+
rw [revAt_le (hn.trans (Nat.le_add_right _ _))]
122+
rw [tsub_le_iff_tsub_le, add_comm, add_tsub_cancel_right]
123+
exact natTrailingDegree_le_of_ne_zero hp
124+
· change p.mirror.coeff _ ≠ 0
125+
rwa [coeff_mirror, revAt_invol]
126+
· exact fun n _ _ => p.coeff_mirror n
127+
#align polynomial.mirror_eval_one Polynomial.mirror_eval_one
128+
129+
theorem mirror_mirror : p.mirror.mirror = p :=
130+
Polynomial.ext fun n => by
131+
rw [coeff_mirror, coeff_mirror, mirror_natDegree, mirror_natTrailingDegree, revAt_invol]
132+
#align polynomial.mirror_mirror Polynomial.mirror_mirror
133+
134+
variable {p q}
135+
136+
theorem mirror_involutive : Function.Involutive (mirror : R[X] → R[X]) :=
137+
mirror_mirror
138+
#align polynomial.mirror_involutive Polynomial.mirror_involutive
139+
140+
theorem mirror_eq_iff : p.mirror = q ↔ p = q.mirror :=
141+
mirror_involutive.eq_iff
142+
#align polynomial.mirror_eq_iff Polynomial.mirror_eq_iff
143+
144+
@[simp]
145+
theorem mirror_inj : p.mirror = q.mirror ↔ p = q :=
146+
mirror_involutive.injective.eq_iff
147+
#align polynomial.mirror_inj Polynomial.mirror_inj
148+
149+
@[simp]
150+
theorem mirror_eq_zero : p.mirror = 0 ↔ p = 0 :=
151+
fun h => by rw [← p.mirror_mirror, h, mirror_zero], fun h => by rw [h, mirror_zero]⟩
152+
#align polynomial.mirror_eq_zero Polynomial.mirror_eq_zero
153+
154+
variable (p q)
155+
156+
@[simp]
157+
theorem mirror_trailingCoeff : p.mirror.trailingCoeff = p.leadingCoeff := by
158+
rw [leadingCoeff, trailingCoeff, mirror_natTrailingDegree, coeff_mirror,
159+
revAt_le (Nat.le_add_left _ _), add_tsub_cancel_right]
160+
#align polynomial.mirror_trailing_coeff Polynomial.mirror_trailingCoeff
161+
162+
@[simp]
163+
theorem mirror_leadingCoeff : p.mirror.leadingCoeff = p.trailingCoeff := by
164+
rw [← p.mirror_mirror, mirror_trailingCoeff, p.mirror_mirror]
165+
#align polynomial.mirror_leading_coeff Polynomial.mirror_leadingCoeff
166+
167+
theorem coeff_mul_mirror :
168+
(p * p.mirror).coeff (p.natDegree + p.natTrailingDegree) = p.sum fun n => (· ^ 2) := by
169+
rw [coeff_mul, Finset.Nat.sum_antidiagonal_eq_sum_range_succ_mk]
170+
refine'
171+
(Finset.sum_congr rfl fun n hn => _).trans
172+
(p.sum_eq_of_subset (fun _ => (· ^ 2)) (fun _ => zero_pow zero_lt_two) _ fun n hn =>
173+
Finset.mem_range_succ_iff.mpr
174+
((le_natDegree_of_mem_supp n hn).trans (Nat.le_add_right _ _))).symm
175+
rw [coeff_mirror, ← revAt_le (Finset.mem_range_succ_iff.mp hn), revAt_invol, ← sq]
176+
#align polynomial.coeff_mul_mirror Polynomial.coeff_mul_mirror
177+
178+
variable [NoZeroDivisors R]
179+
180+
theorem natDegree_mul_mirror : (p * p.mirror).natDegree = 2 * p.natDegree := by
181+
by_cases hp : p = 0
182+
· rw [hp, MulZeroClass.zero_mul, natDegree_zero, MulZeroClass.mul_zero]
183+
rw [natDegree_mul hp (mt mirror_eq_zero.mp hp), mirror_natDegree, two_mul]
184+
#align polynomial.nat_degree_mul_mirror Polynomial.natDegree_mul_mirror
185+
186+
theorem natTrailingDegree_mul_mirror : (p * p.mirror).natTrailingDegree = 2 * p.natTrailingDegree :=
187+
by
188+
by_cases hp : p = 0
189+
· rw [hp, MulZeroClass.zero_mul, natTrailingDegree_zero, MulZeroClass.mul_zero]
190+
rw [natTrailingDegree_mul hp (mt mirror_eq_zero.mp hp), mirror_natTrailingDegree, two_mul]
191+
#align polynomial.nat_trailing_degree_mul_mirror Polynomial.natTrailingDegree_mul_mirror
192+
193+
end Semiring
194+
195+
section Ring
196+
197+
variable {R : Type _} [Ring R] (p q : R[X])
198+
199+
theorem mirror_neg : (-p).mirror = -p.mirror := by
200+
rw [mirror, mirror, reverse_neg, natTrailingDegree_neg, neg_mul_eq_neg_mul]
201+
#align polynomial.mirror_neg Polynomial.mirror_neg
202+
203+
variable [NoZeroDivisors R]
204+
205+
theorem mirror_mul_of_domain : (p * q).mirror = p.mirror * q.mirror := by
206+
by_cases hp : p = 0
207+
· rw [hp, MulZeroClass.zero_mul, mirror_zero, MulZeroClass.zero_mul]
208+
by_cases hq : q = 0
209+
· rw [hq, MulZeroClass.mul_zero, mirror_zero, MulZeroClass.mul_zero]
210+
rw [mirror, mirror, mirror, reverse_mul_of_domain, natTrailingDegree_mul hp hq, pow_add]
211+
rw [mul_assoc, ← mul_assoc q.reverse, ← X_pow_mul (p := reverse q)]
212+
repeat' rw [mul_assoc]
213+
#align polynomial.mirror_mul_of_domain Polynomial.mirror_mul_of_domain
214+
215+
theorem mirror_smul (a : R) : (a • p).mirror = a • p.mirror := by
216+
rw [← C_mul', ← C_mul', mirror_mul_of_domain, mirror_C]
217+
#align polynomial.mirror_smul Polynomial.mirror_smul
218+
219+
end Ring
220+
221+
section CommRing
222+
223+
variable {R : Type _} [CommRing R] [NoZeroDivisors R] {f : R[X]}
224+
225+
theorem irreducible_of_mirror (h1 : ¬IsUnit f)
226+
(h2 : ∀ k, f * f.mirror = k * k.mirror → k = f ∨ k = -f ∨ k = f.mirror ∨ k = -f.mirror)
227+
(h3 : ∀ g, g ∣ f → g ∣ f.mirror → IsUnit g) : Irreducible f := by
228+
constructor
229+
· exact h1
230+
· intro g h fgh
231+
let k := g * h.mirror
232+
have key : f * f.mirror = k * k.mirror := by
233+
rw [fgh, mirror_mul_of_domain, mirror_mul_of_domain, mirror_mirror, mul_assoc, mul_comm h,
234+
mul_comm g.mirror, mul_assoc, ← mul_assoc]
235+
have g_dvd_f : g ∣ f := by
236+
rw [fgh]
237+
exact dvd_mul_right g h
238+
have h_dvd_f : h ∣ f := by
239+
rw [fgh]
240+
exact dvd_mul_left h g
241+
have g_dvd_k : g ∣ k := dvd_mul_right g h.mirror
242+
have h_dvd_k_rev : h ∣ k.mirror := by
243+
rw [mirror_mul_of_domain, mirror_mirror]
244+
exact dvd_mul_left h g.mirror
245+
have hk := h2 k key
246+
rcases hk with (hk | hk | hk | hk)
247+
· exact Or.inr (h3 h h_dvd_f (by rwa [← hk]))
248+
· exact Or.inr (h3 h h_dvd_f (by rwa [← neg_eq_iff_eq_neg.mpr hk, mirror_neg, dvd_neg]))
249+
· exact Or.inl (h3 g g_dvd_f (by rwa [← hk]))
250+
· exact Or.inl (h3 g g_dvd_f (by rwa [← neg_eq_iff_eq_neg.mpr hk, dvd_neg]))
251+
#align polynomial.irreducible_of_mirror Polynomial.irreducible_of_mirror
252+
253+
end CommRing
254+
255+
end Polynomial

0 commit comments

Comments
 (0)