Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit 79bc6ad

Browse files
feat(data/mv_polynomial/equiv): API for mv_polynomial.fin_succ_equiv (#10812)
This PR provides API for `mv_polynomial.fin_succ_equiv`: coefficients, degree, coefficientes of coefficients, degree_of of coefficients, etc. To state and prove these lemmas I had to define `cons` and `tail` for maps `fin (n+1) →₀ M` and prove the usual properties for these. I'm not sure if this is necessary or the correct approach to do this. Co-authored-by: Iván Sadofschi Costa <isadofschi@users.noreply.github.com> Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
1 parent 17d2424 commit 79bc6ad

File tree

2 files changed

+282
-6
lines changed

2 files changed

+282
-6
lines changed

src/data/finsupp/fin.lean

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/-
2+
Copyright (c) 2021 Ivan Sadofschi Costa. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Ivan Sadofschi Costa
5+
-/
6+
import data.fin.tuple
7+
import data.finsupp.basic
8+
/-!
9+
# `cons` and `tail` for maps `fin n →₀ M`
10+
11+
We interpret maps `fin n →₀ M` as `n`-tuples of elements of `M`,
12+
We define the following operations:
13+
* `finsupp.tail` : the tail of a map `fin (n + 1) →₀ M`, i.e., its last `n` entries;
14+
* `finsupp.cons` : adding an element at the beginning of an `n`-tuple, to get an `n + 1`-tuple;
15+
16+
In this context, we prove some usual properties of `tail` and `cons`, analogous to those of
17+
`data.fin.tuple.basic`.
18+
-/
19+
20+
noncomputable theory
21+
22+
namespace finsupp
23+
24+
variables {n : ℕ} (i : fin n) {M : Type*} [has_zero M] (y : M)
25+
(t : fin (n + 1) →₀ M) (s : fin n →₀ M)
26+
27+
28+
/-- `tail` for maps `fin (n + 1) →₀ M`. See `fin.tail` for more details. -/
29+
def tail (s : fin (n + 1) →₀ M) : fin n →₀ M :=
30+
finsupp.equiv_fun_on_fintype.inv_fun (fin.tail s.to_fun)
31+
32+
/-- `cons` for maps `fin n →₀ M`. See `fin.cons` for more details. -/
33+
def cons (y : M) (s : fin n →₀ M) : fin (n + 1) →₀ M :=
34+
finsupp.equiv_fun_on_fintype.inv_fun (fin.cons y s.to_fun)
35+
36+
lemma tail_apply : tail t i = t i.succ :=
37+
begin
38+
simp only [tail, equiv_fun_on_fintype_symm_apply_to_fun, equiv.inv_fun_as_coe],
39+
congr,
40+
end
41+
42+
@[simp] lemma cons_zero : cons y s 0 = y :=
43+
by simp [cons, finsupp.equiv_fun_on_fintype]
44+
45+
@[simp] lemma cons_succ : cons y s i.succ = s i :=
46+
begin
47+
simp only [finsupp.cons, fin.cons, finsupp.equiv_fun_on_fintype, fin.cases_succ, finsupp.coe_mk],
48+
refl,
49+
end
50+
51+
@[simp] lemma tail_cons : tail (cons y s) = s :=
52+
begin
53+
simp only [finsupp.cons, fin.cons, finsupp.tail, fin.tail],
54+
ext,
55+
simp only [equiv_fun_on_fintype_symm_apply_to_fun, equiv.inv_fun_as_coe,
56+
finsupp.coe_mk, fin.cases_succ, equiv_fun_on_fintype],
57+
refl,
58+
end
59+
60+
@[simp] lemma cons_tail : cons (t 0) (tail t) = t :=
61+
begin
62+
ext,
63+
by_cases c_a : a = 0,
64+
{ rw [c_a, cons_zero] },
65+
{ rw [←fin.succ_pred a c_a, cons_succ, ←tail_apply] },
66+
end
67+
68+
@[simp] lemma cons_zero_zero : cons 0 (0 : fin n →₀ M) = 0 :=
69+
begin
70+
ext,
71+
by_cases c : a ≠ 0,
72+
{ rw [←fin.succ_pred a c, cons_succ],
73+
simp },
74+
{ simp only [not_not] at c,
75+
simp [c] },
76+
end
77+
78+
variables {s} {y}
79+
80+
lemma cons_ne_zero_of_left (h : y ≠ 0) : cons y s ≠ 0 :=
81+
begin
82+
by_contradiction c,
83+
have h1 : cons y s 0 = 0 := by simp [c],
84+
rw cons_zero at h1,
85+
cc,
86+
end
87+
88+
lemma cons_ne_zero_of_right (h : s ≠ 0) : cons y s ≠ 0 :=
89+
begin
90+
by_contradiction c,
91+
have h' : s = 0,
92+
{ ext,
93+
simp [ ← cons_succ a y s, c] },
94+
cc,
95+
end
96+
97+
lemma cons_ne_zero_iff : cons y s ≠ 0 ↔ y ≠ 0 ∨ s ≠ 0 :=
98+
begin
99+
apply iff.intro,
100+
{ intro h,
101+
apply or_iff_not_imp_left.2,
102+
intro h',
103+
simp only [not_not] at h',
104+
by_contra c,
105+
rw [h', c] at h,
106+
simpa using h },
107+
{ intro h,
108+
cases h,
109+
{ exact cons_ne_zero_of_left h },
110+
{ exact cons_ne_zero_of_right h } },
111+
end
112+
113+
end finsupp

src/data/mv_polynomial/equiv.lean

Lines changed: 169 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ Authors: Johannes Hölzl, Johan Commelin, Mario Carneiro
66

77
import data.mv_polynomial.rename
88
import data.polynomial.algebra_map
9+
import data.polynomial.lifts
10+
import data.mv_polynomial.variables
11+
import data.finsupp.fin
912
import logic.equiv.fin
13+
import algebra.big_operators.fin
14+
1015

1116
/-!
1217
# Equivalences between polynomial rings
@@ -47,7 +52,7 @@ universes u v w x
4752
variables {R : Type u} {S₁ : Type v} {S₂ : Type w} {S₃ : Type x}
4853

4954
namespace mv_polynomial
50-
variables {σ : Type*} {a a' a₁ a₂ : R} {e : ℕ} {n m : σ} {s : σ →₀ ℕ}
55+
variables {σ : Type*} {a a' a₁ a₂ : R} {e : ℕ} {s : σ →₀ ℕ}
5156

5257
section equiv
5358

@@ -274,19 +279,30 @@ def option_equiv_right : mv_polynomial (option S₁) R ≃ₐ[R] mv_polynomial S
274279
alg_equiv.of_alg_hom
275280
(mv_polynomial.aeval (λ o, o.elim (C polynomial.X) X))
276281
(mv_polynomial.aeval_tower (polynomial.aeval (X none)) (λ i, X (option.some i)))
277-
(by ext : 2; simp [mv_polynomial.algebra_map_eq])
278-
(by ext i : 2; cases i; simp)
282+
begin
283+
ext : 2;
284+
simp only [mv_polynomial.algebra_map_eq, option.elim, alg_hom.coe_comp, alg_hom.id_comp,
285+
is_scalar_tower.coe_to_alg_hom', comp_app, aeval_tower_C, polynomial.aeval_X, aeval_X,
286+
option.elim, aeval_tower_X, alg_hom.coe_id, id.def, eq_self_iff_true, implies_true_iff],
287+
end
288+
begin
289+
ext ⟨i⟩ : 2;
290+
simp only [option.elim, alg_hom.coe_comp, comp_app, aeval_X, aeval_tower_C,
291+
polynomial.aeval_X, alg_hom.coe_id, id.def, aeval_tower_X],
292+
end
293+
294+
variables (n : ℕ)
279295

280296
/--
281297
The algebra isomorphism between multivariable polynomials in `fin (n + 1)` and
282298
polynomials over multivariable polynomials in `fin n`.
283299
-/
284-
def fin_succ_equiv (n : ℕ) :
300+
def fin_succ_equiv :
285301
mv_polynomial (fin (n + 1)) R ≃ₐ[R] polynomial (mv_polynomial (fin n) R) :=
286302
(rename_equiv R (fin_succ_equiv n)).trans
287303
(option_equiv_left R (fin n))
288304

289-
lemma fin_succ_equiv_eq (n : ℕ) :
305+
lemma fin_succ_equiv_eq :
290306
(fin_succ_equiv R n : mv_polynomial (fin (n + 1)) R →+* polynomial (mv_polynomial (fin n) R)) =
291307
eval₂_hom (polynomial.C.comp (C : R →+* mv_polynomial (fin n) R))
292308
(λ i : fin (n+1), fin.cases polynomial.X (λ k, polynomial.C (X k)) i) :=
@@ -301,7 +317,7 @@ begin
301317
simp [fin_succ_equiv] }
302318
end
303319

304-
@[simp] lemma fin_succ_equiv_apply (n : ℕ) (p : mv_polynomial (fin (n + 1)) R) :
320+
@[simp] lemma fin_succ_equiv_apply (p : mv_polynomial (fin (n + 1)) R) :
305321
fin_succ_equiv R n p =
306322
eval₂_hom (polynomial.C.comp (C : R →+* mv_polynomial (fin n) R))
307323
(λ i : fin (n+1), fin.cases polynomial.X (λ k, polynomial.C (X k)) i) p :=
@@ -319,6 +335,153 @@ begin
319335
simp only [mv_polynomial.fin_succ_equiv_apply, mv_polynomial.eval₂_hom_C],
320336
end
321337

338+
variables {n} {R}
339+
340+
lemma fin_succ_equiv_X_zero :
341+
fin_succ_equiv R n (X 0) = polynomial.X := by simp
342+
343+
lemma fin_succ_equiv_X_succ {j : fin n} :
344+
fin_succ_equiv R n (X j.succ) = polynomial.C (X j) := by simp
345+
346+
/-- The coefficient of `m` in the `i`-th coefficient of `fin_succ_equiv R n f` equals the
347+
coefficient of `finsupp.cons i m` in `f`. -/
348+
lemma fin_succ_equiv_coeff_coeff (m : fin n →₀ ℕ)
349+
(f : mv_polynomial (fin (n + 1)) R) (i : ℕ) :
350+
coeff m (polynomial.coeff (fin_succ_equiv R n f) i) = coeff (m.cons i) f :=
351+
begin
352+
induction f using mv_polynomial.induction_on' with j r p q hp hq generalizing i m,
353+
swap,
354+
{ simp only [(fin_succ_equiv R n).map_add, polynomial.coeff_add, coeff_add, hp, hq] },
355+
simp only [fin_succ_equiv_apply, coe_eval₂_hom, eval₂_monomial, ring_hom.coe_comp, prod_pow,
356+
polynomial.coeff_C_mul, coeff_C_mul, coeff_monomial,
357+
fin.prod_univ_succ, fin.cases_zero, fin.cases_succ, ← ring_hom.map_prod, ← ring_hom.map_pow],
358+
rw [← mul_boole, mul_comm (polynomial.X ^ j 0), polynomial.coeff_C_mul_X_pow], congr' 1,
359+
obtain rfl | hjmi := eq_or_ne j (m.cons i),
360+
{ simpa only [cons_zero, cons_succ, if_pos rfl, monomial_eq, C_1, one_mul, prod_pow]
361+
using coeff_monomial m m (1:R), },
362+
{ simp only [hjmi, if_false],
363+
obtain hij | rfl := ne_or_eq i (j 0),
364+
{ simp only [hij, if_false, coeff_zero] },
365+
simp only [eq_self_iff_true, if_true],
366+
have hmj : m ≠ j.tail, { rintro rfl, rw [cons_tail] at hjmi, contradiction },
367+
simpa only [monomial_eq, C_1, one_mul, prod_pow, finsupp.tail_apply, if_neg hmj.symm]
368+
using coeff_monomial m j.tail (1:R), }
369+
end
370+
371+
lemma eval_eq_eval_mv_eval' (s : fin n → R) (y : R) (f : mv_polynomial (fin (n + 1)) R) :
372+
eval (fin.cons y s : fin (n + 1) → R) f =
373+
polynomial.eval y (polynomial.map (eval s) (fin_succ_equiv R n f)) :=
374+
begin
375+
-- turn this into a def `polynomial.map_alg_hom`
376+
let φ : (mv_polynomial (fin n) R)[X] →ₐ[R] R[X] :=
377+
{ commutes' := λ r, by { convert polynomial.map_C _, exact (eval_C _).symm },
378+
.. polynomial.map_ring_hom (eval s) },
379+
show aeval (fin.cons y s : fin (n + 1) → R) f =
380+
(polynomial.aeval y).comp (φ.comp (fin_succ_equiv R n).to_alg_hom) f,
381+
congr' 2,
382+
apply mv_polynomial.alg_hom_ext,
383+
rw fin.forall_fin_succ,
384+
simp only [aeval_X, fin.cons_zero, alg_equiv.to_alg_hom_eq_coe, alg_hom.coe_comp,
385+
polynomial.coe_aeval_eq_eval, polynomial.map_C, alg_hom.coe_mk, ring_hom.to_fun_eq_coe,
386+
polynomial.coe_map_ring_hom, alg_equiv.coe_alg_hom, comp_app, fin_succ_equiv_apply,
387+
eval₂_hom_X', fin.cases_zero, polynomial.map_X, polynomial.eval_X, eq_self_iff_true,
388+
fin.cons_succ, fin.cases_succ, eval_X, polynomial.eval_C, implies_true_iff, and_self],
389+
end
390+
391+
lemma coeff_eval_eq_eval_coeff (s' : fin n → R) (f : polynomial (mv_polynomial (fin n) R))
392+
(i : ℕ) : polynomial.coeff (polynomial.map (eval s') f) i = eval s' (polynomial.coeff f i) :=
393+
by simp only [polynomial.coeff_map]
394+
395+
lemma support_coeff_fin_succ_equiv {f : mv_polynomial (fin (n + 1)) R} {i : ℕ}
396+
{m : fin n →₀ ℕ } : m ∈ (polynomial.coeff ((fin_succ_equiv R n) f) i).support
397+
↔ (finsupp.cons i m) ∈ f.support :=
398+
begin
399+
apply iff.intro,
400+
{ intro h,
401+
simpa [←fin_succ_equiv_coeff_coeff] using h },
402+
{ intro h,
403+
simpa [mem_support_iff, ←fin_succ_equiv_coeff_coeff m f i] using h },
404+
end
405+
406+
lemma fin_succ_equiv_support (f : mv_polynomial (fin (n + 1)) R) :
407+
(fin_succ_equiv R n f).support = finset.image (λ m : fin (n + 1)→₀ ℕ, m 0) f.support :=
408+
begin
409+
ext i,
410+
rw [polynomial.mem_support_iff, finset.mem_image, nonzero_iff_exists],
411+
split,
412+
{ rintro ⟨m, hm⟩,
413+
refine ⟨cons i m, _, cons_zero _ _⟩,
414+
rw ← support_coeff_fin_succ_equiv,
415+
simpa using hm, },
416+
{ rintro ⟨m, h, rfl⟩,
417+
refine ⟨tail m, _⟩,
418+
rwa [← coeff, ← mem_support_iff, support_coeff_fin_succ_equiv, cons_tail] },
419+
end
420+
421+
lemma fin_succ_equiv_support' {f : mv_polynomial (fin (n + 1)) R} {i : ℕ} :
422+
finset.image (finsupp.cons i) (polynomial.coeff ((fin_succ_equiv R n) f) i).support
423+
= f.support.filter(λ m, m 0 = i) :=
424+
begin
425+
ext m,
426+
rw [finset.mem_filter, finset.mem_image, mem_support_iff],
427+
conv_lhs
428+
{ congr,
429+
funext,
430+
rw [mem_support_iff, fin_succ_equiv_coeff_coeff, ne.def] },
431+
split,
432+
{ rintros ⟨m',⟨h, hm'⟩⟩,
433+
simp only [←hm'],
434+
exact ⟨h, by rw cons_zero⟩ },
435+
{ intro h,
436+
use tail m,
437+
rw [← h.2, cons_tail],
438+
simp [h.1] }
439+
end
440+
441+
lemma support_fin_succ_equiv_nonempty {f : mv_polynomial (fin (n + 1)) R} (h : f ≠ 0) :
442+
(fin_succ_equiv R n f).support.nonempty :=
443+
begin
444+
by_contradiction c,
445+
simp only [finset.not_nonempty_iff_eq_empty, polynomial.support_eq_empty] at c,
446+
have t'' : (fin_succ_equiv R n f) ≠ 0,
447+
{ let ii := (fin_succ_equiv R n).symm,
448+
have h' : f = 0 :=
449+
calc f = ii (fin_succ_equiv R n f) : by simpa only [ii, ←alg_equiv.inv_fun_eq_symm]
450+
using ((fin_succ_equiv R n).left_inv f).symm
451+
... = ii 0 : by rw c
452+
... = 0 : by simp,
453+
simpa [h'] using h },
454+
simpa [c] using h,
455+
end
456+
457+
lemma degree_fin_succ_equiv {f : mv_polynomial (fin (n + 1)) R} (h : f ≠ 0) :
458+
(fin_succ_equiv R n f).degree = degree_of 0 f :=
459+
begin
460+
have h' : (fin_succ_equiv R n f).support.sup (λ x , x) = degree_of 0 f,
461+
{ rw [degree_of_eq_sup, fin_succ_equiv_support f, finset.sup_image] },
462+
rw [polynomial.degree, ← h', finset.coe_sup_of_nonempty (support_fin_succ_equiv_nonempty h)],
463+
congr,
464+
end
465+
466+
lemma nat_degree_fin_succ_equiv (f : mv_polynomial (fin (n + 1)) R) :
467+
(fin_succ_equiv R n f).nat_degree = degree_of 0 f :=
468+
begin
469+
by_cases c : f = 0,
470+
{ rw [c, (fin_succ_equiv R n).map_zero, polynomial.nat_degree_zero, degree_of_zero] },
471+
{ rw [polynomial.nat_degree, degree_fin_succ_equiv (by simpa only [ne.def]) ],
472+
simp },
473+
end
474+
475+
lemma degree_of_coeff_fin_succ_equiv (p : mv_polynomial (fin (n + 1)) R) (j : fin n)
476+
(i : ℕ) : degree_of j (polynomial.coeff (fin_succ_equiv R n p) i) ≤ degree_of j.succ p :=
477+
begin
478+
rw [degree_of_eq_sup, degree_of_eq_sup, finset.sup_le_iff],
479+
intros m hm,
480+
rw ← finsupp.cons_succ j i m,
481+
convert finset.le_sup (support_coeff_fin_succ_equiv.1 hm),
482+
refl,
483+
end
484+
322485
end
323486

324487
end equiv

0 commit comments

Comments
 (0)