Skip to content

Commit 0856a89

Browse files
feat: power series over a noetherian ring is noetherian (#31149)
We add that the power series ring over a noetherian ring is noetherian.
1 parent e12f733 commit 0856a89

File tree

5 files changed

+302
-24
lines changed

5 files changed

+302
-24
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6030,6 +6030,7 @@ public import Mathlib.RingTheory.PowerSeries.CoeffMulMem
60306030
public import Mathlib.RingTheory.PowerSeries.Derivative
60316031
public import Mathlib.RingTheory.PowerSeries.Evaluation
60326032
public import Mathlib.RingTheory.PowerSeries.GaussNorm
6033+
public import Mathlib.RingTheory.PowerSeries.Ideal
60336034
public import Mathlib.RingTheory.PowerSeries.Inverse
60346035
public import Mathlib.RingTheory.PowerSeries.NoZeroDivisors
60356036
public import Mathlib.RingTheory.PowerSeries.Order

Mathlib/Algebra/Module/SpanRank.lean

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@ Authors: Wanyi He, Jiedong Jiang, Xuchun Li, Christian Merten, Jingting Wang, An
55
-/
66
module
77

8-
public import Mathlib.Data.Set.Card
98
public import Mathlib.Data.ENat.Lattice
10-
public import Mathlib.RingTheory.Finiteness.Defs
11-
public import Mathlib.LinearAlgebra.FreeModule.Basic
129
public import Mathlib.LinearAlgebra.Dimension.StrongRankCondition
10+
public import Mathlib.RingTheory.Finiteness.Ideal
1311

1412
/-!
1513
# Minimum Cardinality of generating set of a submodule
@@ -118,6 +116,12 @@ lemma spanRank_finite_iff_fg {p : Submodule R M} : p.spanRank < aleph0 ↔ p.FG
118116
· rintro ⟨s, hs₁, hs₂⟩
119117
exact (ciInf_le' _ ⟨s, hs₂⟩).trans_lt (by simpa)
120118

119+
lemma spanFinrank_of_not_fg {p : Submodule R M} (hp : ¬p.FG) : p.spanFinrank = 0 := by
120+
refine toNat_eq_zero.2 ?_
121+
right
122+
by_contra! h
123+
exact hp (spanRank_finite_iff_fg.1 h)
124+
121125
/-- A submodule is finitely generated if and only if its `spanRank` is equal to its `spanFinrank`.
122126
-/
123127
lemma fg_iff_spanRank_eq_spanFinrank {p : Submodule R M} : p.spanRank = p.spanFinrank ↔ p.FG := by
@@ -247,15 +251,58 @@ lemma spanFinrank_singleton {m : M} (hm : m ≠ 0) : (span R {m}).spanFinrank =
247251
simp [Submodule.spanFinrank_eq_zero_iff_eq_bot (fg_span_singleton m), hm] at this
248252

249253
end Defs
254+
250255
end Submodule
251256

257+
section map
258+
259+
universe u
260+
section Submodule
261+
262+
variable {R : Type*} {M N : Type u} [Semiring R] [AddCommMonoid M] [Module R M] [AddCommMonoid N]
263+
[Module R N] (f : M →ₗ[R] N) (p : Submodule R M)
264+
265+
lemma Submodule.spanRank_map_le : (p.map f).spanRank ≤ p.spanRank := by
266+
rw [← generators_card p, FG.spanRank_le_iff_exists_span_set_card_le]
267+
exact ⟨f '' p.generators, Cardinal.mk_image_le, le_antisymm (span_le.2 (fun n ⟨m, hm, h⟩ ↦
268+
⟨m, span_generators p ▸ subset_span hm, h⟩)) (by simp [span_generators])⟩
269+
270+
variable {p} in
271+
lemma Submodule.spanFinrank_map_le_of_fg (hp : p.FG) : (p.map f).spanFinrank ≤ p.spanFinrank :=
272+
(Cardinal.toNat_le_iff_le_of_lt_aleph0 (spanRank_finite_iff_fg.mpr (FG.map f hp))
273+
(spanRank_finite_iff_fg.mpr hp)).2 (p.spanRank_map_le f)
274+
275+
end Submodule
276+
277+
section Ideal
278+
279+
variable {R S : Type u} [Semiring R] [Semiring S] (f : R →+* S) (I : Ideal R)
280+
281+
open Submodule in
282+
lemma Ideal.spanRank_map_le : (I.map f).spanRank ≤ I.spanRank := by
283+
rw [← generators_card I, FG.spanRank_le_iff_exists_span_set_card_le]
284+
refine ⟨f '' I.generators, Cardinal.mk_image_le, le_antisymm (span_le.2 (fun s ⟨r, hr, hfr⟩ ↦
285+
hfr ▸ mem_map_of_mem _ <| span_generators I ▸ subset_span hr)) ?_⟩
286+
refine map_le_of_le_comap (fun r hr ↦ ?_)
287+
simp only [submodule_span_eq, mem_comap]
288+
rw [← map_span, ← submodule_span_eq, span_generators]
289+
exact mem_map_of_mem f hr
290+
291+
open Submodule in
292+
variable {I} in
293+
lemma Ideal.spanFinrank_map_le_of_fg (hI : I.FG) : (I.map f).spanFinrank ≤ I.spanFinrank :=
294+
(Cardinal.toNat_le_iff_le_of_lt_aleph0 (spanRank_finite_iff_fg.mpr (Ideal.FG.map hI f))
295+
((spanRank_finite_iff_fg.mpr hI))).2 (spanRank_map_le f I)
296+
297+
end Ideal
298+
299+
end map
300+
252301
section rank
253302

254303
open Cardinal Module Submodule
255304

256-
universe u v w
257-
258-
variable {R : Type u} {M : Type v} [Semiring R] [AddCommMonoid M] [Module R M]
305+
variable {R M : Type*} [Semiring R] [AddCommMonoid M] [Module R M]
259306

260307
lemma Module.Basis.mk_eq_spanRank [RankCondition R] {ι : Type*} (v : Basis ι R M) :
261308
#(Set.range v) = (⊤ : Submodule R M).spanRank := by
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/-
2+
Copyright (c) 2025 Riccardo Brasca. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Riccardo Brasca, Anthony Fernandes, Marc Robin
5+
-/
6+
module
7+
8+
public import Mathlib.RingTheory.PowerSeries.Inverse
9+
public import Mathlib.RingTheory.PowerSeries.Trunc
10+
public import Mathlib.RingTheory.Finiteness.Ideal
11+
public import Mathlib.RingTheory.Noetherian.OfPrime
12+
public import Mathlib.Algebra.Module.SpanRank
13+
14+
/-!
15+
# Ideals in power series.
16+
17+
We gather miscellaneous results about prime ideals in `R⟦X⟧`. More precisely, we prove that, given
18+
a prime ideal `I` of `R⟦X⟧`, if the ideal generated by the constant coefficients of the `f ∈ I` is
19+
generated by `n` elements, then `I` is generated by at most `n + 1` elements (actually it is
20+
generated by `n` elements if `X ∉ I` and `n + 1` elements otherwise). This implies immediately that
21+
`R⟦X⟧` is noetherian if `R` is. The proof of `eq_of_le_of_X_notMem_of_fg_of_isPrime` is inspired by
22+
[zbMATH05171613].
23+
24+
25+
## Main results
26+
27+
* `PowerSeries.eq_span_insert_X_of_X_mem_of_span_eq` : given an ideal `I` of `R⟦X⟧` such that
28+
`X ∈ I`, if `I.map constantCoeff` is generated by `S : Set T`, then `I` is generated by
29+
`insert X (C '' S)`.
30+
* `PowerSeries.exist_eq_span_eq_ncard_of_X_notMem` : given a prime ideal `I` of `R⟦X⟧` such
31+
that `X ∉ I`, if `I.map constantCoeff` is generated by a finite set `S : Set T`, then there exists
32+
`T : Set R`, of the same cardinality as `S`, that generates `I`.
33+
* `PowerSeries.fg_iff_of_isPrime` : a prime ideal `P` of `R⟦X⟧` is finitely generated if and only
34+
if `P.map constantCoeff` is finitely generated.
35+
36+
37+
## Implementation details
38+
39+
There is a simpler proof of `IsNoetherianRing R → IsNoetherianRing R⟦X⟧`, similar to that for
40+
polynomials. On the other hand our proof has the advantage of giving explicitly the number of
41+
generators, and it will be used to prove that, for a domain `R`, we have
42+
`IsPrincipalIdealRing R → UniqueFactorizationMonoid R⟦X⟧`.
43+
44+
## TODO
45+
Prove noetherianity of `MvPowerSeries` in finitely many variables.
46+
47+
-/
48+
49+
variable {R : Type*}
50+
51+
open Ideal Set Finset
52+
53+
namespace PowerSeries
54+
variable [CommRing R] {I : Ideal R⟦X⟧} {S : Set R}
55+
56+
section X_mem
57+
58+
theorem map_constantCoeff_le_self_of_X_mem (hXI : X ∈ I) :
59+
I.map (C.comp constantCoeff) ≤ I := by
60+
suffices ∀ x ∈ I, C (constantCoeff x) ∈ I by simpa [Ideal.map_le_iff_le_comap]
61+
intro f hf
62+
rw [← sub_eq_iff_eq_add'.mpr f.eq_X_mul_shift_add_const]
63+
exact sub_mem hf (I.mul_mem_right _ hXI)
64+
65+
/-- Given an ideal `I` of `R⟦X⟧` such that `X ∈ I`, if `I.map constantCoeff` is generated by
66+
`S : Set T`, then `I` is generated by `insert X (C '' S)`. -/
67+
theorem eq_span_insert_X_of_X_mem_of_span_eq (hXI : X ∈ I) (hSI : span S = I.map constantCoeff) :
68+
I = span (insert X (C '' S)) := by
69+
rw [Ideal.span_insert, ← Ideal.map_span, hSI, Ideal.map_map]
70+
refine le_antisymm ?_ (by simp [Ideal.span_le, hXI, map_constantCoeff_le_self_of_X_mem])
71+
exact fun f hf ↦ mem_span_singleton_sup.mpr
72+
⟨_, _, mem_map_of_mem _ hf, f.eq_shift_mul_X_add_const.symm⟩
73+
74+
open Submodule in
75+
theorem spanFinrank_le_spanFinrank_map_constantCoeff_add_one_of_X_mem (hI : X ∈ I) :
76+
spanFinrank I ≤ spanFinrank (I.map constantCoeff) + 1 := by
77+
by_cases hfg : I.FG
78+
swap; · exact spanFinrank_of_not_fg hfg ▸ Nat.zero_le _
79+
replace hfg : (Ideal.map constantCoeff I).FG := by
80+
have : RingHomSurjective (constantCoeff (R := R)) := ⟨constantCoeff_surj⟩
81+
exact map_eq_submodule_map constantCoeff I ▸ Submodule.FG.map _ hfg
82+
nth_rw 1 [eq_span_insert_X_of_X_mem_of_span_eq hI (I.map constantCoeff).span_generators]
83+
refine le_trans (spanFinrank_span_le_ncard_of_finite ?_) (le_trans (Set.ncard_insert_le _ _) ?_)
84+
· simpa using Set.Finite.map _ (FG.finite_generators hfg)
85+
· simp only [add_le_add_iff_right]
86+
refine le_trans (Set.ncard_image_le (FG.finite_generators hfg)) ?_
87+
rw [FG.generators_ncard hfg]
88+
89+
end X_mem
90+
91+
section X_notMem
92+
93+
variable (hXI : X ∉ I) [I.IsPrime]
94+
95+
theorem eq_of_le_of_X_notMem_of_fg_of_isPrime {J : Ideal R⟦X⟧} (hJI : J ≤ I) (hXI : X ∉ I)
96+
(hJ : J.FG) (h' : I.map constantCoeff ≤ J.map constantCoeff) : I = J := by
97+
refine hJI.antisymm' ?_
98+
replace h' := h'.antisymm (Ideal.map_mono hJI)
99+
obtain ⟨n, F, rfl⟩ := Submodule.fg_iff_exists_fin_generating_family.mp hJ
100+
rw [submodule_span_eq, map_span, ← Set.range_comp] at h'
101+
choose! T hT using fun g (hg : g ∈ I) ↦
102+
mem_span_range_iff_exists_fun.mp (h'.le (Ideal.mem_map_of_mem _ hg))
103+
dsimp at hT
104+
intro g hg
105+
let G : ℕ → R⟦X⟧ :=
106+
Nat.rec g fun _ G' ↦ mk fun p ↦ coeff (p + 1) G' - ∑ i, T G' i * coeff (p + 1) (F i)
107+
have hG' (n : ℕ) (H : G n ∈ I) : G n - ∑ i, C (T (G n) i) * F i = X * G (n + 1) := by
108+
simpa [hT _ H] using sub_const_eq_X_mul_shift (G n - ∑ i, C (T (G n) i) * F i)
109+
have hG : ∀ n, G n ∈ I := Nat.rec hg fun n IH ↦
110+
(‹I.IsPrime›.mul_mem_iff_mem_or_mem.mp (hG' n IH ▸ I.sub_mem IH (I.sum_mem fun i _ ↦
111+
I.mul_mem_left _ (hJI (subset_span (Set.mem_range_self _)))))).resolve_left hXI
112+
replace hG' := fun n ↦ hG' n (hG n)
113+
let H (i : Fin n) : R⟦X⟧ := mk fun n ↦ T (G n) i
114+
have h₁ (n : ℕ) : g - ∑ i, trunc n (H i) * F i = X ^ n * G n := by
115+
induction n with
116+
| zero => simp [G]
117+
| succ n IH =>
118+
simp [trunc_succ, add_mul, sum_add_distrib, ← sub_sub, IH, pow_succ, mul_assoc, ← hG',
119+
mul_sub, H, mul_sum, monomial_eq_C_mul_X_pow, mul_left_comm (C _)]
120+
have h₂ : g = ∑ i, H i * F i := by
121+
ext n; simpa [coeff_trunc, sub_eq_zero] using congr(($(h₁ (n + 1)).trunc (n + 1)).coeff n)
122+
rw [h₂]
123+
exact Ideal.sum_mem _ fun i _ ↦ Ideal.mul_mem_left _ _ (subset_span (Set.mem_range_self _))
124+
125+
/-- Given a prime ideal `I` of `R⟦X⟧` such that `X ∉ I`, if `I.map constantCoeff` is generated by a
126+
finite set `S : Set T`, then there exists `T : Set R`, of the same cardinality as `S`, that
127+
generates `I`. -/
128+
theorem exist_eq_span_eq_ncard_of_X_notMem (hI : X ∉ I) {S : Set R}
129+
(hSI : span S = I.map constantCoeff) (hS : S.Finite) :
130+
∃ T, I = span T ∧ T.Finite ∧ T.ncard = S.ncard := by
131+
have : SurjOn constantCoeff I S := by
132+
intro r hr
133+
simpa [mem_map_iff_of_surjective _ constantCoeff_surj, hSI] using subset_span hr
134+
obtain ⟨T, hTI, hinj, hT⟩ := this.exists_subset_injOn_image_eq
135+
refine ⟨T, eq_of_le_of_X_notMem_of_fg_of_isPrime (span_le.2 hTI) hI (Submodule.fg_def.2
136+
⟨T, (hT ▸ hS).of_finite_image hinj, rfl⟩) ?_, Finite.of_injOn
137+
(fun f hf ↦ hT ▸ Set.mem_image_of_mem _ hf) hinj hS, hT ▸ (ncard_image_of_injOn hinj).symm⟩
138+
rw [map_le_iff_le_comap]
139+
intro f hf
140+
rw [mem_comap, mem_map_iff_of_surjective _ constantCoeff_surj]
141+
replace hf : constantCoeff f ∈ span S := hSI ▸ Ideal.mem_map_of_mem constantCoeff hf
142+
refine Submodule.span_induction (fun s hs ↦ ?_) ⟨0, zero_mem _, by simp⟩ ?_ ?_ hf
143+
· obtain ⟨t, htmem, ht⟩ := hT ▸ hs
144+
exact ⟨t, subset_span htmem, ht⟩
145+
· intro r₁ r₂ hr₁ hr₂ ⟨s₁, hs₁mem, hs₁⟩ ⟨s₂, hs₂mem, hs₂⟩
146+
exact ⟨s₁ + s₂, Ideal.add_mem _ hs₁mem hs₂mem, by simp [hs₁, hs₂]⟩
147+
· intro r₁ r₂ hr₁ ⟨f, hfmem, hf⟩
148+
exact ⟨r₁ • f, Submodule.smul_of_tower_mem _ _ hfmem, by simp [hf]⟩
149+
150+
open Submodule in
151+
theorem spanFinrank_eq_spanFinrank_map_constantCoeff_of_X_notMem_of_fg_of_isPrime (hI : X ∉ I)
152+
(hfg : I.FG) : spanFinrank I = spanFinrank (I.map constantCoeff) := by
153+
refine le_antisymm ?_ ?_
154+
swap; · exact Ideal.spanFinrank_map_le_of_fg constantCoeff hfg
155+
have : RingHomSurjective (constantCoeff (R := R)) := ⟨constantCoeff_surj⟩
156+
obtain ⟨S, rfl, hS, hScard⟩ := exist_eq_span_eq_ncard_of_X_notMem hI
157+
(I.map constantCoeff).span_generators
158+
(FG.finite_generators <| map_eq_submodule_map constantCoeff I ▸ Submodule.FG.map _ hfg)
159+
refine le_trans (spanFinrank_span_le_ncard_of_finite hS) ?_
160+
rw [hScard, FG.generators_ncard]
161+
exact map_eq_submodule_map constantCoeff (Ideal.span S) ▸ Submodule.FG.map _ hfg
162+
163+
end X_notMem
164+
165+
variable {P : Ideal R⟦X⟧} [P.IsPrime]
166+
167+
open Submodule in
168+
theorem spanFinrank_le_spanFinrank_map_constantCoeff_add_one_of_isPrime :
169+
spanFinrank P ≤ spanFinrank (P.map constantCoeff) + 1 := by
170+
by_cases hfg : P.FG
171+
swap; · exact spanFinrank_of_not_fg hfg ▸ Nat.zero_le _
172+
by_cases hP : X ∈ P
173+
· exact spanFinrank_le_spanFinrank_map_constantCoeff_add_one_of_X_mem hP
174+
· exact le_trans (spanFinrank_eq_spanFinrank_map_constantCoeff_of_X_notMem_of_fg_of_isPrime
175+
hP hfg).le (Nat.le_succ _)
176+
177+
/-- A prime ideal `P` of `R⟦X⟧` is finitely generated if and only if `P.map constantCoeff` is
178+
finitely generated. -/
179+
lemma fg_iff_of_isPrime : P.FG ↔ (P.map constantCoeff).FG := by
180+
constructor
181+
· exact (FG.map · _)
182+
· intro ⟨S, hS⟩
183+
by_cases hX : X ∈ P
184+
· have H := eq_span_insert_X_of_X_mem_of_span_eq hX hS
185+
have : (insert X <| (C (R := R)) '' S).Finite :=
186+
Finite.insert X <| Finite.image _ S.finite_toSet
187+
lift insert X <| (C (R := R)) '' S to Finset R⟦X⟧ using this with T hT
188+
exact ⟨T, hT ▸ H.symm⟩
189+
· obtain ⟨T, hT, hT₂, _⟩ := exist_eq_span_eq_ncard_of_X_notMem hX hS S.finite_toSet
190+
lift T to Finset R⟦X⟧ using hT₂
191+
exact ⟨T, hT.symm⟩
192+
193+
/-- If `R` is noetherian then so is `R⟦X⟧`. -/
194+
instance [IsNoetherianRing R] : IsNoetherianRing R⟦X⟧ :=
195+
IsNoetherianRing.of_prime fun P _ ↦
196+
fg_iff_of_isPrime.2 <| (isNoetherianRing_iff_ideal_fg R).1 inferInstance (P.map constantCoeff)
197+
198+
end PowerSeries

Mathlib/RingTheory/PowerSeries/Trunc.lean

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,29 @@ section Trunc
3737
variable [Semiring R]
3838
open Finset Nat
3939

40-
/-- The `n`th truncation of a formal power series to a polynomial -/
41-
def trunc (n : ℕ) (φ : R⟦X⟧) : R[X] :=
40+
private def trunc_aux (n : ℕ) (φ : R⟦X⟧) : R[X] :=
4241
∑ m ∈ Ico 0 n, Polynomial.monomial m (coeff m φ)
4342

43+
private theorem coeff_trunc_aux (m) (n) (φ : R⟦X⟧) :
44+
(trunc_aux n φ).coeff m = if m < n then coeff m φ else 0 := by
45+
simp [trunc_aux, Polynomial.coeff_monomial]
46+
47+
/-- The `n`th truncation of a formal power series to a polynomial. -/
48+
def trunc (n : ℕ) : R⟦X⟧ →ₗ[R] R[X] where
49+
toFun := trunc_aux n
50+
map_add' φ ψ := Polynomial.ext fun m => by
51+
simp only [coeff_trunc_aux, Polynomial.coeff_add]
52+
split_ifs with H
53+
· rfl
54+
· rw [zero_add]
55+
map_smul' t φ := by ext; simp [trunc_aux, Polynomial.coeff_monomial]
56+
57+
lemma trunc_apply (n : ℕ) (φ : R⟦X⟧) :
58+
trunc n φ = ∑ m ∈ Ico 0 n, Polynomial.monomial m (coeff m φ) := rfl
59+
4460
theorem coeff_trunc (m) (n) (φ : R⟦X⟧) :
4561
(trunc n φ).coeff m = if m < n then coeff m φ else 0 := by
46-
simp [trunc, Polynomial.coeff_monomial]
47-
48-
@[simp]
49-
theorem trunc_zero (n) : trunc n (0 : R⟦X⟧) = 0 :=
50-
Polynomial.ext fun m => by
51-
rw [coeff_trunc, LinearMap.map_zero, Polynomial.coeff_zero]
52-
split_ifs <;> rfl
62+
simp [trunc, coeff_trunc_aux]
5363

5464
@[simp]
5565
theorem trunc_one (n) : trunc (n + 1) (1 : R⟦X⟧) = 1 :=
@@ -62,17 +72,9 @@ theorem trunc_C (n) (a : R) : trunc (n + 1) (C a) = Polynomial.C a :=
6272
rw [coeff_trunc, coeff_C, Polynomial.coeff_C]
6373
split_ifs with H <;> first | rfl | try simp_all
6474

65-
@[simp]
66-
theorem trunc_add (n) (φ ψ : R⟦X⟧) : trunc n (φ + ψ) = trunc n φ + trunc n ψ :=
67-
Polynomial.ext fun m => by
68-
simp only [coeff_trunc, Polynomial.coeff_add]
69-
split_ifs with H
70-
· rfl
71-
· rw [zero_add]
72-
7375
theorem trunc_succ (f : R⟦X⟧) (n : ℕ) :
7476
trunc n.succ f = trunc n f + Polynomial.monomial n (coeff n f) := by
75-
rw [trunc, Ico_zero_eq_range, sum_range_succ, trunc, Ico_zero_eq_range]
77+
rw [trunc_apply, Ico_zero_eq_range, sum_range_succ, trunc_apply, Ico_zero_eq_range]
7678

7779
theorem natDegree_trunc_lt (f : R⟦X⟧) (n) : (trunc (n + 1) f).natDegree < n + 1 := by
7880
rw [Nat.lt_succ_iff, natDegree_le_iff_coeff_eq_zero]
@@ -155,6 +157,13 @@ lemma eq_X_pow_mul_shift_add_trunc (n : ℕ) (f : R⟦X⟧) :
155157
f = X ^ n * (mk fun i ↦ coeff (i + n) f) + (f.trunc n : R⟦X⟧) := by
156158
rw [← (commute_X_pow _ n).eq, ← eq_shift_mul_X_pow_add_trunc]
157159

160+
lemma monomial_eq_C_mul_X_pow (r : R) (n : ℕ) : monomial n r = C r * X ^ n := by
161+
ext; simp [coeff_X_pow, coeff_monomial]
162+
163+
@[simp]
164+
lemma trunc_X_pow_self_mul (n : ℕ) (p : R⟦X⟧) : (X ^ n * p).trunc n = 0 := by
165+
ext; simp +contextual [coeff_trunc, coeff_X_pow_mul']
166+
158167
end Trunc
159168

160169
section Trunc
@@ -237,6 +246,17 @@ theorem coeff_mul_eq_coeff_trunc_mul_trunc {d n} (f g) (h : d < n) :
237246

238247
end Trunc
239248

249+
section Ring
250+
251+
variable [Ring R]
252+
253+
@[simp]
254+
lemma trunc_sub (n : ℕ) (φ ψ : R⟦X⟧) : trunc n (φ - ψ) = trunc n φ - trunc n ψ := by
255+
ext i
256+
simp
257+
258+
end Ring
259+
240260
section Map
241261
variable {S : Type*} [Semiring R] [Semiring S] (f : R →+* S)
242262

0 commit comments

Comments
 (0)