From 8069d2638b346c8a947c345313ea5dca51dcd504 Mon Sep 17 00:00:00 2001 From: John Abbott Date: Wed, 13 May 2026 14:22:09 +0200 Subject: [PATCH 1/7] Extend // to create total_ring_of_fractions if necessary --- src/Fraction.jl | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Fraction.jl b/src/Fraction.jl index 3fe1c239b6..402aa0a6d1 100644 --- a/src/Fraction.jl +++ b/src/Fraction.jl @@ -45,12 +45,21 @@ end ############################################################################### function //(x::T, y::T) where {T <: RingElem} - R = parent(x) iszero(y) && throw(DivideError()) + R = parent(x) g = gcd(x, y) - z = Generic.FracFieldElem{T}(divexact(x, g), divexact(y, g)) - z.parent = get(Generic.FracDict, R) do - return Generic.fraction_field(R) + if is_domain_type(R) + z = Generic.FracFieldElem{T}(divexact(x, g), divexact(y, g)) + z.parent = get(Generic.FracDict, R) do + return Generic.fraction_field(R) + end + return z + end + # R might not be integral, so construct total ring of fractions + is_zero_divisor(y) && error("Division by a zero-divisor") + z = Generic.TotFrac{T}(divexact(x, g), divexact(y, g)) + z.parent = get(Generic.TotFracDict, R) do + return Generic.total_ring_of_fractions(R) end return z end From 5356638f4576507a29d04bd2a4d0df9ccbc7d801 Mon Sep 17 00:00:00 2001 From: John Abbott Date: Wed, 13 May 2026 15:29:23 +0200 Subject: [PATCH 2/7] Extend to allow coercion from TotFrac (previously only FracElem) --- src/generic/Residue.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generic/Residue.jl b/src/generic/Residue.jl index f950346c20..d95e1667bb 100644 --- a/src/generic/Residue.jl +++ b/src/generic/Residue.jl @@ -48,7 +48,7 @@ function (a::EuclideanRingResidueRing{T})(b::Integer) where {T <: RingElement} return z end -function (a::EuclideanRingResidueRing)(b::T) where {T <: Union{Rational, FracElem}} +function (a::EuclideanRingResidueRing)(b::T) where {T <: Union{Rational, FracElem, TotFrac}} return inv(a(denominator(b))) * a(numerator(b)) end From add1be55f363db576a629a1984d73b1d53773efa Mon Sep 17 00:00:00 2001 From: John Abbott Date: Wed, 13 May 2026 16:27:55 +0200 Subject: [PATCH 3/7] Fixed test: TotFrac instead of FracFieldElem --- test/generic/Fraction-test.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/generic/Fraction-test.jl b/test/generic/Fraction-test.jl index dc0c677e2e..2e8e9d060a 100644 --- a/test/generic/Fraction-test.jl +++ b/test/generic/Fraction-test.jl @@ -285,7 +285,7 @@ end S, x = polynomial_ring(R, "x") f = (x^2 + 2)//(x + 1) - @test f isa Generic.FracFieldElem + @test f isa Generic.TotFrac @test evaluate(f, 1) == R(4) @test evaluate(f, R(1)) == R(4) From 3b2136115e7e0a5aebf43f12b7eed5ded2adeea4 Mon Sep 17 00:00:00 2001 From: John Abbott Date: Fri, 15 May 2026 12:16:15 +0200 Subject: [PATCH 4/7] Make evaluate work for TotFrac values (to fix some pre-existing tests) --- src/AbstractTypes.jl | 4 ++++ src/exports.jl | 2 ++ src/generic/TotalFraction.jl | 30 ++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/src/AbstractTypes.jl b/src/AbstractTypes.jl index ae25423a4c..f473e3a568 100644 --- a/src/AbstractTypes.jl +++ b/src/AbstractTypes.jl @@ -102,6 +102,8 @@ abstract type ResidueField{T<:RingElement} <: Field end abstract type FracField{T<:RingElement} <: Field end +abstract type TotFracRing{T<:RingElement} <: Ring end + abstract type MatRing{T<:NCRingElement} <: NCRing end abstract type FreeAssociativeAlgebra{T<:RingElement} <: NCRing end @@ -135,6 +137,8 @@ abstract type ResFieldElem{T<:RingElement} <: FieldElem end abstract type FracElem{T<:RingElement} <: FieldElem end +abstract type TotFrac{T<:RingElement} <: RingElem end + abstract type SeriesElem{T<:RingElement} <: RingElem end abstract type MSeriesElem{T<:RingElement} <: RingElem end diff --git a/src/exports.jl b/src/exports.jl index fc1e5075cd..d3c89498a9 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -108,6 +108,8 @@ export SimpleNumFieldElem export SkewDiagram export Strassen export SymmetricGroup +export TotFrac +export TotFracRing export UniversalPolyRing export UniversalPolyRingElem export UniversalRing diff --git a/src/generic/TotalFraction.jl b/src/generic/TotalFraction.jl index c7f0a117e0..a32f33e91b 100644 --- a/src/generic/TotalFraction.jl +++ b/src/generic/TotalFraction.jl @@ -370,6 +370,36 @@ end # Division is not possible generically due to the possibility of non-units # that are also non-zero divisors +############################################################################## +# +# Evaluation +# +############################################################################## + +function evaluate(f::TotFrac, V::Vector{<:RingElement}) + return evaluate(numerator(f), V)//evaluate(denominator(f), V) +end + +function evaluate(f::TotFrac, v::RingElement) + return evaluate(numerator(f), v)//evaluate(denominator(f), v) +end + +function evaluate(f::TotFrac{<:PolyRingElem}, v::Integer) + return evaluate(numerator(f), v)//evaluate(denominator(f), v) +end + +function evaluate(f::TotFrac, vars::Vector{Int}, vals::Vector{<:RingElement}) + return evaluate(numerator(f), vars, vals)//evaluate(denominator(f), vars, vals) +end + +function (a::TotFrac)(val::RingElement) + return evaluate(a, val) +end + +function (a::TotFrac)(vals::RingElement...) + return evaluate(a, [vals...]) +end + ############################################################################### # # Powering From c25d18113d6fd133481d25decf391e6dcfe25aba Mon Sep 17 00:00:00 2001 From: John Abbott Date: Fri, 15 May 2026 16:02:58 +0200 Subject: [PATCH 5/7] Better subtyping --- src/generic/GenericTypes.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/generic/GenericTypes.jl b/src/generic/GenericTypes.jl index e0e4ab061b..ced7a07ca6 100644 --- a/src/generic/GenericTypes.jl +++ b/src/generic/GenericTypes.jl @@ -930,7 +930,7 @@ end # ############################################################################### -@attributes mutable struct TotFracRing{T <: RingElem} <: AbstractAlgebra.Ring +@attributes mutable struct TotFracRing{T <: RingElem} <: AbstractAlgebra.TotFracRing{T} base_ring::Ring function TotFracRing{T}(R::Ring, cached::Bool = true) where T <: RingElem @@ -942,7 +942,7 @@ end const TotFracDict = CacheDictType{Ring, Ring}() -mutable struct TotFrac{T <: RingElem} <: AbstractAlgebra.RingElem +mutable struct TotFrac{T <: RingElem} <: AbstractAlgebra.TotFrac{T} num::T den::T parent::TotFracRing{T} From ff319392529b6ac31e2fff739e67bdde83bff9b2 Mon Sep 17 00:00:00 2001 From: John Abbott Date: Mon, 18 May 2026 15:08:01 +0200 Subject: [PATCH 6/7] New tests for more coverage --- src/generic/TotalFraction.jl | 14 +++++++++++++- test/generic/Fraction-test.jl | 13 +++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/generic/TotalFraction.jl b/src/generic/TotalFraction.jl index a32f33e91b..ef556edada 100644 --- a/src/generic/TotalFraction.jl +++ b/src/generic/TotalFraction.jl @@ -388,6 +388,12 @@ function evaluate(f::TotFrac{<:PolyRingElem}, v::Integer) return evaluate(numerator(f), v)//evaluate(denominator(f), v) end +# function evaluate(f::TotFrac, vals::Vector{<:RingElement}) +# @req length(vals) == ngens(base_ring(parent(a))) "Evaluation point needs 1 coordinate per variable" +# vars = collect(1:ngens(base_ring(parent(a)))) +# return evaluate(numerator(f), vars, vals)//evaluate(denominator(f), vars, vals) +# end + function evaluate(f::TotFrac, vars::Vector{Int}, vals::Vector{<:RingElement}) return evaluate(numerator(f), vars, vals)//evaluate(denominator(f), vars, vals) end @@ -397,7 +403,13 @@ function (a::TotFrac)(val::RingElement) end function (a::TotFrac)(vals::RingElement...) - return evaluate(a, [vals...]) + vars = collect(1:ngens(base_ring(parent(a)))) + return evaluate(a, vars, [vals...]) +end + +function (a::TotFrac)(vals::Vector{<:RingElement}) + vars = collect(1:ngens(base_ring(parent(a)))) + return evaluate(a, vars, vals) end ############################################################################### diff --git a/test/generic/Fraction-test.jl b/test/generic/Fraction-test.jl index 2e8e9d060a..7715ad69c7 100644 --- a/test/generic/Fraction-test.jl +++ b/test/generic/Fraction-test.jl @@ -308,6 +308,19 @@ end @test f(1, 2) == ZZ(3)//ZZ(4) @test f(ZZ(1), ZZ(2)) == ZZ(3)//ZZ(4) + # multivariate over non domain + R, = residue_ring(ZZ, 15) + S, (x,) = polynomial_ring(R, ["x"]) + + f = (x^2 + 3)//(x + 1) + @test f isa Generic.TotFrac + + @test evaluate(f, [1]) == R(2) + @test evaluate(f, [R(1)]) == R(2) + + @test f([1]) == R(2) + @test f([R(1)]) == R(2) + # universal R = universal_polynomial_ring(ZZ) x, y = gens(R, [:x, :y]) From 7cd46d0fe8e0adf398d0b8ca1bbbfabcee8e9b5b Mon Sep 17 00:00:00 2001 From: John Abbott Date: Fri, 29 May 2026 13:46:14 +0200 Subject: [PATCH 7/7] New tests to achieve better coverage --- test/generic/Fraction-test.jl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/test/generic/Fraction-test.jl b/test/generic/Fraction-test.jl index 7715ad69c7..fa1c000ccf 100644 --- a/test/generic/Fraction-test.jl +++ b/test/generic/Fraction-test.jl @@ -310,16 +310,18 @@ end # multivariate over non domain R, = residue_ring(ZZ, 15) - S, (x,) = polynomial_ring(R, ["x"]) + S, (x,y) = polynomial_ring(R, ["x","y"]) f = (x^2 + 3)//(x + 1) @test f isa Generic.TotFrac - @test evaluate(f, [1]) == R(2) - @test evaluate(f, [R(1)]) == R(2) + @test evaluate(f, [1,2]) == R(2) + @test evaluate(f, [R(1),R(2)]) == R(2) - @test f([1]) == R(2) - @test f([R(1)]) == R(2) + @test f([1,2]) == R(2) + @test f([R(1),R(2)]) == R(2) + @test f(1,2) == R(2) + @test f(R(1),R(2)) == R(2) # universal R = universal_polynomial_ring(ZZ)