From 4f815f5faeb8b8ab64d2ae30078ef16be033e36f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 7 Nov 2024 17:41:11 +0100 Subject: [PATCH] Turn ConstPolyRing example into a doctest ... so that we verify it is correct *there*, instead of testing a copy which is out-of-sync --- docs/src/polynomial.md | 1 - docs/src/ring_interface.md | 69 +++++- test/Rings-test.jl | 1 - test/algorithms/GenericFunctions-test.jl | 294 ----------------------- 4 files changed, 58 insertions(+), 307 deletions(-) delete mode 100644 test/algorithms/GenericFunctions-test.jl diff --git a/docs/src/polynomial.md b/docs/src/polynomial.md index 1bd662c7fe..7e01eb40ff 100644 --- a/docs/src/polynomial.md +++ b/docs/src/polynomial.md @@ -789,7 +789,6 @@ julia> R, x = polynomial_ring(ZZ, :x) julia> S, y = polynomial_ring(R, :y) (Univariate polynomial ring in y over univariate polynomial ring, y) - julia> f = x*y^2 + (x + 1)*y + 3 x*y^2 + (x + 1)*y + 3 diff --git a/docs/src/ring_interface.md b/docs/src/ring_interface.md index da5bdd32c4..d082122347 100644 --- a/docs/src/ring_interface.md +++ b/docs/src/ring_interface.md @@ -762,22 +762,23 @@ permitted. Here is a minimal example of implementing the Ring Interface for a constant polynomial type (i.e. polynomials of degree less than one). -```julia +```jldoctest ConstPoly # ConstPoly.jl : Implements constant polynomials using AbstractAlgebra using Random: Random, SamplerTrivial, GLOBAL_RNG -using RandomExtensions: RandomExtensions, Make2, AbstractRNG +using AbstractAlgebra.RandomExtensions: RandomExtensions, Make2, AbstractRNG import AbstractAlgebra: parent_type, elem_type, base_ring, base_ring_type, parent, is_domain_type, is_exact_type, canonical_unit, isequal, divexact, zero!, mul!, add!, - get_cached!, is_unit, characteristic, Ring, RingElem, expressify + get_cached!, is_unit, characteristic, Ring, RingElem, expressify, + @show_name, @show_special, is_terse, pretty, terse, Lowercase import Base: show, +, -, *, ^, ==, inv, isone, iszero, one, zero, rand, deepcopy_internal, hash -mutable struct ConstPolyRing{T <: RingElement} <: Ring +@attributes mutable struct ConstPolyRing{T <: RingElement} <: Ring base_ring::Ring function ConstPolyRing{T}(R::Ring, cached::Bool) where T <: RingElement @@ -846,8 +847,13 @@ canonical_unit(f::ConstPoly) = canonical_unit(f.c) # String I/O function show(io::IO, R::ConstPolyRing) - print(io, "Constant polynomials over ") - show(io, base_ring(R)) + @show_name(io, R) + @show_special(io, R) + print(io, "Constant polynomials") + if !is_terse(io) + io = pretty(io) + print(terse(io), " over ", Lowercase(), base_ring(R)) + end end function show(io::IO, f::ConstPoly) @@ -928,6 +934,11 @@ function zero!(f::ConstPoly) return f end +function one!(f::ConstPoly) + f.c = one(base_ring(parent(f))) + return f +end + function mul!(f::ConstPoly{T}, g::ConstPoly{T}, h::ConstPoly{T}) where T <: RingElement f.c = g.c*h.c return f @@ -996,19 +1007,55 @@ function constant_polynomial_ring(R::Ring, cached::Bool=true) T = elem_type(R) return ConstPolyRing{T}(R, cached) end + +# output + +constant_polynomial_ring (generic function with 2 methods) ``` The above implementation of `constant_polynomial_ring` may be tested as follows. -```julia +```jldoctest ConstPoly; filter = r"( +|\d+\.\d+s)" using Test include(joinpath(pathof(AbstractAlgebra), "..", "..", "test", "Rings-conformance-tests.jl")) -S, _ = polynomial_ring(QQ, :x) +function test_elem(R::ConstPolyRing{elem_type(ZZ)}) + n = rand(1:999) + return R(rand(-n:n)) +end + +test_Ring_interface(constant_polynomial_ring(ZZ)); -function test_elem(R::ConstPolyRing{elem_type(S)}) - return R(rand(base_ring(R), 1:6, -999:999)) +# output + +Test Summary: | Pass Total Time +Ring interface for Constant polynomials over integers of type ConstPolyRing{BigInt} | 13846 13846 0.2s +``` + +Note that we only showed a minimal implementation of the ring interface. +Additional interfaces exists, e.g. for Euclidean rings. Additional interface +usually require implementing additional methods, and in some cases we also +provide additional conformance tests. In this case, just one necessary +method is missing. + +```jldoctest ConstPoly +function Base.divrem(a::ConstPoly{elem_type(ZZ)}, b::ConstPoly{elem_type(ZZ)}) + check_parent(a, b) + q, r = AbstractAlgebra.divrem(a.c, b.c) + return parent(a)(q), parent(a)(r) end -test_Ring_interface(constant_polynomial_ring(S)) +# output + +``` + +We can test it like this. + +```jldoctest ConstPoly; filter = r"( +|\d+\.\d+s)" +test_EuclideanRing_interface(constant_polynomial_ring(ZZ)); + +# output + +Test Summary: | Pass Total Time +Euclidean Ring interface for Constant polynomials over integers of type ConstPolyRing{BigInt} | 2220 2220 0.0s ``` diff --git a/test/Rings-test.jl b/test/Rings-test.jl index 004a94b0ee..1a5f76bb2c 100644 --- a/test/Rings-test.jl +++ b/test/Rings-test.jl @@ -33,7 +33,6 @@ include("algorithms/MPolyEvaluate-test.jl") include("algorithms/MPolyFactor-test.jl") include("algorithms/MPolyNested-test.jl") include("algorithms/DensePoly-test.jl") -include("algorithms/GenericFunctions-test.jl") include("algorithms/coprime_base-test.jl") include("generic/PolyRingHom-test.jl") diff --git a/test/algorithms/GenericFunctions-test.jl b/test/algorithms/GenericFunctions-test.jl deleted file mode 100644 index 6b4db98da4..0000000000 --- a/test/algorithms/GenericFunctions-test.jl +++ /dev/null @@ -1,294 +0,0 @@ -module GenericTest - -# the following code should be essentially copied and pasted from -# docs/src/ring_interface.md to make sure that it actually works - -using AbstractAlgebra, Test - -using ..Random: Random, SamplerTrivial, GLOBAL_RNG -using ..RandomExtensions: RandomExtensions, Make2, AbstractRNG - -import AbstractAlgebra: Ring -import AbstractAlgebra: RingElem -import AbstractAlgebra: add! -import AbstractAlgebra: base_ring -import AbstractAlgebra: base_ring_type -import AbstractAlgebra: canonical_unit -import AbstractAlgebra: characteristic -import AbstractAlgebra: divexact -import AbstractAlgebra: elem_type -import AbstractAlgebra: expressify -import AbstractAlgebra: get_cached! -import AbstractAlgebra: is_domain_type -import AbstractAlgebra: is_exact_type -import AbstractAlgebra: is_unit -import AbstractAlgebra: isequal -import AbstractAlgebra: mul! -import AbstractAlgebra: parent -import AbstractAlgebra: parent_type -import AbstractAlgebra: zero! - -import Base: * -import Base: + -import Base: - -import Base: == -import Base: ^ -import Base: deepcopy_internal -import Base: hash -import Base: inv -import Base: isone -import Base: iszero -import Base: one -import Base: rand -import Base: show -import Base: zero - -import ..test_Ring_interface -import ..test_EuclideanRing_interface -import ..test_elem - -@attributes mutable struct ConstPolyRing{T <: RingElement} <: Ring - base_ring::Ring - - function ConstPolyRing{T}(R::Ring, cached::Bool) where T <: RingElement - return get_cached!(ConstPolyID, R, cached) do - new{T}(R) - end::ConstPolyRing{T} - end -end - -const ConstPolyID = AbstractAlgebra.CacheDictType{Ring, ConstPolyRing}() - -mutable struct ConstPoly{T <: RingElement} <: RingElem - c::T - parent::ConstPolyRing{T} - - function ConstPoly{T}(c::T) where T <: RingElement - return new(c) - end -end - -# Data type and parent object methods - -parent_type(::Type{ConstPoly{T}}) where T <: RingElement = ConstPolyRing{T} - -elem_type(::Type{ConstPolyRing{T}}) where T <: RingElement = ConstPoly{T} - -base_ring_type(::Type{ConstPolyRing{T}}) where T <: RingElement = parent_type(T) - -base_ring(R::ConstPolyRing) = R.base_ring::base_ring_type(R) - -parent(f::ConstPoly) = f.parent - -is_domain_type(::Type{ConstPoly{T}}) where T <: RingElement = is_domain_type(T) - -is_exact_type(::Type{ConstPoly{T}}) where T <: RingElement = is_exact_type(T) - -function hash(f::ConstPoly, h::UInt) - r = 0x65125ab8e0cd44ca - return xor(r, hash(f.c, h)) -end - -function deepcopy_internal(f::ConstPoly{T}, dict::IdDict) where T <: RingElement - r = ConstPoly{T}(deepcopy_internal(f.c, dict)) - r.parent = f.parent # parent should not be deepcopied - return r -end - -# Basic manipulation - -zero(R::ConstPolyRing) = R() - -one(R::ConstPolyRing) = R(1) - -iszero(f::ConstPoly) = iszero(f.c) - -isone(f::ConstPoly) = isone(f.c) - -is_unit(f::ConstPoly) = is_unit(f.c) - -characteristic(R::ConstPolyRing) = characteristic(base_ring(R)) - -# Canonical unit - -canonical_unit(f::ConstPoly) = canonical_unit(f.c) - -# String I/O - -function show(io::IO, R::ConstPolyRing) - print(io, "Constant polynomials over ") - show(io, base_ring(R)) -end - -function show(io::IO, f::ConstPoly) - print(io, f.c) -end - -# Expressification (optional) - -function expressify(R::ConstPolyRing; context = nothing) - return Expr(:sequence, Expr(:text, "Constant polynomials over "), - expressify(base_ring(R), context = context)) -end - -function expressify(f::ConstPoly; context = nothing) - return expressify(f.c, context = context) -end - -# Unary operations - -function -(f::ConstPoly) - R = parent(f) - return R(-f.c) -end - -# Binary operations - -function +(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement - check_parent(f, g) - R = parent(f) - return R(f.c + g.c) -end - -function -(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement - check_parent(f, g) - R = parent(f) - return R(f.c - g.c) -end - -function *(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement - check_parent(f, g) - R = parent(f) - return R(f.c*g.c) -end - -# Comparison - -function ==(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement - check_parent(f, g) - return f.c == g.c -end - -function isequal(f::ConstPoly{T}, g::ConstPoly{T}) where T <: RingElement - check_parent(f, g) - return isequal(f.c, g.c) -end - -# Powering need not be implemented if * is - -# Exact division - -function divexact(f::ConstPoly{T}, g::ConstPoly{T}; check::Bool = true) where T <: RingElement - check_parent(f, g) - R = parent(f) - return R(divexact(f.c, g.c, check = check)) -end - -# Inverse - -function inv(f::ConstPoly) - R = parent(f) - return R(AbstractAlgebra.inv(f.c)) -end - -# Unsafe operators - -function zero!(f::ConstPoly) - f.c = zero(base_ring(parent(f))) - return f -end - -function mul!(f::ConstPoly{T}, g::ConstPoly{T}, h::ConstPoly{T}) where T <: RingElement - f.c = g.c*h.c - return f -end - -function add!(f::ConstPoly{T}, g::ConstPoly{T}, h::ConstPoly{T}) where T <: RingElement - f.c = g.c + h.c - return f -end - -# Random generation - -RandomExtensions.maketype(R::ConstPolyRing, _) = elem_type(R) - -rand(rng::AbstractRNG, sp::SamplerTrivial{<:Make2{ConstPoly,ConstPolyRing}}) = - sp[][1](rand(rng, sp[][2])) - -rand(rng::AbstractRNG, R::ConstPolyRing, n::AbstractUnitRange{Int}) = R(rand(rng, n)) - -rand(R::ConstPolyRing, n::AbstractUnitRange{Int}) = rand(Random.GLOBAL_RNG, R, n) - -# Promotion rules - -promote_rule(::Type{ConstPoly{T}}, ::Type{ConstPoly{T}}) where T <: RingElement = ConstPoly{T} - -function promote_rule(::Type{ConstPoly{T}}, ::Type{U}) where {T <: RingElement, U <: RingElement} - promote_rule(T, U) == T ? ConstPoly{T} : Union{} -end - -# Constructors - -function (R::ConstPolyRing{T})() where T <: RingElement - r = ConstPoly{T}(base_ring(R)(0)) - r.parent = R - return r -end - -function (R::ConstPolyRing{T})(c::Integer) where T <: RingElement - r = ConstPoly{T}(base_ring(R)(c)) - r.parent = R - return r -end - -# Needed to prevent ambiguity -function (R::ConstPolyRing{T})(c::T) where T <: Integer - r = ConstPoly{T}(base_ring(R)(c)) - r.parent = R - return r -end - -function (R::ConstPolyRing{T})(c::T) where T <: RingElement - base_ring(R) != parent(c) && error("Unable to coerce element") - r = ConstPoly{T}(c) - r.parent = R - return r -end - -function (R::ConstPolyRing{T})(f::ConstPoly{T}) where T <: RingElement - R != parent(f) && error("Unable to coerce element") - return f -end - -# Parent constructor - -function ConstantPolynomialRing(R::Ring, cached::Bool=true) - T = elem_type(R) - return ConstPolyRing{T}(R, cached) -end - -# we need only divrem to satsify the -# Euclidean interface - -function Base.divrem(a::ConstPoly{elem_type(ZZ)}, b::ConstPoly{elem_type(ZZ)}) - check_parent(a, b) - q, r = AbstractAlgebra.divrem(a.c, b.c) - return parent(a)(q), parent(a)(r) -end - -#### - -function test_elem(R::ConstPolyRing{elem_type(ZZ)}) - n = rand(1:999) - return R(rand(-n:n)) -end - -@testset "GenericFunctions.Ring_interface" begin - test_Ring_interface(ConstantPolynomialRing(ZZ)) -end - -@testset "GenericFunctions.EuclideanRing_interface" begin - test_EuclideanRing_interface(ConstantPolynomialRing(ZZ)) -end - -end