Lean sources / SurfaceBlowup / Measure / Normalizer.lean

Generator normalization and residue-ideal counts

381 lines · 9 public declarations · raw file · declaration index

1/-2Copyright (c) 2026 Asvin G, Claude (Anthropic), GPT-6-Astra (OpenAI). All rights reserved.3Released under Apache 2.0 license as described in the file LICENSE.4Authors: Asvin G, Claude (Anthropic), GPT-6-Astra (OpenAI)5-/6import SurfaceBlowup.Blowup.CurveOrders7import SurfaceBlowup.Surfaces.TruncatedSeries8 9/-!10# Generator normalization and residue-ideal counts11 12We study the normal form `(1 + π u) (f + π Σ zᵢ bᵢ) = f + π h` of a perturbed generator, show that13it is unique, continuous for the `π`-adic topology and injective on coordinates, and count the14residue ideals of a crossing state `k⟦T, X⟧ ⧸ (T^a X^b)` with prescribed contacts. We also collect15length/cardinality relations for finite modules over local rings with finite residue field.16 17## Main results18 19* `unique_scaled_generator_normalization`20* `coordinate_ideal_injective`21* `crossing_residue_ideal_count`22* `crossing_state_volume`23* `finite_module_length_card`24* `pi_mul_cokernel_length`25 26Provenance: normalizer_inverse_equation, normalizer_generator_equation,27normalizer_preserves_adic_congruence, coordinate_transition_congruence,28unique_scaled_generator_normalization, coordinate_ideal_injective, crossing_residue_ideal_count,29crossing_state_volume, finite_module_length_card, length_scaling_of_residue_card,30pi_module_length_sum, pi_mul_cokernel_length.31-/32 33open scoped BigOperators ENNReal34 35namespace SurfaceBlowup36 37/-- The generator normal form of `h` is the preimage of `E h` under the adic perturbation by38  `coordinateRemainder pi b E`. -/39private theorem normalizer_inverse_equation (O R : Type) [CommRing O] [CommRing R] [Algebra O R]40    (n : ℕ)41    (pi : O) (b : Fin n → R) (E : R ≃ₗ[O] ((Fin n → O) × R))42    [IsAdicComplete (Ideal.span {pi}) ((Fin n → O) × R)] (h : R) :43    adicPerturb (coordinateRemainder pi b E) (generatorNormalForm pi b E h) = E h := by44  have hb := adic_perturb_bijective O ((Fin n → O) × R) (Ideal.span {pi})45    (coordinateRemainder pi b E)46    (coordinate_remainder_raises_order O R n pi b E)47  exact Function.rightInverse_invFun hb.2 (E h)48 49/-- The normal-form coordinates `(z, u)` of `h` satisfy `(1 + π u) (f + π Σ zᵢ bᵢ) = f + π h`. -/50theorem normalizer_generator_equation (O R : Type) [CommRing O] [CommRing R] [Algebra O R] (n : ℕ)51    (pi : O) (b : Fin n → R) (E : R ≃ₗ[O] ((Fin n → O) × R))52    [IsAdicComplete (Ideal.span {pi}) ((Fin n → O) × R)] (f : R)53    (hE : ∀ s, E.symm s = divisionMap f b s) (h : R) :54    (1 + pi • (generatorNormalForm pi b E h).2) *55      (f + pi • coordinateLift b (generatorNormalForm pi b E h).1) = f + pi • h := by56  rw [scaled_normalization_identity O R n pi f b E hE,57    normalizer_inverse_equation O R n pi b E h, LinearEquiv.symm_apply_apply]58 59/-- The generator normal form preserves congruence modulo `(π)^j`. -/60private theorem normalizer_preserves_adic_congruence (O R : Type) [CommRing O] [CommRing R]Lemma 3.161    [Algebra O R]62    (n : ℕ) (pi : O) (b : Fin n → R) (E : R ≃ₗ[O] ((Fin n → O) × R))63    [IsAdicComplete (Ideal.span {pi}) ((Fin n → O) × R)] (j : ℕ) (h k : R)64    (hhk : adicCongr (Ideal.span {pi}) j h k) :65    adicCongr (Ideal.span {pi}) j (generatorNormalForm pi b E h)66      (generatorNormalForm pi b E k) := by67  have hE := linear_map_preserves_adic_congruence O R ((Fin n → O) × R)68    (Ideal.span {pi}) E.toLinearMap j h k hhk69  simp only [LinearEquiv.coe_coe] at hE70  rw [← normalizer_inverse_equation O R n pi b E h,71    ← normalizer_inverse_equation O R n pi b E k] at hE72  exact (adic_perturb_congruence_iff O ((Fin n → O) × R) (Ideal.span {pi})73    (coordinateRemainder pi b E)74    (coordinate_remainder_raises_order O R n pi b E) j _ _).mp hE75 76/-- The transition between the coordinates of two normalizations preserves congruence modulo77  `(π)^j`. -/78theorem coordinate_transition_congruence (O R : Type) [CommRing O] [CommRing R] [Algebra O R]Lemma 3.179    (n : ℕ) (pi : O) (b : Fin n → R)80    [IsAdicComplete (Ideal.span {pi}) ((Fin n → O) × R)] (c : Fin n → R)81    (F : R ≃ₗ[O] ((Fin n → O) × R)) (h0 : R) (j : ℕ) (z w : Fin n → O)82    (hzw : adicCongr (Ideal.span {pi}) j z w) :83    adicCongr (Ideal.span {pi}) j (idealTransition pi b c F h0 z)84      (idealTransition pi b c F h0 w) := by85  let L : (Fin n → O) →ₗ[O] R :=86    { toFun := fun z => coordinateLift b z87      map_add' := by88        intro x y89        simp [coordinateLift, add_smul, Finset.sum_add_distrib]90      map_smul' := by91        intro r x92        simp [coordinateLift, Finset.smul_sum, smul_smul] }93  have h1 := linear_map_preserves_adic_congruence O _ _ (Ideal.span {pi}) L j z w hzw94  have h2 : adicCongr (Ideal.span {pi}) j (h0 + coordinateLift b z) (h0 + coordinateLift b w) := by95    unfold adicCongr at h1 ⊢96    have : h0 + coordinateLift b z - (h0 + coordinateLift b w) = L z - L w := by97      simp only [add_sub_add_left_eq_sub]; rfl98    rw [this]; exact h199  have h3 := normalizer_preserves_adic_congruence O R n pi c F j _ _ h2100  exact linear_map_preserves_adic_congruence O _ _ (Ideal.span {pi})101    (LinearMap.fst O (Fin n → O) R) j _ _ h3102 103/-- Every `f + π h` is uniquely of the form `(1 + π u) (f + π Σ zᵢ bᵢ)`. -/104theorem unique_scaled_generator_normalization (O R : Type) [CommRing O] [CommRing R] [Algebra O R]Lemma 3.1105    (n : ℕ) [IsDomain R] (pi : O) (hpi : algebraMap O R pi ≠ 0) (f : R) (b : Fin n → R)106    (E : R ≃ₗ[O] ((Fin n → O) × R)) (hE : ∀ s, E.symm s = divisionMap f b s)107    [IsAdicComplete (Ideal.span {pi}) ((Fin n → O) × R)] (h : R) :108    ∃! s : (Fin n → O) × R, (1 + pi • s.2) * (f + pi • coordinateLift b s.1) = f + pi • h := by109  have hbij := adic_perturb_bijective O _ (Ideal.span {pi})110    (coordinateRemainder pi b E)111    (coordinate_remainder_raises_order O R n pi b E)112  have key : ∀ s : (Fin n → O) × R,113      (1 + pi • s.2) * (f + pi • coordinateLift b s.1) = f + pi • h ↔114        adicPerturb (coordinateRemainder pi b E) s = E h := by115    intro s116    rw [scaled_normalization_identity O R n pi f b E hE s]117    constructor118    · intro hs119      have h1 := add_left_cancel hs120      rw [Algebra.smul_def, Algebra.smul_def] at h1121      have h2 := mul_left_cancel₀ hpi h1122      rw [← h2]; simp123    · intro hs124      rw [hs]; simp125  obtain ⟨s, hs⟩ := hbij.2 (E h)126  refine ⟨s, (key s).2 hs, fun t ht => hbij.1 (((key t).1 ht).trans hs.symm)⟩127 128/-- Over a local domain in which `π` is a nonzero nonunit, the normalized ideal129  `coordinateIdeal pi f b z` determines the coordinates `z`. -/130theorem coordinate_ideal_injective (O R : Type) [CommRing O] [CommRing R] [Algebra O R] (n : ℕ)131    (pi : O) (b : Fin n → R) (E : R ≃ₗ[O] ((Fin n → O) × R))132    [IsAdicComplete (Ideal.span {pi}) ((Fin n → O) × R)] [IsDomain R] [IsLocalRing R]133    (hp0 : algebraMap O R pi ≠ 0) (hpm : algebraMap O R pi ∈ IsLocalRing.maximalIdeal R) (f : R)134    (hE : ∀ s, E.symm s = divisionMap f b s)135    (hf : Function.Injective (fun x : R ⧸ Ideal.span {algebraMap O R pi} =>136      x * Ideal.Quotient.mk (Ideal.span {algebraMap O R pi}) f))137    :138    Function.Injective (coordinateIdeal pi f b) := by139  set I := Ideal.span {algebraMap O R pi} with hI140  have hIne : I ≠ ⊤ := by141    intro h142    have : I ≤ IsLocalRing.maximalIdeal R := by143      rw [hI, Ideal.span_le]; simpa using hpm144    exact IsLocalRing.maximalIdeal.isMaximal R |>.ne_top (top_le_iff.mp (h ▸ this))145  have : Nontrivial (R ⧸ I) := Ideal.Quotient.nontrivial_iff.mpr hIne146  have hfbar : Ideal.Quotient.mk I f ≠ 0 := by147    intro h0148    have := @hf 0 1 (by simp [h0])149    exact zero_ne_one this150  have hmk : ∀ z : Fin n → O,151      Ideal.Quotient.mk I (f + pi • coordinateLift b z) = Ideal.Quotient.mk I f := by152    intro z153    rw [Ideal.Quotient.eq]154    simp only [add_sub_cancel_left, Algebra.smul_def]155    exact Ideal.mul_mem_right _ _ (Ideal.subset_span rfl)156  intro z1 z2 hz157  simp only [coordinateIdeal, normalizedIdeal, normalizedGenerator, coordinateLift_smul_eq_mul,158    ← Algebra.smul_def] at hz159  have hg1 : f + pi • coordinateLift b z1 ≠ 0 := by160    intro h0161    apply hfbar162    rw [← hmk z1, h0, map_zero]163  obtain ⟨u, hu⟩ := regular_principal_generators_associated R _ _164    (fun x y hxy => mul_right_cancel₀ hg1 hxy) hz165  have hubar : Ideal.Quotient.mk I (u : R) = 1 := by166    apply hf167    have := congrArg (Ideal.Quotient.mk I) hu168    rw [map_mul, hmk, hmk] at this169    simpa using this.symm170  have : (u : R) - 1 ∈ I := by171    rw [← Ideal.Quotient.eq, hubar, map_one]172  obtain ⟨v, hv⟩ := Ideal.mem_span_singleton'.mp this173  obtain ⟨s, _, huniq⟩ := unique_scaled_generator_normalization O R n pi hp0 f b E hE174    (coordinateLift b z2)175  have e1 := huniq (z1, v) (by176    simp only [Algebra.smul_def] at hu ⊢177    rw [hu]; congr 1; linear_combination hv)178  have e2 := huniq (z2, 0) (by simp)179  exact congrArg Prod.fst (e1.trans e2.symm)180 181/-- The number of crossing residue ideals of `k⟦T, X⟧ ⧸ (T^a X^b)` with contacts `c` with `T` and182  `h` with `X` is `(q - 1) q^(ac + bh - c - h)`, where `q = #k`. -/183theorem crossing_residue_ideal_count (k : Type) [Field k] [Finite k] (a b c h : ℕ) (ha : 0 < a)Proposition 3.3184    (hb : 0 < b) (hc : 0 < c) (hh : 0 < h) :185    Nat.card (crossingResidueIdeals k a b c h) = (Nat.card k-1)*(Nat.card k)^(a*c+b*h-c-h) := by186  have hcN : c ≤ a * c := Nat.le_mul_of_pos_left c ha187  have hhN : h ≤ b * h := Nat.le_mul_of_pos_left h hb188  set N := a*c+b*h with hNdef189  let P : TwoSeries k → Prop := fun F => axisQuotientLength k 0 F = c ∧ axisQuotientLength k 1 F = h190  have hlen : ∀ F, P F →191      Module.length (TwoSeries k) (TwoSeries k ⧸ (monomialIdeal k a b ⊔ Ideal.span {F})) = N := by192    intro F hF193    have h5 := length_double_quotient_eq (TwoSeries k) (monomialIdeal k a b) (Ideal.span {F})194    rw [Ideal.map_span, Set.image_singleton] at h5195    rw [← h5, crossing_special_fiber_length k a b c h ha hb _196      (by rw [contact_fiberT_eq_axisQuotientLength k a b ha, hF.1])197      (by rw [contact_fiberX_eq_axisQuotientLength k a b hb, hF.2]), hNdef]198    push_cast; rfl199  have : Finite (IsLocalRing.ResidueField (TwoSeries k)) :=200    .of_equiv _ (twoSeriesResidueEquiv k).toEquiv.symm201  have hmemS : ∀ j < N+1, ((0:ℕ), j) ∈ truncIndex a b (N+1) := by202    intro j hj; simp [truncIndex]; omega203  have hmemS' : ∀ i < N+1, (i, (0:ℕ)) ∈ truncIndex a b (N+1) := by204    intro i hi; simp [truncIndex]; omega205  have hEj : ∀ j, truncExponent ((0:ℕ), j) = Finsupp.single 1 j := by simp [truncExponent]206  have hEi : ∀ i, truncExponent (i, (0:ℕ)) = Finsupp.single 0 i := by simp [truncExponent]207  let A1 : Finset (truncIndex a b (N+1)) := Finset.univ.filter (fun s => s.1.1 = 0 ∧ s.1.2 < c)208  let A2 : Finset (truncIndex a b (N+1)) := Finset.univ.filter (fun s => s.1.2 = 0 ∧ s.1.1 < h)209  let B : Finset (truncIndex a b (N+1)) :=210    {⟨(0,c), hmemS c (by omega)⟩, ⟨(h,0), hmemS' h (by omega)⟩}211  have hA1 : A1.card = c := card_truncIndex_axis_segment a b _ c Prod.fst Prod.snd ((0, ·))212    (fun _ => ⟨rfl, rfl⟩) (fun x h => Prod.ext h.symm rfl) fun j hj => hmemS j (by omega)213  have hA2 : A2.card = h := card_truncIndex_axis_segment a b _ h Prod.snd Prod.fst ((·, 0))214    (fun _ => ⟨rfl, rfl⟩) (fun x h => Prod.ext rfl h.symm) fun i hi => hmemS' i (by omega)215  have hA12 : (A1 ∩ A2).card = 1 := by216    rw [Finset.card_eq_one]; refine ⟨⟨(0,0), hmemS 0 (by omega)⟩, ?_⟩217    ext ⟨⟨i, j⟩, hij⟩218    simp only [A1, A2, Finset.mem_inter, Finset.mem_filter, Finset.mem_univ, true_and,219      Finset.mem_singleton, Subtype.mk.injEq, Prod.mk.injEq]220    omega221  have hA := Finset.card_union_add_card_inter A1 A2222  have hB : B.card = 2 := by223    rw [Finset.card_pair]224    simp only [ne_eq, Subtype.mk.injEq, Prod.mk.injEq]225    omega226  have hAB : Disjoint (A1 ∪ A2) B := by227    rw [Finset.disjoint_left]228    rintro ⟨⟨i, j⟩, hij⟩ hs hs'229    simp only [A1, A2, B, Finset.mem_union, Finset.mem_filter, Finset.mem_univ, true_and,230      Finset.mem_insert, Finset.mem_singleton, Subtype.mk.injEq, Prod.mk.injEq] at hs hs'231    omega232  have hcrit : ∀ F, P F ↔ (∀ s ∈ A1 ∪ A2, truncCoeffs k a b (N+1) F s = 0) ∧233      (∀ s ∈ B, truncCoeffs k a b (N+1) F s ≠ 0) := by234    intro F235    change axisQuotientLength k 0 F = c ∧ axisQuotientLength k 1 F = h ↔ _236    rw [axisQuotientLength_eq_iff k (by decide : (0 : Fin 2) ≠ 1),237      axisQuotientLength_eq_iff k (by decide : (1 : Fin 2) ≠ 0)]238    simp only [B, Finset.mem_insert, Finset.mem_singleton, forall_eq_or_imp, forall_eq,239      truncCoeffs_apply, hEj, hEi]240    constructor241    · rintro ⟨⟨h1, h2⟩, ⟨h1', h2'⟩⟩242      refine ⟨fun ⟨⟨i, j⟩, hij⟩ hs => ?_, h2, h2'⟩243      simp only [A1, A2, Finset.mem_union, Finset.mem_filter, Finset.mem_univ, true_and] at hs244      rcases hs with ⟨rfl, hj⟩ | ⟨rfl, hi⟩245      · rw [hEj]; exact h1 j hj246      · rw [hEi]; exact h1' i hi247    · rintro ⟨h1, h2, h2'⟩248      refine ⟨⟨fun j hj => ?_, h2⟩, ⟨fun i hi => ?_, h2'⟩⟩249      · simpa [hEj] using h1 ⟨(0, j), hmemS j (by omega)⟩ (by simp [A1, hj])250      · simpa [hEi] using h1 ⟨(i, 0), hmemS' i (by omega)⟩ (by simp [A2, hi])251  have key := principal_residue_ideal_count k a b N ha P252    (fun f => contact f (fiberT k a b) = c ∧ contact f (fiberX k a b) = h)253    (fun F => by254      rw [contact_fiberT_eq_axisQuotientLength k a b ha,255        contact_fiberX_eq_axisQuotientLength k a b hb])256    (fun U F hU hF => by257      change axisQuotientLength k 0 _ = c ∧ axisQuotientLength k 1 _ = h258      rwa [axisQuotientLength, axisQuotientLength, Ideal.span_singleton_mul_left_unit hU])259    hlen (fun F hF => by260      rw [finite_length_module_card (TwoSeries k) _ _ (hlen F hF),261        Nat.card_congr (twoSeriesResidueEquiv k).toEquiv])262    (A1 ∪ A2) B hAB (Finset.insert_nonempty _ _) hcrit263  rw [show (A1 ∪ A2).card + B.card - 1 = c + h by omega, hB,264    show N = c + h + (N - c - h) by omega, pow_add _ (c + h)] at key265  have hp : 0 < Nat.card k - 1 := by have := Finite.one_lt_card (α := k); omega266  have hpos : 0 < (Nat.card k - 1) * Nat.card k ^ (c + h) :=267    Nat.mul_pos hp (pow_pos Nat.card_pos _)268  unfold crossingResidueIdeals269  refine Nat.eq_of_mul_eq_mul_left hpos ?_270  rw [sq] at key271  linarith [key]272 273/-- The total state measure of a crossing state with contacts `c` and `h` is `(q - 1) q^(-(c + h))`,274  where `q` is the residue cardinality. -/275theorem crossing_state_volume (O R : Type) [CommRing O] [IsDomain O] [IsDiscreteValuationRing O]Proposition 3.3276    [IsAdicComplete (IsLocalRing.maximalIdeal O) O] [Finite (IsLocalRing.ResidueField O)]277    [TopologicalSpace O] [IsTopologicalRing O] [CompactSpace O] [T2Space O]278    [SecondCountableTopology O] [MeasurableSpace O] [BorelSpace O]279    (htop : IsAdic (IsLocalRing.maximalIdeal O)) [CommRing R] [Algebra O R]280    [MeasurableSpace (Ideal R)] (pi : O) (X : Set (Ideal R))281    (a b c h : ℕ) (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) (hh : 0 < h)282    (A : IdealAtlas O R pi (a * c + b * h) X)283    (hA : ∀ i, Measurable (coordinateIdeal pi (A.chart i).f (A.chart i).b))284    (hcount : Nonempty (A.ι ≃ crossingResidueIdeals (IsLocalRing.ResidueField O) a b c h)) :285    stateMeasure O R pi (a*c+b*h) (Nat.card (IsLocalRing.ResidueField O)) A Set.univ =286      ((Nat.card (IsLocalRing.ResidueField O) : ℝ≥0∞) - 1) *287        (Nat.card (IsLocalRing.ResidueField O) : ℝ≥0∞)⁻¹^(c+h) := by288  rw [state_measure_total_mass O R htop pi (a*c+b*h) X A hA]289  obtain ⟨e⟩ := hcount290  have hcard : Fintype.card A.ι = (Nat.card (IsLocalRing.ResidueField O) - 1) *291      (Nat.card (IsLocalRing.ResidueField O)) ^ (a*c+b*h-c-h) := by292    rw [← Nat.card_eq_fintype_card, Nat.card_congr e]293    exact crossing_residue_ideal_count _ a b c h ha hb hc hh294  rw [hcard]295  set q := Nat.card (IsLocalRing.ResidueField O)296  have hq : 1 ≤ q := Nat.card_pos297  have hN : a*c+b*h = (a*c+b*h-c-h) + (c+h) := by298    have : c ≤ a*c := Nat.le_mul_of_pos_left c ha299    have : h ≤ b*h := Nat.le_mul_of_pos_left h hb300    omega301  have hq0 : (q:ℝ≥0∞) ≠ 0 := by exact_mod_cast (by omega : q ≠ 0)302  have hqt : (q:ℝ≥0∞) ≠ ⊤ := ENNReal.natCast_ne_top q303  set m := a*c+b*h-c-h304  rw [hN, pow_add, Nat.cast_mul, ENNReal.natCast_sub, Nat.cast_pow, Nat.cast_one]305  have : (q:ℝ≥0∞)^m * (q:ℝ≥0∞)⁻¹^m = 1 := by306    rw [← mul_pow, ENNReal.mul_inv_cancel hq0 hqt, one_pow]307  calc ((q:ℝ≥0∞) - 1) * (q:ℝ≥0∞)^m * ((q:ℝ≥0∞)⁻¹^m * (q:ℝ≥0∞)⁻¹^(c+h))308      = ((q:ℝ≥0∞) - 1) * ((q:ℝ≥0∞)^m * (q:ℝ≥0∞)⁻¹^m) * (q:ℝ≥0∞)⁻¹^(c+h) := by ring309    _ = _ := by rw [this, mul_one]310 311/-- A finite module over a local ring with residue field of cardinality `q` has finite length `ℓ`312  and cardinality `q ^ ℓ`. -/313theorem finite_module_length_card (O : Type) [CommRing O] [IsLocalRing O]314    [Finite (IsLocalRing.ResidueField O)] (M : Type) [AddCommGroup M] [Module O M] [Finite M] :315    ∃ ℓ : ℕ, Module.length O M = ℓ ∧ Nat.card M = Nat.card (IsLocalRing.ResidueField O) ^ ℓ := by316  have hN : IsNoetherian O M := isNoetherian_of_finite O M317  have hA : IsArtinian O M := isArtinian_of_finite318  have hF : IsFiniteLength O M := isFiniteLength_iff_isNoetherian_isArtinian.mpr ⟨hN, hA⟩319  have hne : Module.length O M ≠ ⊤ := Module.length_ne_top_iff.mpr hF320  obtain ⟨ℓ, hℓ⟩ := ENat.ne_top_iff_exists.mp hne321  exact ⟨ℓ, hℓ.symm, finite_length_module_card O M ℓ hℓ.symm⟩322 323/-- If `#k(O') = #k(O) ^ δ`, then a module of `O'`-length `ℓ` has `O`-length `δ ℓ`. -/324theorem length_scaling_of_residue_card (O : Type) [CommRing O] [IsLocalRing O]325    [Finite (IsLocalRing.ResidueField O)] (O' : Type) [CommRing O'] [IsLocalRing O']326    [Finite (IsLocalRing.ResidueField O')] (δ : ℕ)327    (hδ : Nat.card (IsLocalRing.ResidueField O') = Nat.card (IsLocalRing.ResidueField O) ^ δ)328    (M : Type) [AddCommGroup M] [Module O M] [Module O' M] (ℓ : ℕ) (hℓ : Module.length O' M = ℓ) :329    Module.length O M = ((δ * ℓ : ℕ) : ℕ∞) := by330  have h1 := finite_length_module_card O' M ℓ hℓ331  have hq : 2 ≤ Nat.card (IsLocalRing.ResidueField O) := by332    have := Finite.one_lt_card (α := IsLocalRing.ResidueField O)333    omega334  have hne : Nat.card M ≠ 0 := by335    rw [h1, hδ, ← pow_mul]336    exact pow_ne_zero _ (by omega)337  have : Finite M := Nat.finite_of_card_ne_zero hne338  obtain ⟨l, hl, hc⟩ := finite_module_length_card O M339  rw [hl]340  congr 1341  rw [h1, hδ, ← pow_mul] at hc342  exact (Nat.pow_right_injective hq hc).symm343 344/-- The length of a finite product of finite-length modules is the sum of the lengths. -/345private theorem pi_module_length_sum (O : Type) [CommRing O] [IsLocalRing O]346    [Finite (IsLocalRing.ResidueField O)] (ι : Type) [Fintype ι] (M : ι → Type)347    [∀ j, AddCommGroup (M j)] [∀ j, Module O (M j)] (ℓ : ι → ℕ)348    (hℓ : ∀ j, Module.length O (M j) = ℓ j) :349    Module.length O (∀ j, M j) = ((∑ j, ℓ j : ℕ) : ℕ∞) := by350  have hc := fun j => finite_length_module_card O (M j) (ℓ j) (hℓ j)351  set q := Nat.card (IsLocalRing.ResidueField O) with hq352  have hq2 : 2 ≤ q := by353    have : Nontrivial (IsLocalRing.ResidueField O) := inferInstance354    have : Finite (IsLocalRing.ResidueField O) := inferInstance355    exact Nat.succ_le_of_lt (Finite.one_lt_card)356  have hfin : ∀ j, Finite (M j) := fun j =>357    Nat.finite_of_card_ne_zero (by rw [hc j]; positivity)358  have : Finite (∀ j, M j) := inferInstance359  obtain ⟨l, hl, hcard⟩ := finite_module_length_card O (∀ j, M j)360  have h2 : Nat.card (∀ j, M j) = q ^ (∑ j, ℓ j) := by361    rw [Nat.card_pi, ← Finset.prod_pow_eq_pow_sum]362    exact Finset.prod_congr rfl (fun j _ => hc j)363  rw [hl]364  have : l = ∑ j, ℓ j := Nat.pow_right_injective hq2 (hcard.symm.trans h2)365  rw [this]366 367/-- The cokernel of multiplication by `e` on `(Π C_j) ⧸ (g)` has length368  `Σ_j length (C_j ⧸ (g_j, e_j))`. -/369theorem pi_mul_cokernel_length (O : Type) [CommRing O] [IsLocalRing O]370    [Finite (IsLocalRing.ResidueField O)] (ι : Type) [Fintype ι] (C : ι → Type)371    [∀ j, CommRing (C j)] [∀ j, Algebra O (C j)] (g e : ∀ j, C j) (ℓ : ι → ℕ)372    (hℓ : ∀ j, Module.length O (C j ⧸ (Ideal.span {g j} ⊔ Ideal.span {e j})) = ℓ j) :373    Module.length O (((∀ j, C j) ⧸ Ideal.span {g}) ⧸374      LinearMap.range (LinearMap.mulLeft O (Ideal.Quotient.mk (Ideal.span {g}) e))) =375      ((∑ j, ℓ j : ℕ) : ℕ∞) := by376  obtain ⟨φ, -⟩ := quotient_mul_range_equiv O (∀ j, C j) (Ideal.span {g}) e377  obtain ⟨-, ψ', -⟩ := pi_quotient_span_linearEquiv O ι C g e378  rw [φ.length_eq, ψ'.length_eq]379  exact pi_module_length_sum O ι _ ℓ hℓ380 381end SurfaceBlowup