From 11f2008fa771df34fd9b1245d36b1626266a1729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Fri, 10 Jan 2025 16:22:02 +0100 Subject: [PATCH 01/11] Remove `Test` as depedency --- Project.toml | 2 -- src/imports.jl | 2 -- 2 files changed, 4 deletions(-) diff --git a/Project.toml b/Project.toml index 77a5ad7379..44a868cd4c 100644 --- a/Project.toml +++ b/Project.toml @@ -9,7 +9,6 @@ Preferences = "21216c6a-2e73-6563-6e65-726566657250" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" RandomExtensions = "fb686558-2515-59ef-acaa-46db3789a887" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] LinearAlgebra = "1.6" @@ -18,5 +17,4 @@ Preferences = "1" Random = "1.6" RandomExtensions = "0.4.2" SparseArrays = "1.6" -Test = "1.6" julia = "1.6" diff --git a/src/imports.jl b/src/imports.jl index 4c1cfc0a18..2df88b4400 100644 --- a/src/imports.jl +++ b/src/imports.jl @@ -1,8 +1,6 @@ using Random: Random, AbstractRNG, SamplerTrivial using RandomExtensions: RandomExtensions, make, Make, Make2, Make3, Make4 -using Test: @test # for "interface-conformance" functions - import LinearAlgebra import LinearAlgebra: det From 409632908506ff2a0efb679516e7d45f991e0479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Fri, 10 Jan 2025 13:15:14 +0100 Subject: [PATCH 02/11] Basic setup for TestExt package extension --- Project.toml | 13 +++++++++++++ ext/TestExt/TestExt.jl | 8 ++++++++ src/AbstractAlgebra.jl | 14 ++++++++++++++ src/imports.jl | 4 ++++ 4 files changed, 39 insertions(+) create mode 100644 ext/TestExt/TestExt.jl diff --git a/Project.toml b/Project.toml index 44a868cd4c..f7b2129195 100644 --- a/Project.toml +++ b/Project.toml @@ -8,13 +8,26 @@ MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" Preferences = "21216c6a-2e73-6563-6e65-726566657250" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" RandomExtensions = "fb686558-2515-59ef-acaa-46db3789a887" +Requires = "ae029012-a4dd-5104-9daa-d747884805df" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +[extras] +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[weakdeps] +Requires = "ae029012-a4dd-5104-9daa-d747884805df" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[extensions] +TestExt = "Test" + [compat] LinearAlgebra = "1.6" MacroTools = "0.5" Preferences = "1" Random = "1.6" RandomExtensions = "0.4.2" +Requires = "1.3.0" SparseArrays = "1.6" +Test = "1.6" julia = "1.6" diff --git a/ext/TestExt/TestExt.jl b/ext/TestExt/TestExt.jl new file mode 100644 index 0000000000..4c1cf95ed6 --- /dev/null +++ b/ext/TestExt/TestExt.jl @@ -0,0 +1,8 @@ +module TestExt + +using AbstractAlgebra +isdefined(Base, :get_extension) ? (using Test) : (using ..Test) + + + +end # module diff --git a/src/AbstractAlgebra.jl b/src/AbstractAlgebra.jl index f0602f551a..4c29674ba1 100644 --- a/src/AbstractAlgebra.jl +++ b/src/AbstractAlgebra.jl @@ -462,4 +462,18 @@ end ############################################################################### include("utils.jl") +############################################################################### +# +# Pre-1.9-compatibility for package extensions +# +############################################################################### + +# Remove once all supported julia versions support package extensions, i.e. 1.9 or later. +# Same for all other places that use `isdefined(Base, :get_extension)`. +@static if !isdefined(Base, :get_extension) + function __init__() + @require Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" include("../ext/TestExt/TestExt.jl") + end +end + end # module diff --git a/src/imports.jl b/src/imports.jl index 2df88b4400..0cae74ca24 100644 --- a/src/imports.jl +++ b/src/imports.jl @@ -1,6 +1,10 @@ using Random: Random, AbstractRNG, SamplerTrivial using RandomExtensions: RandomExtensions, make, Make, Make2, Make3, Make4 +if !isdefined(Base, :get_extension) + using Requires: @require +end + import LinearAlgebra import LinearAlgebra: det From f15df90f27f241975fc8270e1902ea9cb986133e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Fri, 10 Jan 2025 16:25:39 +0100 Subject: [PATCH 03/11] Add `ConformanceTests` submodule --- src/AbstractAlgebra.jl | 8 +++++--- src/ConformanceTests.jl | 7 +++++++ src/exports.jl | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 src/ConformanceTests.jl diff --git a/src/AbstractAlgebra.jl b/src/AbstractAlgebra.jl index 4c29674ba1..60fe823558 100644 --- a/src/AbstractAlgebra.jl +++ b/src/AbstractAlgebra.jl @@ -364,11 +364,13 @@ getindex(S::Set, i::Int) = gen(S, i) include("error.jl") -############################################################################### +################################################################################ # -# Load Groups/Rings/Fields etc. +# Conformance tests (function stubs for TestExt) # -############################################################################### +################################################################################ + +include("ConformanceTests.jl") # Generic functions to be defined after all rings diff --git a/src/ConformanceTests.jl b/src/ConformanceTests.jl new file mode 100644 index 0000000000..f1ed5621d2 --- /dev/null +++ b/src/ConformanceTests.jl @@ -0,0 +1,7 @@ +module ConformanceTests + +# This file only contains function stubs. +# The actual implementation are in the folder `ext/TestExt/`. + + +end # module diff --git a/src/exports.jl b/src/exports.jl index 11dbc97cb6..fff301911a 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -25,6 +25,7 @@ export AbsPowerSeriesRingElem export AdditiveGroupElem export AllParts export AllPerms +export ConformanceTests export ErrorConstrDimMismatch export EuclideanRingResidueField export EuclideanRingResidueFieldElem From c765523cf7abe17f8a04cce022d443ca55036d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Fri, 10 Jan 2025 16:32:34 +0100 Subject: [PATCH 04/11] Move `test_iterate` to `TestExt` --- ext/TestExt/TestExt.jl | 13 +++++++++++++ src/ConformanceTests.jl | 1 + src/Deprecations.jl | 3 +++ src/algorithms/FinField.jl | 14 -------------- test/julia/GFElem-test.jl | 2 +- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/ext/TestExt/TestExt.jl b/ext/TestExt/TestExt.jl index 4c1cf95ed6..fbbc1e2c47 100644 --- a/ext/TestExt/TestExt.jl +++ b/ext/TestExt/TestExt.jl @@ -4,5 +4,18 @@ using AbstractAlgebra isdefined(Base, :get_extension) ? (using Test) : (using ..Test) +function ConformanceTests.test_iterate(F::FinField) + elts = collect(Iterators.take(F, 20)) + @test elts isa Vector{elem_type(F)} + @test allunique(elts) + @test length(elts) == min(order(F), 20) + if order(F) < 100 + elts = collect(F) + @test elts isa Vector{elem_type(F)} + @test allunique(elts) + @test length(elts) == order(F) + end + return elts +end end # module diff --git a/src/ConformanceTests.jl b/src/ConformanceTests.jl index f1ed5621d2..951ef54f97 100644 --- a/src/ConformanceTests.jl +++ b/src/ConformanceTests.jl @@ -3,5 +3,6 @@ module ConformanceTests # This file only contains function stubs. # The actual implementation are in the folder `ext/TestExt/`. +function test_iterate end end # module diff --git a/src/Deprecations.jl b/src/Deprecations.jl index 11585ee111..16b2785b01 100644 --- a/src/Deprecations.jl +++ b/src/Deprecations.jl @@ -64,6 +64,9 @@ import .Generic: degree; @deprecate degree(f::Generic.MPoly{T}, i::Int, ::Type{V @deprecate mulmod(a::S, b::S, mod::Vector{S}) where {S <: MPolyRingElem} Base.divrem(a * b, mod)[2] @deprecate var"@attr"(__source__::LineNumberNode, __module__::Base.Module, expr::Expr) var"@attr"(__source__, __module__, :Any, expr) # delegate `@attr functionexpression` to `@attr Any functionexpression` (macros are just functions with this weird extra syntax) +# to be deprecated in next breaking release +test_iterate = ConformanceTests.test_iterate + # to be removed in next breaking release function var"@attr"(__source__::LineNumberNode, __module__::Base.Module, rettype, options, expr::Expr) @assert options.head == :(=) diff --git a/src/algorithms/FinField.jl b/src/algorithms/FinField.jl index edc7fba49c..847f2f67f0 100644 --- a/src/algorithms/FinField.jl +++ b/src/algorithms/FinField.jl @@ -67,17 +67,3 @@ end Base.length(f::FinField) = BigInt(order(f)) Base.eltype(::Type{F}) where {F<:FinField} = elem_type(F) - -function test_iterate(f::FinField) - elts = collect(Iterators.take(f, 20)) - @test elts isa Vector{elem_type(f)} - @test allunique(elts) - @test length(elts) == min(order(f), 20) - if order(f) < 100 - elts = collect(f) - @test elts isa Vector{elem_type(f)} - @test allunique(elts) - @test length(elts) == order(f) - end - return elts -end diff --git a/test/julia/GFElem-test.jl b/test/julia/GFElem-test.jl index 1e19a46b43..b4bf2e8680 100644 --- a/test/julia/GFElem-test.jl +++ b/test/julia/GFElem-test.jl @@ -319,7 +319,7 @@ end @testset "Julia.GFElem.iteration" begin for n = [2, 3, 5, 13, 31] R = GF(n) - elts = AbstractAlgebra.test_iterate(R) + elts = ConformanceTests.test_iterate(R) @test elts == R.(0:n-1) end end From 82cca80ecd25a37e54ae5ba83a2734ae02644168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Fri, 10 Jan 2025 16:45:50 +0100 Subject: [PATCH 05/11] Move Groups conformance tests to TestExt --- ext/TestExt/Groups-conformance-tests.jl | 328 +++++++++++++++++++++++ ext/TestExt/TestExt.jl | 3 + src/ConformanceTests.jl | 5 + test/AbstractAlgebra-test.jl | 2 +- test/Groups-conformance-tests.jl | 333 +----------------------- test/conformance-tests.jl | 2 + test/generic/PermGroupAPI-test.jl | 4 +- 7 files changed, 349 insertions(+), 328 deletions(-) create mode 100644 ext/TestExt/Groups-conformance-tests.jl diff --git a/ext/TestExt/Groups-conformance-tests.jl b/ext/TestExt/Groups-conformance-tests.jl new file mode 100644 index 0000000000..5596a91f31 --- /dev/null +++ b/ext/TestExt/Groups-conformance-tests.jl @@ -0,0 +1,328 @@ +############################################################################### +# +# Conformance tests for the group and group element interfaces. +# +# +# The code in this file is based on v0.4 of the GroupsCore.jl package, which +# is copyright (c) 2021 Marek Kaluba and contributors, +# and licensed under the MIT license . +# +# The interfaces have since then diverged, with several breaking changes. +# Function and type names differ (e.g. `istrivial` vs. `is_trivial`), and +# also semantics (e.g. definition of equality for group elements in +# GroupsCore allows returning false for mathematically equal elements when it +# is "too hard" to prove equality; we don't). +# +############################################################################### + + +function ConformanceTests.test_Group_interface(G::Group) + @testset "Group interface" begin +# @testset "Iteration protocol" begin +# IS = Base.IteratorSize(typeof(G)) +# if IS isa Base.IsInfinite +# @test is_finite(G) == false +# else +# isfiniteG = false +# if IS isa Base.HasLength || IS isa Base.HasShape +# @test is_finite(G) == true +# isfiniteG = true +# else +# @test IS isa Base.SizeUnknown +# try +# @test is_finite(G) isa Bool +# isfiniteG = is_finite(G) +# catch e +# @test e isa AbstractAlgebra.InfiniteOrderError +# isfiniteG = false +# end +# end +# +# if isfiniteG +# @test length(G) isa Int +# @test length(G) > 0 +# +# @test elem_type(G) <: GroupElem +# @test one(G) isa elem_type(G) +# +# if has_gens(G) +# @test first(iterate(G)) isa elem_type(G) +# _, s = iterate(G) +# @test first(iterate(G, s)) isa elem_type(G) +# @test isone(first(G)) +# end +# end +# end +# end + + @testset "Group generators" begin + @test has_gens(G) isa Bool + + if has_gens(G) + @test ngens(G) isa Int + @test gens(G) isa AbstractVector{elem_type(G)} + @test length(gens(G)) == ngens(G) + if ngens(G) > 0 + @test first(gens(G)) == gen(G, 1) + @test last(gens(G)) == gen(G, ngens(G)) + end + else + # TODO: throw something more specific + @test_throws ErrorException gens(G) + @test_throws ErrorException ngens(G) + end + end + + @testset "order, rand" begin + if is_finite(G) + ord = order(BigInt, G) + @test ord isa BigInt + if ord < typemax(Int16) + @test order(Int16, G) isa Int16 + else + @test_throws InexactError order(Int16, G) + end + @test order(G) >= 1 + @test is_trivial(G) == (order(G) == 1) + else + @test_throws AbstractAlgebra.InfiniteOrderError order(G) + @test !is_trivial(G) + end + + @test rand(G) isa GroupElem + @test rand(G, 2) isa AbstractVector{elem_type(G)} + g, h = rand(G, 2) + @test parent(g) === parent(h) === G + +# @test GroupsCore.rand_pseudo(G) isa elem_type(G) +# @test GroupsCore.rand_pseudo(G, 2, 2) isa AbstractMatrix{elem_type(G)} +# +# g, h = GroupsCore.rand_pseudo(G, 2) +# @test parent(g) === parent(h) === G + end + end +end + +function ConformanceTests.test_GroupElem_interface(g::GEl, h::GEl) where {GEl<:GroupElem} + + @testset "GroupElem interface" begin + + @testset "Parent methods" begin + @test parent(g) isa Group + @test parent(g) === parent(h) + G = parent(g) + + @test elem_type(G) == typeof(g) + + @test one(g) isa elem_type(G) + + @test one(G) == one(g) == one(h) + + @test isone(one(G)) + end + + @testset "Equality, deepcopy && hash" begin + @test (g == h) isa Bool + @test isequal(g, h) isa Bool + + @test g == g + @test isequal(g, g) + + if g != h + @test !isequal(g, h) + end + + @test deepcopy(g) isa typeof(g) + @test deepcopy(g) == g + k = deepcopy(g) + @test parent(k) === parent(g) + @test hash(g) isa UInt + @test hash(g) == hash(k) + + if isequal(g, h) + @test hash(g) == hash(h) + end + end + + @testset "Group operations" begin + old_g, old_h = deepcopy(g), deepcopy(h) + + # check that the default operations don't mutate their arguments + @test inv(g) isa typeof(g) + @test (g, h) == (old_g, old_h) + + @test g * h isa typeof(g) + @test (g, h) == (old_g, old_h) + + @test g^2 == g * g + @test (g, h) == (old_g, old_h) + + @test g^-3 == inv(g) * inv(g) * inv(g) + @test (g, h) == (old_g, old_h) + + @test (g * h)^-1 == inv(h) * inv(g) + @test (g, h) == (old_g, old_h) + + @test conj(g, h) == inv(h) * g * h + @test (g, h) == (old_g, old_h) + + @test ^(g, h) == inv(h) * g * h + @test (g, h) == (old_g, old_h) + + @test comm(g, h) == g^-1 * h^-1 * g * h + @test (g, h) == (old_g, old_h) + + @test comm(g, h, g) == conj(inv(g), h) * conj(conj(g, h), g) + @test (g, h) == (old_g, old_h) + + @test isone(g * inv(g)) && isone(inv(g) * g) + @test (g, h) == (old_g, old_h) + + @test g / h == g * inv(h) + @test (g, h) == (old_g, old_h) + + @test div_right(g, h) == g * inv(h) + @test (g, h) == (old_g, old_h) + + @test g \ h == inv(g) * h + @test (g, h) == (old_g, old_h) + + @test div_left(g, h) == inv(h) * g + @test (g, h) == (old_g, old_h) + end + + @testset "Misc GroupElem methods" begin + @test one(g) isa typeof(g) + @test isone(g) isa Bool + @test isone(one(g)) + + @test is_finite_order(g) isa Bool + + if is_finite_order(g) + @test order(Int16, g) isa Int16 + @test order(BigInt, g) isa BigInt + @test order(g) >= 1 + if is_finite(parent(g)) + @test iszero(order(parent(g)) % order(g)) + end + if !isone(g) && !isone(g^2) + @test order(g) > 2 + end + @test order(inv(g)) == order(g) + @test order(one(g)) == 1 + else + @test_throws AbstractAlgebra.InfiniteOrderError order(g) + end + + @test similar(g) isa typeof(g) + end + + @testset "In-place operations" begin + old_g, old_h = deepcopy(g), deepcopy(h) + out = similar(g) + + @test isone(one!(g)) + g = deepcopy(old_g) + + @test inv!(out, g) == inv(old_g) + @test g == old_g + @test inv!(out, g) == inv(old_g) + g = deepcopy(old_g) + + @testset "mul!" begin + @test mul!(out, g, h) == old_g * old_h + @test (g, h) == (old_g, old_h) + + @test mul!(out, g, h) == old_g * old_h + @test (g, h) == (old_g, old_h) + + @test mul!(g, g, h) == old_g * old_h + @test h == old_h + g = deepcopy(old_g) + + @test mul!(h, g, h) == old_g * old_h + @test g == old_g + h = deepcopy(old_h) + + @test mul!(g, g, g) == old_g * old_g + g = deepcopy(old_g) + end + + @testset "conj!" begin + res = old_h^-1 * old_g * old_h + @test conj!(out, g, h) == res + @test (g, h) == (old_g, old_h) + + @test conj!(g, g, h) == res + @test h == old_h + g = deepcopy(old_g) + + @test conj!(h, g, h) == res + @test g == old_g + h = deepcopy(old_h) + + @test conj!(g, g, g) == old_g + g = deepcopy(old_g) + end + + @testset "comm!" begin + res = old_g^-1 * old_h^-1 * old_g * old_h + + @test comm!(out, g, h) == res + @test (g, h) == (old_g, old_h) + + @test comm!(out, g, h) == res + @test (g, h) == (old_g, old_h) + + @test comm!(g, g, h) == res + @test h == old_h + g = deepcopy(old_g) + + @test comm!(h, g, h) == res + @test g == old_g + h = deepcopy(old_h) + end + + @testset "div_[left|right]!" begin + res = g * h^-1 + @test div_right!(out, g, h) == res + @test (g, h) == (old_g, old_h) + + @test div_right!(g, g, h) == res + @test h == old_h + g = deepcopy(old_g) + + @test div_right!(h, g, h) == res + @test g == old_g + h = deepcopy(old_h) + + @test div_right!(g, g, g) == one(g) + g = deepcopy(old_g) + + + res = h^-1 * g + @test div_left!(out, g, h) == res + @test (g, h) == (old_g, old_h) + + @test div_left!(g, g, h) == res + @test h == old_h + g = deepcopy(old_g) + + @test div_left!(h, g, h) == res + @test g == old_g + h = deepcopy(old_h) + + @test div_left!(g, g, g) == one(g) + g = deepcopy(old_g) + end + end + + @testset "Broadcasting" begin + @test g .* [g, h] == [g * g, g * h] + G = parent(g) + if has_gens(G) + @test g .* gens(G) == [g * x for x in gens(G)] + end + end + end +end diff --git a/ext/TestExt/TestExt.jl b/ext/TestExt/TestExt.jl index fbbc1e2c47..a61384d6a7 100644 --- a/ext/TestExt/TestExt.jl +++ b/ext/TestExt/TestExt.jl @@ -4,6 +4,9 @@ using AbstractAlgebra isdefined(Base, :get_extension) ? (using Test) : (using ..Test) +include("Groups-conformance-tests.jl") + + function ConformanceTests.test_iterate(F::FinField) elts = collect(Iterators.take(F, 20)) @test elts isa Vector{elem_type(F)} diff --git a/src/ConformanceTests.jl b/src/ConformanceTests.jl index 951ef54f97..bb109c9008 100644 --- a/src/ConformanceTests.jl +++ b/src/ConformanceTests.jl @@ -5,4 +5,9 @@ module ConformanceTests function test_iterate end +# Groups-conformance-tests.jl +function test_Group_interface end +function test_GroupElem_interface end + + end # module diff --git a/test/AbstractAlgebra-test.jl b/test/AbstractAlgebra-test.jl index 64148a922a..bc31a81223 100644 --- a/test/AbstractAlgebra-test.jl +++ b/test/AbstractAlgebra-test.jl @@ -1,4 +1,4 @@ -include("conformance-tests.jl") +include("Rings-conformance-tests.jl") include("error-test.jl") include("AliasMacro-test.jl") diff --git a/test/Groups-conformance-tests.jl b/test/Groups-conformance-tests.jl index 064703cfdf..1354c8d9a4 100644 --- a/test/Groups-conformance-tests.jl +++ b/test/Groups-conformance-tests.jl @@ -1,328 +1,11 @@ -############################################################################### -# -# Conformance tests for the group and group element interfaces. -# -# -# The code in this file is based on v0.4 of the GroupsCore.jl package, which -# is copyright (c) 2021 Marek Kaluba and contributors, -# and licensed under the MIT license . -# -# The interfaces have since then diverged, with several breaking changes. -# Function and type names differ (e.g. `istrivial` vs. `is_trivial`), and -# also semantics (e.g. definition of equality for group elements in -# GroupsCore allows returning false for mathematically equal elements when it -# is "too hard" to prove equality; we don't). -# -############################################################################### +# This file is just for backwards compatibility and should be removed in the future. +# Assumptions (as that was already required with the previous setup): +# - `AbstractAlgebra` is already loaded +# - `Test` is available in the environment -function test_Group_interface(G::Group) - @testset "Group interface" begin -# @testset "Iteration protocol" begin -# IS = Base.IteratorSize(typeof(G)) -# if IS isa Base.IsInfinite -# @test is_finite(G) == false -# else -# isfiniteG = false -# if IS isa Base.HasLength || IS isa Base.HasShape -# @test is_finite(G) == true -# isfiniteG = true -# else -# @test IS isa Base.SizeUnknown -# try -# @test is_finite(G) isa Bool -# isfiniteG = is_finite(G) -# catch e -# @test e isa AbstractAlgebra.InfiniteOrderError -# isfiniteG = false -# end -# end -# -# if isfiniteG -# @test length(G) isa Int -# @test length(G) > 0 -# -# @test elem_type(G) <: GroupElem -# @test one(G) isa elem_type(G) -# -# if has_gens(G) -# @test first(iterate(G)) isa elem_type(G) -# _, s = iterate(G) -# @test first(iterate(G, s)) isa elem_type(G) -# @test isone(first(G)) -# end -# end -# end -# end +# load TestExt +using Test - @testset "Group generators" begin - @test has_gens(G) isa Bool - - if has_gens(G) - @test ngens(G) isa Int - @test gens(G) isa AbstractVector{elem_type(G)} - @test length(gens(G)) == ngens(G) - if ngens(G) > 0 - @test first(gens(G)) == gen(G, 1) - @test last(gens(G)) == gen(G, ngens(G)) - end - else - # TODO: throw something more specific - @test_throws ErrorException gens(G) - @test_throws ErrorException ngens(G) - end - end - - @testset "order, rand" begin - if is_finite(G) - ord = order(BigInt, G) - @test ord isa BigInt - if ord < typemax(Int16) - @test order(Int16, G) isa Int16 - else - @test_throws InexactError order(Int16, G) - end - @test order(G) >= 1 - @test is_trivial(G) == (order(G) == 1) - else - @test_throws AbstractAlgebra.InfiniteOrderError order(G) - @test !is_trivial(G) - end - - @test rand(G) isa GroupElem - @test rand(G, 2) isa AbstractVector{elem_type(G)} - g, h = rand(G, 2) - @test parent(g) === parent(h) === G - -# @test GroupsCore.rand_pseudo(G) isa elem_type(G) -# @test GroupsCore.rand_pseudo(G, 2, 2) isa AbstractMatrix{elem_type(G)} -# -# g, h = GroupsCore.rand_pseudo(G, 2) -# @test parent(g) === parent(h) === G - end - end -end - -function test_GroupElem_interface(g::GEl, h::GEl) where {GEl<:GroupElem} - - @testset "GroupElem interface" begin - - @testset "Parent methods" begin - @test parent(g) isa Group - @test parent(g) === parent(h) - G = parent(g) - - @test elem_type(G) == typeof(g) - - @test one(g) isa elem_type(G) - - @test one(G) == one(g) == one(h) - - @test isone(one(G)) - end - - @testset "Equality, deepcopy && hash" begin - @test (g == h) isa Bool - @test isequal(g, h) isa Bool - - @test g == g - @test isequal(g, g) - - if g != h - @test !isequal(g, h) - end - - @test deepcopy(g) isa typeof(g) - @test deepcopy(g) == g - k = deepcopy(g) - @test parent(k) === parent(g) - @test hash(g) isa UInt - @test hash(g) == hash(k) - - if isequal(g, h) - @test hash(g) == hash(h) - end - end - - @testset "Group operations" begin - old_g, old_h = deepcopy(g), deepcopy(h) - - # check that the default operations don't mutate their arguments - @test inv(g) isa typeof(g) - @test (g, h) == (old_g, old_h) - - @test g * h isa typeof(g) - @test (g, h) == (old_g, old_h) - - @test g^2 == g * g - @test (g, h) == (old_g, old_h) - - @test g^-3 == inv(g) * inv(g) * inv(g) - @test (g, h) == (old_g, old_h) - - @test (g * h)^-1 == inv(h) * inv(g) - @test (g, h) == (old_g, old_h) - - @test conj(g, h) == inv(h) * g * h - @test (g, h) == (old_g, old_h) - - @test ^(g, h) == inv(h) * g * h - @test (g, h) == (old_g, old_h) - - @test comm(g, h) == g^-1 * h^-1 * g * h - @test (g, h) == (old_g, old_h) - - @test comm(g, h, g) == conj(inv(g), h) * conj(conj(g, h), g) - @test (g, h) == (old_g, old_h) - - @test isone(g * inv(g)) && isone(inv(g) * g) - @test (g, h) == (old_g, old_h) - - @test g / h == g * inv(h) - @test (g, h) == (old_g, old_h) - - @test div_right(g, h) == g * inv(h) - @test (g, h) == (old_g, old_h) - - @test g \ h == inv(g) * h - @test (g, h) == (old_g, old_h) - - @test div_left(g, h) == inv(h) * g - @test (g, h) == (old_g, old_h) - end - - @testset "Misc GroupElem methods" begin - @test one(g) isa typeof(g) - @test isone(g) isa Bool - @test isone(one(g)) - - @test is_finite_order(g) isa Bool - - if is_finite_order(g) - @test order(Int16, g) isa Int16 - @test order(BigInt, g) isa BigInt - @test order(g) >= 1 - if is_finite(parent(g)) - @test iszero(order(parent(g)) % order(g)) - end - if !isone(g) && !isone(g^2) - @test order(g) > 2 - end - @test order(inv(g)) == order(g) - @test order(one(g)) == 1 - else - @test_throws AbstractAlgebra.InfiniteOrderError order(g) - end - - @test similar(g) isa typeof(g) - end - - @testset "In-place operations" begin - old_g, old_h = deepcopy(g), deepcopy(h) - out = similar(g) - - @test isone(one!(g)) - g = deepcopy(old_g) - - @test inv!(out, g) == inv(old_g) - @test g == old_g - @test inv!(out, g) == inv(old_g) - g = deepcopy(old_g) - - @testset "mul!" begin - @test mul!(out, g, h) == old_g * old_h - @test (g, h) == (old_g, old_h) - - @test mul!(out, g, h) == old_g * old_h - @test (g, h) == (old_g, old_h) - - @test mul!(g, g, h) == old_g * old_h - @test h == old_h - g = deepcopy(old_g) - - @test mul!(h, g, h) == old_g * old_h - @test g == old_g - h = deepcopy(old_h) - - @test mul!(g, g, g) == old_g * old_g - g = deepcopy(old_g) - end - - @testset "conj!" begin - res = old_h^-1 * old_g * old_h - @test conj!(out, g, h) == res - @test (g, h) == (old_g, old_h) - - @test conj!(g, g, h) == res - @test h == old_h - g = deepcopy(old_g) - - @test conj!(h, g, h) == res - @test g == old_g - h = deepcopy(old_h) - - @test conj!(g, g, g) == old_g - g = deepcopy(old_g) - end - - @testset "comm!" begin - res = old_g^-1 * old_h^-1 * old_g * old_h - - @test comm!(out, g, h) == res - @test (g, h) == (old_g, old_h) - - @test comm!(out, g, h) == res - @test (g, h) == (old_g, old_h) - - @test comm!(g, g, h) == res - @test h == old_h - g = deepcopy(old_g) - - @test comm!(h, g, h) == res - @test g == old_g - h = deepcopy(old_h) - end - - @testset "div_[left|right]!" begin - res = g * h^-1 - @test div_right!(out, g, h) == res - @test (g, h) == (old_g, old_h) - - @test div_right!(g, g, h) == res - @test h == old_h - g = deepcopy(old_g) - - @test div_right!(h, g, h) == res - @test g == old_g - h = deepcopy(old_h) - - @test div_right!(g, g, g) == one(g) - g = deepcopy(old_g) - - - res = h^-1 * g - @test div_left!(out, g, h) == res - @test (g, h) == (old_g, old_h) - - @test div_left!(g, g, h) == res - @test h == old_h - g = deepcopy(old_g) - - @test div_left!(h, g, h) == res - @test g == old_g - h = deepcopy(old_h) - - @test div_left!(g, g, g) == one(g) - g = deepcopy(old_g) - end - end - - @testset "Broadcasting" begin - @test g .* [g, h] == [g * g, g * h] - G = parent(g) - if has_gens(G) - @test g .* gens(G) == [g * x for x in gens(G)] - end - end - end -end +test_Group_interface = ConformanceTests.test_Group_interface +test_GroupElem_interface = ConformanceTests.test_GroupElem_interface diff --git a/test/conformance-tests.jl b/test/conformance-tests.jl index b1c4b56388..edc34f0cb0 100644 --- a/test/conformance-tests.jl +++ b/test/conformance-tests.jl @@ -1,2 +1,4 @@ +# This file is just for backwards compatibility and should be removed in the future. + include("Groups-conformance-tests.jl") include("Rings-conformance-tests.jl") diff --git a/test/generic/PermGroupAPI-test.jl b/test/generic/PermGroupAPI-test.jl index 26a51c7096..5a348a44fe 100644 --- a/test/generic/PermGroupAPI-test.jl +++ b/test/generic/PermGroupAPI-test.jl @@ -1,7 +1,7 @@ @testset "Groups API PermGroup" begin @testset "Sym($n)" for n in [1,2,5,10] G = SymmetricGroup(n) - test_Group_interface(G) - test_GroupElem_interface(rand(G, 2)...) + ConformanceTests.test_Group_interface(G) + ConformanceTests.test_GroupElem_interface(rand(G, 2)...) end end From af5c1ee5a8418c498cadee423ac754fb740fde91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 13 Jan 2025 12:14:34 +0100 Subject: [PATCH 06/11] Move Ring conformance tests to TestExt --- ext/TestExt/Mutating-ops.jl | 142 +++ ext/TestExt/Rings-conformance-tests.jl | 784 ++++++++++++++ ext/TestExt/TestExt.jl | 7 + src/ConformanceTests.jl | 137 ++- test/Rings-conformance-tests.jl | 1069 +------------------ test/generic/AbsMSeries-test.jl | 2 +- test/generic/AbsSeries-test.jl | 2 +- test/generic/FactoredFraction-test.jl | 2 +- test/generic/FreeAssociativeAlgebra-test.jl | 4 +- test/generic/FunctionField-test.jl | 2 +- test/generic/LaurentMPoly-test.jl | 6 +- test/generic/LaurentPoly-test.jl | 8 +- test/generic/LaurentSeries-test.jl | 2 +- test/generic/MPoly-test.jl | 10 +- test/generic/Poly-test.jl | 8 +- test/generic/PuiseuxSeries-test.jl | 2 +- test/generic/RationalFunctionField-test.jl | 2 +- test/generic/RelSeries-test.jl | 2 +- test/generic/Residue-test.jl | 10 +- test/generic/UnivPoly-test.jl | 2 +- test/julia/Floats-test.jl | 4 +- test/julia/GFElem-test.jl | 8 +- test/julia/Integers-test.jl | 4 +- test/julia/Rationals-test.jl | 2 +- 24 files changed, 1138 insertions(+), 1083 deletions(-) create mode 100644 ext/TestExt/Mutating-ops.jl create mode 100644 ext/TestExt/Rings-conformance-tests.jl diff --git a/ext/TestExt/Mutating-ops.jl b/ext/TestExt/Mutating-ops.jl new file mode 100644 index 0000000000..b70da0f728 --- /dev/null +++ b/ext/TestExt/Mutating-ops.jl @@ -0,0 +1,142 @@ +# The following functions should not expect that their input is a `NCRingElem` or similar. +# They should be usable in more general types, that don't even have a `parent/elem` correspondence + +function ConformanceTests.test_mutating_op_like_zero(f::Function, f!::Function, A) + a = deepcopy(A) + a = f!(a) + @test equality(a, f(A)) +end + +function ConformanceTests.test_mutating_op_like_neg(f::Function, f!::Function, A) + # initialize storage var with different values to check that its value is not used + for z in [zero(A), deepcopy(A)] + a = deepcopy(A) + z = f!(z, a) + @test equality(z, f(A)) + @test a == A + end + + a = deepcopy(A) + a = f!(a) + @test equality(a, f(A)) +end + +function ConformanceTests.test_mutating_op_like_add(f::Function, f!::Function, A, B, T = Any) + @req A isa T || B isa T "Invalid argument types" + + # initialize storage var with different values to check that its value is not used + storage_values = T[] + if A isa T + push!(storage_values, zero(A)) + push!(storage_values, deepcopy(A)) + end + if B isa T + push!(storage_values, zero(B)) + push!(storage_values, deepcopy(B)) + end + for z in storage_values + a = deepcopy(A) + b = deepcopy(B) + z = f!(z, a, b) + @test equality(z, f(A, B)) + @test a == A + @test b == B + end + + if A isa T + a = deepcopy(A) + b = deepcopy(B) + a = f!(a, a, b) + @test equality(a, f(A, B)) + @test b == B + + a = deepcopy(A) + b = deepcopy(B) + a = f!(a, b) + @test equality(a, f(A, B)) + @test b == B + end + + if B isa T + a = deepcopy(A) + b = deepcopy(B) + b = f!(b, a, b) + @test equality(b, f(A, B)) + @test a == A + end + + if A isa T && B isa T + # `f(B, B)` may fail if `!(A isa T)`, since we call it with different arguments than the intended `f(A, B)` (same for f!) + a = deepcopy(A) + b = deepcopy(B) + a = f!(a, b, b) + @test equality(a, f(B, B)) + @test b == B + + b = deepcopy(B) + b = f!(b, b, b) + @test equality(b, f(B, B)) + + b = deepcopy(B) + b = f!(b, b) + @test equality(b, f(B, B)) + end +end + +function ConformanceTests.test_mutating_op_like_addmul(f::Function, f!_::Function, Z, A, B, T = Any) + @req Z isa T "Invalid argument types" + @req A isa T || B isa T "Invalid argument types" + + f!(z, a, b, ::Nothing) = f!_(z, a, b) + f!(z, a, b, t) = f!_(z, a, b, t) + + # initialize storage var with different values to check that its value is not used + # and `nothing` for the three-arg dispatch + storage_values = Union{T,Nothing}[nothing] + if A isa T + push!(storage_values, zero(A)) + push!(storage_values, deepcopy(A)) + end + if B isa T + push!(storage_values, zero(B)) + push!(storage_values, deepcopy(B)) + end + for t in storage_values + z = deepcopy(Z) + a = deepcopy(A) + b = deepcopy(B) + z = f!(z, a, b, t) + @test equality(z, f(Z, A, B)) + @test a == A + @test b == B + + if A isa T + a = deepcopy(A) + b = deepcopy(B) + a = f!(a, a, b, t) + @test equality(a, f(A, A, B)) + @test b == B + end + + if B isa T + a = deepcopy(A) + b = deepcopy(B) + b = f!(b, a, b, t) + @test equality(b, f(B, A, B)) + @test a == A + end + + if A isa T && B isa T + # `f(B, B)` may fail if `!(A isa T)`, since we call it with different arguments than the intended `f(A, B)` (same for f!) + a = deepcopy(A) + b = deepcopy(B) + a = f!(a, b, b, t) + @test equality(a, f(A, B, B)) + @test b == B + + b = deepcopy(B) + b = f!(b, b, b, t) + @test equality(b, f(B, B, B)) + end + end +end diff --git a/ext/TestExt/Rings-conformance-tests.jl b/ext/TestExt/Rings-conformance-tests.jl new file mode 100644 index 0000000000..69209c83f6 --- /dev/null +++ b/ext/TestExt/Rings-conformance-tests.jl @@ -0,0 +1,784 @@ +# very generic testing: just define test_elem(R) to produce elements of R, +# then invoke one of these functions, as appropriate: +# - test_NCRing_interface(R) +# - test_Ring_interface(R) +# - test_Ring_interface_recursive(R) +# - test_Field_interface(R) +# - test_Field_interface_recursive(R) +# +# The "recursive" variants perform additional tests on algebraic +# structures derived from the original ring, by calling these helpers: +# - test_EuclideanRing_interface(R) +# - test_Poly_interface(R) +# - test_MPoly_interface(R) +# - test_MatSpace_interface(R) +# - test_MatAlgebra_interface(R) + + +function ConformanceTests.test_NCRing_interface(R::AbstractAlgebra.NCRing; reps = 50) + + T = elem_type(R) + + @testset "NCRing interface for $(R) of type $(typeof(R))" begin + + @test T <: NCRingElem || T <: RingElement + + @testset "Functions for types and parents of rings" begin + @test elem_type(typeof(R)) == T + @test parent_type(T) == typeof(R) + for i in 1:reps + a = test_elem(R)::T + @test parent(a) == R + end + @test is_domain_type(T) isa Bool + @test is_exact_type(T) isa Bool + + # if the ring supports base_ring, verify it also supports base_ring_type and is consistent + if applicable(base_ring, R) + @test base_ring_type(R) == typeof(base_ring(R)) + @test base_ring_type(zero(R)) == typeof(base_ring(zero(R))) + @test base_ring_type(typeof(R)) == typeof(base_ring(R)) + @test base_ring_type(T) == typeof(base_ring(zero(R))) + end + + # some rings don't support characteristic and raise an exception (see issue #993) + try ch = characteristic(R) + @test iszero(R(characteristic(R))) + @test iszero(characteristic(R) * one(R)) + @test iszero(one(R) * characteristic(R)) + catch + end + end + + @testset "Constructors" begin + @test R() isa T + @test R(true) isa T + @test R(false) isa T + @test R(0) isa T + @test R(1) isa T + @test R(-2) isa T + @test R(BigInt(0)) isa T + @test R(BigInt(1)) isa T + @test R(BigInt(-2)) isa T + @test R(BigInt(3)^100) isa T + for i in 1:reps + a = test_elem(R)::T + @test R(a) isa T + end + end + + @testset "Basic functions" begin + @test iszero(R()) # R() is supposed to construct 0 ? + @test iszero(zero(R)) + @test isone(one(R)) + @test iszero(R(0)) + @test isone(R(1)) + @test isone(R(0)) || !is_unit(R(0)) + @test is_unit(R(1)) + for i in 1:reps + a = test_elem(R)::T + @test hash(a) isa UInt + A = deepcopy(a) + @test !ismutable(a) || a !== A + @test equality(a, A) + @test hash(a) == hash(A) + @test parent(a) === parent(A) + @test sprint(show, "text/plain", a) isa String + end + @test sprint(show, "text/plain", R) isa String + + for i in 1:reps + a = test_elem(R)::T + b = test_elem(R)::T + c = test_elem(R)::T + A = deepcopy(a) + B = deepcopy(b) + C = deepcopy(c) + @test equality(+(a), a) + @test equality(*(a), a) + @test equality(a^1, a) + @test equality(a^2, a*a) + @test equality(a^3, a*a*a) + @test equality(a^4, a*a*a*a) + @test equality((a + b) + c, a + (b + c)) + @test equality(a + b, b + a) + @test equality(a - c, a + (-c)) + @test equality(a + zero(R), a) + @test equality(a + (-a), zero(R)) + @test equality((a*b)*c, a*(b*c)) + @test equality(a*one(R), a) + @test equality(one(R)*a, a) + @test equality(a*(b + c), a*b + a*c) + @test equality((a + b)*c, a*c + b*c) + @test iszero(a*zero(R)) + @test iszero(zero(R)*a) + @test A == a + @test B == b + @test C == c + end + end + + if is_exact_type(T) + @testset "Adhoc operations with $S" for S in adhoc_partner_rings(R) + s0 = zero(S) + r0 = zero(R) + s1 = one(S) + r1 = one(R) + for i in 1:reps + s2 = test_elem(S) + r2 = R(s2) + x = test_elem(R) + + for (s,r) in ((s0, r0), (s1, r1), (s2, r2)) + @test equality(r, s) + @test equality(s, r) + + @test equality(x + s, x + r) + @test equality(s + x, r + x) + + @test equality(x - s, x - r) + @test equality(s - x, r - x) + + @test equality(x * s, x * r) + @test equality(s * x, r * x) + end + end + end + end + + if !(R isa AbstractAlgebra.Ring) + @testset "Basic functionality for noncommutative rings only" begin + for i in 1:reps + a = test_elem(R)::T + b = test_elem(R)::T + A = deepcopy(a) + B = deepcopy(b) + # documentation is not clear on divexact + if is_domain_type(T) + @test iszero(b) || equality(divexact_left(b*a, b), a) + @test iszero(b) || equality(divexact_left(b*a, b, check = true), a) + @test iszero(b) || equality(divexact_left(b*a, b, check = false), a) + @test iszero(b) || equality(b \ (b*a), a) + + @test iszero(b) || equality(divexact_right(a*b, b), a) + @test iszero(b) || equality(divexact_right(a*b, b, check = true), a) + @test iszero(b) || equality(divexact_right(a*b, b, check = false), a) + @test iszero(b) || equality((a*b) / b, a) + else + try + t = divexact_left(b*a, b) + @test equality(b*t, b*a) + t = divexact_left(b*a, b, check = true) + @test equality(b*t, b*a) + t = divexact_left(b*a, b, check = false) + @test equality(b*t, b*a) + t = b \ (b*a) + @test equality(b*t, b*a) + catch + end + try + t = divexact_right(a*b, b) + @test equality(t*b, a*b) + t = divexact_right(a*b, b, check = true) + @test equality(t*b, a*b) + t = divexact_right(a*b, b, check = false) + @test equality(t*b, a*b) + t = (a*b) / b + @test equality(t*b, a*b) + catch + end + end + @test A == a + @test B == b + end + end + end + + @testset "Unsafe ring operators" begin + for i in 1:reps + a = test_elem(R)::T + b = test_elem(R)::T + c = test_elem(R)::T + + ConformanceTests.test_mutating_op_like_zero(zero, zero!, a) + ConformanceTests.test_mutating_op_like_zero(one, one!, a) + + ConformanceTests.test_mutating_op_like_neg(-, neg!, a) + + ConformanceTests.test_mutating_op_like_add(+, add!, a, b) + ConformanceTests.test_mutating_op_like_add(-, sub!, a, b) + ConformanceTests.test_mutating_op_like_add(*, mul!, a, b) + + ConformanceTests.test_mutating_op_like_addmul((a, b, c) -> a + b*c, addmul!, a, b, c) + ConformanceTests.test_mutating_op_like_addmul((a, b, c) -> a - b*c, submul!, a, b, c) + end + end + end + + return nothing +end + + +function ConformanceTests.test_Ring_interface(R::AbstractAlgebra.Ring; reps = 50) + + T = elem_type(R) + + @testset "Ring interface for $(R) of type $(typeof(R))" begin + + @test T <: RingElement + + ConformanceTests.test_NCRing_interface(R; reps = reps) + + @testset "Basic functionality for commutative rings only" begin + @test isone(AbstractAlgebra.inv(one(R))) + ConformanceTests.test_mutating_op_like_neg(AbstractAlgebra.inv, inv!, one(R)) + ConformanceTests.test_mutating_op_like_neg(AbstractAlgebra.inv, inv!, -one(R)) + for i in 1:reps + a = test_elem(R)::T + b = test_elem(R)::T + A = deepcopy(a) + B = deepcopy(b) + @test a*b == b*a + # documentation is not clear on divexact + if is_domain_type(T) + @test iszero(b) || equality(divexact(b*a, b), a) + @test iszero(b) || equality(divexact(b*a, b, check = true), a) + @test iszero(b) || equality(divexact(b*a, b, check = false), a) + if T isa RingElem + @test iszero(b) || equality((b*a) / b, a) + end + iszero(b) || ConformanceTests.test_mutating_op_like_add(divexact, divexact!, b*a, b) + else + try + t = divexact(b*a, b) + @test equality(t*b, a*b) + t = divexact(b*a, b, check = true) + @test equality(t*b, a*b) + t = divexact(b*a, b, check = false) + @test equality(t*b, a*b) + if T isa RingElem + t = (b*a) / b + @test equality(t*b, a*b) + end + catch + end + end + try + (f, h) = is_zero_divisor_with_annihilator(a) + @test parent(h) == R + @test f == is_zero_divisor(a) + if f + @test !is_zero(h) + @test is_zero(a*h) + end + catch + end + @test A == a + @test B == b + end + end + end + + return nothing +end + +function ConformanceTests.test_Field_interface(R::AbstractAlgebra.Field; reps = 50) + + T = elem_type(R) + + @testset "Field interface for $(R) of type $(typeof(R))" begin + + ConformanceTests.test_Ring_interface(R, reps = reps) + + @test iszero(R(characteristic(R))) + @test iszero(characteristic(R) * one(R)) + @test iszero(one(R) * characteristic(R)) + + for i in 1:reps + a = test_elem(R)::T + A = deepcopy(a) + @test is_unit(a) == !iszero(a) + if !is_zero(a) + @test is_one(a * inv(a)) + @test is_one(inv(a) * a) + ConformanceTests.test_mutating_op_like_neg(inv, inv!, a) + end + @test A == a + end + end + + return nothing +end + +function ConformanceTests.test_EuclideanRing_interface(R::AbstractAlgebra.Ring; reps = 20) + + T = elem_type(R) + + is_exact_type(T) || return + + @testset "Euclidean Ring interface for $(R) of type $(typeof(R))" begin + + for i in 1:reps + f = test_elem(R)::T + g = test_elem(R)::T + m = test_elem(R)::T + if iszero(m) + m = one(R) + end + + @test (AbstractAlgebra.div(f, m), mod(f, m)) == AbstractAlgebra.divrem(f, m) + @test divides(mulmod(f, g, m) - mod(f*g, m), m)[1] + + fi = one(R) + for i in 1:5 + fi *= f + @test divides(fi - powermod(f, i, m), m)[1] + @test divides(fi - mod(f^i, m), m)[1] + end + + if is_unit(gcd(f, m)) + a = invmod(f, m) + @test divides(mulmod(a, f, m) - one(R), m)[1] + @test divides(powermod(f, -1, m) - a^1, m)[1] + @test divides(powermod(f, -2, m) - a^2, m)[1] + @test divides(powermod(f, -3, m) - a^3, m)[1] + end + + @test divides(f*m, m) == (true, f) + (a, b) = divides(f*m + g, m) + @test !a || b*m == f*m + g + + @test_throws Exception remove(f, zero(R)) + @test_throws Exception valuation(f, zero(R)) + + if !is_unit(m) && !iszero(f) + n = rand(0:3) + f *= m^n + (v, q) = remove(f, m) + @test valuation(f, m) == v + @test v >= n + @test q*m^v == f + @test remove(q, m) == (0, q) + @test valuation(q, m) == 0 + end + + @test !(iszero(f) && iszero(g)) || iszero(gcd(f, g)) + @test equality_up_to_units(gcd(f, g)*lcm(f, g), f*g) + + g1 = gcd(f, gcd(g, m)) + g2 = gcd(gcd(f, g), m) + g3 = gcd(f, g, m) + g4 = gcd([f, g, m]) + @test equality_up_to_units(g1, g2) + @test equality_up_to_units(g2, g3) + @test equality_up_to_units(g3, g4) + + l1 = lcm(f, lcm(g, m)) + l2 = lcm(lcm(f, g), m) + l3 = lcm(f, g, m) + l4 = lcm([f, g, m]) + @test equality_up_to_units(l1, l2) + @test equality_up_to_units(l2, l3) + @test equality_up_to_units(l3, l4) + + (d, s, t) = gcdx(f, g) + @test d == gcd(f, g) + @test d == s*f + t*g + @test gcdinv(f, g) == (d, s) + + ConformanceTests.test_mutating_op_like_add(AbstractAlgebra.div, div!, f, m) + ConformanceTests.test_mutating_op_like_add(mod, mod!, f, m) + ConformanceTests.test_mutating_op_like_add(gcd, gcd!, f, m) + ConformanceTests.test_mutating_op_like_add(lcm, lcm!, f, m) + end + + end + + return nothing +end + + +function ConformanceTests.test_Poly_interface(Rx::AbstractAlgebra.PolyRing; reps = 30) + + T = elem_type(Rx) + + @testset "Poly interface for $(Rx) of type $(typeof(Rx))" begin + + ConformanceTests.test_Ring_interface(Rx; reps = reps) + + x = gen(Rx) + R = base_ring(Rx) + + @testset "Polynomial Constructors" begin + for i in 1:reps + a = test_elem(Rx)::T + for b in coefficients(a) + @assert Rx(b) isa T + end + @test a == Rx(collect(coefficients(a))) + + B = MPolyBuildCtx(Rx) # TODO rename to BuildCtx + for (c, e) in zip(AbstractAlgebra.coefficients(a), AbstractAlgebra.exponent_vectors(a)) + push_term!(B, c, e) + end + @test finish(B) == a + end + @test Rx(Int[]) == zero(Rx) + @test Rx([0, 1, 2]) == x + 2*x^2 + @test Rx([big(0), big(1), big(2)]) == x + 2*x^2 + @test Rx(map(R, [0, 1, 2])) == x + 2*x^2 + end + + if R isa AbstractAlgebra.Field + ConformanceTests.test_EuclideanRing_interface(Rx, reps = 2 + fld(reps, 2)) + @testset "Half-GCD" begin + for i in 1:reps + a = test_elem(Rx) + b = test_elem(Rx) + for j in 1:8 + q = test_elem(Rx) + a, b = q*a + b, a + end + g, s, t = gcdx(a, b) + @test g == gcd(a, b) + @test g == s*a + t*b + @test (g, s) == gcdinv(a, b) + if degree(a) < degree(b) + a, b = b, a + end + degree(a) > degree(b) >= 0 || continue + (A, B, m11, m12, m21, m22, s) = hgcd(a, b) + @test degree(A) >= cld(degree(a), 2) > degree(B) + @test m11*A + m12*B == a + @test m21*A + m22*B == b + @test m11*m22 - m21*m12 == s + @test s^2 == 1 + end + end + end + + @testset "Basic functionality" begin + @test var(Rx) isa Symbol + @test symbols(Rx) isa Vector{Symbol} + @test length(symbols(Rx)) == 1 + @test is_gen(gen(Rx)) + @test is_gen(x) + @test is_monic(x) + @test is_trivial(Rx) || !is_gen(x^2) + for i in 1:reps + a = test_elem(Rx) + @test iszero(a) || degree(a) >= 0 + @test equality(a, leading_coefficient(a)*x^max(0, degree(a)) + tail(a)) + @test constant_coefficient(a) isa elem_type(R) + @test trailing_coefficient(a) isa elem_type(R) + @test is_monic(a) == isone(leading_coefficient(a)) + end + end + end + + return nothing +end + + +function ConformanceTests.test_MPoly_interface(Rxy::AbstractAlgebra.MPolyRing; reps = 30) + + # for simplicity, these tests for now assume exactly two generators + @assert ngens(Rxy) == 2 + + T = elem_type(Rxy) + + @testset "MPoly interface for $(Rxy) of type $(typeof(Rxy))" begin + + ConformanceTests.test_Ring_interface(Rxy; reps = reps) + + @testset "Basic functionality" begin + @test symbols(Rxy) isa Vector{Symbol} + @test length(symbols(Rxy)) == ngens(Rxy) + @test length(gens(Rxy)) == ngens(Rxy) + @test gens(Rxy) == [gen(Rxy, i) for i in 1:ngens(Rxy)] + @test all(is_gen, gens(Rxy)) || is_trivial(Rxy) + end + + @testset "Polynomial Constructors" begin + for i in 1:reps + a = test_elem(Rxy)::T + for b in coefficients(a) + @assert Rxy(b) isa T + end + + # test MPolyBuildCtx + B = MPolyBuildCtx(Rxy) + for (c, e) in zip(AbstractAlgebra.coefficients(a), AbstractAlgebra.exponent_vectors(a)) + push_term!(B, c, e) + end + @test finish(B) == a + end + x, y = gens(Rxy) + f = 13*x^3*y^4 + 2*x - 7 + #@test Rxy([2,-7,13], [[1,0],[0,0],[3,4]]) == f # FIXME: interface spec does not say this is required? + + R = base_ring(Rxy) + @test Rxy(R.([2,-7,13]), [[1,0],[0,0],[3,4]]) == f + end + + # skip trivial rings after this, it is not worth the bother + is_trivial(Rxy) && return + + @testset "Element properties" begin + R = base_ring(Rxy) + x, y = gens(Rxy) + + a = zero(Rxy) + @test !is_monomial(a) + @test !is_term(a) + @test is_constant(a) + @test !is_gen(a) + @test !is_unit(a) + @test is_nilpotent(a) + @test length(a) == 0 + @test total_degree(a) < 0 + @test all(is_negative, degrees(a)) + + a = one(Rxy) + @test is_monomial(a) + @test is_term(a) + @test is_constant(a) + @test !is_gen(a) + @test is_unit(a) + @test !is_nilpotent(a) + @test length(a) == 1 + @test total_degree(a) == 0 + @test degrees(a) == [0, 0] + + a = x + @test is_monomial(a) + @test is_term(a) + @test !is_constant(a) + @test is_gen(a) + @test !is_unit(a) + @test !is_nilpotent(a) + @test length(a) == 1 + @test total_degree(a) == 1 + @test degrees(a) == [1, 0] + + a = x^2 + @test is_monomial(a) + @test is_term(a) + @test !is_constant(a) + @test !is_gen(a) + @test !is_unit(a) + @test !is_nilpotent(a) + @test length(a) == 1 + @test total_degree(a) == 2 + @test degrees(a) == [2, 0] + + if !is_zero(R(2)) + a = 2*x + @test !is_monomial(a) + @test is_term(a) + @test !is_constant(a) + @test !is_gen(a) + @test !is_unit(a) + @test is_nilpotent(a) == is_nilpotent(R(2)) + @test length(a) == 1 + @test total_degree(a) == 1 + @test degrees(a) == [1, 0] + end + + a = x^3 + y^4 + @test !is_monomial(a) + @test !is_term(a) + @test !is_constant(a) + @test !is_gen(a) + @test !is_unit(a) + @test !is_nilpotent(a) + @test length(a) == 2 + @test total_degree(a) == 4 + @test degrees(a) == [3, 4] + + for i in 1:reps + a = test_elem(Rxy) + iszero(a) && continue + @test length(a) >= 0 + @test sum(degrees(a)) >= total_degree(a) + end + + end + + # TODO: add more tests, covering everything described in the manual, see + # https://nemocas.github.io/AbstractAlgebra.jl/dev/mpoly_interface/ + # https://nemocas.github.io/AbstractAlgebra.jl/dev/mpolynomial/ + end + + return nothing +end + + +function ConformanceTests.test_MatSpace_interface(S::MatSpace; reps = 20) + + ST = elem_type(S) + R = base_ring(S) + T = elem_type(R) + + @test base_ring_type(S) == typeof(R) + @test parent_type(ST) == typeof(S) + @test dense_matrix_type(R) == ST + + @testset "MatSpace interface for $(S) of type $(typeof(S))" begin + + @testset "Constructors" begin + for k in 1:reps + a = test_elem(S)::ST + @test nrows(a) == nrows(S) + @test ncols(a) == ncols(S) + @test a == S(T[a[i, j] for i in 1:nrows(a), j in 1:ncols(a)]) + @test a == S(T[a[i, j] for i in 1:nrows(a) for j in 1:ncols(a)]) + @test a == matrix(R, T[a[i, j] for i in 1:nrows(a), j in 1:ncols(a)]) + @test a == matrix(R, nrows(S), ncols(S), + T[a[i, j] for i in 1:nrows(a) for j in 1:ncols(a)]) + + b = similar(a) + @test b isa ST + @test nrows(b) == nrows(S) + @test ncols(b) == ncols(S) + + b = similar(a, nrows(S)+1, ncols(S)+1) + @test b isa ST + @test nrows(b) == nrows(S)+1 + @test ncols(b) == ncols(S)+1 + + b = similar(a, R) + @test b isa MatElem + #@test b isa ST # undefined + @test nrows(b) == nrows(S) + @test ncols(b) == ncols(S) + + b = similar(a, R, nrows(S)+1, ncols(S)+1) + @test b isa MatElem + #@test b isa ST # undefined + @test nrows(b) == nrows(S)+1 + @test ncols(b) == ncols(S)+1 + + end + @test iszero(zero_matrix(R, nrows(S), ncols(S))) + end + + @testset "Views" begin + M = matrix(R, 3, 3, BigInt[1, 2, 3, 2, 3, 4, 3, 4, 5]) + N1 = @view M[1:2, :] + N2 = @view M[:, 1:2] + @test N1*N2 == matrix(R, 2, 2, BigInt[14, 20, 20, 29]) + end + + @testset "Basic manipulation of matrices" begin + for k in 1:reps + a = test_elem(S)::ST + A = deepcopy(a) + @test A isa ST + + b = zero_matrix(R, nrows(a), ncols(a)) + @test b isa ST + for i in 1:nrows(a), j in 1:ncols(a) + b[i, j] = a[i, j] + end + @test b == a + + t = transpose(a) + @test t isa ST + @test nrows(t) == ncols(S) + @test ncols(t) == nrows(S) + @test transpose(t) == a + @test a == A + end + end + + @testset "Row & column permutations" begin + a = matrix(R, [1 2 ; 3 4]) + b = swap_rows(a, 1, 2) + @test b == matrix(R, [3 4 ; 1 2]) + @test a == matrix(R, [1 2 ; 3 4]) + + a = matrix(R, [1 2 ; 3 4]) + b = swap_cols(a, 1, 2) + @test b == matrix(R, [2 1 ; 4 3]) + @test a == matrix(R, [1 2 ; 3 4]) + + # TODO: reverse_rows, reverse_cols + # TODO: add_column, add_row + # TODO: multiply_column, multiply_row + # TODO: ! variants (such as `swap_cols!` etc.) of all of the above + end + + end + + return nothing +end + +function ConformanceTests.test_MatAlgebra_interface(S::MatRing; reps = 20) + + ST = elem_type(S) + R = base_ring(S) + T = elem_type(R) + + @test nrows(S) == ncols(S) + + @testset "MatRing interface for $(S) of type $(typeof(S))" begin + + ConformanceTests.test_NCRing_interface(S, reps = reps) + + @testset "Constructors" begin + for k in 1:reps + a = test_elem(S)::ST + @test nrows(a) == nrows(S) + @test ncols(a) == ncols(S) + @test a == S(T[a[i, j] for i in 1:nrows(a), j in 1:ncols(a)]) + @test a == S(T[a[i, j] for i in 1:nrows(a) for j in 1:ncols(a)]) + end + end + + @testset "Basic manipulation of matrices" begin + for k in 1:reps + a = test_elem(S)::ST + A = deepcopy(a) + b = zero(S) + for i in 1:nrows(a), j in 1:ncols(a) + b[i, j] = a[i, j] + end + @test b == a + @test transpose(transpose(a)) == a + @test a == A + end + end + + @testset "Determinant" begin + for k in 1:reps + a = test_elem(S)::ST + b = test_elem(S)::ST + A = deepcopy(a) + B = deepcopy(b) + @test det(a*b) == det(a)*det(b) + @test a == A + @test b == B + end + end + end + + return nothing +end + +function ConformanceTests.test_Ring_interface_recursive(R::AbstractAlgebra.Ring; reps = 50) + ConformanceTests.test_Ring_interface(R; reps = reps) + Rx, _ = polynomial_ring(R, :x) + ConformanceTests.test_Poly_interface(Rx, reps = 2 + fld(reps, 2)) + Rxy, _ = polynomial_ring(R, [:x, :y]) + ConformanceTests.test_MPoly_interface(Rxy, reps = 2 + fld(reps, 2)) + S = matrix_ring(R, rand(0:3)) + ConformanceTests.test_MatAlgebra_interface(S, reps = 2 + fld(reps, 2)) + S = matrix_space(R, rand(0:3), rand(0:3)) + ConformanceTests.test_MatSpace_interface(S, reps = 2 + fld(reps, 2)) +end + +function ConformanceTests.test_Field_interface_recursive(R::AbstractAlgebra.Field; reps = 50) + ConformanceTests.test_Ring_interface_recursive(R, reps = reps) + ConformanceTests.test_Field_interface(R, reps = reps) +end diff --git a/ext/TestExt/TestExt.jl b/ext/TestExt/TestExt.jl index a61384d6a7..b512f9fbca 100644 --- a/ext/TestExt/TestExt.jl +++ b/ext/TestExt/TestExt.jl @@ -3,8 +3,15 @@ module TestExt using AbstractAlgebra isdefined(Base, :get_extension) ? (using Test) : (using ..Test) +using .ConformanceTests: + equality, + equality_up_to_units, + adhoc_partner_rings, + test_elem include("Groups-conformance-tests.jl") +include("Mutating-ops.jl") +include("Rings-conformance-tests.jl") function ConformanceTests.test_iterate(F::FinField) diff --git a/src/ConformanceTests.jl b/src/ConformanceTests.jl index bb109c9008..7de0c2631e 100644 --- a/src/ConformanceTests.jl +++ b/src/ConformanceTests.jl @@ -1,13 +1,148 @@ module ConformanceTests -# This file only contains function stubs. +using ..AbstractAlgebra + +# This file mostly contains function stubs. # The actual implementation are in the folder `ext/TestExt/`. + +# helper +function equality(a, b) + if is_exact_type(typeof(a)) && is_exact_type(typeof(b)) + return a == b + else + return isapprox(a, b) + end +end + +function equality_up_to_units(a, b) + iszero(a) && return iszero(b) + iszero(b) && return iszero(a) + return divides(a, b)[1] && divides(b, a)[1] +end + +const default_adhoc_partner_rings = [ + AbstractAlgebra.Integers{BigInt}(), + AbstractAlgebra.Integers{Int}(), + AbstractAlgebra.Integers{UInt}(), + AbstractAlgebra.Integers{UInt8}(), + ] + +adhoc_partner_rings(R::NCRing) = default_adhoc_partner_rings + + +# +# add methods for test_elem on ring elements here +# +function test_elem(R::AbstractAlgebra.Integers{T}) where {T <: Signed} + n = T(2)^rand((1,1,1,2,3,10,31,32,33,63,64,65,100)) + return rand(R, -n:n) +end + +function test_elem(R::AbstractAlgebra.Integers{T}) where {T <: Unsigned} + n = T(2)^rand((1,1,1,2,3,10,31,32,33,63,64,65,100)) + return rand(R, 0:n) +end + +function test_elem(R::AbstractAlgebra.Rationals) + B = base_ring(R) + n = test_elem(B) + d = test_elem(B) + return is_zero(d) ? R(n) : R(n, d) +end + +function test_elem(R::AbstractAlgebra.FinField) + return rand(R) +end + +function test_elem(R::AbstractAlgebra.Floats{T}) where T + return rand(T)*rand(-100:100) +end + +function test_elem(Rx::AbstractAlgebra.PolyRing) + R = base_ring(Rx) + return Rx(elem_type(R)[test_elem(R) for i in 1:rand(0:6)]) +end + +function test_elem(Rx::AbstractAlgebra.MPolyRing) + R = base_ring(Rx) + num_gens = ngens(Rx) + iszero(num_gens) && return Rx(test_elem(R)) + len_bound = 8 + exp_bound = rand(1:5) + len = rand(0:len_bound) + coeffs = [test_elem(R) for _ in 1:len] + exps = [[rand(0:exp_bound) for _ in 1:num_gens] for _ in 1:len] + return Rx(coeffs, exps) +end + +function test_elem(S::Union{AbstractAlgebra.MatSpace, + AbstractAlgebra.MatRing}) + R = base_ring(S) + return S(elem_type(R)[test_elem(R) for i in 1:nrows(S), j in 1:ncols(S)]) +end + +function test_elem(R::AbstractAlgebra.EuclideanRingResidueRing) + return R(test_elem(base_ring(R))) +end + +function test_elem(Rx::AbstractAlgebra.SeriesRing) + R = base_ring(Rx) + prec = rand(3:10) + len = rand(0:prec-1) + val = rand(0:prec-len) + # FIXME: constructors don't seem to catch use of negative val + @assert val >= 0 + A = elem_type(R)[test_elem(R) for i in 1:len] + if len > 0 && is_zero(A[1]) + A[1] = one(R) + end + if elem_type(Rx) <: RelPowerSeriesRingElem + @assert prec >= len + val + return Rx(A, len, prec, val) + else + @assert prec >= len + return Rx(A, len, prec) + end +end + +function test_elem(S::AbstractAlgebra.FreeAssociativeAlgebra) + f = S() + g = gens(S) + R = base_ring(S) + isempty(g) && return S(test_elem(R)) + len_bound = 8 + exp_bound = 6 + for i in 1:rand(0:len_bound) + f += test_elem(R) * prod(rand(g) for _ in 1:rand(0:exp_bound); init = S(1)) + end + return f +end + + function test_iterate end # Groups-conformance-tests.jl function test_Group_interface end function test_GroupElem_interface end +# Mutating-ops.jl +function test_mutating_op_like_zero end +function test_mutating_op_like_neg end +function test_mutating_op_like_add end +function test_mutating_op_like_addmul end + +# Rings-conformance-tests.jl +function test_NCRing_interface end +function test_Ring_interface end +function test_Field_interface end +function test_EuclideanRing_interface end +function test_Poly_interface end +function test_MPoly_interface end +function test_MatSpace_interface end +function test_MatAlgebra_interface end +function test_Ring_interface_recursive end +function test_Field_interface_recursive end + end # module diff --git a/test/Rings-conformance-tests.jl b/test/Rings-conformance-tests.jl index 0e9aa40979..8c31d44c59 100644 --- a/test/Rings-conformance-tests.jl +++ b/test/Rings-conformance-tests.jl @@ -1,1041 +1,28 @@ -# very generic testing: just define test_elem(R) to produce elements of R, -# then invoke one of these functions, as appropriate: -# - test_NCRing_interface(R) -# - test_Ring_interface(R) -# - test_Ring_interface_recursive(R) -# - test_Field_interface(R) -# - test_Field_interface_recursive(R) -# -# The "recursive" variants perform additional tests on algebraic -# structures derived from the original ring, by calling these helpers: -# - test_EuclideanRing_interface(R) -# - test_Poly_interface(R) -# - test_MatSpace_interface(R) -# - test_MatAlgebra_interface(R) - -# -# -# -const default_adhoc_partner_rings = [ - AbstractAlgebra.Integers{BigInt}(), - AbstractAlgebra.Integers{Int}(), - AbstractAlgebra.Integers{UInt}(), - AbstractAlgebra.Integers{UInt8}(), - ] - -adhoc_partner_rings(R::NCRing) = default_adhoc_partner_rings - -# -# add methods for test_elem on ring elements here -# - -function test_elem(R::AbstractAlgebra.Integers{T}) where {T <: Signed} - n = T(2)^rand((1,1,1,2,3,10,31,32,33,63,64,65,100)) - return rand(R, -n:n) -end - -function test_elem(R::AbstractAlgebra.Integers{T}) where {T <: Unsigned} - n = T(2)^rand((1,1,1,2,3,10,31,32,33,63,64,65,100)) - return rand(R, 0:n) -end - -function test_elem(R::AbstractAlgebra.Rationals) - B = base_ring(R) - n = test_elem(B) - d = test_elem(B) - return is_zero(d) ? R(n) : R(n, d) -end - -function test_elem(R::AbstractAlgebra.FinField) - return rand(R) -end - -function test_elem(R::AbstractAlgebra.Floats{T}) where T - return rand(T)*rand(-100:100) -end - -function test_elem(Rx::AbstractAlgebra.PolyRing) - R = base_ring(Rx) - return Rx(elem_type(R)[test_elem(R) for i in 1:rand(0:6)]) -end - -function test_elem(Rx::AbstractAlgebra.MPolyRing) - R = base_ring(Rx) - num_gens = ngens(Rx) - iszero(num_gens) && return Rx(test_elem(R)) - len_bound = 8 - exp_bound = rand(1:5) - len = rand(0:len_bound) - coeffs = [test_elem(R) for _ in 1:len] - exps = [[rand(0:exp_bound) for _ in 1:num_gens] for _ in 1:len] - return Rx(coeffs, exps) -end - -function test_elem(S::Union{AbstractAlgebra.MatSpace, - AbstractAlgebra.MatRing}) - R = base_ring(S) - return S(elem_type(R)[test_elem(R) for i in 1:nrows(S), j in 1:ncols(S)]) -end - -function test_elem(R::AbstractAlgebra.EuclideanRingResidueRing) - return R(test_elem(base_ring(R))) -end - -function test_elem(Rx::AbstractAlgebra.SeriesRing) - R = base_ring(Rx) - prec = rand(3:10) - len = rand(0:prec-1) - val = rand(0:prec-len) - # FIXME: constructors don't seem to catch use of negative val - @assert val >= 0 - A = elem_type(R)[test_elem(R) for i in 1:len] - if len > 0 && is_zero(A[1]) - A[1] = one(R) - end - if elem_type(Rx) <: RelPowerSeriesRingElem - @assert prec >= len + val - return Rx(A, len, prec, val) - else - @assert prec >= len - return Rx(A, len, prec) - end -end - -function test_elem(S::AbstractAlgebra.FreeAssociativeAlgebra) - f = S() - g = gens(S) - R = base_ring(S) - isempty(g) && return S(test_elem(R)) - len_bound = 8 - exp_bound = 6 - for i in 1:rand(0:len_bound) - f += test_elem(R) * prod(rand(g) for _ in 1:rand(0:exp_bound); init = S(1)) - end - return f -end - - -# helper -function equality(a, b) - if is_exact_type(typeof(a)) && is_exact_type(typeof(b)) - return a == b - else - return isapprox(a, b) - end -end - -# The following functions should not expect that their input is a `NCRingElem` or similar. -# They should be usable in more general types, that don't even have a `parent/elem` correspondence -function test_mutating_op_like_zero(f::Function, f!::Function, A) - a = deepcopy(A) - a = f!(a) - @test equality(a, f(A)) -end - -function test_mutating_op_like_neg(f::Function, f!::Function, A) - # initialize storage var with different values to check that its value is not used - for z in [zero(A), deepcopy(A)] - a = deepcopy(A) - z = f!(z, a) - @test equality(z, f(A)) - @test a == A - end - - a = deepcopy(A) - a = f!(a) - @test equality(a, f(A)) -end - -function test_mutating_op_like_add(f::Function, f!::Function, A, B, T = Any) - @req A isa T || B isa T "Invalid argument types" - - # initialize storage var with different values to check that its value is not used - storage_values = T[] - if A isa T - push!(storage_values, zero(A)) - push!(storage_values, deepcopy(A)) - end - if B isa T - push!(storage_values, zero(B)) - push!(storage_values, deepcopy(B)) - end - for z in storage_values - a = deepcopy(A) - b = deepcopy(B) - z = f!(z, a, b) - @test equality(z, f(A, B)) - @test a == A - @test b == B - end - - if A isa T - a = deepcopy(A) - b = deepcopy(B) - a = f!(a, a, b) - @test equality(a, f(A, B)) - @test b == B - - a = deepcopy(A) - b = deepcopy(B) - a = f!(a, b) - @test equality(a, f(A, B)) - @test b == B - end - - if B isa T - a = deepcopy(A) - b = deepcopy(B) - b = f!(b, a, b) - @test equality(b, f(A, B)) - @test a == A - end - - if A isa T && B isa T - # `f(B, B)` may fail if `!(A isa T)`, since we call it with different arguments than the intended `f(A, B)` (same for f!) - a = deepcopy(A) - b = deepcopy(B) - a = f!(a, b, b) - @test equality(a, f(B, B)) - @test b == B - - b = deepcopy(B) - b = f!(b, b, b) - @test equality(b, f(B, B)) - - b = deepcopy(B) - b = f!(b, b) - @test equality(b, f(B, B)) - end -end - -function test_mutating_op_like_addmul(f::Function, f!_::Function, Z, A, B, T = Any) - @req Z isa T "Invalid argument types" - @req A isa T || B isa T "Invalid argument types" - - f!(z, a, b, ::Nothing) = f!_(z, a, b) - f!(z, a, b, t) = f!_(z, a, b, t) - - # initialize storage var with different values to check that its value is not used - # and `nothing` for the three-arg dispatch - storage_values = Union{T,Nothing}[nothing] - if A isa T - push!(storage_values, zero(A)) - push!(storage_values, deepcopy(A)) - end - if B isa T - push!(storage_values, zero(B)) - push!(storage_values, deepcopy(B)) - end - for t in storage_values - z = deepcopy(Z) - a = deepcopy(A) - b = deepcopy(B) - z = f!(z, a, b, t) - @test equality(z, f(Z, A, B)) - @test a == A - @test b == B - - if A isa T - a = deepcopy(A) - b = deepcopy(B) - a = f!(a, a, b, t) - @test equality(a, f(A, A, B)) - @test b == B - end - - if B isa T - a = deepcopy(A) - b = deepcopy(B) - b = f!(b, a, b, t) - @test equality(b, f(B, A, B)) - @test a == A - end - - if A isa T && B isa T - # `f(B, B)` may fail if `!(A isa T)`, since we call it with different arguments than the intended `f(A, B)` (same for f!) - a = deepcopy(A) - b = deepcopy(B) - a = f!(a, b, b, t) - @test equality(a, f(A, B, B)) - @test b == B - - b = deepcopy(B) - b = f!(b, b, b, t) - @test equality(b, f(B, B, B)) - end - end -end - -function test_NCRing_interface(R::AbstractAlgebra.NCRing; reps = 50) - - T = elem_type(R) - - @testset "NCRing interface for $(R) of type $(typeof(R))" begin - - @test T <: NCRingElem || T <: RingElement - - @testset "Functions for types and parents of rings" begin - @test elem_type(typeof(R)) == T - @test parent_type(T) == typeof(R) - for i in 1:reps - a = test_elem(R)::T - @test parent(a) == R - end - @test is_domain_type(T) isa Bool - @test is_exact_type(T) isa Bool - - # if the ring supports base_ring, verify it also supports base_ring_type and is consistent - if applicable(base_ring, R) - @test base_ring_type(R) == typeof(base_ring(R)) - @test base_ring_type(zero(R)) == typeof(base_ring(zero(R))) - @test base_ring_type(typeof(R)) == typeof(base_ring(R)) - @test base_ring_type(T) == typeof(base_ring(zero(R))) - end - - # some rings don't support characteristic and raise an exception (see issue #993) - try ch = characteristic(R) - @test iszero(R(characteristic(R))) - @test iszero(characteristic(R) * one(R)) - @test iszero(one(R) * characteristic(R)) - catch - end - end - - @testset "Constructors" begin - @test R() isa T - @test R(true) isa T - @test R(false) isa T - @test R(0) isa T - @test R(1) isa T - @test R(-2) isa T - @test R(BigInt(0)) isa T - @test R(BigInt(1)) isa T - @test R(BigInt(-2)) isa T - @test R(BigInt(3)^100) isa T - for i in 1:reps - a = test_elem(R)::T - @test R(a) isa T - end - end - - @testset "Basic functions" begin - @test iszero(R()) # R() is supposed to construct 0 ? - @test iszero(zero(R)) - @test isone(one(R)) - @test iszero(R(0)) - @test isone(R(1)) - @test isone(R(0)) || !is_unit(R(0)) - @test is_unit(R(1)) - for i in 1:reps - a = test_elem(R)::T - @test hash(a) isa UInt - A = deepcopy(a) - @test !ismutable(a) || a !== A - @test equality(a, A) - @test hash(a) == hash(A) - @test parent(a) === parent(A) - @test sprint(show, "text/plain", a) isa String - end - @test sprint(show, "text/plain", R) isa String - - for i in 1:reps - a = test_elem(R)::T - b = test_elem(R)::T - c = test_elem(R)::T - A = deepcopy(a) - B = deepcopy(b) - C = deepcopy(c) - @test equality(+(a), a) - @test equality(*(a), a) - @test equality(a^1, a) - @test equality(a^2, a*a) - @test equality(a^3, a*a*a) - @test equality(a^4, a*a*a*a) - @test equality((a + b) + c, a + (b + c)) - @test equality(a + b, b + a) - @test equality(a - c, a + (-c)) - @test equality(a + zero(R), a) - @test equality(a + (-a), zero(R)) - @test equality((a*b)*c, a*(b*c)) - @test equality(a*one(R), a) - @test equality(one(R)*a, a) - @test equality(a*(b + c), a*b + a*c) - @test equality((a + b)*c, a*c + b*c) - @test iszero(a*zero(R)) - @test iszero(zero(R)*a) - @test A == a - @test B == b - @test C == c - end - end - - if is_exact_type(T) - @testset "Adhoc operations with $S" for S in adhoc_partner_rings(R) - s0 = zero(S) - r0 = zero(R) - s1 = one(S) - r1 = one(R) - for i in 1:reps - s2 = test_elem(S) - r2 = R(s2) - x = test_elem(R) - - for (s,r) in ((s0, r0), (s1, r1), (s2, r2)) - @test equality(r, s) - @test equality(s, r) - - @test equality(x + s, x + r) - @test equality(s + x, r + x) - - @test equality(x - s, x - r) - @test equality(s - x, r - x) - - @test equality(x * s, x * r) - @test equality(s * x, r * x) - end - end - end - end - - if !(R isa AbstractAlgebra.Ring) - @testset "Basic functionality for noncommutative rings only" begin - for i in 1:reps - a = test_elem(R)::T - b = test_elem(R)::T - A = deepcopy(a) - B = deepcopy(b) - # documentation is not clear on divexact - if is_domain_type(T) - @test iszero(b) || equality(divexact_left(b*a, b), a) - @test iszero(b) || equality(divexact_left(b*a, b, check = true), a) - @test iszero(b) || equality(divexact_left(b*a, b, check = false), a) - @test iszero(b) || equality(b \ (b*a), a) - - @test iszero(b) || equality(divexact_right(a*b, b), a) - @test iszero(b) || equality(divexact_right(a*b, b, check = true), a) - @test iszero(b) || equality(divexact_right(a*b, b, check = false), a) - @test iszero(b) || equality((a*b) / b, a) - else - try - t = divexact_left(b*a, b) - @test equality(b*t, b*a) - t = divexact_left(b*a, b, check = true) - @test equality(b*t, b*a) - t = divexact_left(b*a, b, check = false) - @test equality(b*t, b*a) - t = b \ (b*a) - @test equality(b*t, b*a) - catch - end - try - t = divexact_right(a*b, b) - @test equality(t*b, a*b) - t = divexact_right(a*b, b, check = true) - @test equality(t*b, a*b) - t = divexact_right(a*b, b, check = false) - @test equality(t*b, a*b) - t = (a*b) / b - @test equality(t*b, a*b) - catch - end - end - @test A == a - @test B == b - end - end - end - - @testset "Unsafe ring operators" begin - for i in 1:reps - a = test_elem(R)::T - b = test_elem(R)::T - c = test_elem(R)::T - - test_mutating_op_like_zero(zero, zero!, a) - test_mutating_op_like_zero(one, one!, a) - - test_mutating_op_like_neg(-, neg!, a) - - test_mutating_op_like_add(+, add!, a, b) - test_mutating_op_like_add(-, sub!, a, b) - test_mutating_op_like_add(*, mul!, a, b) - - test_mutating_op_like_addmul((a, b, c) -> a + b*c, addmul!, a, b, c) - test_mutating_op_like_addmul((a, b, c) -> a - b*c, submul!, a, b, c) - end - end - end - - return nothing -end - - -function test_Ring_interface(R::AbstractAlgebra.Ring; reps = 50) - - T = elem_type(R) - - @testset "Ring interface for $(R) of type $(typeof(R))" begin - - @test T <: RingElement - - test_NCRing_interface(R; reps = reps) - - @testset "Basic functionality for commutative rings only" begin - @test isone(AbstractAlgebra.inv(one(R))) - test_mutating_op_like_neg(AbstractAlgebra.inv, inv!, one(R)) - test_mutating_op_like_neg(AbstractAlgebra.inv, inv!, -one(R)) - for i in 1:reps - a = test_elem(R)::T - b = test_elem(R)::T - A = deepcopy(a) - B = deepcopy(b) - @test a*b == b*a - # documentation is not clear on divexact - if is_domain_type(T) - @test iszero(b) || equality(divexact(b*a, b), a) - @test iszero(b) || equality(divexact(b*a, b, check = true), a) - @test iszero(b) || equality(divexact(b*a, b, check = false), a) - if T isa RingElem - @test iszero(b) || equality((b*a) / b, a) - end - iszero(b) || test_mutating_op_like_add(divexact, divexact!, b*a, b) - else - try - t = divexact(b*a, b) - @test equality(t*b, a*b) - t = divexact(b*a, b, check = true) - @test equality(t*b, a*b) - t = divexact(b*a, b, check = false) - @test equality(t*b, a*b) - if T isa RingElem - t = (b*a) / b - @test equality(t*b, a*b) - end - catch - end - end - try - (f, h) = is_zero_divisor_with_annihilator(a) - @test parent(h) == R - @test f == is_zero_divisor(a) - if f - @test !is_zero(h) - @test is_zero(a*h) - end - catch - end - @test A == a - @test B == b - end - end - end - - return nothing -end - -function test_Field_interface(R::AbstractAlgebra.Field; reps = 50) - - T = elem_type(R) - - @testset "Field interface for $(R) of type $(typeof(R))" begin - - test_Ring_interface(R, reps = reps) - - @test iszero(R(characteristic(R))) - @test iszero(characteristic(R) * one(R)) - @test iszero(one(R) * characteristic(R)) - - for i in 1:reps - a = test_elem(R)::T - A = deepcopy(a) - @test is_unit(a) == !iszero(a) - if !is_zero(a) - @test is_one(a * inv(a)) - @test is_one(inv(a) * a) - test_mutating_op_like_neg(inv, inv!, a) - end - @test A == a - end - end - - return nothing -end - -function equality_up_to_units(a, b) - iszero(a) && return iszero(b) - iszero(b) && return iszero(a) - return divides(a, b)[1] && divides(b, a)[1] -end - -function test_EuclideanRing_interface(R::AbstractAlgebra.Ring; reps = 20) - - T = elem_type(R) - - is_exact_type(T) || return - - @testset "Euclidean Ring interface for $(R) of type $(typeof(R))" begin - - for i in 1:reps - f = test_elem(R)::T - g = test_elem(R)::T - m = test_elem(R)::T - if iszero(m) - m = one(R) - end - - @test (AbstractAlgebra.div(f, m), mod(f, m)) == AbstractAlgebra.divrem(f, m) - @test divides(mulmod(f, g, m) - mod(f*g, m), m)[1] - - fi = one(R) - for i in 1:5 - fi *= f - @test divides(fi - powermod(f, i, m), m)[1] - @test divides(fi - mod(f^i, m), m)[1] - end - - if is_unit(gcd(f, m)) - a = invmod(f, m) - @test divides(mulmod(a, f, m) - one(R), m)[1] - @test divides(powermod(f, -1, m) - a^1, m)[1] - @test divides(powermod(f, -2, m) - a^2, m)[1] - @test divides(powermod(f, -3, m) - a^3, m)[1] - end - - @test divides(f*m, m) == (true, f) - (a, b) = divides(f*m + g, m) - @test !a || b*m == f*m + g - - @test_throws Exception remove(f, zero(R)) - @test_throws Exception valuation(f, zero(R)) - - if !is_unit(m) && !iszero(f) - n = rand(0:3) - f *= m^n - (v, q) = remove(f, m) - @test valuation(f, m) == v - @test v >= n - @test q*m^v == f - @test remove(q, m) == (0, q) - @test valuation(q, m) == 0 - end - - @test !(iszero(f) && iszero(g)) || iszero(gcd(f, g)) - @test equality_up_to_units(gcd(f, g)*lcm(f, g), f*g) - - g1 = gcd(f, gcd(g, m)) - g2 = gcd(gcd(f, g), m) - g3 = gcd(f, g, m) - g4 = gcd([f, g, m]) - @test equality_up_to_units(g1, g2) - @test equality_up_to_units(g2, g3) - @test equality_up_to_units(g3, g4) - - l1 = lcm(f, lcm(g, m)) - l2 = lcm(lcm(f, g), m) - l3 = lcm(f, g, m) - l4 = lcm([f, g, m]) - @test equality_up_to_units(l1, l2) - @test equality_up_to_units(l2, l3) - @test equality_up_to_units(l3, l4) - - (d, s, t) = gcdx(f, g) - @test d == gcd(f, g) - @test d == s*f + t*g - @test gcdinv(f, g) == (d, s) - - test_mutating_op_like_add(AbstractAlgebra.div, div!, f, m) - test_mutating_op_like_add(mod, mod!, f, m) - test_mutating_op_like_add(gcd, gcd!, f, m) - test_mutating_op_like_add(lcm, lcm!, f, m) - end - - end - - return nothing -end - - -function test_Poly_interface(Rx::AbstractAlgebra.PolyRing; reps = 30) - - T = elem_type(Rx) - - @testset "Poly interface for $(Rx) of type $(typeof(Rx))" begin - - test_Ring_interface(Rx; reps = reps) - - x = gen(Rx) - R = base_ring(Rx) - - @testset "Polynomial Constructors" begin - for i in 1:reps - a = test_elem(Rx)::T - for b in coefficients(a) - @assert Rx(b) isa T - end - @test a == Rx(collect(coefficients(a))) - - B = MPolyBuildCtx(Rx) # TODO rename to BuildCtx - for (c, e) in zip(AbstractAlgebra.coefficients(a), AbstractAlgebra.exponent_vectors(a)) - push_term!(B, c, e) - end - @test finish(B) == a - end - @test Rx(Int[]) == zero(Rx) - @test Rx([0, 1, 2]) == x + 2*x^2 - @test Rx([big(0), big(1), big(2)]) == x + 2*x^2 - @test Rx(map(R, [0, 1, 2])) == x + 2*x^2 - end - - if R isa AbstractAlgebra.Field - test_EuclideanRing_interface(Rx, reps = 2 + fld(reps, 2)) - @testset "Half-GCD" begin - for i in 1:reps - a = test_elem(Rx) - b = test_elem(Rx) - for j in 1:8 - q = test_elem(Rx) - a, b = q*a + b, a - end - g, s, t = gcdx(a, b) - @test g == gcd(a, b) - @test g == s*a + t*b - @test (g, s) == gcdinv(a, b) - if degree(a) < degree(b) - a, b = b, a - end - degree(a) > degree(b) >= 0 || continue - (A, B, m11, m12, m21, m22, s) = hgcd(a, b) - @test degree(A) >= cld(degree(a), 2) > degree(B) - @test m11*A + m12*B == a - @test m21*A + m22*B == b - @test m11*m22 - m21*m12 == s - @test s^2 == 1 - end - end - end - - @testset "Basic functionality" begin - @test var(Rx) isa Symbol - @test symbols(Rx) isa Vector{Symbol} - @test length(symbols(Rx)) == 1 - @test is_gen(gen(Rx)) - @test is_gen(x) - @test is_monic(x) - @test is_trivial(Rx) || !is_gen(x^2) - for i in 1:reps - a = test_elem(Rx) - @test iszero(a) || degree(a) >= 0 - @test equality(a, leading_coefficient(a)*x^max(0, degree(a)) + tail(a)) - @test constant_coefficient(a) isa elem_type(R) - @test trailing_coefficient(a) isa elem_type(R) - @test is_monic(a) == isone(leading_coefficient(a)) - end - end - end - - return nothing -end - - -function test_MPoly_interface(Rxy::AbstractAlgebra.MPolyRing; reps = 30) - - # for simplicity, these tests for now assume exactly two generators - @assert ngens(Rxy) == 2 - - T = elem_type(Rxy) - - @testset "MPoly interface for $(Rxy) of type $(typeof(Rxy))" begin - - test_Ring_interface(Rxy; reps = reps) - - @testset "Basic functionality" begin - @test symbols(Rxy) isa Vector{Symbol} - @test length(symbols(Rxy)) == ngens(Rxy) - @test length(gens(Rxy)) == ngens(Rxy) - @test gens(Rxy) == [gen(Rxy, i) for i in 1:ngens(Rxy)] - @test all(is_gen, gens(Rxy)) || is_trivial(Rxy) - end - - @testset "Polynomial Constructors" begin - for i in 1:reps - a = test_elem(Rxy)::T - for b in coefficients(a) - @assert Rxy(b) isa T - end - - # test MPolyBuildCtx - B = MPolyBuildCtx(Rxy) - for (c, e) in zip(AbstractAlgebra.coefficients(a), AbstractAlgebra.exponent_vectors(a)) - push_term!(B, c, e) - end - @test finish(B) == a - end - x, y = gens(Rxy) - f = 13*x^3*y^4 + 2*x - 7 - #@test Rxy([2,-7,13], [[1,0],[0,0],[3,4]]) == f # FIXME: interface spec does not say this is required? - - R = base_ring(Rxy) - @test Rxy(R.([2,-7,13]), [[1,0],[0,0],[3,4]]) == f - end - - # skip trivial rings after this, it is not worth the bother - is_trivial(Rxy) && return - - @testset "Element properties" begin - R = base_ring(Rxy) - x, y = gens(Rxy) - - a = zero(Rxy) - @test !is_monomial(a) - @test !is_term(a) - @test is_constant(a) - @test !is_gen(a) - @test !is_unit(a) - @test is_nilpotent(a) - @test length(a) == 0 - @test total_degree(a) < 0 - @test all(is_negative, degrees(a)) - - a = one(Rxy) - @test is_monomial(a) - @test is_term(a) - @test is_constant(a) - @test !is_gen(a) - @test is_unit(a) - @test !is_nilpotent(a) - @test length(a) == 1 - @test total_degree(a) == 0 - @test degrees(a) == [0, 0] - - a = x - @test is_monomial(a) - @test is_term(a) - @test !is_constant(a) - @test is_gen(a) - @test !is_unit(a) - @test !is_nilpotent(a) - @test length(a) == 1 - @test total_degree(a) == 1 - @test degrees(a) == [1, 0] - - a = x^2 - @test is_monomial(a) - @test is_term(a) - @test !is_constant(a) - @test !is_gen(a) - @test !is_unit(a) - @test !is_nilpotent(a) - @test length(a) == 1 - @test total_degree(a) == 2 - @test degrees(a) == [2, 0] - - if !is_zero(R(2)) - a = 2*x - @test !is_monomial(a) - @test is_term(a) - @test !is_constant(a) - @test !is_gen(a) - @test !is_unit(a) - @test is_nilpotent(a) == is_nilpotent(R(2)) - @test length(a) == 1 - @test total_degree(a) == 1 - @test degrees(a) == [1, 0] - end - - a = x^3 + y^4 - @test !is_monomial(a) - @test !is_term(a) - @test !is_constant(a) - @test !is_gen(a) - @test !is_unit(a) - @test !is_nilpotent(a) - @test length(a) == 2 - @test total_degree(a) == 4 - @test degrees(a) == [3, 4] - - for i in 1:reps - a = test_elem(Rxy) - iszero(a) && continue - @test length(a) >= 0 - @test sum(degrees(a)) >= total_degree(a) - end - - end - - # TODO: add more tests, covering everything described in the manual, see - # https://nemocas.github.io/AbstractAlgebra.jl/dev/mpoly_interface/ - # https://nemocas.github.io/AbstractAlgebra.jl/dev/mpolynomial/ - end - - return nothing -end - - -function test_MatSpace_interface(S::MatSpace; reps = 20) - - ST = elem_type(S) - R = base_ring(S) - T = elem_type(R) - - @test base_ring_type(S) == typeof(R) - @test parent_type(ST) == typeof(S) - @test dense_matrix_type(R) == ST - - @testset "MatSpace interface for $(S) of type $(typeof(S))" begin - - @testset "Constructors" begin - for k in 1:reps - a = test_elem(S)::ST - @test nrows(a) == nrows(S) - @test ncols(a) == ncols(S) - @test a == S(T[a[i, j] for i in 1:nrows(a), j in 1:ncols(a)]) - @test a == S(T[a[i, j] for i in 1:nrows(a) for j in 1:ncols(a)]) - @test a == matrix(R, T[a[i, j] for i in 1:nrows(a), j in 1:ncols(a)]) - @test a == matrix(R, nrows(S), ncols(S), - T[a[i, j] for i in 1:nrows(a) for j in 1:ncols(a)]) - - b = similar(a) - @test b isa ST - @test nrows(b) == nrows(S) - @test ncols(b) == ncols(S) - - b = similar(a, nrows(S)+1, ncols(S)+1) - @test b isa ST - @test nrows(b) == nrows(S)+1 - @test ncols(b) == ncols(S)+1 - - b = similar(a, R) - @test b isa MatElem - #@test b isa ST # undefined - @test nrows(b) == nrows(S) - @test ncols(b) == ncols(S) - - b = similar(a, R, nrows(S)+1, ncols(S)+1) - @test b isa MatElem - #@test b isa ST # undefined - @test nrows(b) == nrows(S)+1 - @test ncols(b) == ncols(S)+1 - - end - @test iszero(zero_matrix(R, nrows(S), ncols(S))) - end - - @testset "Views" begin - M = matrix(R, 3, 3, BigInt[1, 2, 3, 2, 3, 4, 3, 4, 5]) - N1 = @view M[1:2, :] - N2 = @view M[:, 1:2] - @test N1*N2 == matrix(R, 2, 2, BigInt[14, 20, 20, 29]) - end - - @testset "Basic manipulation of matrices" begin - for k in 1:reps - a = test_elem(S)::ST - A = deepcopy(a) - @test A isa ST - - b = zero_matrix(R, nrows(a), ncols(a)) - @test b isa ST - for i in 1:nrows(a), j in 1:ncols(a) - b[i, j] = a[i, j] - end - @test b == a - - t = transpose(a) - @test t isa ST - @test nrows(t) == ncols(S) - @test ncols(t) == nrows(S) - @test transpose(t) == a - @test a == A - end - end - - @testset "Row & column permutations" begin - a = matrix(R, [1 2 ; 3 4]) - b = swap_rows(a, 1, 2) - @test b == matrix(R, [3 4 ; 1 2]) - @test a == matrix(R, [1 2 ; 3 4]) - - a = matrix(R, [1 2 ; 3 4]) - b = swap_cols(a, 1, 2) - @test b == matrix(R, [2 1 ; 4 3]) - @test a == matrix(R, [1 2 ; 3 4]) - - # TODO: reverse_rows, reverse_cols - # TODO: add_column, add_row - # TODO: multiply_column, multiply_row - # TODO: ! variants (such as `swap_cols!` etc.) of all of the above - end - - end - - return nothing -end - -function test_MatAlgebra_interface(S::MatRing; reps = 20) - - ST = elem_type(S) - R = base_ring(S) - T = elem_type(R) - - @test nrows(S) == ncols(S) - - @testset "MatRing interface for $(S) of type $(typeof(S))" begin - - test_NCRing_interface(S, reps = reps) - - @testset "Constructors" begin - for k in 1:reps - a = test_elem(S)::ST - @test nrows(a) == nrows(S) - @test ncols(a) == ncols(S) - @test a == S(T[a[i, j] for i in 1:nrows(a), j in 1:ncols(a)]) - @test a == S(T[a[i, j] for i in 1:nrows(a) for j in 1:ncols(a)]) - end - end - - @testset "Basic manipulation of matrices" begin - for k in 1:reps - a = test_elem(S)::ST - A = deepcopy(a) - b = zero(S) - for i in 1:nrows(a), j in 1:ncols(a) - b[i, j] = a[i, j] - end - @test b == a - @test transpose(transpose(a)) == a - @test a == A - end - end - - @testset "Determinant" begin - for k in 1:reps - a = test_elem(S)::ST - b = test_elem(S)::ST - A = deepcopy(a) - B = deepcopy(b) - @test det(a*b) == det(a)*det(b) - @test a == A - @test b == B - end - end - end - - return nothing -end - -function test_Ring_interface_recursive(R::AbstractAlgebra.Ring; reps = 50) - test_Ring_interface(R; reps = reps) - Rx, _ = polynomial_ring(R, :x) - test_Poly_interface(Rx, reps = 2 + fld(reps, 2)) - Rxy, _ = polynomial_ring(R, [:x, :y]) - test_MPoly_interface(Rxy, reps = 2 + fld(reps, 2)) - S = matrix_ring(R, rand(0:3)) - test_MatAlgebra_interface(S, reps = 2 + fld(reps, 2)) - S = matrix_space(R, rand(0:3), rand(0:3)) - test_MatSpace_interface(S, reps = 2 + fld(reps, 2)) -end - -function test_Field_interface_recursive(R::AbstractAlgebra.Field; reps = 50) - test_Ring_interface_recursive(R, reps = reps) - test_Field_interface(R, reps = reps) -end +# This file is just for backwards compatibility and should be removed in the future. + +# Assumptions (as that was already required with the previous setup): +# - `AbstractAlgebra` is already loaded +# - `Test` is available in the environment + +# load TestExt +using Test + +import .ConformanceTests: test_elem as test_elem +import .ConformanceTests: adhoc_partner_rings as adhoc_partner_rings +import .ConformanceTests: equality as equality + +test_mutating_op_like_zero = ConformanceTests.test_mutating_op_like_zero +test_mutating_op_like_neg = ConformanceTests.test_mutating_op_like_neg +test_mutating_op_like_add = ConformanceTests.test_mutating_op_like_add +test_mutating_op_like_addmul = ConformanceTests.test_mutating_op_like_addmul + +test_NCRing_interface = ConformanceTests.test_NCRing_interface +test_Ring_interface = ConformanceTests.test_Ring_interface +test_Field_interface = ConformanceTests.test_Field_interface +test_EuclideanRing_interface = ConformanceTests.test_EuclideanRing_interface +test_Poly_interface = ConformanceTests.test_Poly_interface +test_MPoly_interface = ConformanceTests.test_MPoly_interface +test_MatSpace_interface = ConformanceTests.test_MatSpace_interface +test_MatAlgebra_interface = ConformanceTests.test_MatAlgebra_interface +test_Ring_interface_recursive = ConformanceTests.test_Ring_interface_recursive +test_Field_interface_recursive = ConformanceTests.test_Field_interface_recursive diff --git a/test/generic/AbsMSeries-test.jl b/test/generic/AbsMSeries-test.jl index a41d49469f..45e8887d06 100644 --- a/test/generic/AbsMSeries-test.jl +++ b/test/generic/AbsMSeries-test.jl @@ -4,7 +4,7 @@ end @testset "Generic.AbsMSeries.conformance" begin R, (x, y) = power_series_ring(ZZ, [5, 3], ["x", "y"]) - test_Ring_interface(R) + ConformanceTests.test_Ring_interface(R) end @testset "Generic.AbsMSeries.constructors" begin diff --git a/test/generic/AbsSeries-test.jl b/test/generic/AbsSeries-test.jl index 442c917888..67de078a50 100644 --- a/test/generic/AbsSeries-test.jl +++ b/test/generic/AbsSeries-test.jl @@ -18,7 +18,7 @@ @testset "Generic.AbsSeries.conformance" begin R, x = power_series_ring(ZZ, 30, "x", model=:capped_absolute) - test_Ring_interface(R) + ConformanceTests.test_Ring_interface(R) end @testset "Generic.AbsSeries.types" begin diff --git a/test/generic/FactoredFraction-test.jl b/test/generic/FactoredFraction-test.jl index db22cd09d7..d5faadef6c 100644 --- a/test/generic/FactoredFraction-test.jl +++ b/test/generic/FactoredFraction-test.jl @@ -11,7 +11,7 @@ end @testset "Generic.FactoredFracFieldElem.ZZ.conformance" begin FF = FactoredFractionField(ZZ) - test_Field_interface(FF) + ConformanceTests.test_Field_interface(FF) end @testset "Generic.FactoredFracFieldElem.ZZ.adhoc" begin diff --git a/test/generic/FreeAssociativeAlgebra-test.jl b/test/generic/FreeAssociativeAlgebra-test.jl index a89e3e3631..a581a55b7b 100644 --- a/test/generic/FreeAssociativeAlgebra-test.jl +++ b/test/generic/FreeAssociativeAlgebra-test.jl @@ -276,10 +276,10 @@ end @testset "Generic.FreeAssociativeAlgebra.NCRing_interface" begin S, = free_associative_algebra(ZZ, 3) - test_NCRing_interface(S) + ConformanceTests.test_NCRing_interface(S) R, = QQ[:x, :y] S, = free_associative_algebra(R, :z => 1:3) - test_NCRing_interface(S) + ConformanceTests.test_NCRing_interface(S) end diff --git a/test/generic/FunctionField-test.jl b/test/generic/FunctionField-test.jl index c533c788ba..1e5dd76b77 100644 --- a/test/generic/FunctionField-test.jl +++ b/test/generic/FunctionField-test.jl @@ -18,7 +18,7 @@ P2 = [(x2 + 1)*z2 + (x2 + 2), z2 + (x2 + 1)//(x2 + 2), z2^2 + 3z2 + 1, # #@testset "Generic.FunctionField.conformance" begin # S, y = function_field(P1[4], "y") -# test_Ring_interface(S) +# ConformanceTests.test_Ring_interface(S) #end @testset "Generic.FunctionField.constructors" begin diff --git a/test/generic/LaurentMPoly-test.jl b/test/generic/LaurentMPoly-test.jl index 213f5f20c9..ca6df1947d 100644 --- a/test/generic/LaurentMPoly-test.jl +++ b/test/generic/LaurentMPoly-test.jl @@ -16,11 +16,11 @@ end @testset "Generic.LaurentMPoly.conformance" begin L, (x, y) = laurent_polynomial_ring(ZZ, ["x", "y"]) - test_Ring_interface(L) - test_Ring_interface_recursive(L) + ConformanceTests.test_Ring_interface(L) + ConformanceTests.test_Ring_interface_recursive(L) L, (x, y) = laurent_polynomial_ring(residue_ring(ZZ, ZZ(6))[1], ["x", "y"]) - test_Ring_interface(L) + ConformanceTests.test_Ring_interface(L) end @testset "Generic.LaurentMPoly.constructors" begin diff --git a/test/generic/LaurentPoly-test.jl b/test/generic/LaurentPoly-test.jl index 98b3cd5708..17c1240ce7 100644 --- a/test/generic/LaurentPoly-test.jl +++ b/test/generic/LaurentPoly-test.jl @@ -481,12 +481,12 @@ end @testset "conformance" begin L, y = laurent_polynomial_ring(QQ, "y") - test_Ring_interface(L) - test_EuclideanRing_interface(L) - test_Ring_interface_recursive(L) + ConformanceTests.test_Ring_interface(L) + ConformanceTests.test_EuclideanRing_interface(L) + ConformanceTests.test_Ring_interface_recursive(L) L, y = laurent_polynomial_ring(residue_ring(ZZ, ZZ(6))[1], "y") - test_Ring_interface(L) + ConformanceTests.test_Ring_interface(L) end end diff --git a/test/generic/LaurentSeries-test.jl b/test/generic/LaurentSeries-test.jl index 3b87119b0d..56a80b6c16 100644 --- a/test/generic/LaurentSeries-test.jl +++ b/test/generic/LaurentSeries-test.jl @@ -22,7 +22,7 @@ end @testset "Generic.LaurentSeries.conformance" begin R, x = laurent_series_ring(ZZ, 10, "x") - test_Ring_interface(R) + ConformanceTests.test_Ring_interface(R) end @testset "Generic.LaurentSeries.constructors" begin diff --git a/test/generic/MPoly-test.jl b/test/generic/MPoly-test.jl index f5d3658b17..e622ae7102 100644 --- a/test/generic/MPoly-test.jl +++ b/test/generic/MPoly-test.jl @@ -1697,17 +1697,17 @@ end @testset "Generic.MPoly.Ring_interface" begin S, = polynomial_ring(QQ, 0) - test_Ring_interface_recursive(S) + ConformanceTests.test_Ring_interface_recursive(S) S, = polynomial_ring(QQ, 1) - test_Ring_interface_recursive(S) + ConformanceTests.test_Ring_interface_recursive(S) S, = polynomial_ring(ZZ, 2) - test_Ring_interface_recursive(S) + ConformanceTests.test_Ring_interface_recursive(S) R, = QQ[:x] S, = polynomial_ring(R, :z => 1:3) - test_Ring_interface(S) # _recursive needs too many ressources + ConformanceTests.test_Ring_interface(S) # _recursive needs too many ressources end @testset "Generic.MPoly.zero_rings" begin @@ -1715,7 +1715,7 @@ end S, = polynomial_ring(R, 2) @test is_zero(gen(S, 1)) && is_one(gen(S, 1)) @test is_zero(one(S)) - test_Ring_interface_recursive(S) + ConformanceTests.test_Ring_interface_recursive(S) end # ------------------------------------------------------- diff --git a/test/generic/Poly-test.jl b/test/generic/Poly-test.jl index 9ab0fe8d80..f653c2dc31 100644 --- a/test/generic/Poly-test.jl +++ b/test/generic/Poly-test.jl @@ -142,11 +142,11 @@ end @testset "Generic.Poly.conformance" begin R, x = polynomial_ring(ZZ, "x") - test_Poly_interface(R) + ConformanceTests.test_Poly_interface(R) R, x = polynomial_ring(QQ, "x") - test_Poly_interface(R) + ConformanceTests.test_Poly_interface(R) R, x = polynomial_ring(GF(5), "x") - test_Poly_interface(R) + ConformanceTests.test_Poly_interface(R) end @testset "Generic.Poly.printing" begin @@ -3039,5 +3039,5 @@ end R, = residue_ring(ZZ, 1) Rx, = R[:x] @test is_zero(gen(Rx)) && is_one(gen(Rx)) - test_Ring_interface_recursive(Rx) + ConformanceTests.test_Ring_interface_recursive(Rx) end diff --git a/test/generic/PuiseuxSeries-test.jl b/test/generic/PuiseuxSeries-test.jl index c983393f9f..a44f29e4f5 100644 --- a/test/generic/PuiseuxSeries-test.jl +++ b/test/generic/PuiseuxSeries-test.jl @@ -22,7 +22,7 @@ end @testset "Generic.PuiseuxSeries.conformance" begin R, x = puiseux_series_ring(ZZ, 10, "x") - test_Ring_interface(R) + ConformanceTests.test_Ring_interface(R) end @testset "Generic.PuiseuxSeries.constructors" begin diff --git a/test/generic/RationalFunctionField-test.jl b/test/generic/RationalFunctionField-test.jl index e56b8ad82d..602b769cee 100644 --- a/test/generic/RationalFunctionField-test.jl +++ b/test/generic/RationalFunctionField-test.jl @@ -4,7 +4,7 @@ end @testset "Generic.FunctionField.conformance" begin S, x = rational_function_field(QQ, "x") - test_Ring_interface(S) + ConformanceTests.test_Ring_interface(S) end @testset "Generic.RationalFunctionField.constructors" begin diff --git a/test/generic/RelSeries-test.jl b/test/generic/RelSeries-test.jl index 8c0992d3d6..6cd5dab01e 100644 --- a/test/generic/RelSeries-test.jl +++ b/test/generic/RelSeries-test.jl @@ -18,7 +18,7 @@ @testset "Generic.RelSeries.conformance" begin R, x = power_series_ring(ZZ, 10, "x") - test_Ring_interface(R) + ConformanceTests.test_Ring_interface(R) end @testset "Generic.RelSeries.types" begin diff --git a/test/generic/Residue-test.jl b/test/generic/Residue-test.jl index ec607dd58b..ddc7507cec 100644 --- a/test/generic/Residue-test.jl +++ b/test/generic/Residue-test.jl @@ -1,20 +1,20 @@ @testset "EuclideanRingResidueRingElem.conformance_tests" begin - test_Ring_interface(residue_ring(ZZ, 1)[1]) # is_gen fails on polys - test_Ring_interface_recursive(residue_ring(ZZ, -4)[1]) + ConformanceTests.test_Ring_interface(residue_ring(ZZ, 1)[1]) # is_gen fails on polys + ConformanceTests.test_Ring_interface_recursive(residue_ring(ZZ, -4)[1]) # R, = residue_ring(ZZ, 16453889) - test_Ring_interface_recursive(R) + ConformanceTests.test_Ring_interface_recursive(R) # S, x = polynomial_ring(R, "x") T, = residue_ring(S, x^3 + 3x + 1) - test_Ring_interface_recursive(T) + ConformanceTests.test_Ring_interface_recursive(T) # S, x = polynomial_ring(QQ, "x") T, = residue_ring(S, x^2 + 1) - test_Ring_interface_recursive(T) + ConformanceTests.test_Ring_interface_recursive(T) @test !occursin("\n", sprint(show, T)) end diff --git a/test/generic/UnivPoly-test.jl b/test/generic/UnivPoly-test.jl index 23dfd47cec..8641f93c27 100644 --- a/test/generic/UnivPoly-test.jl +++ b/test/generic/UnivPoly-test.jl @@ -134,7 +134,7 @@ end @testset "Generic.UnivPoly.conformance" begin S = universal_polynomial_ring(residue_ring(ZZ, ZZ(6))[1]) gen(S, "x") - test_Ring_interface(S) + ConformanceTests.test_Ring_interface(S) end @testset "Generic.UnivPoly.printing" begin diff --git a/test/julia/Floats-test.jl b/test/julia/Floats-test.jl index 270abf5bd7..2ad98f933e 100644 --- a/test/julia/Floats-test.jl +++ b/test/julia/Floats-test.jl @@ -1,6 +1,6 @@ @testset "Julia.Floats.conformance_tests" begin - test_Ring_interface(RDF) - test_Ring_interface(RealField) + ConformanceTests.test_Ring_interface(RDF) + ConformanceTests.test_Ring_interface(RealField) end @testset "Julia.Floats.printing" begin diff --git a/test/julia/GFElem-test.jl b/test/julia/GFElem-test.jl index b4bf2e8680..20ec32b441 100644 --- a/test/julia/GFElem-test.jl +++ b/test/julia/GFElem-test.jl @@ -1,8 +1,8 @@ @testset "Julia.GFElem.conformance_tests" begin - test_Field_interface_recursive(GF(3)) - test_Field_interface_recursive(GF(13)) - test_Field_interface_recursive(GF(big(13))) - test_Field_interface_recursive(GF(big(10)^20 + 39)) + ConformanceTests.test_Field_interface_recursive(GF(3)) + ConformanceTests.test_Field_interface_recursive(GF(13)) + ConformanceTests.test_Field_interface_recursive(GF(big(13))) + ConformanceTests.test_Field_interface_recursive(GF(big(10)^20 + 39)) end @testset "Julia.GFElem.constructors" begin diff --git a/test/julia/Integers-test.jl b/test/julia/Integers-test.jl index b55d96d7c2..c51551bc8d 100644 --- a/test/julia/Integers-test.jl +++ b/test/julia/Integers-test.jl @@ -1,6 +1,6 @@ @testset "Julia.Integers.conformance_tests" begin - test_Ring_interface_recursive(ZZ) - test_EuclideanRing_interface(ZZ) + ConformanceTests.test_Ring_interface_recursive(ZZ) + ConformanceTests.test_EuclideanRing_interface(ZZ) end @testset "Julia.Integers.manipulation" begin diff --git a/test/julia/Rationals-test.jl b/test/julia/Rationals-test.jl index b80cea244f..116c51ffd5 100644 --- a/test/julia/Rationals-test.jl +++ b/test/julia/Rationals-test.jl @@ -1,5 +1,5 @@ @testset "Julia.Rationals.conformance_tests" begin - test_Field_interface_recursive(QQ) + ConformanceTests.test_Field_interface_recursive(QQ) end @testset "Julia.Rationals.constructors" begin From 1fa02cc14375b5025b0d2a94cd831f2d329a0fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 13 Jan 2025 15:48:09 +0100 Subject: [PATCH 07/11] Move `test_elem` methods in respective src files --- src/AbstractAlgebra.jl | 17 ++-- src/ConformanceTests.jl | 97 ++-------------------- src/FreeAssociativeAlgebra.jl | 19 +++++ src/LaurentMPoly.jl | 22 +++++ src/MPoly.jl | 18 ++++ src/MatRing.jl | 11 +++ src/Matrix.jl | 11 +++ src/Poly.jl | 11 +++ src/RelSeries.jl | 25 ++++++ src/algorithms/FinField.jl | 10 +++ src/generic/AbsMSeries.jl | 10 +++ src/generic/FactoredFraction.jl | 17 ++++ src/generic/FunctionField.jl | 10 +++ src/generic/LaurentPoly.jl | 15 ++++ src/generic/LaurentSeries.jl | 9 ++ src/generic/PuiseuxSeries.jl | 9 ++ src/generic/RationalFunctionField.jl | 10 +++ src/generic/Residue.jl | 10 +++ src/generic/UnivPoly.jl | 10 +++ src/julia/Float.jl | 11 +++ src/julia/Integer.jl | 17 +++- src/julia/Rational.jl | 13 +++ test/AbstractAlgebra-test.jl | 2 - test/generic/AbsMSeries-test.jl | 4 - test/generic/FactoredFraction-test.jl | 21 ++--- test/generic/FunctionField-test.jl | 4 - test/generic/LaurentMPoly-test.jl | 16 ---- test/generic/LaurentPoly-test.jl | 10 --- test/generic/LaurentSeries-test.jl | 4 - test/generic/PuiseuxSeries-test.jl | 4 +- test/generic/RationalFunctionField-test.jl | 4 - test/generic/UnivPoly-test.jl | 4 +- 32 files changed, 290 insertions(+), 165 deletions(-) diff --git a/src/AbstractAlgebra.jl b/src/AbstractAlgebra.jl index 60fe823558..6e8efd0be5 100644 --- a/src/AbstractAlgebra.jl +++ b/src/AbstractAlgebra.jl @@ -200,6 +200,15 @@ using .PrettyPrinting import .PrettyPrinting: expressify + +################################################################################ +# +# Conformance tests (function stubs for TestExt) +# +################################################################################ + +include("ConformanceTests.jl") + ############################################################################### # # Generic algorithms defined on abstract types @@ -364,14 +373,6 @@ getindex(S::Set, i::Int) = gen(S, i) include("error.jl") -################################################################################ -# -# Conformance tests (function stubs for TestExt) -# -################################################################################ - -include("ConformanceTests.jl") - # Generic functions to be defined after all rings include("broadcasting.jl") diff --git a/src/ConformanceTests.jl b/src/ConformanceTests.jl index 7de0c2631e..7de3fb7fb9 100644 --- a/src/ConformanceTests.jl +++ b/src/ConformanceTests.jl @@ -2,10 +2,6 @@ module ConformanceTests using ..AbstractAlgebra -# This file mostly contains function stubs. -# The actual implementation are in the folder `ext/TestExt/`. - - # helper function equality(a, b) if is_exact_type(typeof(a)) && is_exact_type(typeof(b)) @@ -30,95 +26,16 @@ const default_adhoc_partner_rings = [ adhoc_partner_rings(R::NCRing) = default_adhoc_partner_rings +# To be implemented in the src files of the respective types. +# This function is used to generate a pseudo-random element in the Ring conformance tests. +function test_elem end + +############################################################################### # -# add methods for test_elem on ring elements here +# The following function stubs' actual implementations are in the folder `ext/TestExt/`. # -function test_elem(R::AbstractAlgebra.Integers{T}) where {T <: Signed} - n = T(2)^rand((1,1,1,2,3,10,31,32,33,63,64,65,100)) - return rand(R, -n:n) -end - -function test_elem(R::AbstractAlgebra.Integers{T}) where {T <: Unsigned} - n = T(2)^rand((1,1,1,2,3,10,31,32,33,63,64,65,100)) - return rand(R, 0:n) -end - -function test_elem(R::AbstractAlgebra.Rationals) - B = base_ring(R) - n = test_elem(B) - d = test_elem(B) - return is_zero(d) ? R(n) : R(n, d) -end - -function test_elem(R::AbstractAlgebra.FinField) - return rand(R) -end - -function test_elem(R::AbstractAlgebra.Floats{T}) where T - return rand(T)*rand(-100:100) -end - -function test_elem(Rx::AbstractAlgebra.PolyRing) - R = base_ring(Rx) - return Rx(elem_type(R)[test_elem(R) for i in 1:rand(0:6)]) -end - -function test_elem(Rx::AbstractAlgebra.MPolyRing) - R = base_ring(Rx) - num_gens = ngens(Rx) - iszero(num_gens) && return Rx(test_elem(R)) - len_bound = 8 - exp_bound = rand(1:5) - len = rand(0:len_bound) - coeffs = [test_elem(R) for _ in 1:len] - exps = [[rand(0:exp_bound) for _ in 1:num_gens] for _ in 1:len] - return Rx(coeffs, exps) -end - -function test_elem(S::Union{AbstractAlgebra.MatSpace, - AbstractAlgebra.MatRing}) - R = base_ring(S) - return S(elem_type(R)[test_elem(R) for i in 1:nrows(S), j in 1:ncols(S)]) -end - -function test_elem(R::AbstractAlgebra.EuclideanRingResidueRing) - return R(test_elem(base_ring(R))) -end - -function test_elem(Rx::AbstractAlgebra.SeriesRing) - R = base_ring(Rx) - prec = rand(3:10) - len = rand(0:prec-1) - val = rand(0:prec-len) - # FIXME: constructors don't seem to catch use of negative val - @assert val >= 0 - A = elem_type(R)[test_elem(R) for i in 1:len] - if len > 0 && is_zero(A[1]) - A[1] = one(R) - end - if elem_type(Rx) <: RelPowerSeriesRingElem - @assert prec >= len + val - return Rx(A, len, prec, val) - else - @assert prec >= len - return Rx(A, len, prec) - end -end - -function test_elem(S::AbstractAlgebra.FreeAssociativeAlgebra) - f = S() - g = gens(S) - R = base_ring(S) - isempty(g) && return S(test_elem(R)) - len_bound = 8 - exp_bound = 6 - for i in 1:rand(0:len_bound) - f += test_elem(R) * prod(rand(g) for _ in 1:rand(0:exp_bound); init = S(1)) - end - return f -end - +############################################################################### function test_iterate end diff --git a/src/FreeAssociativeAlgebra.jl b/src/FreeAssociativeAlgebra.jl index 1a52f65cc2..30ff85f6d8 100644 --- a/src/FreeAssociativeAlgebra.jl +++ b/src/FreeAssociativeAlgebra.jl @@ -259,6 +259,25 @@ function rand(S::FreeAssociativeAlgebra, term_range, exp_bound, v...) rand(Random.default_rng(), S, term_range, exp_bound, v...) end +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(S::FreeAssociativeAlgebra) + f = S() + g = gens(S) + R = base_ring(S) + isempty(g) && return S(ConformanceTests.test_elem(R)) + len_bound = 8 + exp_bound = 6 + for i in 1:rand(0:len_bound) + f += ConformanceTests.test_elem(R) * prod(rand(g) for _ in 1:rand(0:exp_bound); init = S(1)) + end + return f +end + ############################################################################### # # free_associative_algebra constructor diff --git a/src/LaurentMPoly.jl b/src/LaurentMPoly.jl index 29ff124934..fadefab9b1 100644 --- a/src/LaurentMPoly.jl +++ b/src/LaurentMPoly.jl @@ -146,6 +146,28 @@ function rand(S::LaurentMPolyRing, term_range, exp_bound, v...) rand(Random.default_rng(), S, term_range, exp_bound, v...) end +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(R::LaurentMPolyRing{BigInt}) + n = rand(1:10) + # R: length between 1 and 9 + # R: exponents between -n and n + # ZZ: coeffs between -99 and 99 + rand(R, 1:9, -n:n, -99:99) +end + +function ConformanceTests.test_elem(R::LaurentMPolyRing{<:ResElem{BigInt}}) + n = rand(1:5) + # R: length between 1 and 9 + # R: exponents between -n and n + # ZZ/6ZZ: coeffs between ??? <- TODO + rand(R, 1:4, -n:n, 1:10) +end + ############################################################################### # # laurent_polynomial_ring constructor diff --git a/src/MPoly.jl b/src/MPoly.jl index dad68a4301..e34a009444 100644 --- a/src/MPoly.jl +++ b/src/MPoly.jl @@ -1427,6 +1427,24 @@ function rand(S::MPolyRing, term_range, exp_bound, v...) rand(Random.default_rng(), S, term_range, exp_bound, v...) end +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(Rx::MPolyRing) + R = base_ring(Rx) + num_gens = ngens(Rx) + iszero(num_gens) && return Rx(ConformanceTests.test_elem(R)) + len_bound = 8 + exp_bound = rand(1:5) + len = rand(0:len_bound) + coeffs = [ConformanceTests.test_elem(R) for _ in 1:len] + exps = [[rand(0:exp_bound) for _ in 1:num_gens] for _ in 1:len] + return Rx(coeffs, exps) +end + ############################################################################### # # polynomial_ring constructor diff --git a/src/MatRing.jl b/src/MatRing.jl index 61f940bcb0..a913a668a0 100644 --- a/src/MatRing.jl +++ b/src/MatRing.jl @@ -405,6 +405,17 @@ end randmat_with_rank(S::MatRing{T}, rank::Int, v...) where {T <: RingElement} = randmat_with_rank(Random.default_rng(), S, rank, v...) +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(S::MatRing) + R = base_ring(S) + return S(elem_type(R)[ConformanceTests.test_elem(R) for i in 1:nrows(S), j in 1:ncols(S)]) +end + ############################################################################### # # Identity matrix diff --git a/src/Matrix.jl b/src/Matrix.jl index fad37b389f..c866451771 100644 --- a/src/Matrix.jl +++ b/src/Matrix.jl @@ -6690,6 +6690,17 @@ end randmat_with_rank(S::MatSpace{T}, rank::Int, v...) where {T <: RingElement} = randmat_with_rank(Random.default_rng(), S, rank, v...) +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(S::MatSpace) + R = base_ring(S) + return S(elem_type(R)[ConformanceTests.test_elem(R) for i in 1:nrows(S), j in 1:ncols(S)]) +end + ################################################################################ # # Matrix constructors diff --git a/src/Poly.jl b/src/Poly.jl index 236078cdb0..7e15f8be0c 100644 --- a/src/Poly.jl +++ b/src/Poly.jl @@ -3404,6 +3404,17 @@ rand(rng::AbstractRNG, S::PolyRing, deg::Int, v...) = rand(S::PolyRing, degs, v...) = rand(Random.default_rng(), S, degs, v...) +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(Rx::PolyRing) + R = base_ring(Rx) + return Rx(elem_type(R)[ConformanceTests.test_elem(R) for i in 1:rand(0:6)]) +end + ############################################################################### # # Polynomial substitution diff --git a/src/RelSeries.jl b/src/RelSeries.jl index a5ee32dec7..ade91c1e48 100644 --- a/src/RelSeries.jl +++ b/src/RelSeries.jl @@ -1453,6 +1453,31 @@ rand(rng::AbstractRNG, S::SeriesRing, val_range::AbstractUnitRange{Int}, v...) = rand(S::SeriesRing, val_range, v...) = rand(Random.default_rng(), S, val_range, v...) +############################################################################### +# +# Conformance test element generation +# +############################################################################### +function ConformanceTests.test_elem(Rx::SeriesRing) + R = base_ring(Rx) + prec = rand(3:10) + len = rand(0:prec-1) + val = rand(0:prec-len) + # FIXME: constructors don't seem to catch use of negative val + @assert val >= 0 + A = elem_type(R)[ConformanceTests.test_elem(R) for i in 1:len] + if len > 0 && is_zero(A[1]) + A[1] = one(R) + end + if elem_type(Rx) <: RelPowerSeriesRingElem + @assert prec >= len + val + return Rx(A, len, prec, val) + else + @assert prec >= len + return Rx(A, len, prec) + end +end + ############################################################################### # # power_series_ring constructor diff --git a/src/algorithms/FinField.jl b/src/algorithms/FinField.jl index 847f2f67f0..c6f5ce1510 100644 --- a/src/algorithms/FinField.jl +++ b/src/algorithms/FinField.jl @@ -67,3 +67,13 @@ end Base.length(f::FinField) = BigInt(order(f)) Base.eltype(::Type{F}) where {F<:FinField} = elem_type(F) + +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(R::FinField) + return rand(R) +end diff --git a/src/generic/AbsMSeries.jl b/src/generic/AbsMSeries.jl index 8bc630e456..9f20ae0611 100644 --- a/src/generic/AbsMSeries.jl +++ b/src/generic/AbsMSeries.jl @@ -657,6 +657,16 @@ function promote_rule(::Type{AbsMSeries{T, V}}, ::Type{U}) where promote_rule(T, U) == T ? AbsMSeries{T, V} : Union{} end +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(R::Generic.AbsMSeriesRing{BigInt}) + rand(R, 0:12, -10:10) +end + ############################################################################### # # Parent object call overload diff --git a/src/generic/FactoredFraction.jl b/src/generic/FactoredFraction.jl index 11c09ec9a4..119706a5f1 100644 --- a/src/generic/FactoredFraction.jl +++ b/src/generic/FactoredFraction.jl @@ -688,6 +688,23 @@ function _gcdhelper(b::FactoredFracFieldElem{T}, c::FactoredFracFieldElem{T}) wh return (z, bbar, cbar) end +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(FF::Generic.FactoredFracField{BigInt}) + limit = 10 + t = one(FF) + for i in 1:abs(rand(Int)%limit) + s = FF(rand(Int)%(20*limit)) + e = rand(Int)%limit + t *= iszero(s) ? s^abs(e) : s^e + end + return t +end + ############################################################################### # # FactoredFractionField constructor diff --git a/src/generic/FunctionField.jl b/src/generic/FunctionField.jl index b64f542591..e8c6385b50 100644 --- a/src/generic/FunctionField.jl +++ b/src/generic/FunctionField.jl @@ -1225,6 +1225,16 @@ rand(rng::AbstractRNG, K::FunctionField, v...) = rand(rng, make(K, v...)) rand(K::FunctionField, v...) = rand(Random.default_rng(), K, v...) +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(R::FunctionField{Rational{BigInt}}) + rand(R, 1:10, -10:10) +end + ############################################################################### # # Promotion rules diff --git a/src/generic/LaurentPoly.jl b/src/generic/LaurentPoly.jl index bb8ad7b090..a422b6459b 100644 --- a/src/generic/LaurentPoly.jl +++ b/src/generic/LaurentPoly.jl @@ -437,6 +437,21 @@ rand(rng::AbstractRNG, S::LaurentPolyWrapRing, degrees_range, v...) = rand(S::LaurentPolyWrapRing, degrees_range, v...) = rand(Random.default_rng(), S, degrees_range, v...) +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(R::Generic.LaurentPolyWrapRing) + n = rand(0:10) + if n == 0 + return zero(R) + else + m = rand(0:5) + rand(R, -m:n-m, -99:99) + end +end ############################################################################### # diff --git a/src/generic/LaurentSeries.jl b/src/generic/LaurentSeries.jl index e39e14dbd9..f911a1c03c 100644 --- a/src/generic/LaurentSeries.jl +++ b/src/generic/LaurentSeries.jl @@ -1782,6 +1782,15 @@ rand(rng::AbstractRNG, S::LaurentSeriesRingOrField, val_range::AbstractUnitRange rand(S::LaurentSeriesRingOrField, val_range, v...) = rand(Random.default_rng(), S, val_range, v...) +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(R::LaurentSeriesRing{BigInt}) + rand(R, 0:12, -10:10) +end ############################################################################### # diff --git a/src/generic/PuiseuxSeries.jl b/src/generic/PuiseuxSeries.jl index 3aa7db182b..5dda91326b 100644 --- a/src/generic/PuiseuxSeries.jl +++ b/src/generic/PuiseuxSeries.jl @@ -729,6 +729,15 @@ rand(rng::AbstractRNG, S::PuiseuxSeriesRingOrField, val_range::AbstractUnitRange rand(S::PuiseuxSeriesRingOrField, val_range, scale_range, v...) = rand(Random.default_rng(), S, val_range, scale_range, v...) +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(R::PuiseuxSeriesRing{BigInt}) + rand(R, -12:12, 1:6, -10:10) +end ############################################################################### # diff --git a/src/generic/RationalFunctionField.jl b/src/generic/RationalFunctionField.jl index ccd1bcba48..afeb593088 100644 --- a/src/generic/RationalFunctionField.jl +++ b/src/generic/RationalFunctionField.jl @@ -521,6 +521,16 @@ rand(rng::AbstractRNG, S::RationalFunctionField, v...) = rand(S::RationalFunctionField, v...) = rand(Random.default_rng(), S, v...) +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(R::RationalFunctionField{Rational{BigInt}}) + rand(R, 0:3, -3:3) +end + ############################################################################### # # Promotion rules diff --git a/src/generic/Residue.jl b/src/generic/Residue.jl index 34b8abb529..8429286746 100644 --- a/src/generic/Residue.jl +++ b/src/generic/Residue.jl @@ -146,3 +146,13 @@ function add!(c::T, a::T, b::T) where {T <: EuclideanRingResidueRingElem} c.data = mod(data(a) + data(b), modulus(a)) return c end + +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(R::EuclideanRingResidueRing) + return R(ConformanceTests.test_elem(base_ring(R))) +end diff --git a/src/generic/UnivPoly.jl b/src/generic/UnivPoly.jl index 5c8bd3249a..7bdf612143 100644 --- a/src/generic/UnivPoly.jl +++ b/src/generic/UnivPoly.jl @@ -1000,6 +1000,16 @@ function rand(S::AbstractAlgebra.UniversalPolyRing, term_range, exp_bound, v...) rand(Random.default_rng(), S, term_range, exp_bound, v...) end +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(R::UniversalPolyRing{EuclideanRingResidueRingElem{BigInt}}) + return rand(R, 0:4, 0:10, -10:10) +end + ############################################################################### # # Unsafe functions diff --git a/src/julia/Float.jl b/src/julia/Float.jl index e47145f7a6..d662e6d915 100644 --- a/src/julia/Float.jl +++ b/src/julia/Float.jl @@ -190,6 +190,16 @@ rand(rng::AbstractRNG, R::Floats, n::AbstractUnitRange) = rand(rng, make(R, n)) rand(R::Floats, n) = rand(Random.default_rng(), R, n) +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(R::Floats{T}) where T + return rand(T)*rand(-100:100) +end + ############################################################################### # # Parent object call overload @@ -219,3 +229,4 @@ end function (a::Floats{BigFloat})(b::Rational{BigInt}) return BigFloat(b) end + diff --git a/src/julia/Integer.jl b/src/julia/Integer.jl index 33fc7959a1..71eedffe0b 100644 --- a/src/julia/Integer.jl +++ b/src/julia/Integer.jl @@ -573,6 +573,22 @@ rand(rng::AbstractRNG, R::Integers, n) = R(rand(rng, n)) rand(R::Integers, n) = rand(Random.default_rng(), R, n) +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(R::Integers{T}) where {T <: Signed} + n = T(2)^rand((1,1,1,2,3,10,31,32,33,63,64,65,100)) + return rand(R, -n:n) +end + +function ConformanceTests.test_elem(R::Integers{T}) where {T <: Unsigned} + n = T(2)^rand((1,1,1,2,3,10,31,32,33,63,64,65,100)) + return rand(R, 0:n) +end + ############################################################################### # # Parent object call overload @@ -586,4 +602,3 @@ end function (a::Integers{T})(b::Union{Integer, Rational}) where T <: Integer return T(b) end - diff --git a/src/julia/Rational.jl b/src/julia/Rational.jl index 1a7152239e..4faa88e005 100644 --- a/src/julia/Rational.jl +++ b/src/julia/Rational.jl @@ -222,6 +222,19 @@ rand(rng::AbstractRNG, R::Rationals, n) = rand(rng, make(R, n)) rand(R::Rationals, n) = rand(Random.default_rng(), R, n) +############################################################################### +# +# Conformance test element generation +# +############################################################################### + +function ConformanceTests.test_elem(R::Rationals) + B = base_ring(R) + n = ConformanceTests.test_elem(B) + d = ConformanceTests.test_elem(B) + return is_zero(d) ? R(n) : R(n, d) +end + ############################################################################### # # valutaion / remove diff --git a/test/AbstractAlgebra-test.jl b/test/AbstractAlgebra-test.jl index bc31a81223..533455a685 100644 --- a/test/AbstractAlgebra-test.jl +++ b/test/AbstractAlgebra-test.jl @@ -1,5 +1,3 @@ -include("Rings-conformance-tests.jl") - include("error-test.jl") include("AliasMacro-test.jl") include("Attributes-test.jl") diff --git a/test/generic/AbsMSeries-test.jl b/test/generic/AbsMSeries-test.jl index 45e8887d06..1d651c1f09 100644 --- a/test/generic/AbsMSeries-test.jl +++ b/test/generic/AbsMSeries-test.jl @@ -1,7 +1,3 @@ -function test_elem(R::AbstractAlgebra.Generic.AbsMSeriesRing{BigInt}) - rand(R, 0:12, -10:10) -end - @testset "Generic.AbsMSeries.conformance" begin R, (x, y) = power_series_ring(ZZ, [5, 3], ["x", "y"]) ConformanceTests.test_Ring_interface(R) diff --git a/test/generic/FactoredFraction-test.jl b/test/generic/FactoredFraction-test.jl index d5faadef6c..095e142ffb 100644 --- a/test/generic/FactoredFraction-test.jl +++ b/test/generic/FactoredFraction-test.jl @@ -1,14 +1,3 @@ -function test_elem(FF::Generic.FactoredFracField{BigInt}) - limit = 10 - t = one(FF) - for i in 1:abs(rand(Int)%limit) - s = FF(rand(Int)%(20*limit)) - e = rand(Int)%limit - t *= iszero(s) ? s^abs(e) : s^e - end - return t -end - @testset "Generic.FactoredFracFieldElem.ZZ.conformance" begin FF = FactoredFractionField(ZZ) ConformanceTests.test_Field_interface(FF) @@ -81,7 +70,7 @@ end test_reps = 20 for i in 1:test_reps - a = test_elem(FF) + a = ConformanceTests.test_elem(FF) b = a - FF(1) if isone(a) @test iszero(b) @@ -94,8 +83,8 @@ end end for i in 1:test_reps - a = test_elem(FF) - b = test_elem(FF) + a = ConformanceTests.test_elem(FF) + b = ConformanceTests.test_elem(FF) c = a*b if iszero(b) d = c @@ -115,8 +104,8 @@ end end for i in 1:test_reps - a = test_elem(FF) - b = test_elem(FF) + a = ConformanceTests.test_elem(FF) + b = ConformanceTests.test_elem(FF) c = a + b d = c - b @test d == a diff --git a/test/generic/FunctionField-test.jl b/test/generic/FunctionField-test.jl index 1e5dd76b77..22bbd9b784 100644 --- a/test/generic/FunctionField-test.jl +++ b/test/generic/FunctionField-test.jl @@ -12,10 +12,6 @@ P2 = [(x2 + 1)*z2 + (x2 + 2), z2 + (x2 + 1)//(x2 + 2), z2^2 + 3z2 + 1, (x2^2 + 1)//(x2 + 1)*z2^5 + 4z2^4 + (x2 + 2)*z2^3 + x2//(x2 + 1)*z2 + 1//(x2 + 1)] # FIXME/TODO: conformance tests run into infinite loop??? -#function test_elem(R::AbstractAlgebra.Generic.FunctionField{Rational{BigInt}}) -# rand(R, 1:10, -10:10) -#end -# #@testset "Generic.FunctionField.conformance" begin # S, y = function_field(P1[4], "y") # ConformanceTests.test_Ring_interface(S) diff --git a/test/generic/LaurentMPoly-test.jl b/test/generic/LaurentMPoly-test.jl index ca6df1947d..271bb02f1a 100644 --- a/test/generic/LaurentMPoly-test.jl +++ b/test/generic/LaurentMPoly-test.jl @@ -1,19 +1,3 @@ -function test_elem(R::AbstractAlgebra.LaurentMPolyRing{BigInt}) - n = rand(1:10) - # R: length between 1 and 9 - # R: exponents between -n and n - # ZZ: coeffs between -99 and 99 - rand(R, 1:9, -n:n, -99:99) -end - -function test_elem(R::AbstractAlgebra.Generic.LaurentMPolyWrapRing{AbstractAlgebra.EuclideanRingResidueRingElem{BigInt}}) - n = rand(1:5) - # R: length between 1 and 9 - # R: exponents between -n and n - # ZZ/6ZZ: coeffs between ??? <- TODO - rand(R, 1:4, -n:n, 1:10) -end - @testset "Generic.LaurentMPoly.conformance" begin L, (x, y) = laurent_polynomial_ring(ZZ, ["x", "y"]) ConformanceTests.test_Ring_interface(L) diff --git a/test/generic/LaurentPoly-test.jl b/test/generic/LaurentPoly-test.jl index 17c1240ce7..b74549f564 100644 --- a/test/generic/LaurentPoly-test.jl +++ b/test/generic/LaurentPoly-test.jl @@ -3,16 +3,6 @@ using AbstractAlgebra: terms_degrees, LaurentPolyRingElem using AbstractAlgebra.Generic: Integers, LaurentPolyWrapRing, LaurentPolyWrap, trail_degree, lead_degree -function test_elem(R::LaurentPolyWrapRing) - n = rand(0:10) - if n == 0 - return zero(R) - else - m = rand(0:5) - rand(R, -m:n-m, -99:99) - end -end - @testset "Generic.LaurentPoly" begin @testset "constructors" begin L0, y0 = laurent_polynomial_ring(zz, "y0") diff --git a/test/generic/LaurentSeries-test.jl b/test/generic/LaurentSeries-test.jl index 56a80b6c16..bd41a48989 100644 --- a/test/generic/LaurentSeries-test.jl +++ b/test/generic/LaurentSeries-test.jl @@ -16,10 +16,6 @@ # Note: only useful to distinguish rings and fields for 1/2, 3/4, 5/6 if the # algos differ, and 7 can often stand in for 5/6 if the algorithm supports it. -function test_elem(R::AbstractAlgebra.Generic.LaurentSeriesRing{BigInt}) - rand(R, 0:12, -10:10) -end - @testset "Generic.LaurentSeries.conformance" begin R, x = laurent_series_ring(ZZ, 10, "x") ConformanceTests.test_Ring_interface(R) diff --git a/test/generic/PuiseuxSeries-test.jl b/test/generic/PuiseuxSeries-test.jl index a44f29e4f5..9bddad4812 100644 --- a/test/generic/PuiseuxSeries-test.jl +++ b/test/generic/PuiseuxSeries-test.jl @@ -16,9 +16,7 @@ # Note: only useful to distinguish rings and fields for 1/2, 3/4, 5/6 if the # algos differ, and 7 can often stand in for 5/6 if the algorithm supports it. -function test_elem(R::AbstractAlgebra.Generic.PuiseuxSeriesRing{BigInt}) - rand(R, -12:12, 1:6, -10:10) -end + @testset "Generic.PuiseuxSeries.conformance" begin R, x = puiseux_series_ring(ZZ, 10, "x") diff --git a/test/generic/RationalFunctionField-test.jl b/test/generic/RationalFunctionField-test.jl index 602b769cee..f08a28d060 100644 --- a/test/generic/RationalFunctionField-test.jl +++ b/test/generic/RationalFunctionField-test.jl @@ -1,7 +1,3 @@ -function test_elem(R::AbstractAlgebra.Generic.RationalFunctionField{Rational{BigInt}}) - rand(R, 0:3, -3:3) -end - @testset "Generic.FunctionField.conformance" begin S, x = rational_function_field(QQ, "x") ConformanceTests.test_Ring_interface(S) diff --git a/test/generic/UnivPoly-test.jl b/test/generic/UnivPoly-test.jl index 8641f93c27..84ef36e152 100644 --- a/test/generic/UnivPoly-test.jl +++ b/test/generic/UnivPoly-test.jl @@ -127,9 +127,7 @@ end end end -function test_elem(R::AbstractAlgebra.Generic.UniversalPolyRing{EuclideanRingResidueRingElem{BigInt}}) - return rand(R, 0:4, 0:10, -10:10) -end + @testset "Generic.UnivPoly.conformance" begin S = universal_polynomial_ring(residue_ring(ZZ, ZZ(6))[1]) From ed807dbd73f5f86d6107022882a8ad18a2a14d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 13 Jan 2025 16:53:03 +0100 Subject: [PATCH 08/11] Adjust documentation --- docs/src/ring_interface.md | 3 +-- ext/TestExt/Rings-conformance-tests.jl | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/src/ring_interface.md b/docs/src/ring_interface.md index 158c708982..0aebebb1f2 100644 --- a/docs/src/ring_interface.md +++ b/docs/src/ring_interface.md @@ -1017,9 +1017,8 @@ The above implementation of `constant_polynomial_ring` may be tested as follows. ```jldoctest ConstPoly; filter = r".*"s using Test -include(joinpath(pathof(AbstractAlgebra), "..", "..", "test", "Rings-conformance-tests.jl")) -function test_elem(R::ConstPolyRing{elem_type(ZZ)}) +function ConformanceTests.test_elem(R::ConstPolyRing{elem_type(ZZ)}) n = rand(1:999) return R(rand(-n:n)) end diff --git a/ext/TestExt/Rings-conformance-tests.jl b/ext/TestExt/Rings-conformance-tests.jl index 69209c83f6..c51711f5e3 100644 --- a/ext/TestExt/Rings-conformance-tests.jl +++ b/ext/TestExt/Rings-conformance-tests.jl @@ -1,4 +1,4 @@ -# very generic testing: just define test_elem(R) to produce elements of R, +# very generic testing: just define ConformanceTests.test_elem(R) to produce elements of R, # then invoke one of these functions, as appropriate: # - test_NCRing_interface(R) # - test_Ring_interface(R) From 3b0ec17a7b29e78432f1d618686981a078d83d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 13 Jan 2025 16:56:11 +0100 Subject: [PATCH 09/11] Rename `test_elem` -> `generate_element` --- docs/src/ring_interface.md | 2 +- ext/TestExt/Rings-conformance-tests.jl | 66 +++++++++++++------------- ext/TestExt/TestExt.jl | 2 +- src/ConformanceTests.jl | 2 +- src/FreeAssociativeAlgebra.jl | 6 +-- src/LaurentMPoly.jl | 4 +- src/MPoly.jl | 6 +-- src/MatRing.jl | 4 +- src/Matrix.jl | 4 +- src/Poly.jl | 4 +- src/RelSeries.jl | 4 +- src/algorithms/FinField.jl | 2 +- src/generic/AbsMSeries.jl | 2 +- src/generic/FactoredFraction.jl | 2 +- src/generic/FunctionField.jl | 2 +- src/generic/LaurentPoly.jl | 2 +- src/generic/LaurentSeries.jl | 2 +- src/generic/PuiseuxSeries.jl | 2 +- src/generic/RationalFunctionField.jl | 2 +- src/generic/Residue.jl | 4 +- src/generic/UnivPoly.jl | 2 +- src/julia/Float.jl | 2 +- src/julia/Integer.jl | 4 +- src/julia/Rational.jl | 6 +-- test/Rings-conformance-tests.jl | 2 +- test/generic/FactoredFraction-test.jl | 10 ++-- 26 files changed, 75 insertions(+), 75 deletions(-) diff --git a/docs/src/ring_interface.md b/docs/src/ring_interface.md index 0aebebb1f2..2897b856d2 100644 --- a/docs/src/ring_interface.md +++ b/docs/src/ring_interface.md @@ -1018,7 +1018,7 @@ The above implementation of `constant_polynomial_ring` may be tested as follows. ```jldoctest ConstPoly; filter = r".*"s using Test -function ConformanceTests.test_elem(R::ConstPolyRing{elem_type(ZZ)}) +function ConformanceTests.generate_element(R::ConstPolyRing{elem_type(ZZ)}) n = rand(1:999) return R(rand(-n:n)) end diff --git a/ext/TestExt/Rings-conformance-tests.jl b/ext/TestExt/Rings-conformance-tests.jl index c51711f5e3..9f1140433a 100644 --- a/ext/TestExt/Rings-conformance-tests.jl +++ b/ext/TestExt/Rings-conformance-tests.jl @@ -1,4 +1,4 @@ -# very generic testing: just define ConformanceTests.test_elem(R) to produce elements of R, +# very generic testing: just define ConformanceTests.generate_element(R) to produce elements of R, # then invoke one of these functions, as appropriate: # - test_NCRing_interface(R) # - test_Ring_interface(R) @@ -27,7 +27,7 @@ function ConformanceTests.test_NCRing_interface(R::AbstractAlgebra.NCRing; reps @test elem_type(typeof(R)) == T @test parent_type(T) == typeof(R) for i in 1:reps - a = test_elem(R)::T + a = generate_element(R)::T @test parent(a) == R end @test is_domain_type(T) isa Bool @@ -62,7 +62,7 @@ function ConformanceTests.test_NCRing_interface(R::AbstractAlgebra.NCRing; reps @test R(BigInt(-2)) isa T @test R(BigInt(3)^100) isa T for i in 1:reps - a = test_elem(R)::T + a = generate_element(R)::T @test R(a) isa T end end @@ -76,7 +76,7 @@ function ConformanceTests.test_NCRing_interface(R::AbstractAlgebra.NCRing; reps @test isone(R(0)) || !is_unit(R(0)) @test is_unit(R(1)) for i in 1:reps - a = test_elem(R)::T + a = generate_element(R)::T @test hash(a) isa UInt A = deepcopy(a) @test !ismutable(a) || a !== A @@ -88,9 +88,9 @@ function ConformanceTests.test_NCRing_interface(R::AbstractAlgebra.NCRing; reps @test sprint(show, "text/plain", R) isa String for i in 1:reps - a = test_elem(R)::T - b = test_elem(R)::T - c = test_elem(R)::T + a = generate_element(R)::T + b = generate_element(R)::T + c = generate_element(R)::T A = deepcopy(a) B = deepcopy(b) C = deepcopy(c) @@ -125,9 +125,9 @@ function ConformanceTests.test_NCRing_interface(R::AbstractAlgebra.NCRing; reps s1 = one(S) r1 = one(R) for i in 1:reps - s2 = test_elem(S) + s2 = generate_element(S) r2 = R(s2) - x = test_elem(R) + x = generate_element(R) for (s,r) in ((s0, r0), (s1, r1), (s2, r2)) @test equality(r, s) @@ -149,8 +149,8 @@ function ConformanceTests.test_NCRing_interface(R::AbstractAlgebra.NCRing; reps if !(R isa AbstractAlgebra.Ring) @testset "Basic functionality for noncommutative rings only" begin for i in 1:reps - a = test_elem(R)::T - b = test_elem(R)::T + a = generate_element(R)::T + b = generate_element(R)::T A = deepcopy(a) B = deepcopy(b) # documentation is not clear on divexact @@ -196,9 +196,9 @@ function ConformanceTests.test_NCRing_interface(R::AbstractAlgebra.NCRing; reps @testset "Unsafe ring operators" begin for i in 1:reps - a = test_elem(R)::T - b = test_elem(R)::T - c = test_elem(R)::T + a = generate_element(R)::T + b = generate_element(R)::T + c = generate_element(R)::T ConformanceTests.test_mutating_op_like_zero(zero, zero!, a) ConformanceTests.test_mutating_op_like_zero(one, one!, a) @@ -234,8 +234,8 @@ function ConformanceTests.test_Ring_interface(R::AbstractAlgebra.Ring; reps = 50 ConformanceTests.test_mutating_op_like_neg(AbstractAlgebra.inv, inv!, one(R)) ConformanceTests.test_mutating_op_like_neg(AbstractAlgebra.inv, inv!, -one(R)) for i in 1:reps - a = test_elem(R)::T - b = test_elem(R)::T + a = generate_element(R)::T + b = generate_element(R)::T A = deepcopy(a) B = deepcopy(b) @test a*b == b*a @@ -295,7 +295,7 @@ function ConformanceTests.test_Field_interface(R::AbstractAlgebra.Field; reps = @test iszero(one(R) * characteristic(R)) for i in 1:reps - a = test_elem(R)::T + a = generate_element(R)::T A = deepcopy(a) @test is_unit(a) == !iszero(a) if !is_zero(a) @@ -319,9 +319,9 @@ function ConformanceTests.test_EuclideanRing_interface(R::AbstractAlgebra.Ring; @testset "Euclidean Ring interface for $(R) of type $(typeof(R))" begin for i in 1:reps - f = test_elem(R)::T - g = test_elem(R)::T - m = test_elem(R)::T + f = generate_element(R)::T + g = generate_element(R)::T + m = generate_element(R)::T if iszero(m) m = one(R) end @@ -411,7 +411,7 @@ function ConformanceTests.test_Poly_interface(Rx::AbstractAlgebra.PolyRing; reps @testset "Polynomial Constructors" begin for i in 1:reps - a = test_elem(Rx)::T + a = generate_element(Rx)::T for b in coefficients(a) @assert Rx(b) isa T end @@ -433,10 +433,10 @@ function ConformanceTests.test_Poly_interface(Rx::AbstractAlgebra.PolyRing; reps ConformanceTests.test_EuclideanRing_interface(Rx, reps = 2 + fld(reps, 2)) @testset "Half-GCD" begin for i in 1:reps - a = test_elem(Rx) - b = test_elem(Rx) + a = generate_element(Rx) + b = generate_element(Rx) for j in 1:8 - q = test_elem(Rx) + q = generate_element(Rx) a, b = q*a + b, a end g, s, t = gcdx(a, b) @@ -466,7 +466,7 @@ function ConformanceTests.test_Poly_interface(Rx::AbstractAlgebra.PolyRing; reps @test is_monic(x) @test is_trivial(Rx) || !is_gen(x^2) for i in 1:reps - a = test_elem(Rx) + a = generate_element(Rx) @test iszero(a) || degree(a) >= 0 @test equality(a, leading_coefficient(a)*x^max(0, degree(a)) + tail(a)) @test constant_coefficient(a) isa elem_type(R) @@ -501,7 +501,7 @@ function ConformanceTests.test_MPoly_interface(Rxy::AbstractAlgebra.MPolyRing; r @testset "Polynomial Constructors" begin for i in 1:reps - a = test_elem(Rxy)::T + a = generate_element(Rxy)::T for b in coefficients(a) @assert Rxy(b) isa T end @@ -597,7 +597,7 @@ function ConformanceTests.test_MPoly_interface(Rxy::AbstractAlgebra.MPolyRing; r @test degrees(a) == [3, 4] for i in 1:reps - a = test_elem(Rxy) + a = generate_element(Rxy) iszero(a) && continue @test length(a) >= 0 @test sum(degrees(a)) >= total_degree(a) @@ -628,7 +628,7 @@ function ConformanceTests.test_MatSpace_interface(S::MatSpace; reps = 20) @testset "Constructors" begin for k in 1:reps - a = test_elem(S)::ST + a = generate_element(S)::ST @test nrows(a) == nrows(S) @test ncols(a) == ncols(S) @test a == S(T[a[i, j] for i in 1:nrows(a), j in 1:ncols(a)]) @@ -672,7 +672,7 @@ function ConformanceTests.test_MatSpace_interface(S::MatSpace; reps = 20) @testset "Basic manipulation of matrices" begin for k in 1:reps - a = test_elem(S)::ST + a = generate_element(S)::ST A = deepcopy(a) @test A isa ST @@ -728,7 +728,7 @@ function ConformanceTests.test_MatAlgebra_interface(S::MatRing; reps = 20) @testset "Constructors" begin for k in 1:reps - a = test_elem(S)::ST + a = generate_element(S)::ST @test nrows(a) == nrows(S) @test ncols(a) == ncols(S) @test a == S(T[a[i, j] for i in 1:nrows(a), j in 1:ncols(a)]) @@ -738,7 +738,7 @@ function ConformanceTests.test_MatAlgebra_interface(S::MatRing; reps = 20) @testset "Basic manipulation of matrices" begin for k in 1:reps - a = test_elem(S)::ST + a = generate_element(S)::ST A = deepcopy(a) b = zero(S) for i in 1:nrows(a), j in 1:ncols(a) @@ -752,8 +752,8 @@ function ConformanceTests.test_MatAlgebra_interface(S::MatRing; reps = 20) @testset "Determinant" begin for k in 1:reps - a = test_elem(S)::ST - b = test_elem(S)::ST + a = generate_element(S)::ST + b = generate_element(S)::ST A = deepcopy(a) B = deepcopy(b) @test det(a*b) == det(a)*det(b) diff --git a/ext/TestExt/TestExt.jl b/ext/TestExt/TestExt.jl index b512f9fbca..789de5c4a6 100644 --- a/ext/TestExt/TestExt.jl +++ b/ext/TestExt/TestExt.jl @@ -7,7 +7,7 @@ using .ConformanceTests: equality, equality_up_to_units, adhoc_partner_rings, - test_elem + generate_element include("Groups-conformance-tests.jl") include("Mutating-ops.jl") diff --git a/src/ConformanceTests.jl b/src/ConformanceTests.jl index 7de3fb7fb9..227a2de6c2 100644 --- a/src/ConformanceTests.jl +++ b/src/ConformanceTests.jl @@ -28,7 +28,7 @@ adhoc_partner_rings(R::NCRing) = default_adhoc_partner_rings # To be implemented in the src files of the respective types. # This function is used to generate a pseudo-random element in the Ring conformance tests. -function test_elem end +function generate_element end ############################################################################### diff --git a/src/FreeAssociativeAlgebra.jl b/src/FreeAssociativeAlgebra.jl index 30ff85f6d8..0afdfe7bd8 100644 --- a/src/FreeAssociativeAlgebra.jl +++ b/src/FreeAssociativeAlgebra.jl @@ -265,15 +265,15 @@ end # ############################################################################### -function ConformanceTests.test_elem(S::FreeAssociativeAlgebra) +function ConformanceTests.generate_element(S::FreeAssociativeAlgebra) f = S() g = gens(S) R = base_ring(S) - isempty(g) && return S(ConformanceTests.test_elem(R)) + isempty(g) && return S(ConformanceTests.generate_element(R)) len_bound = 8 exp_bound = 6 for i in 1:rand(0:len_bound) - f += ConformanceTests.test_elem(R) * prod(rand(g) for _ in 1:rand(0:exp_bound); init = S(1)) + f += ConformanceTests.generate_element(R) * prod(rand(g) for _ in 1:rand(0:exp_bound); init = S(1)) end return f end diff --git a/src/LaurentMPoly.jl b/src/LaurentMPoly.jl index fadefab9b1..e049d7f65a 100644 --- a/src/LaurentMPoly.jl +++ b/src/LaurentMPoly.jl @@ -152,7 +152,7 @@ end # ############################################################################### -function ConformanceTests.test_elem(R::LaurentMPolyRing{BigInt}) +function ConformanceTests.generate_element(R::LaurentMPolyRing{BigInt}) n = rand(1:10) # R: length between 1 and 9 # R: exponents between -n and n @@ -160,7 +160,7 @@ function ConformanceTests.test_elem(R::LaurentMPolyRing{BigInt}) rand(R, 1:9, -n:n, -99:99) end -function ConformanceTests.test_elem(R::LaurentMPolyRing{<:ResElem{BigInt}}) +function ConformanceTests.generate_element(R::LaurentMPolyRing{<:ResElem{BigInt}}) n = rand(1:5) # R: length between 1 and 9 # R: exponents between -n and n diff --git a/src/MPoly.jl b/src/MPoly.jl index e34a009444..c08a31f630 100644 --- a/src/MPoly.jl +++ b/src/MPoly.jl @@ -1433,14 +1433,14 @@ end # ############################################################################### -function ConformanceTests.test_elem(Rx::MPolyRing) +function ConformanceTests.generate_element(Rx::MPolyRing) R = base_ring(Rx) num_gens = ngens(Rx) - iszero(num_gens) && return Rx(ConformanceTests.test_elem(R)) + iszero(num_gens) && return Rx(ConformanceTests.generate_element(R)) len_bound = 8 exp_bound = rand(1:5) len = rand(0:len_bound) - coeffs = [ConformanceTests.test_elem(R) for _ in 1:len] + coeffs = [ConformanceTests.generate_element(R) for _ in 1:len] exps = [[rand(0:exp_bound) for _ in 1:num_gens] for _ in 1:len] return Rx(coeffs, exps) end diff --git a/src/MatRing.jl b/src/MatRing.jl index a913a668a0..9c2655bb76 100644 --- a/src/MatRing.jl +++ b/src/MatRing.jl @@ -411,9 +411,9 @@ randmat_with_rank(S::MatRing{T}, rank::Int, v...) where {T <: RingElement} = # ############################################################################### -function ConformanceTests.test_elem(S::MatRing) +function ConformanceTests.generate_element(S::MatRing) R = base_ring(S) - return S(elem_type(R)[ConformanceTests.test_elem(R) for i in 1:nrows(S), j in 1:ncols(S)]) + return S(elem_type(R)[ConformanceTests.generate_element(R) for i in 1:nrows(S), j in 1:ncols(S)]) end ############################################################################### diff --git a/src/Matrix.jl b/src/Matrix.jl index c866451771..41fd65c2d5 100644 --- a/src/Matrix.jl +++ b/src/Matrix.jl @@ -6696,9 +6696,9 @@ randmat_with_rank(S::MatSpace{T}, rank::Int, v...) where {T <: RingElement} = # ############################################################################### -function ConformanceTests.test_elem(S::MatSpace) +function ConformanceTests.generate_element(S::MatSpace) R = base_ring(S) - return S(elem_type(R)[ConformanceTests.test_elem(R) for i in 1:nrows(S), j in 1:ncols(S)]) + return S(elem_type(R)[ConformanceTests.generate_element(R) for i in 1:nrows(S), j in 1:ncols(S)]) end ################################################################################ diff --git a/src/Poly.jl b/src/Poly.jl index 7e15f8be0c..24d62bfdba 100644 --- a/src/Poly.jl +++ b/src/Poly.jl @@ -3410,9 +3410,9 @@ rand(S::PolyRing, degs, v...) = rand(Random.default_rng(), S, degs, v...) # ############################################################################### -function ConformanceTests.test_elem(Rx::PolyRing) +function ConformanceTests.generate_element(Rx::PolyRing) R = base_ring(Rx) - return Rx(elem_type(R)[ConformanceTests.test_elem(R) for i in 1:rand(0:6)]) + return Rx(elem_type(R)[ConformanceTests.generate_element(R) for i in 1:rand(0:6)]) end ############################################################################### diff --git a/src/RelSeries.jl b/src/RelSeries.jl index ade91c1e48..a62a3fe3dc 100644 --- a/src/RelSeries.jl +++ b/src/RelSeries.jl @@ -1458,14 +1458,14 @@ rand(S::SeriesRing, val_range, v...) = rand(Random.default_rng(), S, val_range, # Conformance test element generation # ############################################################################### -function ConformanceTests.test_elem(Rx::SeriesRing) +function ConformanceTests.generate_element(Rx::SeriesRing) R = base_ring(Rx) prec = rand(3:10) len = rand(0:prec-1) val = rand(0:prec-len) # FIXME: constructors don't seem to catch use of negative val @assert val >= 0 - A = elem_type(R)[ConformanceTests.test_elem(R) for i in 1:len] + A = elem_type(R)[ConformanceTests.generate_element(R) for i in 1:len] if len > 0 && is_zero(A[1]) A[1] = one(R) end diff --git a/src/algorithms/FinField.jl b/src/algorithms/FinField.jl index c6f5ce1510..917524f4af 100644 --- a/src/algorithms/FinField.jl +++ b/src/algorithms/FinField.jl @@ -74,6 +74,6 @@ Base.eltype(::Type{F}) where {F<:FinField} = elem_type(F) # ############################################################################### -function ConformanceTests.test_elem(R::FinField) +function ConformanceTests.generate_element(R::FinField) return rand(R) end diff --git a/src/generic/AbsMSeries.jl b/src/generic/AbsMSeries.jl index 9f20ae0611..b302f263a2 100644 --- a/src/generic/AbsMSeries.jl +++ b/src/generic/AbsMSeries.jl @@ -663,7 +663,7 @@ end # ############################################################################### -function ConformanceTests.test_elem(R::Generic.AbsMSeriesRing{BigInt}) +function ConformanceTests.generate_element(R::Generic.AbsMSeriesRing{BigInt}) rand(R, 0:12, -10:10) end diff --git a/src/generic/FactoredFraction.jl b/src/generic/FactoredFraction.jl index 119706a5f1..38a5647616 100644 --- a/src/generic/FactoredFraction.jl +++ b/src/generic/FactoredFraction.jl @@ -694,7 +694,7 @@ end # ############################################################################### -function ConformanceTests.test_elem(FF::Generic.FactoredFracField{BigInt}) +function ConformanceTests.generate_element(FF::Generic.FactoredFracField{BigInt}) limit = 10 t = one(FF) for i in 1:abs(rand(Int)%limit) diff --git a/src/generic/FunctionField.jl b/src/generic/FunctionField.jl index e8c6385b50..13033a4a88 100644 --- a/src/generic/FunctionField.jl +++ b/src/generic/FunctionField.jl @@ -1231,7 +1231,7 @@ rand(K::FunctionField, v...) = rand(Random.default_rng(), K, v...) # ############################################################################### -function ConformanceTests.test_elem(R::FunctionField{Rational{BigInt}}) +function ConformanceTests.generate_element(R::FunctionField{Rational{BigInt}}) rand(R, 1:10, -10:10) end diff --git a/src/generic/LaurentPoly.jl b/src/generic/LaurentPoly.jl index a422b6459b..6a83f5432c 100644 --- a/src/generic/LaurentPoly.jl +++ b/src/generic/LaurentPoly.jl @@ -443,7 +443,7 @@ rand(S::LaurentPolyWrapRing, degrees_range, v...) = # ############################################################################### -function ConformanceTests.test_elem(R::Generic.LaurentPolyWrapRing) +function ConformanceTests.generate_element(R::Generic.LaurentPolyWrapRing) n = rand(0:10) if n == 0 return zero(R) diff --git a/src/generic/LaurentSeries.jl b/src/generic/LaurentSeries.jl index f911a1c03c..4532901d18 100644 --- a/src/generic/LaurentSeries.jl +++ b/src/generic/LaurentSeries.jl @@ -1788,7 +1788,7 @@ rand(S::LaurentSeriesRingOrField, val_range, v...) = # ############################################################################### -function ConformanceTests.test_elem(R::LaurentSeriesRing{BigInt}) +function ConformanceTests.generate_element(R::LaurentSeriesRing{BigInt}) rand(R, 0:12, -10:10) end diff --git a/src/generic/PuiseuxSeries.jl b/src/generic/PuiseuxSeries.jl index 5dda91326b..6e71d2fe78 100644 --- a/src/generic/PuiseuxSeries.jl +++ b/src/generic/PuiseuxSeries.jl @@ -735,7 +735,7 @@ rand(S::PuiseuxSeriesRingOrField, val_range, scale_range, v...) = # ############################################################################### -function ConformanceTests.test_elem(R::PuiseuxSeriesRing{BigInt}) +function ConformanceTests.generate_element(R::PuiseuxSeriesRing{BigInt}) rand(R, -12:12, 1:6, -10:10) end diff --git a/src/generic/RationalFunctionField.jl b/src/generic/RationalFunctionField.jl index afeb593088..0fa5e5e9df 100644 --- a/src/generic/RationalFunctionField.jl +++ b/src/generic/RationalFunctionField.jl @@ -527,7 +527,7 @@ rand(S::RationalFunctionField, v...) = rand(Random.default_rng(), S, v...) # ############################################################################### -function ConformanceTests.test_elem(R::RationalFunctionField{Rational{BigInt}}) +function ConformanceTests.generate_element(R::RationalFunctionField{Rational{BigInt}}) rand(R, 0:3, -3:3) end diff --git a/src/generic/Residue.jl b/src/generic/Residue.jl index 8429286746..b0f0350786 100644 --- a/src/generic/Residue.jl +++ b/src/generic/Residue.jl @@ -153,6 +153,6 @@ end # ############################################################################### -function ConformanceTests.test_elem(R::EuclideanRingResidueRing) - return R(ConformanceTests.test_elem(base_ring(R))) +function ConformanceTests.generate_element(R::EuclideanRingResidueRing) + return R(ConformanceTests.generate_element(base_ring(R))) end diff --git a/src/generic/UnivPoly.jl b/src/generic/UnivPoly.jl index 7bdf612143..40ddae052b 100644 --- a/src/generic/UnivPoly.jl +++ b/src/generic/UnivPoly.jl @@ -1006,7 +1006,7 @@ end # ############################################################################### -function ConformanceTests.test_elem(R::UniversalPolyRing{EuclideanRingResidueRingElem{BigInt}}) +function ConformanceTests.generate_element(R::UniversalPolyRing{EuclideanRingResidueRingElem{BigInt}}) return rand(R, 0:4, 0:10, -10:10) end diff --git a/src/julia/Float.jl b/src/julia/Float.jl index d662e6d915..6240210ba7 100644 --- a/src/julia/Float.jl +++ b/src/julia/Float.jl @@ -196,7 +196,7 @@ rand(R::Floats, n) = rand(Random.default_rng(), R, n) # ############################################################################### -function ConformanceTests.test_elem(R::Floats{T}) where T +function ConformanceTests.generate_element(R::Floats{T}) where T return rand(T)*rand(-100:100) end diff --git a/src/julia/Integer.jl b/src/julia/Integer.jl index 71eedffe0b..afe27b8841 100644 --- a/src/julia/Integer.jl +++ b/src/julia/Integer.jl @@ -579,12 +579,12 @@ rand(R::Integers, n) = rand(Random.default_rng(), R, n) # ############################################################################### -function ConformanceTests.test_elem(R::Integers{T}) where {T <: Signed} +function ConformanceTests.generate_element(R::Integers{T}) where {T <: Signed} n = T(2)^rand((1,1,1,2,3,10,31,32,33,63,64,65,100)) return rand(R, -n:n) end -function ConformanceTests.test_elem(R::Integers{T}) where {T <: Unsigned} +function ConformanceTests.generate_element(R::Integers{T}) where {T <: Unsigned} n = T(2)^rand((1,1,1,2,3,10,31,32,33,63,64,65,100)) return rand(R, 0:n) end diff --git a/src/julia/Rational.jl b/src/julia/Rational.jl index 4faa88e005..84ff6014ee 100644 --- a/src/julia/Rational.jl +++ b/src/julia/Rational.jl @@ -228,10 +228,10 @@ rand(R::Rationals, n) = rand(Random.default_rng(), R, n) # ############################################################################### -function ConformanceTests.test_elem(R::Rationals) +function ConformanceTests.generate_element(R::Rationals) B = base_ring(R) - n = ConformanceTests.test_elem(B) - d = ConformanceTests.test_elem(B) + n = ConformanceTests.generate_element(B) + d = ConformanceTests.generate_element(B) return is_zero(d) ? R(n) : R(n, d) end diff --git a/test/Rings-conformance-tests.jl b/test/Rings-conformance-tests.jl index 8c31d44c59..afed31649c 100644 --- a/test/Rings-conformance-tests.jl +++ b/test/Rings-conformance-tests.jl @@ -7,7 +7,7 @@ # load TestExt using Test -import .ConformanceTests: test_elem as test_elem +import .ConformanceTests: generate_element as test_elem import .ConformanceTests: adhoc_partner_rings as adhoc_partner_rings import .ConformanceTests: equality as equality diff --git a/test/generic/FactoredFraction-test.jl b/test/generic/FactoredFraction-test.jl index 095e142ffb..79396ab0db 100644 --- a/test/generic/FactoredFraction-test.jl +++ b/test/generic/FactoredFraction-test.jl @@ -70,7 +70,7 @@ end test_reps = 20 for i in 1:test_reps - a = ConformanceTests.test_elem(FF) + a = ConformanceTests.generate_element(FF) b = a - FF(1) if isone(a) @test iszero(b) @@ -83,8 +83,8 @@ end end for i in 1:test_reps - a = ConformanceTests.test_elem(FF) - b = ConformanceTests.test_elem(FF) + a = ConformanceTests.generate_element(FF) + b = ConformanceTests.generate_element(FF) c = a*b if iszero(b) d = c @@ -104,8 +104,8 @@ end end for i in 1:test_reps - a = ConformanceTests.test_elem(FF) - b = ConformanceTests.test_elem(FF) + a = ConformanceTests.generate_element(FF) + b = ConformanceTests.generate_element(FF) c = a + b d = c - b @test d == a From 1e75e2c0a5b19a7b81fe4c0453e93cb3a6f6b6fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Tue, 14 Jan 2025 09:11:17 +0100 Subject: [PATCH 10/11] Add docstring to `generate_element` --- src/ConformanceTests.jl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ConformanceTests.jl b/src/ConformanceTests.jl index 227a2de6c2..dfe8c85ffa 100644 --- a/src/ConformanceTests.jl +++ b/src/ConformanceTests.jl @@ -26,8 +26,14 @@ const default_adhoc_partner_rings = [ adhoc_partner_rings(R::NCRing) = default_adhoc_partner_rings -# To be implemented in the src files of the respective types. -# This function is used to generate a pseudo-random element in the Ring conformance tests. +""" + generate_element(::AbstractAlgebra.NCRing) + +Generates some random, representative element of the given set for use +in the conformance tests. + +It is supposed to be implemented in the src file of the respective type. +""" function generate_element end From b154ce47ade34ec39d60f3c308da4708fb1b5c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Sat, 25 Jan 2025 15:57:41 +0100 Subject: [PATCH 11/11] Use imports for backwards compatibility --- test/Groups-conformance-tests.jl | 4 ++-- test/Rings-conformance-tests.jl | 32 ++++++++++++++++---------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/test/Groups-conformance-tests.jl b/test/Groups-conformance-tests.jl index 1354c8d9a4..48e09ded33 100644 --- a/test/Groups-conformance-tests.jl +++ b/test/Groups-conformance-tests.jl @@ -7,5 +7,5 @@ # load TestExt using Test -test_Group_interface = ConformanceTests.test_Group_interface -test_GroupElem_interface = ConformanceTests.test_GroupElem_interface +import .ConformanceTests: test_Group_interface +import .ConformanceTests: test_GroupElem_interface diff --git a/test/Rings-conformance-tests.jl b/test/Rings-conformance-tests.jl index afed31649c..2e54bd134d 100644 --- a/test/Rings-conformance-tests.jl +++ b/test/Rings-conformance-tests.jl @@ -8,21 +8,21 @@ using Test import .ConformanceTests: generate_element as test_elem -import .ConformanceTests: adhoc_partner_rings as adhoc_partner_rings -import .ConformanceTests: equality as equality +import .ConformanceTests: adhoc_partner_rings +import .ConformanceTests: equality -test_mutating_op_like_zero = ConformanceTests.test_mutating_op_like_zero -test_mutating_op_like_neg = ConformanceTests.test_mutating_op_like_neg -test_mutating_op_like_add = ConformanceTests.test_mutating_op_like_add -test_mutating_op_like_addmul = ConformanceTests.test_mutating_op_like_addmul +import .ConformanceTests: test_mutating_op_like_zero +import .ConformanceTests: test_mutating_op_like_neg +import .ConformanceTests: test_mutating_op_like_add +import .ConformanceTests: test_mutating_op_like_addmul -test_NCRing_interface = ConformanceTests.test_NCRing_interface -test_Ring_interface = ConformanceTests.test_Ring_interface -test_Field_interface = ConformanceTests.test_Field_interface -test_EuclideanRing_interface = ConformanceTests.test_EuclideanRing_interface -test_Poly_interface = ConformanceTests.test_Poly_interface -test_MPoly_interface = ConformanceTests.test_MPoly_interface -test_MatSpace_interface = ConformanceTests.test_MatSpace_interface -test_MatAlgebra_interface = ConformanceTests.test_MatAlgebra_interface -test_Ring_interface_recursive = ConformanceTests.test_Ring_interface_recursive -test_Field_interface_recursive = ConformanceTests.test_Field_interface_recursive +import .ConformanceTests: test_NCRing_interface +import .ConformanceTests: test_Ring_interface +import .ConformanceTests: test_Field_interface +import .ConformanceTests: test_EuclideanRing_interface +import .ConformanceTests: test_Poly_interface +import .ConformanceTests: test_MPoly_interface +import .ConformanceTests: test_MatSpace_interface +import .ConformanceTests: test_MatAlgebra_interface +import .ConformanceTests: test_Ring_interface_recursive +import .ConformanceTests: test_Field_interface_recursive