Skip to content

Commit d7375dd

Browse files
feat(RingTheory/MvPowerSeries/Substitution) : better API for rescale (#23642)
This redefines `MvPowerSeries.rescale` under commutative semirings, to keep in line with [PowerSeries.rescale](https://leanprover-community.github.io/mathlib4_docs/Mathlib/RingTheory/PowerSeries/Basic.html#PowerSeries.rescale).
1 parent 2df98ee commit d7375dd

File tree

2 files changed

+171
-100
lines changed

2 files changed

+171
-100
lines changed

Mathlib/RingTheory/MvPowerSeries/Substitution.lean

Lines changed: 169 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@ In the other cases, it is defined as 0 (dummy value).
2828
When `HasSubst a`, `MvPowerSeries.subst a` gives rise to an algebra homomorphism
2929
`MvPowerSeries.substAlgHom ha : MvPowerSeries σ R →ₐ[R] MvPowerSeries τ S`.
3030
31-
As an application, we define `MvPowerSeries.rescale` which rescales a multivariate
32-
power series `f : MvPowerSeries σ R` by a map `a : σ → R`.
31+
We also define `MvPowerSeries.rescale` which rescales a multivariate
32+
power series `f : MvPowerSeries σ R` by a map `a : σ → R`
33+
and show its relation with substitution (under `CommRing R`).
34+
To stay in line with `PowerSeries.rescale`, this is defined by hand
35+
for commutative *semirings*.
3336
3437
## Implementation note
3538
@@ -48,8 +51,6 @@ as it is discrete.
4851
4952
## TODO
5053
51-
* Refactor `PowerSeries.rescale` using this API.
52-
5354
* `MvPowerSeries.IsNilpotent_subst` asserts that the constant coefficient
5455
of a legit substitution is nilpotent; prove that the converse holds when
5556
the kernel of `algebraMap R S` is a nilideal.
@@ -94,35 +95,46 @@ theorem HasSubst.hasEval [TopologicalSpace S] (ha : HasSubst a) :
9495
HasEval a := HasEval.mono (instTopologicalSpace_mono τ bot_le) <|
9596
(@hasSubst_iff_hasEval_of_discreteTopology σ τ _ _ a ⊥ (@DiscreteTopology.mk S ⊥ rfl)).mp ha
9697

97-
theorem hasSubst_X : HasSubst (fun (s : σ) ↦ (X s : MvPowerSeries σ S)) := by
98-
letI : UniformSpace S := ⊥
99-
simpa [hasSubst_iff_hasEval_of_discreteTopology] using HasEval.X
100-
101-
theorem hasSubst_zero : HasSubst (fun (_ : σ) ↦ (0 : MvPowerSeries τ S)) := by
98+
theorem HasSubst.zero : HasSubst (fun (_ : σ) ↦ (0 : MvPowerSeries τ S)) := by
10299
letI : UniformSpace S := ⊥
103100
simpa [hasSubst_iff_hasEval_of_discreteTopology] using HasEval.zero
104101

105-
theorem hasSubst_add {a b : σ → MvPowerSeries τ S} (ha : HasSubst a) (hb : HasSubst b) :
102+
theorem HasSubst.add {a b : σ → MvPowerSeries τ S} (ha : HasSubst a) (hb : HasSubst b) :
106103
HasSubst (a + b) := by
107104
letI : UniformSpace S := ⊥
108105
rw [hasSubst_iff_hasEval_of_discreteTopology] at ha hb ⊢
109106
exact ha.add hb
110107

111-
theorem hasSubst_mul (b : σ → MvPowerSeries τ S) {a : σ → MvPowerSeries τ S} (ha : HasSubst a) :
108+
theorem HasSubst.mul_left (b : σ → MvPowerSeries τ S)
109+
{a : σ → MvPowerSeries τ S} (ha : HasSubst a) :
112110
HasSubst (b * a) := by
113111
letI : UniformSpace S := ⊥
114112
rw [hasSubst_iff_hasEval_of_discreteTopology] at ha ⊢
115113
exact ha.mul_left b
116114

117-
theorem hasSubst_smul (r : MvPowerSeries τ S) {a : σ → MvPowerSeries τ S} (ha : HasSubst a) :
118-
HasSubst (r • a) := hasSubst_mul _ ha
115+
theorem HasSubst.mul_right (b : σ → MvPowerSeries τ S)
116+
{a : σ → MvPowerSeries τ S} (ha : HasSubst a) :
117+
HasSubst (a * b) :=
118+
mul_comm a b ▸ ha.mul_left b
119+
120+
theorem HasSubst.smul (r : MvPowerSeries τ S) {a : σ → MvPowerSeries τ S} (ha : HasSubst a) :
121+
HasSubst (r • a) := ha.mul_left _
122+
123+
protected theorem HasSubst.X : HasSubst (fun (s : σ) ↦ (X s : MvPowerSeries σ S)) := by
124+
letI : UniformSpace S := ⊥
125+
simpa [hasSubst_iff_hasEval_of_discreteTopology] using HasEval.X
126+
127+
theorem HasSubst.smul_X (a : σ → R) :
128+
HasSubst (a • X : σ → MvPowerSeries σ R) := by
129+
convert HasSubst.X.mul_left (fun s ↦ algebraMap R (MvPowerSeries σ R) (a s))
130+
simp [funext_iff, algebra_compatible_smul (MvPowerSeries σ R)]
119131

120132
/-- Families of `MvPowerSeries` that can be substituted, as an `Ideal` -/
121-
noncomputable def hasSubst.ideal : Ideal (σ → MvPowerSeries τ S) :=
133+
noncomputable def hasSubstIdeal : Ideal (σ → MvPowerSeries τ S) :=
122134
{ carrier := setOf HasSubst
123-
add_mem' := hasSubst_add
124-
zero_mem' := hasSubst_zero
125-
smul_mem' := hasSubst_mul }
135+
add_mem' := HasSubst.add
136+
zero_mem' := HasSubst.zero
137+
smul_mem' := HasSubst.mul_left }
126138

127139
/-- If `σ` is finite, then the nilpotent condition is enough for `HasSubst` -/
128140
theorem hasSubst_of_constantCoeff_nilpotent [Finite σ]
@@ -185,6 +197,15 @@ theorem coe_substAlgHom (ha : HasSubst a) : ⇑(substAlgHom ha) = subst (R := R)
185197
letI : UniformSpace S := ⊥
186198
rw [substAlgHom_eq_aeval, coe_aeval ha.hasEval, subst_eq_eval₂]
187199

200+
theorem subst_self : subst (MvPowerSeries.X : σ → MvPowerSeries σ R) = id := by
201+
rw [← coe_substAlgHom HasSubst.X]
202+
letI : UniformSpace R := ⊥
203+
ext1 f
204+
simp only [← coe_substAlgHom HasSubst.X, substAlgHom_eq_aeval]
205+
have := aeval_unique (ε := AlgHom.id R (MvPowerSeries σ R)) continuous_id
206+
rw [DFunLike.ext_iff] at this
207+
exact this f
208+
188209
@[simp]
189210
theorem substAlgHom_apply (ha : HasSubst a) (f : MvPowerSeries σ R) :
190211
substAlgHom ha f = subst a f := by
@@ -259,7 +280,7 @@ theorem constantCoeff_subst (ha : HasSubst a) (f : MvPowerSeries σ R) :
259280
theorem map_algebraMap_eq_subst_X (f : MvPowerSeries σ R) :
260281
map σ (algebraMap R S) f = subst X f := by
261282
ext e
262-
rw [coeff_map, coeff_subst hasSubst_X f e, finsum_eq_single _ e]
283+
rw [coeff_map, coeff_subst HasSubst.X f e, finsum_eq_single _ e]
263284
· rw [← MvPowerSeries.monomial_one_eq, coeff_monomial_same,
264285
algebra_compatible_smul S, smul_eq_mul, mul_one]
265286
· intro d hd
@@ -363,97 +384,147 @@ theorem subst_comp_subst_apply (ha : HasSubst a) (hb : HasSubst b) (f : MvPowerS
363384

364385
section rescale
365386

366-
/-- Rescale multivariate power series -/
367-
noncomputable def rescale (a : σ → R) (f : MvPowerSeries σ R) :
368-
MvPowerSeries σ R :=
369-
subst (a • X) f
387+
section CommSemiring
388+
389+
variable {R : Type*} [CommSemiring R]
390+
391+
-- To match the `PowerSeries.rescale` API which holds for `CommSemiring`,
392+
-- we redo it by hand.
393+
394+
/-- The ring homomorphism taking a multivariate power series `f(X)` to `f(aX)`. -/
395+
noncomputable def rescale (a : σ → R) : MvPowerSeries σ R →+* MvPowerSeries σ R where
396+
toFun f := fun n ↦ (n.prod fun s m ↦ a s ^ m) * f.coeff R n
397+
map_zero' := by
398+
ext
399+
simp [map_zero, coeff_apply]
400+
map_one' := by
401+
ext1 n
402+
classical
403+
simp only [coeff_one, mul_ite, mul_one, mul_zero]
404+
split_ifs with h
405+
· simp [h, coeff_apply]
406+
· simp only [coeff_apply, ite_eq_right_iff]
407+
exact fun a_1 ↦ False.elim (h a_1)
408+
map_add' := by
409+
intros
410+
ext
411+
exact mul_add _ _ _
412+
map_mul' f g := by
413+
ext n
414+
classical
415+
rw [coeff_apply, coeff_mul, coeff_mul, Finset.mul_sum]
416+
apply Finset.sum_congr rfl
417+
intro x hx
418+
simp only [Finset.mem_antidiagonal] at hx
419+
rw [← hx]
420+
simp only [coeff_apply]
421+
rw [Finsupp.prod_of_support_subset _ Finsupp.support_add,
422+
Finsupp.prod_of_support_subset x.1 Finset.subset_union_left,
423+
Finsupp.prod_of_support_subset x.2 Finset.subset_union_right]
424+
· simp only [← mul_assoc]
425+
congr 1
426+
rw [mul_assoc, mul_comm (f x.1), ← mul_assoc]
427+
congr 1
428+
rw [← Finset.prod_mul_distrib]
429+
apply Finset.prod_congr rfl
430+
simp [pow_add]
431+
all_goals {simp}
370432

371-
theorem rescale_eq_subst (a : σ → R) (f : MvPowerSeries σ R) :
372-
rescale a f = subst (a • X) f := rfl
373-
374-
theorem hasSubst_rescale (a : σ → R) :
375-
HasSubst ((a • X) : σ → MvPowerSeries σ R) := by
376-
convert hasSubst_mul (fun s ↦ algebraMap R (MvPowerSeries σ R) (a s)) hasSubst_X
377-
simp [funext_iff, algebra_compatible_smul (MvPowerSeries σ R)]
433+
@[simp]
434+
theorem coeff_rescale (f : MvPowerSeries σ R) (a : σ → R) (n : σ →₀ ℕ) :
435+
coeff R n (rescale a f) = (n.prod fun s m ↦ a s ^ m) * f.coeff R n := by
436+
simp [rescale, coeff_apply]
378437

379-
/-- Rescale multivariate power series, as an `AlgHom` -/
380-
noncomputable def rescale_algHom (a : σ → R) :
381-
MvPowerSeries σ R →ₐ[R] MvPowerSeries σ R :=
382-
substAlgHom (hasSubst_rescale a)
438+
@[simp]
439+
theorem rescale_zero :
440+
(rescale 0 : MvPowerSeries σ R →+* MvPowerSeries σ R) = (C σ R).comp (constantCoeff σ R) := by
441+
classical
442+
ext x n
443+
simp [Function.comp_apply, RingHom.coe_comp, rescale, RingHom.coe_mk, coeff_C]
444+
split_ifs with h
445+
· simp [h, coeff_apply, ← @coeff_zero_eq_constantCoeff_apply, coeff_apply]
446+
· simp only [coeff_apply]
447+
convert zero_mul _
448+
simp only [DFunLike.ext_iff, not_forall, Finsupp.coe_zero, Pi.zero_apply] at h
449+
obtain ⟨s, h⟩ := h
450+
simp only [Finsupp.prod]
451+
apply Finset.prod_eq_zero (i := s) _ (zero_pow h)
452+
simpa using h
383453

384-
theorem coe_rescale_algHom (a : σ → R) :
385-
rescale_algHom a = rescale a :=
386-
coe_substAlgHom (hasSubst_rescale a)
454+
theorem rescale_zero_apply (f : MvPowerSeries σ R) :
455+
rescale 0 f = C σ R (constantCoeff σ R f) := by simp
387456

388-
theorem rescale_algHom_comp (a b : σ → R) :
389-
(rescale_algHom a).comp (rescale_algHom b) = rescale_algHom (a * b) := by
390-
ext f
391-
simp only [AlgHom.coe_comp, Function.comp_apply, rescale_algHom]
392-
rw [substAlgHom_comp_substAlgHom_apply]
393-
congr
394-
rw [funext_iff]
395-
intro s
396-
simp only [Pi.smul_apply', Pi.mul_apply]
397-
rw [AlgHom.map_smul_of_tower, ← MvPolynomial.coe_X, substAlgHom_coe]
398-
simp [algebraMap_smul, ← mul_smul, mul_comm]
399-
400-
theorem rescale_rescale_apply (a b : σ → R) (f : MvPowerSeries σ R) :
401-
(f.rescale b).rescale a = f.rescale (a * b) := by
402-
simp only [← coe_rescale_algHom, ← AlgHom.comp_apply, rescale_algHom_comp]
403-
404-
theorem coeff_rescale (r : σ → R) (f : MvPowerSeries σ R) (d : σ →₀ ℕ) :
405-
coeff R d (rescale r f) = (d.prod fun s n ↦ r s ^ n) • coeff R d f := by
406-
rw [rescale_eq_subst, coeff_subst (hasSubst_rescale _)]
407-
simp only [Pi.smul_apply', smul_eq_mul, prod_smul_X_eq_smul_monomial_one]
408-
simp only [LinearMap.map_smul_of_tower, Algebra.mul_smul_comm]
409-
rw [finsum_eq_single _ d]
410-
· simp
411-
· intro e he
412-
simp [coeff_monomial_ne he.symm]
413-
414-
theorem rescale_one :
415-
rescale 1 = @id (MvPowerSeries σ R) := by
416-
ext f d
457+
@[simp]
458+
theorem rescale_one : rescale 1 = RingHom.id (MvPowerSeries σ R) := by
459+
ext f n
417460
simp [coeff_rescale, Finsupp.prod]
418461

419-
theorem rescale_algHom_one :
420-
rescale_algHom 1 = AlgHom.id R (MvPowerSeries σ R):= by
421-
rw [DFunLike.ext_iff]
422-
intro f
423-
simp [coe_rescale_algHom, rescale_one]
462+
theorem rescale_rescale (f : MvPowerSeries σ R) (a b : σ → R) :
463+
rescale b (rescale a f) = rescale (a * b) f := by
464+
ext n
465+
simp [← mul_assoc, mul_pow, mul_comm]
424466

425-
/-- Rescale a multivariate power series, as a `MonoidHom` in the scaling parameters -/
426-
noncomputable def rescale_MonoidHom : (σ → R) →* MvPowerSeries σ R →ₐ[R] MvPowerSeries σ R where
427-
toFun := rescale_algHom
428-
map_one' := rescale_algHom_one
429-
map_mul' a b := by
430-
rw [← rescale_algHom_comp, AlgHom.End_toSemigroup_toMul_mul]
467+
theorem rescale_mul (a b : σ → R) : rescale (a * b) = (rescale b).comp (rescale a) := by
468+
ext
469+
simp [← rescale_rescale]
431470

432-
theorem rescale_zero_apply (f : MvPowerSeries σ R) :
433-
rescale 0 f = MvPowerSeries.C σ R (constantCoeff σ R f) := by
434-
classical
435-
ext d
436-
simp only [coeff_rescale, coeff_C]
437-
by_cases hd : d = 0
438-
· simp [hd]
439-
· simp only [Pi.zero_apply, smul_eq_mul, if_neg hd]
440-
convert zero_smul R _
441-
simp only [DFunLike.ext_iff, Finsupp.coe_zero, Pi.zero_apply, not_forall] at hd
442-
obtain ⟨s, hs⟩ := hd
443-
apply Finset.prod_eq_zero (Finsupp.mem_support_iff.mpr hs)
444-
simp [hs]
445-
446-
/-- Rescaling a linear power series is `smul` -/
447-
lemma rescale_linear_eq_smul (r : R) (f : MvPowerSeries σ R)
448-
(hf : ∀ (d : σ →₀ ℕ), (d.sum (fun _ n ↦ n) ≠ 1) → MvPowerSeries.coeff R d f = 0) :
449-
MvPowerSeries.rescale (Function.const σ r) f = r • f := by
471+
/-- Rescaling a homogeneous power series -/
472+
lemma rescale_homogeneous_eq_smul {n : ℕ} {r : R} {f : MvPowerSeries σ R}
473+
(hf : ∀ d ∈ f.support, d.degree = n) :
474+
MvPowerSeries.rescale (Function.const σ r) f = r ^ n • f := by
450475
ext e
451476
simp only [MvPowerSeries.coeff_rescale, map_smul, Finsupp.prod, Function.const_apply,
452477
Finset.prod_pow_eq_pow_sum, smul_eq_mul]
453-
by_cases he : Finsupp.sum e (fun _ n ↦ n) = 1
454-
· simp only [Finsupp.sum] at he
455-
simp [he]
456-
· simp [hf e he]
478+
by_cases he : e ∈ f.support
479+
· rw [← hf e he, Finsupp.degree]
480+
· simp only [Function.mem_support, ne_eq, not_not] at he
481+
simp [he, mul_zero, coeff_apply]
482+
483+
/-- Rescale a multivariate power series, as a `MonoidHom` in the scaling parameters -/
484+
noncomputable def rescale_MonoidHom :
485+
(σ → R) →* MvPowerSeries σ R →+* MvPowerSeries σ R where
486+
toFun := rescale
487+
map_one' := rescale_one
488+
map_mul' a b := by ext; simp [mul_comm, rescale_rescale]
489+
490+
end CommSemiring
491+
492+
section CommRing
493+
494+
theorem rescale_eq_subst (a : σ → R) (f : MvPowerSeries σ R) :
495+
rescale a f = subst (a • X) f := by
496+
classical
497+
ext n
498+
rw [coeff_rescale]
499+
rw [coeff_subst (HasSubst.smul_X a),
500+
finsum_eq_sum _ (coeff_subst_finite (HasSubst.smul_X a) f n)]
501+
simp only [Pi.smul_apply', smul_eq_mul]
502+
rw [Finset.sum_eq_single n _ _]
503+
· simp [mul_comm, ← monomial_eq, coeff_monomial]
504+
· intro b hb hbn
505+
rw [← monomial_eq, coeff_monomial, if_neg (Ne.symm hbn), mul_zero]
506+
· intro hn
507+
simpa using hn
508+
509+
noncomputable def rescaleAlgHom (a : σ → R) :
510+
MvPowerSeries σ R →ₐ[R] MvPowerSeries σ R :=
511+
substAlgHom (HasSubst.smul_X a)
512+
513+
theorem rescaleAlgHom_apply (a : σ → R) (f : MvPowerSeries σ R) :
514+
rescaleAlgHom a f = rescale a f := by
515+
simp [rescaleAlgHom, rescale_eq_subst]
516+
517+
theorem rescaleAlgHom_mul (a b : σ → R) :
518+
rescaleAlgHom (a * b) = (rescaleAlgHom b).comp (rescaleAlgHom a) := by
519+
ext1 f
520+
simp [rescaleAlgHom_apply, rescale_rescale]
521+
522+
theorem rescaleAlgHom_one :
523+
rescaleAlgHom 1 = AlgHom.id R (MvPowerSeries σ R):= by
524+
ext1 f
525+
simp [rescaleAlgHom, subst_self]
526+
527+
end CommRing
457528

458529
end rescale
459530

Mathlib/RingTheory/PowerSeries/Basic.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -547,12 +547,12 @@ theorem rescale_zero : rescale 0 = (C R).comp (constantCoeff R) := by
547547
PowerSeries.coeff_mk _ _, coeff_C]
548548
split_ifs with h <;> simp [h]
549549

550-
theorem rescale_zero_apply : rescale 0 X = C R (constantCoeff R X) := by simp
550+
theorem rescale_zero_apply (f : R⟦X⟧) : rescale 0 f = C R (constantCoeff R f) := by simp
551551

552552
@[simp]
553553
theorem rescale_one : rescale 1 = RingHom.id R⟦X⟧ := by
554554
ext
555-
simp only [coeff_rescale, one_pow, one_mul, RingHom.id_apply]
555+
simp [coeff_rescale]
556556

557557
theorem rescale_mk (f : ℕ → R) (a : R) : rescale a (mk f) = mk fun n : ℕ => a ^ n * f n := by
558558
ext

0 commit comments

Comments
 (0)