From 27c43f3f43dad8e19934b707724b48f1d007f240 Mon Sep 17 00:00:00 2001 From: Martin Wagner Date: Thu, 9 Oct 2025 15:44:09 +0200 Subject: [PATCH 1/4] Add `coefficient_ring` for modules and improve the docs for `base_ring` --- docs/src/extending_abstractalgebra.md | 8 +++++ src/fundamental_interface.jl | 49 +++++++++++++++++++++++++-- src/generic/FreeModule.jl | 4 +++ src/generic/QuotientModule.jl | 4 +++ 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/docs/src/extending_abstractalgebra.md b/docs/src/extending_abstractalgebra.md index 90813b21f9..fd9f9bacf1 100644 --- a/docs/src/extending_abstractalgebra.md +++ b/docs/src/extending_abstractalgebra.md @@ -29,6 +29,14 @@ base_ring base_ring_type ``` +If there is a well-defined notion of a coefficient ring (e.g. in the case of +polynomial rings or modules), then one should implement + +```@docs +coefficient_ring +coefficient_ring_type +``` + ## Special elements For rings, one has to extend the following methods: diff --git a/src/fundamental_interface.jl b/src/fundamental_interface.jl index 6c0b1f5f90..57d8d12841 100644 --- a/src/fundamental_interface.jl +++ b/src/fundamental_interface.jl @@ -77,7 +77,7 @@ parent_type(T::DataType) = throw(MethodError(parent_type, (T,))) @doc raw""" base_ring(a) -Return base ring $R$ of given element or parent $a$. +Return the internal base ring of the given element or parent $a$. # Examples ```jldoctest @@ -101,7 +101,7 @@ base_ring(x::NCRingElement) = base_ring(parent(x)) @doc raw""" base_ring_type(a) -Return the type of the base ring of the given element, element type, parent or parent type $a$. +Return the type of the internal base ring of the given element, element type, parent or parent type $a$. # Examples ```jldoctest @@ -133,9 +133,52 @@ base_ring_type(x::Type{<:ModuleElem}) = base_ring_type(parent_type(x)) base_ring_type(x::Type{<:Ideal}) = base_ring_type(parent_type(x)) base_ring_type(T::DataType) = throw(MethodError(base_ring_type, (T,))) -# generic coefficient_ring method +@doc raw""" + coefficient_ring(a) + +Return the coefficient ring of the given element or parent $a$. + +# Examples +```jldoctest +julia> R, x = polynomial_ring(QQ, :x) +(Univariate polynomial ring in x over rationals, x) + +julia> coefficient_ring(x^2+1) == QQ +true + +julia> S, (z,w) = universal_polynomial_ring(QQ, [:z,:w]) +(Universal Polynomial Ring over Rationals, AbstractAlgebra.Generic.UnivPoly{Rational{BigInt}}[z, w]) + +julia> coefficient_ring(S) == QQ +true +``` +""" +function coefficient_ring end coefficient_ring(x::NCRingElement) = coefficient_ring(parent(x)) +@doc raw""" + coefficient_ring_type(a) + +Return the type of the coefficient ring of the given element, element type, parent or parent type $a$. + +# Examples +```jldoctest +julia> R, x = polynomial_ring(ZZ, :x) +(Univariate polynomial ring in x over integers, x) + +julia> coefficient_ring_type(R) == typeof(coefficient_ring(R)) +true + +julia> coefficient_ring_type(zero(R)) == typeof(coefficient_ring(zero(R))) +true + +julia> coefficient_ring_type(typeof(R)) == typeof(coefficient_ring(R)) +true + +julia> coefficient_ring_type(typeof(zero(R))) == typeof(coefficient_ring(zero(R))) +true +``` +""" coefficient_ring_type(x) = coefficient_ring_type(typeof(x)) coefficient_ring_type(x::Type{<:NCRingElement}) = coefficient_ring_type(parent_type(x)) coefficient_ring_type(x::Type{<:ModuleElem}) = coefficient_ring_type(parent_type(x)) diff --git a/src/generic/FreeModule.jl b/src/generic/FreeModule.jl index f2201e8a45..a865fda09f 100644 --- a/src/generic/FreeModule.jl +++ b/src/generic/FreeModule.jl @@ -16,6 +16,10 @@ base_ring_type(::Type{FreeModule{T}}) where T <: Union{RingElement, NCRingElem} base_ring(M::FreeModule{T}) where T <: Union{RingElement, NCRingElem} = M.base_ring::parent_type(T) +coefficient_ring_type(T::Type{FreeModule}) = base_ring_type(T) + +coefficient_ring(M::FreeModule) = base_ring(M) + elem_type(::Type{FreeModule{T}}) where T <: Union{RingElement, NCRingElem} = FreeModuleElem{T} parent(m::FreeModuleElem{T}) where T <: Union{RingElement, NCRingElem} = m.parent diff --git a/src/generic/QuotientModule.jl b/src/generic/QuotientModule.jl index 536a06f595..aefefa9409 100644 --- a/src/generic/QuotientModule.jl +++ b/src/generic/QuotientModule.jl @@ -20,6 +20,10 @@ base_ring_type(::Type{QuotientModule{T}}) where T <: RingElement = parent_type(T base_ring(N::QuotientModule{T}) where T <: RingElement = N.base_ring::parent_type(T) +coefficient_ring_type(T::Type{QuotientModule}) = base_ring_type(T) + +coefficient_ring(N::QuotientModule) = base_ring(N) + number_of_generators(N::QuotientModule{T}) where T <: RingElement = length(N.gen_cols) gens(N::QuotientModule{T}) where T <: RingElement = elem_type(N)[gen(N, i) for i = 1:ngens(N)] From 5be8c33ddffe1cbfe3a837c237ec91614e45240d Mon Sep 17 00:00:00 2001 From: Martin Wagner Date: Fri, 10 Oct 2025 10:13:09 +0200 Subject: [PATCH 2/4] Add tests for `coefficient_ring` on free and quotien modules --- test/generic/FreeModule-test.jl | 3 +++ test/generic/QuotientModule-test.jl | 3 +++ 2 files changed, 6 insertions(+) diff --git a/test/generic/FreeModule-test.jl b/test/generic/FreeModule-test.jl index 01ff3db296..85d64b0008 100644 --- a/test/generic/FreeModule-test.jl +++ b/test/generic/FreeModule-test.jl @@ -11,6 +11,9 @@ @test elem_type(Generic.FreeModule{elem_type(R)}) == Generic.FreeModuleElem{elem_type(R)} @test parent_type(Generic.FreeModuleElem{elem_type(R)}) == Generic.FreeModule{elem_type(R)} + @test coefficient_ring(M) == R + @test coefficient_ring_type(M) == typeof(coefficient_ring(M)) + @test isa(M, Generic.FreeModule) @test isa(M([x, x, x, x, x]), Generic.FreeModuleElem) diff --git a/test/generic/QuotientModule-test.jl b/test/generic/QuotientModule-test.jl index 35e4c0429d..ef6f5f663f 100644 --- a/test/generic/QuotientModule-test.jl +++ b/test/generic/QuotientModule-test.jl @@ -18,6 +18,9 @@ @test elem_type(Generic.QuotientModule{elem_type(R)}) == Generic.QuotientModuleElem{elem_type(R)} @test parent_type(Generic.QuotientModuleElem{elem_type(R)}) == Generic.QuotientModule{elem_type(R)} + @test coefficient_ring(M) == R + @test coefficient_ring_type(M) == typeof(coefficient_ring(M)) + @test isa(Q([R(2)]), Generic.QuotientModuleElem) R = QQ From 614b51cb02f00578316bcc6d5d9c7a037f2af683 Mon Sep 17 00:00:00 2001 From: Martin Wagner Date: Fri, 10 Oct 2025 11:01:21 +0200 Subject: [PATCH 3/4] Fix `coefficient_ring_type` --- src/generic/FreeModule.jl | 2 +- src/generic/QuotientModule.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/generic/FreeModule.jl b/src/generic/FreeModule.jl index a865fda09f..0240d833ce 100644 --- a/src/generic/FreeModule.jl +++ b/src/generic/FreeModule.jl @@ -16,7 +16,7 @@ base_ring_type(::Type{FreeModule{T}}) where T <: Union{RingElement, NCRingElem} base_ring(M::FreeModule{T}) where T <: Union{RingElement, NCRingElem} = M.base_ring::parent_type(T) -coefficient_ring_type(T::Type{FreeModule}) = base_ring_type(T) +coefficient_ring_type(T::Type{<:FreeModule}) = base_ring_type(T) coefficient_ring(M::FreeModule) = base_ring(M) diff --git a/src/generic/QuotientModule.jl b/src/generic/QuotientModule.jl index aefefa9409..77e98e1add 100644 --- a/src/generic/QuotientModule.jl +++ b/src/generic/QuotientModule.jl @@ -20,7 +20,7 @@ base_ring_type(::Type{QuotientModule{T}}) where T <: RingElement = parent_type(T base_ring(N::QuotientModule{T}) where T <: RingElement = N.base_ring::parent_type(T) -coefficient_ring_type(T::Type{QuotientModule}) = base_ring_type(T) +coefficient_ring_type(T::Type{<:QuotientModule}) = base_ring_type(T) coefficient_ring(N::QuotientModule) = base_ring(N) From 7dd8e29fd53562306cfa8ac28d4885e52c206897 Mon Sep 17 00:00:00 2001 From: Martin Wagner Date: Wed, 15 Oct 2025 10:36:58 +0200 Subject: [PATCH 4/4] Add `coefficient_ring` for series rings --- src/RelSeries.jl | 4 ++++ src/generic/LaurentSeries.jl | 8 ++++++++ src/generic/PuiseuxSeries.jl | 8 ++++++++ test/generic/LaurentSeries-test.jl | 6 ++++++ test/generic/PuiseuxSeries-test.jl | 6 ++++++ test/generic/RelSeries-test.jl | 6 ++++++ 6 files changed, 38 insertions(+) diff --git a/src/RelSeries.jl b/src/RelSeries.jl index fd9370a060..682a65c0ea 100644 --- a/src/RelSeries.jl +++ b/src/RelSeries.jl @@ -29,6 +29,10 @@ base_ring_type(::Type{<:SeriesRing{T}}) where T <: RingElement = parent_type(T) base_ring(R::SeriesRing{T}) where T <: RingElement = R.base_ring::parent_type(T) +coefficient_ring_type(T::Type{<:SeriesRing}) = base_ring_type(T) + +coefficient_ring(R::SeriesRing) = base_ring(R) + function is_domain_type(::Type{T}) where {S <: RingElement, T <: SeriesElem{S}} return is_domain_type(S) end diff --git a/src/generic/LaurentSeries.jl b/src/generic/LaurentSeries.jl index ff51d6031e..5798b69ee7 100644 --- a/src/generic/LaurentSeries.jl +++ b/src/generic/LaurentSeries.jl @@ -41,6 +41,14 @@ base_ring(R::LaurentSeriesRing{T}) where T <: RingElement = R.base_ring::parent_ base_ring(R::LaurentSeriesField{T}) where T <: FieldElement = R.base_ring::parent_type(T) +coefficient_ring_type(T::Type{<:LaurentSeriesRing}) = base_ring_type(T) + +coefficient_ring_type(T::Type{<:LaurentSeriesField}) = base_ring_type(T) + +coefficient_ring(R::LaurentSeriesRing) = base_ring(R) + +coefficient_ring(R::LaurentSeriesField) = base_ring(R) + function is_domain_type(::Type{T}) where {S <: RingElement, T <: LaurentSeriesElem{S}} return is_domain_type(S) end diff --git a/src/generic/PuiseuxSeries.jl b/src/generic/PuiseuxSeries.jl index 6e71d2fe78..85bcf68315 100644 --- a/src/generic/PuiseuxSeries.jl +++ b/src/generic/PuiseuxSeries.jl @@ -57,6 +57,14 @@ base_ring(R::PuiseuxSeriesRing{T}) where T <: RingElement = base_ring(laurent_ri base_ring(R::PuiseuxSeriesField{T}) where T <: FieldElement = base_ring(laurent_ring(R)) +coefficient_ring_type(T::Type{<:PuiseuxSeriesRing}) = base_ring_type(T) + +coefficient_ring_type(T::Type{<:PuiseuxSeriesField}) = base_ring_type(T) + +coefficient_ring(R::PuiseuxSeriesRing) = base_ring(R) + +coefficient_ring(R::PuiseuxSeriesField) = base_ring(R) + @doc raw""" max_precision(R::PuiseuxSeriesRing{T}) where T <: RingElement diff --git a/test/generic/LaurentSeries-test.jl b/test/generic/LaurentSeries-test.jl index bd41a48989..c3fa19df1c 100644 --- a/test/generic/LaurentSeries-test.jl +++ b/test/generic/LaurentSeries-test.jl @@ -40,10 +40,16 @@ end @test elem_type(Generic.LaurentSeriesRing{elem_type(S)}) == Generic.LaurentSeriesRingElem{elem_type(S)} @test parent_type(Generic.LaurentSeriesRingElem{elem_type(S)}) == Generic.LaurentSeriesRing{elem_type(S)} + @test coefficient_ring(T) == S + @test coefficient_ring_type(T) == typeof(coefficient_ring(T)) + @test elem_type(U) == Generic.LaurentSeriesFieldElem{Rational{BigInt}} @test elem_type(Generic.LaurentSeriesField{Rational{BigInt}}) == Generic.LaurentSeriesFieldElem{Rational{BigInt}} @test parent_type(Generic.LaurentSeriesFieldElem{Rational{BigInt}}) == Generic.LaurentSeriesField{Rational{BigInt}} + @test coefficient_ring(U) === QQ + @test coefficient_ring_type(U) == typeof(coefficient_ring(U)) + @test isa(R, Generic.LaurentSeriesRing) @test isa(T, Generic.LaurentSeriesRing) @test isa(U, Generic.LaurentSeriesField) diff --git a/test/generic/PuiseuxSeries-test.jl b/test/generic/PuiseuxSeries-test.jl index 9bddad4812..930946a89c 100644 --- a/test/generic/PuiseuxSeries-test.jl +++ b/test/generic/PuiseuxSeries-test.jl @@ -42,10 +42,16 @@ end @test elem_type(Generic.PuiseuxSeriesRing{elem_type(S)}) == Generic.PuiseuxSeriesRingElem{elem_type(S)} @test parent_type(Generic.PuiseuxSeriesRingElem{elem_type(S)}) == Generic.PuiseuxSeriesRing{elem_type(S)} + @test coefficient_ring(T) == S + @test coefficient_ring_type(T) == typeof(coefficient_ring(T)) + @test elem_type(U) == Generic.PuiseuxSeriesFieldElem{Rational{BigInt}} @test elem_type(Generic.PuiseuxSeriesField{Rational{BigInt}}) == Generic.PuiseuxSeriesFieldElem{Rational{BigInt}} @test parent_type(Generic.PuiseuxSeriesFieldElem{Rational{BigInt}}) == Generic.PuiseuxSeriesField{Rational{BigInt}} + @test coefficient_ring(U) === QQ + @test coefficient_ring_type(U) == typeof(coefficient_ring(U)) + @test isa(R, Generic.PuiseuxSeriesRing) @test isa(T, Generic.PuiseuxSeriesRing) @test isa(U, Generic.PuiseuxSeriesField) diff --git a/test/generic/RelSeries-test.jl b/test/generic/RelSeries-test.jl index 6cd5dab01e..edb03b32f7 100644 --- a/test/generic/RelSeries-test.jl +++ b/test/generic/RelSeries-test.jl @@ -45,10 +45,16 @@ end @test elem_type(Generic.RelPowerSeriesRing{BigInt}) == Generic.RelSeries{BigInt} @test parent_type(Generic.RelSeries{BigInt}) == Generic.RelPowerSeriesRing{BigInt} + @test coefficient_ring(R) === ZZ + @test coefficient_ring_type(R) == typeof(coefficient_ring(R)) + @test elem_type(T) == Generic.RelSeries{elem_type(S)} @test elem_type(Generic.RelPowerSeriesRing{elem_type(S)}) == Generic.RelSeries{elem_type(S)} @test parent_type(Generic.RelSeries{elem_type(S)}) == Generic.RelPowerSeriesRing{elem_type(S)} + @test coefficient_ring(T) == S + @test coefficient_ring_type(T) == typeof(coefficient_ring(T)) + @test isa(R, Generic.RelPowerSeriesRing) @test isa(T, Generic.RelPowerSeriesRing)