Skip to content

Commit

Permalink
Promote integer to rational for division (#296)
Browse files Browse the repository at this point in the history
* Promote integer to rational for division

* Fix format

* Fixes

* Fix
  • Loading branch information
blegat authored May 9, 2024
1 parent 14c11d0 commit a5b8931
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 4 deletions.
4 changes: 4 additions & 0 deletions docs/src/division.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 19 additions & 2 deletions src/division.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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
Expand Down
10 changes: 8 additions & 2 deletions test/division.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit a5b8931

Please sign in to comment.