diff --git a/docs/src/division.md b/docs/src/division.md index fe11e597..a20a6b1d 100644 --- a/docs/src/division.md +++ b/docs/src/division.md @@ -14,6 +14,10 @@ div_multiple Note that the coefficients of the polynomials need to be a field for `div`, `rem` and `divrem` to work. +If the coefficient type is not a field, it is promoted to a field using [`promote_to_field`](@ref). +```@docs +promote_to_field +``` Alternatively, [`pseudo_rem`](@ref) or [`pseudo_divrem`](@ref) can be used instead as they do not require the coefficient type to be a field. ```@docs diff --git a/src/division.jl b/src/division.jl index 7ca299c4..3541c332 100644 --- a/src/division.jl +++ b/src/division.jl @@ -64,8 +64,25 @@ struct Field end struct UniqueFactorizationDomain end const UFD = UniqueFactorizationDomain +""" + promote_to_field(::Type{T}) + +Promote the type `T` to a field. For instance, `promote_to_field(T)` returns +`Rational{T}` if `T` is an integer and `promote_to_field(T)` returns `RationalPoly{T}` +if `T` is a polynomial. +""" +function promote_to_field end + +function promote_to_field(::Type{T}) where {T<:Integer} + return Rational{T} +end +function promote_to_field(::Type{T}) where {T<:_APL} + return RationalPoly{T,T} +end +promote_to_field(::Type{T}) where {T} = T + algebraic_structure(::Type{<:Integer}) = UFD() -algebraic_structure(::Type{<:AbstractPolynomialLike}) = UFD() +algebraic_structure(::Type{<:_APL}) = UFD() # `Rational`, `AbstractFloat`, JuMP expressions, etc... are fields algebraic_structure(::Type) = Field() _field_absorb(::UFD, ::UFD) = UFD() @@ -430,7 +447,7 @@ function MA.promote_operation( ::Type{P}, ::Type{Q}, ) where {T,S,P<:_APL{T},Q<:_APL{S}} - U = MA.promote_operation(/, T, S) + U = MA.promote_operation(/, promote_to_field(T), promote_to_field(S)) # `promote_type(P, Q)` is needed for TypedPolynomials in case they use different variables return polynomial_type(promote_type(P, Q), MA.promote_operation(-, U, U)) end diff --git a/test/division.jl b/test/division.jl index 36b995ab..cce74b1e 100644 --- a/test/division.jl +++ b/test/division.jl @@ -54,8 +54,14 @@ end function divrem_test() Mod.@polyvar x y - @test (@inferred div(x * y^2 + 1, x * y + 1)) == y - @test (@inferred rem(x * y^2 + 1, x * y + 1)) == -y + 1 + p = x * y^2 + 1 + q = x * y + 1 + @test typeof(div(p, q)) == MA.promote_operation(div, typeof(p), typeof(q)) + @test typeof(rem(p, q)) == MA.promote_operation(rem, typeof(p), typeof(q)) + @test coefficient_type(div(p, q)) == Rational{Int} + @test coefficient_type(rem(p, q)) == Rational{Int} + @test (@inferred div(p, q)) == y + @test (@inferred rem(p, q)) == -y + 1 @test (@inferred div(x * y^2 + x, y)) == x * y @test (@inferred rem(x * y^2 + x, y)) == x @test (@inferred rem(x^4 + x^3 + (1 + 1e-10) * x^2 + 1, x^2 + x + 1)) == 1