Skip to content

Commit ee6a3f9

Browse files
feat: port Data.MvPolynomial.Rename (#2886)
- [x] depends on: #2861 Co-authored-by: ChrisHughes24 <chrishughes24@gmail.com>
1 parent 4661306 commit ee6a3f9

File tree

2 files changed

+350
-0
lines changed

2 files changed

+350
-0
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,7 @@ import Mathlib.Data.Multiset.Sections
716716
import Mathlib.Data.Multiset.Sort
717717
import Mathlib.Data.Multiset.Sum
718718
import Mathlib.Data.MvPolynomial.Basic
719+
import Mathlib.Data.MvPolynomial.Rename
719720
import Mathlib.Data.Nat.Basic
720721
import Mathlib.Data.Nat.Bits
721722
import Mathlib.Data.Nat.Bitwise
Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
/-
2+
Copyright (c) 2017 Johannes Hölzl. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Johannes Hölzl, Johan Commelin, Mario Carneiro
5+
6+
! This file was ported from Lean 3 source module data.mv_polynomial.rename
7+
! leanprover-community/mathlib commit eabc6192c84ccce3936a8577a987b80b95ba75f6
8+
! Please do not edit these lines, except to modify the commit id
9+
! if you have ported upstream changes.
10+
-/
11+
import Mathlib.Data.MvPolynomial.Basic
12+
13+
/-!
14+
# Renaming variables of polynomials
15+
16+
This file establishes the `rename` operation on multivariate polynomials,
17+
which modifies the set of variables.
18+
19+
## Main declarations
20+
21+
* `MvPolynomial.rename`
22+
* `MvPolynomial.renameEquiv`
23+
24+
## Notation
25+
26+
As in other polynomial files, we typically use the notation:
27+
28+
+ `σ τ α : Type*` (indexing the variables)
29+
30+
+ `R S : Type*` `[CommSemiring R]` `[CommSemiring S]` (the coefficients)
31+
32+
+ `s : σ →₀ ℕ`, a function from `σ` to `ℕ` which is zero away from a finite set.
33+
This will give rise to a monomial in `MvPolynomial σ R` which mathematicians might call `X^s`
34+
35+
+ `r : R` elements of the coefficient ring
36+
37+
+ `i : σ`, with corresponding monomial `X i`, often denoted `X_i` by mathematicians
38+
39+
+ `p : MvPolynomial σ α`
40+
41+
-/
42+
43+
44+
noncomputable section
45+
46+
open Classical BigOperators
47+
48+
open Set Function Finsupp AddMonoidAlgebra
49+
50+
open BigOperators
51+
52+
variable {σ τ α R S : Type _} [CommSemiring R] [CommSemiring S]
53+
54+
namespace MvPolynomial
55+
56+
section Rename
57+
58+
/-- Rename all the variables in a multivariable polynomial. -/
59+
def rename (f : σ → τ) : MvPolynomial σ R →ₐ[R] MvPolynomial τ R :=
60+
aeval (X ∘ f)
61+
#align mv_polynomial.rename MvPolynomial.rename
62+
63+
@[simp]
64+
theorem rename_C (f : σ → τ) (r : R) : rename f (C r) = C r :=
65+
eval₂_C _ _ _
66+
set_option linter.uppercaseLean3 false in
67+
#align mv_polynomial.rename_C MvPolynomial.rename_C
68+
69+
@[simp]
70+
theorem rename_X (f : σ → τ) (i : σ) : rename f (X i : MvPolynomial σ R) = X (f i) :=
71+
eval₂_X _ _ _
72+
set_option linter.uppercaseLean3 false in
73+
#align mv_polynomial.rename_X MvPolynomial.rename_X
74+
75+
theorem map_rename (f : R →+* S) (g : σ → τ) (p : MvPolynomial σ R) :
76+
map f (rename g p) = rename g (map f p) := by
77+
apply MvPolynomial.induction_on p
78+
(fun a => by simp only [map_C, rename_C])
79+
(fun p q hp hq => by simp only [hp, hq, AlgHom.map_add, RingHom.map_add]) fun p n hp => by
80+
simp only [hp, rename_X, map_X, RingHom.map_mul, AlgHom.map_mul]
81+
#align mv_polynomial.map_rename MvPolynomial.map_rename
82+
83+
@[simp]
84+
theorem rename_rename (f : σ → τ) (g : τ → α) (p : MvPolynomial σ R) :
85+
rename g (rename f p) = rename (g ∘ f) p :=
86+
show rename g (eval₂ C (X ∘ f) p) = _
87+
by
88+
simp only [rename, aeval_eq_eval₂Hom]
89+
-- porting note: the Lean 3 proof of this was very fragile and included a nonterminal `simp`.
90+
-- Hopefully this is less prone to breaking
91+
rw [eval₂_comp_left (eval₂Hom (algebraMap R (MvPolynomial α R)) (X ∘ g)) C (X ∘ f) p]
92+
simp only [(· ∘ ·), eval₂Hom_X', coe_eval₂Hom]
93+
refine' eval₂Hom_congr _ rfl rfl
94+
ext1; simp only [comp_apply, RingHom.coe_comp, eval₂Hom_C]
95+
#align mv_polynomial.rename_rename MvPolynomial.rename_rename
96+
97+
@[simp]
98+
theorem rename_id (p : MvPolynomial σ R) : rename id p = p :=
99+
eval₂_eta p
100+
#align mv_polynomial.rename_id MvPolynomial.rename_id
101+
102+
theorem rename_monomial (f : σ → τ) (d : σ →₀ ℕ) (r : R) :
103+
rename f (monomial d r) = monomial (d.mapDomain f) r := by
104+
rw [rename, aeval_monomial, monomial_eq (s := Finsupp.mapDomain f d),
105+
Finsupp.prod_mapDomain_index]
106+
· rfl
107+
· exact fun n => pow_zero _
108+
· exact fun n i₁ i₂ => pow_add _ _ _
109+
#align mv_polynomial.rename_monomial MvPolynomial.rename_monomial
110+
111+
theorem rename_eq (f : σ → τ) (p : MvPolynomial σ R) :
112+
rename f p = Finsupp.mapDomain (Finsupp.mapDomain f) p := by
113+
simp only [rename, aeval_def, eval₂, Finsupp.mapDomain, algebraMap_eq, comp_apply,
114+
X_pow_eq_monomial, ← monomial_finsupp_sum_index]
115+
rfl
116+
#align mv_polynomial.rename_eq MvPolynomial.rename_eq
117+
118+
theorem rename_injective (f : σ → τ) (hf : Function.Injective f) :
119+
Function.Injective (rename f : MvPolynomial σ R → MvPolynomial τ R) := by
120+
have :
121+
(rename f : MvPolynomial σ R → MvPolynomial τ R) = Finsupp.mapDomain (Finsupp.mapDomain f) :=
122+
funext (rename_eq f)
123+
rw [this]
124+
exact Finsupp.mapDomain_injective (Finsupp.mapDomain_injective hf)
125+
#align mv_polynomial.rename_injective MvPolynomial.rename_injective
126+
127+
section
128+
129+
variable {f : σ → τ} (hf : Function.Injective f)
130+
131+
open Classical
132+
133+
/-- Given a function between sets of variables `f : σ → τ` that is injective with proof `hf`,
134+
`MvPolynomial.killCompl hf` is the `AlgHom` from `R[τ]` to `R[σ]` that is left inverse to
135+
`rename f : R[σ] → R[τ]` and sends the variables in the complement of the range of `f` to `0`. -/
136+
def killCompl : MvPolynomial τ R →ₐ[R] MvPolynomial σ R :=
137+
aeval fun i => if h : i ∈ Set.range f then X <| (Equiv.ofInjective f hf).symm ⟨i, h⟩ else 0
138+
#align mv_polynomial.kill_compl MvPolynomial.killCompl
139+
140+
theorem killCompl_comp_rename : (killCompl hf).comp (rename f) = AlgHom.id R _ :=
141+
algHom_ext fun i => by
142+
dsimp
143+
rw [rename, killCompl, aeval_X, comp_apply, aeval_X, dif_pos, Equiv.ofInjective_symm_apply]
144+
#align mv_polynomial.kill_compl_comp_rename MvPolynomial.killCompl_comp_rename
145+
146+
@[simp]
147+
theorem killCompl_rename_app (p : MvPolynomial σ R) : killCompl hf (rename f p) = p :=
148+
AlgHom.congr_fun (killCompl_comp_rename hf) p
149+
#align mv_polynomial.kill_compl_rename_app MvPolynomial.killCompl_rename_app
150+
151+
end
152+
153+
section
154+
155+
variable (R)
156+
157+
/-- `MvPolynomial.rename e` is an equivalence when `e` is. -/
158+
@[simps apply]
159+
def renameEquiv (f : σ ≃ τ) : MvPolynomial σ R ≃ₐ[R] MvPolynomial τ R :=
160+
{ rename f with
161+
toFun := rename f
162+
invFun := rename f.symm
163+
left_inv := fun p => by rw [rename_rename, f.symm_comp_self, rename_id]
164+
right_inv := fun p => by rw [rename_rename, f.self_comp_symm, rename_id] }
165+
#align mv_polynomial.rename_equiv MvPolynomial.renameEquiv
166+
167+
@[simp]
168+
theorem renameEquiv_refl : renameEquiv R (Equiv.refl σ) = AlgEquiv.refl :=
169+
AlgEquiv.ext rename_id
170+
#align mv_polynomial.rename_equiv_refl MvPolynomial.renameEquiv_refl
171+
172+
@[simp]
173+
theorem renameEquiv_symm (f : σ ≃ τ) : (renameEquiv R f).symm = renameEquiv R f.symm :=
174+
rfl
175+
#align mv_polynomial.rename_equiv_symm MvPolynomial.renameEquiv_symm
176+
177+
@[simp]
178+
theorem renameEquiv_trans (e : σ ≃ τ) (f : τ ≃ α) :
179+
(renameEquiv R e).trans (renameEquiv R f) = renameEquiv R (e.trans f) :=
180+
AlgEquiv.ext (rename_rename e f)
181+
#align mv_polynomial.rename_equiv_trans MvPolynomial.renameEquiv_trans
182+
183+
end
184+
185+
section
186+
187+
variable (f : R →+* S) (k : σ → τ) (g : τ → S) (p : MvPolynomial σ R)
188+
189+
theorem eval₂_rename : (rename k p).eval₂ f g = p.eval₂ f (g ∘ k) := by
190+
apply MvPolynomial.induction_on p <;>
191+
· intros
192+
simp [*]
193+
#align mv_polynomial.eval₂_rename MvPolynomial.eval₂_rename
194+
195+
theorem eval₂Hom_rename : eval₂Hom f g (rename k p) = eval₂Hom f (g ∘ k) p :=
196+
eval₂_rename _ _ _ _
197+
#align mv_polynomial.eval₂_hom_rename MvPolynomial.eval₂Hom_rename
198+
199+
theorem aeval_rename [Algebra R S] : aeval g (rename k p) = aeval (g ∘ k) p :=
200+
eval₂Hom_rename _ _ _ _
201+
#align mv_polynomial.aeval_rename MvPolynomial.aeval_rename
202+
203+
theorem rename_eval₂ (g : τ → MvPolynomial σ R) :
204+
rename k (p.eval₂ C (g ∘ k)) = (rename k p).eval₂ C (rename k ∘ g) := by
205+
apply MvPolynomial.induction_on p <;>
206+
· intros
207+
simp [*]
208+
#align mv_polynomial.rename_eval₂ MvPolynomial.rename_eval₂
209+
210+
theorem rename_prodmk_eval₂ (j : τ) (g : σ → MvPolynomial σ R) :
211+
rename (Prod.mk j) (p.eval₂ C g) = p.eval₂ C fun x => rename (Prod.mk j) (g x) := by
212+
apply MvPolynomial.induction_on p <;>
213+
· intros
214+
simp [*]
215+
#align mv_polynomial.rename_prodmk_eval₂ MvPolynomial.rename_prodmk_eval₂
216+
217+
theorem eval₂_rename_prod_mk (g : σ × τ → S) (i : σ) (p : MvPolynomial τ R) :
218+
(rename (Prod.mk i) p).eval₂ f g = eval₂ f (fun j => g (i, j)) p := by
219+
apply MvPolynomial.induction_on p <;>
220+
· intros
221+
simp [*]
222+
#align mv_polynomial.eval₂_rename_prodmk MvPolynomial.eval₂_rename_prod_mk
223+
224+
theorem eval_rename_prod_mk (g : σ × τ → R) (i : σ) (p : MvPolynomial τ R) :
225+
eval g (rename (Prod.mk i) p) = eval (fun j => g (i, j)) p :=
226+
eval₂_rename_prod_mk (RingHom.id _) _ _ _
227+
#align mv_polynomial.eval_rename_prodmk MvPolynomial.eval_rename_prod_mk
228+
229+
end
230+
231+
/-- Every polynomial is a polynomial in finitely many variables. -/
232+
theorem exists_finset_rename (p : MvPolynomial σ R) :
233+
∃ (s : Finset σ)(q : MvPolynomial { x // x ∈ s } R), p = rename (↑) q := by
234+
apply induction_on p
235+
· intro r
236+
exact ⟨∅, C r, by rw [rename_C]⟩
237+
· rintro p q ⟨s, p, rfl⟩ ⟨t, q, rfl⟩
238+
refine' ⟨s ∪ t, ⟨_, _⟩⟩
239+
·
240+
refine' rename (Subtype.map id _) p + rename (Subtype.map id _) q <;>
241+
simp (config := { contextual := true }) only [id.def, true_or_iff, or_true_iff,
242+
Finset.mem_union, forall_true_iff]
243+
· simp only [rename_rename, AlgHom.map_add]
244+
rfl
245+
· rintro p n ⟨s, p, rfl⟩
246+
refine' ⟨insert n s, ⟨_, _⟩⟩
247+
· refine' rename (Subtype.map id _) p * X ⟨n, s.mem_insert_self n⟩
248+
simp (config := { contextual := true }) only [id.def, or_true_iff, Finset.mem_insert,
249+
forall_true_iff]
250+
· simp only [rename_rename, rename_X, Subtype.coe_mk, AlgHom.map_mul]
251+
rfl
252+
#align mv_polynomial.exists_finset_rename MvPolynomial.exists_finset_rename
253+
254+
/-- `exists_finset_rename` for two polyonomials at once: for any two polynomials `p₁`, `p₂` in a
255+
polynomial semiring `R[σ]` of possibly infinitely many variables, `exists_finset_rename₂` yields
256+
a finite subset `s` of `σ` such that both `p₁` and `p₂` are contained in the polynomial semiring
257+
`R[s]` of finitely many variables. -/
258+
theorem exists_finset_rename₂ (p₁ p₂ : MvPolynomial σ R) :
259+
∃ (s : Finset σ)(q₁ q₂ : MvPolynomial s R), p₁ = rename (↑) q₁ ∧ p₂ = rename (↑) q₂ := by
260+
obtain ⟨s₁, q₁, rfl⟩ := exists_finset_rename p₁
261+
obtain ⟨s₂, q₂, rfl⟩ := exists_finset_rename p₂
262+
classical
263+
use s₁ ∪ s₂
264+
use rename (Set.inclusion <| s₁.subset_union_left s₂) q₁
265+
use rename (Set.inclusion <| s₁.subset_union_right s₂) q₂
266+
constructor -- porting note: was `<;> simp <;> rfl` but Lean couldn't infer the arguments
267+
· rw [rename_rename (Set.inclusion <| s₁.subset_union_left s₂)]
268+
rfl
269+
· rw [rename_rename (Set.inclusion <| s₁.subset_union_right s₂)]
270+
rfl
271+
#align mv_polynomial.exists_finset_rename₂ MvPolynomial.exists_finset_rename₂
272+
273+
/-- Every polynomial is a polynomial in finitely many variables. -/
274+
theorem exists_fin_rename (p : MvPolynomial σ R) :
275+
∃ (n : ℕ)(f : Fin n → σ) (_hf : Injective f)(q : MvPolynomial (Fin n) R), p = rename f q := by
276+
obtain ⟨s, q, rfl⟩ := exists_finset_rename p
277+
let n := Fintype.card { x // x ∈ s }
278+
let e := Fintype.equivFin { x // x ∈ s }
279+
refine' ⟨n, (↑) ∘ e.symm, Subtype.val_injective.comp e.symm.injective, rename e q, _⟩
280+
rw [← rename_rename, rename_rename e]
281+
simp only [Function.comp, Equiv.symm_apply_apply, rename_rename]
282+
#align mv_polynomial.exists_fin_rename MvPolynomial.exists_fin_rename
283+
284+
end Rename
285+
286+
theorem eval₂_cast_comp (f : σ → τ) (c : ℤ →+* R) (g : τ → R) (p : MvPolynomial σ ℤ) :
287+
eval₂ c (g ∘ f) p = eval₂ c g (rename f p) := by
288+
apply MvPolynomial.induction_on p (fun n => by simp only [eval₂_C, rename_C])
289+
(fun p q hp hq => by simp only [hp, hq, rename, eval₂_add, AlgHom.map_add])
290+
fun p n hp => by simp only [eval₂_mul, hp, eval₂_X, comp_apply, map_mul, rename_X, eval₂_mul]
291+
#align mv_polynomial.eval₂_cast_comp MvPolynomial.eval₂_cast_comp
292+
293+
section Coeff
294+
295+
@[simp]
296+
theorem coeff_rename_mapDomain (f : σ → τ) (hf : Injective f) (φ : MvPolynomial σ R) (d : σ →₀ ℕ) :
297+
(rename f φ).coeff (d.mapDomain f) = φ.coeff d := by
298+
apply φ.induction_on' (P := fun ψ => coeff (Finsupp.mapDomain f d) ((rename f) ψ) = coeff d ψ)
299+
-- Lean could no longer infer the motive
300+
· intro u r
301+
rw [rename_monomial, coeff_monomial, coeff_monomial]
302+
simp only [(Finsupp.mapDomain_injective hf).eq_iff]
303+
· intros
304+
simp only [*, AlgHom.map_add, coeff_add]
305+
#align mv_polynomial.coeff_rename_map_domain MvPolynomial.coeff_rename_mapDomain
306+
307+
theorem coeff_rename_eq_zero (f : σ → τ) (φ : MvPolynomial σ R) (d : τ →₀ ℕ)
308+
(h : ∀ u : σ →₀ ℕ, u.mapDomain f = d → φ.coeff u = 0) : (rename f φ).coeff d = 0 := by
309+
rw [rename_eq, ← not_mem_support_iff]
310+
intro H
311+
replace H := mapDomain_support H
312+
rw [Finset.mem_image] at H
313+
obtain ⟨u, hu, rfl⟩ := H
314+
specialize h u rfl
315+
simp at h hu
316+
contradiction
317+
#align mv_polynomial.coeff_rename_eq_zero MvPolynomial.coeff_rename_eq_zero
318+
319+
theorem coeff_rename_ne_zero (f : σ → τ) (φ : MvPolynomial σ R) (d : τ →₀ ℕ)
320+
(h : (rename f φ).coeff d ≠ 0) : ∃ u : σ →₀ ℕ, u.mapDomain f = d ∧ φ.coeff u ≠ 0 := by
321+
contrapose! h
322+
apply coeff_rename_eq_zero _ _ _ h
323+
#align mv_polynomial.coeff_rename_ne_zero MvPolynomial.coeff_rename_ne_zero
324+
325+
@[simp]
326+
theorem constantCoeff_rename {τ : Type _} (f : σ → τ) (φ : MvPolynomial σ R) :
327+
constantCoeff (rename f φ) = constantCoeff φ := by
328+
apply φ.induction_on
329+
· intro a
330+
simp only [constantCoeff_C, rename_C]
331+
· intro p q hp hq
332+
simp only [hp, hq, RingHom.map_add, AlgHom.map_add]
333+
· intro p n hp
334+
simp only [hp, rename_X, constantCoeff_X, RingHom.map_mul, AlgHom.map_mul]
335+
#align mv_polynomial.constant_coeff_rename MvPolynomial.constantCoeff_rename
336+
337+
end Coeff
338+
339+
section Support
340+
341+
theorem support_rename_of_injective {p : MvPolynomial σ R} {f : σ → τ} (h : Function.Injective f) :
342+
(rename f p).support = Finset.image (Finsupp.mapDomain f) p.support := by
343+
rw [rename_eq]
344+
exact Finsupp.mapDomain_support_of_injective (mapDomain_injective h) _
345+
#align mv_polynomial.support_rename_of_injective MvPolynomial.support_rename_of_injective
346+
347+
end Support
348+
349+
end MvPolynomial

0 commit comments

Comments
 (0)