Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 566a #570

Merged
merged 2 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ function offset_vector_combine(op, p::MutableDenseLaurentPolynomial{B,T,X}, q::M

end

# multiply by xⁿ
_shift(p::P, n::Int) where {P <: MutableDenseLaurentPolynomial} =
P(Val(false), p.coeffs, firstindex(p) + n)

function Base.numerator(q::MutableDenseLaurentPolynomial{B,T,X}) where {B,T,X}
p = chop(q)
o = firstindex(p)
Expand Down
4 changes: 4 additions & 0 deletions src/polynomials/standard-basis/laurent-polynomial.jl
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ function evalpoly(c, p::LaurentPolynomial{T,X}) where {T,X}
EvalPoly.evalpoly(c, p.coeffs) * c^p.order[]
end

# ---



# scalar add
function scalar_add(c::S, p::LaurentPolynomial{T,X}) where {S, T, X}
R = promote_type(T,S)
Expand Down
4 changes: 2 additions & 2 deletions src/promotions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ Base.promote_rule(::Type{P}, ::Type{Q}) where {B,T,S,X,
Q<:AbstractLaurentUnivariatePolynomial{B,S,X}} = MutableDenseLaurentPolynomial{B,promote_type(T,S),X}



# Methods to ensure that matrices of polynomials behave as desired
Base.promote_rule(::Type{P},::Type{Q}) where {T,X, P<:AbstractPolynomial{T,X},
S, Q<:AbstractPolynomial{S,X}} =
Polynomial{promote_type(T, S),X}
LaurentPolynomial{promote_type(T, S),X}


Base.promote_rule(::Type{P},::Type{Q}) where {T,X, P<:AbstractPolynomial{T,X},
S,Y, Q<:AbstractPolynomial{S,Y}} =
Expand Down
21 changes: 2 additions & 19 deletions src/rational-functions/common.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,6 @@ function Base.convert(::Type{PQ}, p::Number) where {PQ <: AbstractRationalFuncti
rational_function(PQ, p * one(P), one(P))
end

function Base.convert(::Type{PQ}, q::LaurentPolynomial) where {PQ <: AbstractRationalFunction}
m = firstindex(q)
if m >= 0
p = convert(Polynomial, q)
return convert(PQ, p)
else
z = variable(q)
zᵐ = z^(-m)
p = convert(Polynomial, zᵐ * q)
return rational_function(PQ, p, convert(Polynomial, zᵐ))
end

end


function Base.convert(::Type{PQ}, p::P) where {PQ <: AbstractRationalFunction, P<:AbstractPolynomial}
T′ = _eltype(_eltype((PQ)))
T = isnothing(T′) ? eltype(p) : T′
Expand All @@ -74,9 +59,6 @@ function Base.convert(::Type{PQ}, p::P) where {PQ <: AbstractRationalFunction, P
rational_function(PQ, 𝐩, one(𝐩))
end




function Base.convert(::Type{P}, pq::PQ) where {P<:AbstractPolynomial, PQ<:AbstractRationalFunction}
p,q = pqs(pq)
isconstant(q) || throw(ArgumentError("Can't convert rational function with non-constant denominator to a polynomial."))
Expand All @@ -97,7 +79,8 @@ function Base.promote_rule(::Type{PQ}, ::Type{PQ′}) where {T,X,P,PQ <: Abstrac
assert_same_variable(X,X′)
PQ_, PQ′_ = constructorof(PQ), constructorof(PQ′)
𝑷𝑸 = PQ_ == PQ′ ? PQ_ : RationalFunction
𝑷 = constructorof(typeof(variable(P)+variable(P′))); 𝑷 = Polynomial
𝑷 = constructorof(typeof(variable(P)+variable(P′)));
#𝑷 = Polynomial
𝑻 = promote_type(T,T′)
𝑷𝑸{𝑻,X,𝑷{𝑻,X}}
end
Expand Down
63 changes: 50 additions & 13 deletions src/rational-functions/rational-function.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,51 @@
struct RationalFunction{T, X, P<:AbstractPolynomial{T,X}} <: AbstractRationalFunction{T,X,P}
num::P
den::P
function RationalFunction(p::P, q::P) where {T,X, P<:AbstractPolynomial{T,X}}
function RationalFunction{T,X,P}(p, q) where {T,X, P<:AbstractPolynomial{T,X}}
new{T,X,P}(p, q)
end
function RationalFunction(p::P, q::T) where {T,X, P<:AbstractPolynomial{T,X}}
new{T,X,P}(p, q*one(P))
end
function RationalFunction(p::T, q::Q) where {T,X, Q<:AbstractPolynomial{T,X}}
new{T,X,Q}(p*one(Q), q)

end

function RationalFunction(p::P, q::P) where {T,X, P<:AbstractPolynomial{T,X}}
RationalFunction{T,X,P}(p, q)
end

RationalFunction(p::AbstractPolynomial{T,X}, q::AbstractPolynomial{S,X}) where {T,S,X} =
RationalFunction(promote(p,q)...)

function RationalFunction(p::P, q::T) where {T,X, P<:AbstractPolynomial{T,X}}
RationalFunction(p, (q * one(p)))
end
function RationalFunction(p::T, q::Q) where {T,X, Q<:AbstractPolynomial{T,X}}
RationalFunction(p * one(q), q)

Check warning on line 67 in src/rational-functions/rational-function.jl

View check run for this annotation

Codecov / codecov/patch

src/rational-functions/rational-function.jl#L66-L67

Added lines #L66 - L67 were not covered by tests
end

function RationalFunction(p::P,q::P) where {T, X, P <: LaurentPolynomial{T,X}}

m,n = firstindex(p), firstindex(q)
p′,q′ = _shift(p, -m), _shift(q, -n)
if m-n ≥ 0
return RationalFunction{T,X,P}(_shift(p′, m-n), q′)
else
return RationalFunction{T,X,P}(p′, _shift(q′, n-m))
end
end

RationalFunction(p,q) = RationalFunction(convert(LaurentPolynomial,p), convert(LaurentPolynomial,q))
function RationalFunction(p::LaurentPolynomial,q::LaurentPolynomial)
𝐩 = convert(RationalFunction, p)
𝐪 = convert(RationalFunction, q)
𝐩 // 𝐪
# RationalFunction(p,q) = RationalFunction(convert(LaurentPolynomial,p), convert(LaurentPolynomial,q))


# special case Laurent
function lowest_terms(pq::PQ; method=:numerical, kwargs...) where {T,X,
P<:LaurentPolynomial{T,X}, #StandardBasisPolynomial{T,X},
PQ<:AbstractRationalFunction{T,X,P}}
p,q = pqs(pq)
p′,q′ = convert(Polynomial, p), convert(Polynomial,q)
u,v,w = uvw(p′,q′; method=method, kwargs...)
v′,w′ = convert(LaurentPolynomial, v), convert(LaurentPolynomial, w)
rational_function(PQ, v′/w′[end], w′/w′[end])
end
RationalFunction(p::LaurentPolynomial,q::Number) = convert(RationalFunction, p) // q
RationalFunction(p::Number,q::LaurentPolynomial) = q // convert(RationalFunction, p)


RationalFunction(p::AbstractPolynomial) = RationalFunction(p,one(p))

Expand All @@ -76,3 +102,14 @@
function Base.:https://(p::AbstractPolynomial,q::AbstractPolynomial)
RationalFunction(p,q)
end


# promotion
function Base.promote(pq::RationalFunction{T,X,P},
rs::RationalFunction{S,X,Q}) where {T,S,X,P<:AbstractPolynomial{T,X},
Q<:AbstractPolynomial{S,X}}
𝑃 = promote_type(P, Q)
p,q = pq
r,s = rs
(convert(𝑃,p) // convert(𝑃,q), convert(𝑃,r) // convert(𝑃,s))
end
21 changes: 18 additions & 3 deletions test/rational-functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ using LinearAlgebra
# constructor
@test p // q isa RationalFunction
@test p // r isa RationalFunction
@test_throws ArgumentError r // s
@test_throws MethodError r // s
@test RationalFunction(p) == p // one(p)

pq = p // t # promotes to type of t
Expand Down Expand Up @@ -76,6 +76,21 @@ using LinearAlgebra
@test numerator(p) == p * variable(p)^2
@test denominator(p) == convert(Polynomial, variable(p)^2)

# issue 566
q = LaurentPolynomial([1], -1)
p = LaurentPolynomial([1], 1)
@test degree(numerator(q // p)) == 0 # q/p = 1/x^2
@test degree(denominator(q // p)) == 2

@test degree(numerator(p // q)) == 2 # p/q = x^2 / 1
@test degree(denominator(p // q)) == 0

@test degree(numerator(q // q^2)) == 1
@test degree(denominator(q // q^2)) == 0

@test degree(numerator(q^2 // q)) == 0
@test degree(denominator(q^2 // q)) == 1

end

@testset "zeros, poles, residues" begin
Expand Down Expand Up @@ -112,7 +127,7 @@ end
p, q = Polynomial([1,2], :x), Polynomial([1,2],:y)
pp = p // (p-1)
PP = typeof(pp)

PP′ = RationalFunction{Int64, :x, LaurentPolynomial{Int64, :x}}
r, s = SparsePolynomial([1,2], :x), SparsePolynomial([1,2],:y)
rr = r // (r-1)

Expand All @@ -124,7 +139,7 @@ end
# @test eltype(eltype(eltype([im, p, pp]))) == Complex{Int}

## test mixed types promote polynomial type
@test eltype([pp rr p r]) == PP
@test eltype([pp rr p r]) == PP′ # promotes to LaurentPolynomial

## test non-constant polys of different symbols throw error
@test_throws ArgumentError [pp, q]
Expand Down
Loading