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

Commit 0b0d8e7

Browse files
committed
refactor(ring_theory): turn localization_map into a typeclass (#8119)
This PR replaces the previous `localization_map (M : submodule R) Rₘ` definition (a ring hom `R →+* Rₘ` that presents `Rₘ` as the localization of `R` at `M`) with a new `is_localization M Rₘ` typeclass that puts these requirements on `algebra_map R Rₘ` instead. An important benefit is that we no longer need to mess with `localization_map.codomain` to put an `R`-algebra structure on `Rₘ`, we can just work with `Rₘ` directly. The important API changes are in commit 0de78dc, all other commits are simply fixes to the dependent files. Main changes: * `localization_map` has been replaced with `is_localization`, similarly `away_map` -> `is_localization.away`, `localization_map.at_prime` -> `is_localization.at_prime` and `fraction_map` -> `is_fraction_ring` * many declarations taking the `localization_map` as a parameter now take `R` and/or `M` and/or `Rₘ`, depending on what can be inferred easily * `localization_map.to_map` has been replaced with `algebra_map R Rₘ` * `localization_map.codomain` and its instances have been removed (you can now directly use `Rₘ`) * `is_localization.alg_equiv` generalizes `fraction_map.alg_equiv_of_quotient` (which has been renamed to `is_fraction_ring.alg_equiv`) * `is_localization.sec` has been introduced to replace `(to_localization_map _ _).sec` * `localization.of` have been replaced with `algebra` and `is_localization` instances on `localization`, similarly for `localization.away.of`, `localization.at_prime.of` and `fraction_ring.of`. * `int.fraction_map` is now an instance `rat.is_fraction_ring` * All files depending on the above definitions have had fixes. These were mostly straightforward, except: * [Some category-theory arrows in `algebraic_geometry/structure.sheaf` are now plain `ring_hom`s. This change was suggested by @justus-springer in order to help the elaborator figure out the arguments to `is_localization`.](cf3acc9) * Deleted `minpoly.over_int_eq_over_rat` and `minpoly.integer_dvd`, now you can just use `gcd_domain_eq_field_fractions` or `gcd_domain_dvd` respectively. [This removes code duplication in `minpoly.lean`](5695924) * `fractional_ideal` does not need to assume `is_localization` everywhere, only for certain specific definitions Things that stay the same: * `localization`, `localization.away`, `localization.at_prime` and `fraction_ring` are still a construction of localizations (although see above for `{localization,localization.away,localization.at_prime,fraction_ring}.of`) Zulip thread: https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/Refactoring.20.60localization_map.60
1 parent 6bad4c6 commit 0b0d8e7

File tree

16 files changed

+1667
-1564
lines changed

16 files changed

+1667
-1564
lines changed

docs/overview.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ General algebra:
104104
algebraically closed field: 'is_alg_closed'
105105
existence of algebraic closure of a field: 'algebraic_closure'
106106
$\C$ is algebraically closed: 'complex.exists_root'
107-
field of fractions of an integral domain: 'fraction_map'
107+
field of fractions of an integral domain: 'is_fraction_ring'
108108
algebraic extension: 'algebra.is_algebraic'
109109
rupture field: 'adjoin_root'
110110
splitting field: 'polynomial.splitting_field'

docs/undergrad.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ Ring Theory:
178178
field $\R$ of real numbers: 'real.division_ring'
179179
field $\C$ of complex numbers: 'complex.field'
180180
$\C$ is algebraically closed: 'complex.exists_root'
181-
field of fractions of an integral domain: 'fraction_map'
181+
field of fractions of an integral domain: 'is_fraction_ring'
182182
algebraic elements: 'is_algebraic'
183183
transcendental elements: 'transcendental'
184184
algebraic extensions: 'algebra.is_algebraic'

src/algebra/char_p/algebra.lean

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,25 @@ char_zero_of_injective_algebra_map free_algebra.algebra_map_left_inverse.injecti
6868

6969
end free_algebra
7070

71-
namespace fraction_ring
71+
namespace is_fraction_ring
7272

73-
variables {R : Type*} [integral_domain R] (p : ℕ)
73+
variables (R : Type*) {K : Type*} [integral_domain R] [field K] [algebra R K] [is_fraction_ring R K]
74+
variables (p : ℕ)
75+
76+
/-- If `R` has characteristic `p`, then so does Frac(R). -/
77+
lemma char_p_of_is_fraction_ring [char_p R p] : char_p K p :=
78+
char_p_of_injective_algebra_map (is_fraction_ring.injective R K) p
7479

7580
/-- If `R` has characteristic `p`, then so does `fraction_ring R`. -/
7681
instance char_p [char_p R p] : char_p (fraction_ring R) p :=
77-
char_p_of_injective_algebra_map (fraction_map.injective (fraction_ring.of R)) p
82+
char_p_of_is_fraction_ring R p
83+
84+
/-- If `R` has characteristic `0`, then so does Frac(R). -/
85+
lemma char_zero_of_is_fraction_ring [char_zero R] : char_zero K :=
86+
@char_p.char_p_to_char_zero K _ (char_p_of_is_fraction_ring R 0)
7887

7988
/-- If `R` has characteristic `0`, then so does `fraction_ring R`. -/
8089
instance char_zero [char_zero R] : char_zero (fraction_ring R) :=
81-
char_p.char_p_to_char_zero (fraction_ring R)
90+
char_zero_of_is_fraction_ring R
8291

83-
end fraction_ring
92+
end is_fraction_ring

src/algebraic_geometry/structure_sheaf.lean

Lines changed: 75 additions & 57 deletions
Large diffs are not rendered by default.

src/field_theory/minpoly.lean

Lines changed: 15 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -325,67 +325,34 @@ section gcd_domain
325325

326326
/-- For GCD domains, the minimal polynomial over the ring is the same as the minimal polynomial
327327
over the fraction field. -/
328-
lemma gcd_domain_eq_field_fractions {A K R : Type*} [integral_domain A]
329-
[gcd_monoid A] [field K] [integral_domain R] (f : fraction_map A K) [algebra f.codomain R]
330-
[algebra A R] [is_scalar_tower A f.codomain R] {x : R} (hx : is_integral A x) :
331-
minpoly f.codomain x = (minpoly A x).map (localization_map.to_ring_hom f) :=
328+
lemma gcd_domain_eq_field_fractions {A R : Type*} (K : Type*) [integral_domain A]
329+
[gcd_monoid A] [field K] [integral_domain R] [algebra A K] [is_fraction_ring A K]
330+
[algebra K R] [algebra A R] [is_scalar_tower A K R] {x : R} (hx : is_integral A x) :
331+
minpoly K x = (minpoly A x).map (algebra_map A K) :=
332332
begin
333333
symmetry,
334334
refine unique' _ _ _,
335-
{ exact (polynomial.is_primitive.irreducible_iff_irreducible_map_fraction_map f
336-
(polynomial.monic.is_primitive (monic hx))).1 (irreducible hx) },
337-
{ have htower := is_scalar_tower.aeval_apply A f.codomain R x (minpoly A x),
338-
simp only [localization_map.algebra_map_eq, aeval] at htower,
339-
exact htower.symm },
340-
{ exact monic_map _ (monic hx) }
341-
end
342-
343-
/-- The minimal polynomial over `ℤ` is the same as the minimal polynomial over `ℚ`. -/
344-
--TODO use `gcd_domain_eq_field_fractions` directly when localizations are defined
345-
-- in terms of algebras instead of `ring_hom`s
346-
lemma over_int_eq_over_rat {A : Type*} [integral_domain A] {x : A} [hℚA : algebra ℚ A]
347-
(hx : is_integral ℤ x) :
348-
minpoly ℚ x = map (int.cast_ring_hom ℚ) (minpoly ℤ x) :=
349-
begin
350-
symmetry,
351-
refine unique' _ _ _,
352-
{ exact (is_primitive.int.irreducible_iff_irreducible_map_cast
353-
(polynomial.monic.is_primitive (monic hx))).1 (irreducible hx) },
354-
{ have htower := is_scalar_tower.aeval_apply ℤ ℚ A x (minpoly ℤ x),
355-
simp only [localization_map.algebra_map_eq, aeval] at htower,
356-
exact htower.symm },
335+
{ exact (polynomial.is_primitive.irreducible_iff_irreducible_map_fraction_map
336+
(polynomial.monic.is_primitive (monic hx))).1 (irreducible hx) },
337+
{ have htower := is_scalar_tower.aeval_apply A K R x (minpoly A x),
338+
rwa [aeval, eq_comm] at htower },
357339
{ exact monic_map _ (monic hx) }
358340
end
359341

360342
/-- For GCD domains, the minimal polynomial divides any primitive polynomial that has the integral
361343
element as root. -/
362-
lemma gcd_domain_dvd {A K R : Type*}
363-
[integral_domain A] [gcd_monoid A] [field K] [integral_domain R]
364-
(f : fraction_map A K) [algebra f.codomain R] [algebra A R] [is_scalar_tower A f.codomain R]
344+
lemma gcd_domain_dvd {A R : Type*} (K : Type*)
345+
[integral_domain A] [gcd_monoid A] [field K] [integral_domain R] [algebra A K]
346+
[is_fraction_ring A K] [algebra K R] [algebra A R] [is_scalar_tower A K R]
365347
{x : R} (hx : is_integral A x)
366348
{P : polynomial A} (hprim : is_primitive P) (hroot : polynomial.aeval x P = 0) :
367349
minpoly A x ∣ P :=
368350
begin
369-
apply (is_primitive.dvd_iff_fraction_map_dvd_fraction_map f
370-
(monic.is_primitive (monic hx)) hprim ).2,
371-
rw [← gcd_domain_eq_field_fractions f hx],
372-
refine dvd _ _ _,
373-
rwa [← localization_map.algebra_map_eq, ← is_scalar_tower.aeval_apply]
374-
end
375-
376-
/-- The minimal polynomial over `ℤ` divides any primitive polynomial that has the integral element
377-
as root. -/
378-
-- TODO use `gcd_domain_dvd` directly when localizations are defined in terms of algebras
379-
-- instead of `ring_hom`s
380-
lemma integer_dvd {A : Type*} [integral_domain A] [algebra ℚ A] {x : A} (hx : is_integral ℤ x)
381-
{P : polynomial ℤ} (hprim : is_primitive P) (hroot : polynomial.aeval x P = 0) :
382-
minpoly ℤ x ∣ P :=
383-
begin
384-
apply (is_primitive.int.dvd_iff_map_cast_dvd_map_cast _ _
385-
(monic.is_primitive (monic hx)) hprim ).2,
386-
rw [← over_int_eq_over_rat hx],
351+
apply (is_primitive.dvd_iff_fraction_map_dvd_fraction_map K
352+
(monic.is_primitive (monic hx)) hprim).2,
353+
rw ← gcd_domain_eq_field_fractions K hx,
387354
refine dvd _ _ _,
388-
rwa [(int.cast_ring_hom ℚ).ext_int (algebra_map ℤ ℚ), ← is_scalar_tower.aeval_apply]
355+
rwa ← is_scalar_tower.aeval_apply
389356
end
390357

391358
end gcd_domain

src/ring_theory/dedekind_domain.lean

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ dedekind domain, dedekind ring
4242

4343
variables (R A K : Type*) [comm_ring R] [integral_domain A] [field K]
4444

45+
local notation R`⁰`:9000 := non_zero_divisors R
46+
4547
/-- A ring `R` has Krull dimension at most one if all nonzero prime ideals are maximal. -/
4648
def ring.dimension_le_one : Prop :=
4749
∀ p ≠ (⊥ : ideal R), p.is_prime → p.is_maximal
@@ -82,16 +84,14 @@ class is_dedekind_domain : Prop :=
8284
/-- An integral domain is a Dedekind domain iff and only if it is not a field, is
8385
Noetherian, has dimension ≤ 1, and is integrally closed in a given fraction field.
8486
In particular, this definition does not depend on the choice of this fraction field. -/
85-
lemma is_dedekind_domain_iff (f : fraction_map A K) :
87+
lemma is_dedekind_domain_iff (K : Type*) [field K] [algebra A K] [is_fraction_ring A K] :
8688
is_dedekind_domain A ↔
8789
(¬ is_field A) ∧ is_noetherian_ring A ∧ dimension_le_one A ∧
88-
integral_closure A f.codomain = ⊥ :=
90+
integral_closure A K = ⊥ :=
8991
⟨λ ⟨hf, hr, hd, hi⟩, ⟨hf, hr, hd,
90-
by rw [←integral_closure_map_alg_equiv (fraction_ring.alg_equiv_of_quotient f),
91-
hi, algebra.map_bot]⟩,
92+
by rw [←integral_closure_map_alg_equiv (fraction_ring.alg_equiv A K), hi, algebra.map_bot]⟩,
9293
λ ⟨hf, hr, hd, hi⟩, ⟨hf, hr, hd,
93-
by rw [←integral_closure_map_alg_equiv (fraction_ring.alg_equiv_of_quotient f).symm,
94-
hi, algebra.map_bot]⟩⟩
94+
by rw [←integral_closure_map_alg_equiv (fraction_ring.alg_equiv A K).symm, hi, algebra.map_bot]⟩⟩
9595

9696
/--
9797
A Dedekind domain is an integral domain that is not a field, is Noetherian, and the
@@ -110,25 +110,25 @@ section inverse
110110

111111
open_locale classical
112112

113-
variables {R₁ : Type*} [integral_domain R₁] {g : fraction_map R₁ K}
114-
variables {I J : fractional_ideal g}
113+
variables {R₁ : Type*} [integral_domain R₁] [algebra R₁ K] [is_fraction_ring R₁ K]
114+
variables {I J : fractional_ideal R₁⁰ K}
115115

116-
noncomputable instance : has_inv (fractional_ideal g) := ⟨λ I, 1 / I⟩
116+
noncomputable instance : has_inv (fractional_ideal R₁⁰ K) := ⟨λ I, 1 / I⟩
117117

118118
lemma inv_eq : I⁻¹ = 1 / I := rfl
119119

120-
lemma inv_zero' : (0 : fractional_ideal g)⁻¹ = 0 := fractional_ideal.div_zero
120+
lemma inv_zero' : (0 : fractional_ideal R₁⁰ K)⁻¹ = 0 := fractional_ideal.div_zero
121121

122-
lemma inv_nonzero {J : fractional_ideal g} (h : J ≠ 0) :
123-
J⁻¹ = ⟨(1 : fractional_ideal g) / J, fractional_ideal.fractional_div_of_nonzero h⟩ :=
122+
lemma inv_nonzero {J : fractional_ideal R₁⁰ K} (h : J ≠ 0) :
123+
J⁻¹ = ⟨(1 : fractional_ideal R₁⁰ K) / J, fractional_ideal.fractional_div_of_nonzero h⟩ :=
124124
fractional_ideal.div_nonzero _
125125

126-
lemma coe_inv_of_nonzero {J : fractional_ideal g} (h : J ≠ 0) :
127-
(↑J⁻¹ : submodule R₁ g.codomain) = g.coe_submodule 1 / J :=
126+
lemma coe_inv_of_nonzero {J : fractional_ideal R₁⁰ K} (h : J ≠ 0) :
127+
(↑J⁻¹ : submodule R₁ K) = is_localization.coe_submodule K 1 / J :=
128128
by { rwa inv_nonzero _, refl, assumption}
129129

130130
/-- `I⁻¹` is the inverse of `I` if `I` has an inverse. -/
131-
theorem right_inverse_eq (I J : fractional_ideal g) (h : I * J = 1) :
131+
theorem right_inverse_eq (I J : fractional_ideal R₁⁰ K) (h : I * J = 1) :
132132
J = I⁻¹ :=
133133
begin
134134
have hI : I ≠ 0 := fractional_ideal.ne_zero_of_mul_eq_one I J h,
@@ -148,27 +148,27 @@ begin
148148
exact fractional_ideal.mul_mem_mul hx hy
149149
end
150150

151-
theorem mul_inv_cancel_iff {I : fractional_ideal g} :
151+
theorem mul_inv_cancel_iff {I : fractional_ideal R₁⁰ K} :
152152
I * I⁻¹ = 1 ↔ ∃ J, I * J = 1 :=
153-
⟨λ h, ⟨I⁻¹, h⟩, λ ⟨J, hJ⟩, by rwa [← @right_inverse_eq _ _ _ _ _ I J hJ]
153+
⟨λ h, ⟨I⁻¹, h⟩, λ ⟨J, hJ⟩, by rwa right_inverse_eq K I J hJ⟩
154154

155-
variables {K' : Type*} [field K'] {g' : fraction_map R₁ K'}
155+
variables {K' : Type*} [field K'] [algebra R₁ K'] [is_fraction_ring R₁ K']
156156

157-
@[simp] lemma map_inv (I : fractional_ideal g) (h : g.codomain ≃ₐ[R₁] g'.codomain) :
158-
(I⁻¹).map (h : g.codomain →ₐ[R₁] g'.codomain) = (I.map h)⁻¹ :=
157+
@[simp] lemma map_inv (I : fractional_ideal R₁⁰ K) (h : K ≃ₐ[R₁] K') :
158+
(I⁻¹).map (h : K →ₐ[R₁] K') = (I.map h)⁻¹ :=
159159
by rw [inv_eq, fractional_ideal.map_div, fractional_ideal.map_one, inv_eq]
160160

161161
open_locale classical
162162

163163
open submodule submodule.is_principal
164164

165-
@[simp] lemma span_singleton_inv (x : g.codomain) :
166-
(fractional_ideal.span_singleton x)⁻¹ = fractional_ideal.span_singleton (x⁻¹) :=
165+
@[simp] lemma span_singleton_inv (x : K) :
166+
(fractional_ideal.span_singleton R₁⁰ x)⁻¹ = fractional_ideal.span_singleton _ (x⁻¹) :=
167167
fractional_ideal.one_div_span_singleton x
168168

169-
lemma mul_generator_self_inv (I : fractional_ideal g)
170-
[submodule.is_principal (I : submodule R₁ g.codomain)] (h : I ≠ 0) :
171-
I * fractional_ideal.span_singleton (generator (I : submodule R₁ g.codomain))⁻¹ = 1 :=
169+
lemma mul_generator_self_inv (I : fractional_ideal R₁⁰ K)
170+
[submodule.is_principal (I : submodule R₁ K)] (h : I ≠ 0) :
171+
I * fractional_ideal.span_singleton _ (generator (I : submodule R₁ K))⁻¹ = 1 :=
172172
begin
173173
-- Rewrite only the `I` that appears alone.
174174
conv_lhs { congr, rw fractional_ideal.eq_span_singleton_of_principal I },
@@ -180,16 +180,16 @@ begin
180180
fractional_ideal.span_singleton_zero]
181181
end
182182

183-
lemma invertible_of_principal (I : fractional_ideal g)
184-
[submodule.is_principal (I : submodule R₁ g.codomain)] (h : I ≠ 0) :
183+
lemma invertible_of_principal (I : fractional_ideal R₁⁰ K)
184+
[submodule.is_principal (I : submodule R₁ K)] (h : I ≠ 0) :
185185
I * I⁻¹ = 1 :=
186186
(fractional_ideal.mul_div_self_cancel_iff).mpr
187-
⟨fractional_ideal.span_singleton (generator (I : submodule R₁ g.codomain))⁻¹,
188-
@mul_generator_self_inv _ _ _ _ _ I _ h⟩
187+
⟨fractional_ideal.span_singleton _ (generator (I : submodule R₁ K))⁻¹,
188+
mul_generator_self_inv _ I h⟩
189189

190-
lemma invertible_iff_generator_nonzero (I : fractional_ideal g)
191-
[submodule.is_principal (I : submodule R₁ g.codomain)] :
192-
I * I⁻¹ = 1 ↔ generator (I : submodule R₁ g.codomain) ≠ 0 :=
190+
lemma invertible_iff_generator_nonzero (I : fractional_ideal R₁⁰ K)
191+
[submodule.is_principal (I : submodule R₁ K)] :
192+
I * I⁻¹ = 1 ↔ generator (I : submodule R₁ K) ≠ 0 :=
193193
begin
194194
split,
195195
{ intros hI hg,
@@ -200,21 +200,21 @@ begin
200200
apply invertible_of_principal,
201201
rw [fractional_ideal.eq_span_singleton_of_principal I],
202202
intro hI,
203-
have := fractional_ideal.mem_span_singleton_self (generator (I : submodule R₁ g.codomain)),
203+
have := fractional_ideal.mem_span_singleton_self _ (generator (I : submodule R₁ K)),
204204
rw [hI, fractional_ideal.mem_zero_iff] at this,
205205
contradiction }
206206
end
207207

208-
lemma is_principal_inv (I : fractional_ideal g)
209-
[submodule.is_principal (I : submodule R₁ g.codomain)] (h : I ≠ 0) :
208+
lemma is_principal_inv (I : fractional_ideal R₁⁰ K)
209+
[submodule.is_principal (I : submodule R₁ K)] (h : I ≠ 0) :
210210
submodule.is_principal (I⁻¹).1 :=
211211
begin
212212
rw [fractional_ideal.val_eq_coe, fractional_ideal.is_principal_iff],
213-
use (generator (I : submodule R₁ g.codomain))⁻¹,
214-
have hI : I * fractional_ideal.span_singleton ((generator (I : submodule R₁ g.codomain))⁻¹) = 1,
215-
apply @mul_generator_self_inv _ _ _ _ _ I _ h,
216-
apply (@right_inverse_eq _ _ _ _ _ I (fractional_ideal.span_singleton
217-
( (generator (I : submodule R₁ g.codomain))⁻¹)) hI).symm,
213+
use (generator (I : submodule R₁ K))⁻¹,
214+
have hI : I * fractional_ideal.span_singleton _ ((generator (I : submodule R₁ K))⁻¹) = 1,
215+
apply mul_generator_self_inv _ I h,
216+
exact (right_inverse_eq _ I (fractional_ideal.span_singleton _
217+
((generator (I : submodule R₁ K))⁻¹)) hI).symm
218218
end
219219

220220
/--
@@ -226,22 +226,22 @@ TODO: prove the equivalence.
226226
-/
227227
structure is_dedekind_domain_inv : Prop :=
228228
(not_is_field : ¬ is_field A)
229-
(mul_inv_cancel : ∀ I ≠ (⊥ : fractional_ideal (fraction_ring.of A)), I * (1 / I) = 1)
229+
(mul_inv_cancel : ∀ I ≠ (⊥ : fractional_ideal A⁰ (fraction_ring A)), I * (1 / I) = 1)
230230

231231
open ring.fractional_ideal
232232

233-
lemma is_dedekind_domain_inv_iff (f : fraction_map A K) :
233+
lemma is_dedekind_domain_inv_iff (K : Type*) [field K] [algebra A K] [is_fraction_ring A K] :
234234
is_dedekind_domain_inv A ↔
235-
(¬ is_field A) ∧ (∀ I ≠ (⊥ : fractional_ideal f), I * I⁻¹ = 1) :=
235+
(¬ is_field A) ∧ (∀ I ≠ (⊥ : fractional_ideal A⁰ K), I * I⁻¹ = 1) :=
236236
begin
237-
set h : (fraction_ring.of A).codomain ≃ₐ[A] f.codomain := fraction_ring.alg_equiv_of_quotient f,
237+
set h : fraction_ring A ≃ₐ[A] K := fraction_ring.alg_equiv A K,
238238
split; rintros ⟨hf, hi⟩; use hf; intros I hI,
239239
{ have := hi (map ↑h.symm I) (map_ne_zero _ hI),
240-
convert congr_arg (map (h : (fraction_ring.of A).codomain →ₐ[A] f.codomain)) this;
240+
convert congr_arg (map (h : fraction_ring A →ₐ[A] K)) this;
241241
simp only [map_symm_map, map_one, fractional_ideal.map_mul, fractional_ideal.map_div,
242242
inv_eq] },
243243
{ have := hi (map ↑h I) (map_ne_zero _ hI),
244-
convert congr_arg (map (h.symm : f.codomain →ₐ[A] (fraction_ring.of A).codomain)) this;
244+
convert congr_arg (map (h.symm : K →ₐ[A] fraction_ring A)) this;
245245
simp only [map_map_symm, map_one, fractional_ideal.map_mul, fractional_ideal.map_div,
246246
inv_eq] },
247247
end

0 commit comments

Comments
 (0)