Skip to content

Commit 87f02db

Browse files
authored
Issue 566a (#570)
* laurent and rational type issue * use Laurent for promotion
1 parent 263b965 commit 87f02db

File tree

6 files changed

+80
-37
lines changed

6 files changed

+80
-37
lines changed

src/polynomial-container-types/mutable-dense-laurent-polynomial.jl

+4
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@ function offset_vector_combine(op, p::MutableDenseLaurentPolynomial{B,T,X}, q::M
204204

205205
end
206206

207+
# multiply by xⁿ
208+
_shift(p::P, n::Int) where {P <: MutableDenseLaurentPolynomial} =
209+
P(Val(false), p.coeffs, firstindex(p) + n)
210+
207211
function Base.numerator(q::MutableDenseLaurentPolynomial{B,T,X}) where {B,T,X}
208212
p = chop(q)
209213
o = firstindex(p)

src/polynomials/standard-basis/laurent-polynomial.jl

+4
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ function evalpoly(c, p::LaurentPolynomial{T,X}) where {T,X}
9999
EvalPoly.evalpoly(c, p.coeffs) * c^p.order[]
100100
end
101101

102+
# ---
103+
104+
105+
102106
# scalar add
103107
function scalar_add(c::S, p::LaurentPolynomial{T,X}) where {S, T, X}
104108
R = promote_type(T,S)

src/promotions.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ Base.promote_rule(::Type{P}, ::Type{Q}) where {B,T,S,X,
1515
Q<:AbstractLaurentUnivariatePolynomial{B,S,X}} = MutableDenseLaurentPolynomial{B,promote_type(T,S),X}
1616

1717

18-
1918
# Methods to ensure that matrices of polynomials behave as desired
2019
Base.promote_rule(::Type{P},::Type{Q}) where {T,X, P<:AbstractPolynomial{T,X},
2120
S, Q<:AbstractPolynomial{S,X}} =
22-
Polynomial{promote_type(T, S),X}
21+
LaurentPolynomial{promote_type(T, S),X}
22+
2323

2424
Base.promote_rule(::Type{P},::Type{Q}) where {T,X, P<:AbstractPolynomial{T,X},
2525
S,Y, Q<:AbstractPolynomial{S,Y}} =

src/rational-functions/common.jl

+2-19
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,6 @@ function Base.convert(::Type{PQ}, p::Number) where {PQ <: AbstractRationalFuncti
4949
rational_function(PQ, p * one(P), one(P))
5050
end
5151

52-
function Base.convert(::Type{PQ}, q::LaurentPolynomial) where {PQ <: AbstractRationalFunction}
53-
m = firstindex(q)
54-
if m >= 0
55-
p = convert(Polynomial, q)
56-
return convert(PQ, p)
57-
else
58-
z = variable(q)
59-
zᵐ = z^(-m)
60-
p = convert(Polynomial, zᵐ * q)
61-
return rational_function(PQ, p, convert(Polynomial, zᵐ))
62-
end
63-
64-
end
65-
66-
6752
function Base.convert(::Type{PQ}, p::P) where {PQ <: AbstractRationalFunction, P<:AbstractPolynomial}
6853
T′ = _eltype(_eltype((PQ)))
6954
T = isnothing(T′) ? eltype(p) : T′
@@ -74,9 +59,6 @@ function Base.convert(::Type{PQ}, p::P) where {PQ <: AbstractRationalFunction, P
7459
rational_function(PQ, 𝐩, one(𝐩))
7560
end
7661

77-
78-
79-
8062
function Base.convert(::Type{P}, pq::PQ) where {P<:AbstractPolynomial, PQ<:AbstractRationalFunction}
8163
p,q = pqs(pq)
8264
isconstant(q) || throw(ArgumentError("Can't convert rational function with non-constant denominator to a polynomial."))
@@ -97,7 +79,8 @@ function Base.promote_rule(::Type{PQ}, ::Type{PQ′}) where {T,X,P,PQ <: Abstrac
9779
assert_same_variable(X,X′)
9880
PQ_, PQ′_ = constructorof(PQ), constructorof(PQ′)
9981
𝑷𝑸 = PQ_ == PQ′ ? PQ_ : RationalFunction
100-
𝑷 = constructorof(typeof(variable(P)+variable(P′))); 𝑷 = Polynomial
82+
𝑷 = constructorof(typeof(variable(P)+variable(P′)));
83+
#𝑷 = Polynomial
10184
𝑻 = promote_type(T,T′)
10285
𝑷𝑸{𝑻,X,𝑷{𝑻,X}}
10386
end

src/rational-functions/rational-function.jl

+50-13
Original file line numberDiff line numberDiff line change
@@ -47,25 +47,51 @@ julia> derivative(pq)
4747
struct RationalFunction{T, X, P<:AbstractPolynomial{T,X}} <: AbstractRationalFunction{T,X,P}
4848
num::P
4949
den::P
50-
function RationalFunction(p::P, q::P) where {T,X, P<:AbstractPolynomial{T,X}}
50+
function RationalFunction{T,X,P}(p, q) where {T,X, P<:AbstractPolynomial{T,X}}
5151
new{T,X,P}(p, q)
5252
end
53-
function RationalFunction(p::P, q::T) where {T,X, P<:AbstractPolynomial{T,X}}
54-
new{T,X,P}(p, q*one(P))
55-
end
56-
function RationalFunction(p::T, q::Q) where {T,X, Q<:AbstractPolynomial{T,X}}
57-
new{T,X,Q}(p*one(Q), q)
53+
54+
end
55+
56+
function RationalFunction(p::P, q::P) where {T,X, P<:AbstractPolynomial{T,X}}
57+
RationalFunction{T,X,P}(p, q)
58+
end
59+
60+
RationalFunction(p::AbstractPolynomial{T,X}, q::AbstractPolynomial{S,X}) where {T,S,X} =
61+
RationalFunction(promote(p,q)...)
62+
63+
function RationalFunction(p::P, q::T) where {T,X, P<:AbstractPolynomial{T,X}}
64+
RationalFunction(p, (q * one(p)))
65+
end
66+
function RationalFunction(p::T, q::Q) where {T,X, Q<:AbstractPolynomial{T,X}}
67+
RationalFunction(p * one(q), q)
68+
end
69+
70+
function RationalFunction(p::P,q::P) where {T, X, P <: LaurentPolynomial{T,X}}
71+
72+
m,n = firstindex(p), firstindex(q)
73+
p′,q′ = _shift(p, -m), _shift(q, -n)
74+
if m-n 0
75+
return RationalFunction{T,X,P}(_shift(p′, m-n), q′)
76+
else
77+
return RationalFunction{T,X,P}(p′, _shift(q′, n-m))
5878
end
5979
end
6080

61-
RationalFunction(p,q) = RationalFunction(convert(LaurentPolynomial,p), convert(LaurentPolynomial,q))
62-
function RationalFunction(p::LaurentPolynomial,q::LaurentPolynomial)
63-
𝐩 = convert(RationalFunction, p)
64-
𝐪 = convert(RationalFunction, q)
65-
𝐩 // 𝐪
81+
# RationalFunction(p,q) = RationalFunction(convert(LaurentPolynomial,p), convert(LaurentPolynomial,q))
82+
83+
84+
# special case Laurent
85+
function lowest_terms(pq::PQ; method=:numerical, kwargs...) where {T,X,
86+
P<:LaurentPolynomial{T,X}, #StandardBasisPolynomial{T,X},
87+
PQ<:AbstractRationalFunction{T,X,P}}
88+
p,q = pqs(pq)
89+
p′,q′ = convert(Polynomial, p), convert(Polynomial,q)
90+
u,v,w = uvw(p′,q′; method=method, kwargs...)
91+
v′,w′ = convert(LaurentPolynomial, v), convert(LaurentPolynomial, w)
92+
rational_function(PQ, v′/w′[end], w′/w′[end])
6693
end
67-
RationalFunction(p::LaurentPolynomial,q::Number) = convert(RationalFunction, p) // q
68-
RationalFunction(p::Number,q::LaurentPolynomial) = q // convert(RationalFunction, p)
94+
6995

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

@@ -76,3 +102,14 @@ RationalFunction(p::AbstractPolynomial) = RationalFunction(p,one(p))
76102
function Base.://(p::AbstractPolynomial,q::AbstractPolynomial)
77103
RationalFunction(p,q)
78104
end
105+
106+
107+
# promotion
108+
function Base.promote(pq::RationalFunction{T,X,P},
109+
rs::RationalFunction{S,X,Q}) where {T,S,X,P<:AbstractPolynomial{T,X},
110+
Q<:AbstractPolynomial{S,X}}
111+
𝑃 = promote_type(P, Q)
112+
p,q = pq
113+
r,s = rs
114+
(convert(𝑃,p) // convert(𝑃,q), convert(𝑃,r) // convert(𝑃,s))
115+
end

test/rational-functions.jl

+18-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ using LinearAlgebra
1111
# constructor
1212
@test p // q isa RationalFunction
1313
@test p // r isa RationalFunction
14-
@test_throws ArgumentError r // s
14+
@test_throws MethodError r // s
1515
@test RationalFunction(p) == p // one(p)
1616

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

79+
# issue 566
80+
q = LaurentPolynomial([1], -1)
81+
p = LaurentPolynomial([1], 1)
82+
@test degree(numerator(q // p)) == 0 # q/p = 1/x^2
83+
@test degree(denominator(q // p)) == 2
84+
85+
@test degree(numerator(p // q)) == 2 # p/q = x^2 / 1
86+
@test degree(denominator(p // q)) == 0
87+
88+
@test degree(numerator(q // q^2)) == 1
89+
@test degree(denominator(q // q^2)) == 0
90+
91+
@test degree(numerator(q^2 // q)) == 0
92+
@test degree(denominator(q^2 // q)) == 1
93+
7994
end
8095

8196
@testset "zeros, poles, residues" begin
@@ -112,7 +127,7 @@ end
112127
p, q = Polynomial([1,2], :x), Polynomial([1,2],:y)
113128
pp = p // (p-1)
114129
PP = typeof(pp)
115-
130+
PP′ = RationalFunction{Int64, :x, LaurentPolynomial{Int64, :x}}
116131
r, s = SparsePolynomial([1,2], :x), SparsePolynomial([1,2],:y)
117132
rr = r // (r-1)
118133

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

126141
## test mixed types promote polynomial type
127-
@test eltype([pp rr p r]) == PP
142+
@test eltype([pp rr p r]) == PP# promotes to LaurentPolynomial
128143

129144
## test non-constant polys of different symbols throw error
130145
@test_throws ArgumentError [pp, q]

0 commit comments

Comments
 (0)