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/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 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/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} 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 diff --git a/src/generic/TotalFraction.jl b/src/generic/TotalFraction.jl index c7f0a117e0..ef556edada 100644 --- a/src/generic/TotalFraction.jl +++ b/src/generic/TotalFraction.jl @@ -370,6 +370,48 @@ 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, 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 + +function (a::TotFrac)(val::RingElement) + return evaluate(a, val) +end + +function (a::TotFrac)(vals::RingElement...) + 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 + ############################################################################### # # Powering diff --git a/test/generic/Fraction-test.jl b/test/generic/Fraction-test.jl index dc0c677e2e..fa1c000ccf 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) @@ -308,6 +308,21 @@ 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,y) = polynomial_ring(R, ["x","y"]) + + f = (x^2 + 3)//(x + 1) + @test f isa Generic.TotFrac + + @test evaluate(f, [1,2]) == R(2) + @test evaluate(f, [R(1),R(2)]) == 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) x, y = gens(R, [:x, :y])