Skip to content

Commit 5574b86

Browse files
jverzanijishnub
andauthored
Jishnub sparseneg int der (#413)
* negative exponents in SparsePolynomials * fix conversions to polynomial types * fix conversions * version bump to v3.1.2 * test conversions * test minimumexponent for SparsePolynomial * test show for negative exponents * firstindex instead of minimumexponent in LP * missing tests for PolynomialValues/Keys * fix testset * non-allocating == check * adjust integrate, derivative, setindex! * integrate, derivative fix Co-authored-by: Jishnu Bhattacharya <[email protected]>
1 parent 095c3ba commit 5574b86

File tree

5 files changed

+34
-60
lines changed

5 files changed

+34
-60
lines changed

src/common.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@ Base.firstindex(p::AbstractPolynomial) = 0
622622
Base.lastindex(p::AbstractPolynomial) = length(p) - 1 + firstindex(p)
623623
Base.eachindex(p::AbstractPolynomial) = firstindex(p):lastindex(p)
624624
Base.broadcastable(p::AbstractPolynomial) = Ref(p)
625+
degreerange(p::AbstractPolynomial) = firstindex(p):lastindex(p)
625626

626627
# getindex
627628
function Base.getindex(p::AbstractPolynomial{T}, idx::Int) where {T}

src/polynomials/LaurentPolynomial.jl

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ julia> x^degree(p) * p(x⁻¹) # reverses coefficients
6969
LaurentPolynomial(3.0 + 2.0*x + 1.0*x²)
7070
```
7171
"""
72-
struct LaurentPolynomial{T, X} <: StandardBasisPolynomial{T, X}
72+
struct LaurentPolynomial{T, X} <: LaurentBasisPolynomial{T, X}
7373
coeffs::Vector{T}
7474
m::Base.RefValue{Int}
7575
n::Base.RefValue{Int}
@@ -213,7 +213,7 @@ minimumexponent(::Type{<:LaurentPolynomial}) = typemin(Int)
213213
minimumexponent(p::LaurentPolynomial) = p.m[]
214214
Base.firstindex(p::LaurentPolynomial) = minimumexponent(p)
215215
degree(p::LaurentPolynomial) = p.n[]
216-
degreerange(p::LaurentPolynomial) = firstindex(p):lastindex(p)
216+
217217

218218
_convert(p::P, as) where {T,X,P <: LaurentPolynomial{T,X}} = (P)(as, firstindex(p), Var(X))
219219

@@ -512,12 +512,13 @@ function derivative(p::P, order::Integer = 1) where {T, X, P<:LaurentPolynomial{
512512
n = n - order
513513
as = zeros(T, length(m:n))
514514

515-
for k in eachindex(p)
515+
for (k, pₖ) in pairs(p)
516+
iszero(pₖ) && continue
516517
idx = 1 + k - order - m
517518
if 0 k order - 1
518519
as[idx] = zero(T)
519520
else
520-
as[idx] = reduce(*, (k - order + 1):k, init = p[k])
521+
as[idx] = reduce(*, (k - order + 1):k, init = pₖ)
521522
end
522523
end
523524

@@ -526,38 +527,6 @@ function derivative(p::P, order::Integer = 1) where {T, X, P<:LaurentPolynomial{
526527
end
527528

528529

529-
function integrate(p::P) where {T, X, P<: LaurentPolynomial{T, X}}
530-
531-
!iszero(p[-1]) && throw(ArgumentError("Can't integrate Laurent polynomial with `x⁻¹` term"))
532-
R = eltype(one(T)/1)
533-
Q = (P){R, X}
534-
535-
if hasnan(p)
536-
return Q([NaN],0)
537-
end
538-
539-
540-
m,n = (extrema degreerange)(p)
541-
if n < 0
542-
n = 0
543-
else
544-
n += 1
545-
end
546-
if m < 0
547-
m += 1
548-
else
549-
m = 0
550-
end
551-
as = zeros(R, length(m:n))
552-
553-
for k in eachindex(p)
554-
as[1 + k+1-m] = p[k]/(k+1)
555-
end
556-
557-
return Q(as, m)
558-
559-
end
560-
561530
function Base.gcd(p::LaurentPolynomial{T,X}, q::LaurentPolynomial{T,Y}, args...; kwargs...) where {T,X,Y}
562531
mp, Mp = (extrema degreerange)(p)
563532
mq, Mq = (extrema degreerange)(q)

src/polynomials/SparsePolynomial.jl

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ julia> p(1)
3838
```
3939
4040
"""
41-
struct SparsePolynomial{T, X} <: StandardBasisPolynomial{T, X}
41+
struct SparsePolynomial{T, X} <: LaurentBasisPolynomial{T, X}
4242
coeffs::Dict{Int, T}
4343
function SparsePolynomial{T, X}(coeffs::AbstractDict{Int, S}) where {T, X, S}
4444
c = Dict{Int, T}(coeffs)
@@ -112,7 +112,6 @@ function Base.getindex(p::SparsePolynomial{T}, idx::Int) where {T}
112112
end
113113

114114
function Base.setindex!(p::SparsePolynomial, value::Number, idx::Int)
115-
idx < 0 && return p
116115
if iszero(value)
117116
haskey(p.coeffs, idx) && pop!(p.coeffs, idx)
118117
else
@@ -241,32 +240,12 @@ function derivative(p::SparsePolynomial{T,X}, order::Integer = 1) where {T,X}
241240
hasnan(p) && return P{R,X}(Dict(0 => R(NaN)))
242241

243242
n = degree(p)
244-
order > n && return zero(P{R,X})
245243

246244
dpn = zero(P{R,X})
247-
@inbounds for k in eachindex(p)
248-
dpn[k-order] = reduce(*, (k - order + 1):k, init = p[k])
245+
@inbounds for (k,v) in pairs(p)
246+
dpn[k-order] = reduce(*, (k - order + 1):k, init = v)
249247
end
250248

251249
return dpn
252250

253251
end
254-
255-
256-
function integrate(p::P) where {T, X, P<:SparsePolynomial{T,X}}
257-
258-
R = eltype(one(T)/1)
259-
Q = SparsePolynomial{R,X}
260-
261-
if hasnan(p)
262-
return Q(Dict(0 => NaN))
263-
end
264-
265-
∫p = zero(Q)
266-
for k in eachindex(p)
267-
∫p[k + 1] = p[k] / (k+1)
268-
end
269-
270-
return ∫p
271-
272-
end

src/polynomials/standard-basis.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
abstract type StandardBasisPolynomial{T,X} <: AbstractPolynomial{T,X} end
2+
abstract type LaurentBasisPolynomial{T,X} <: StandardBasisPolynomial{T,X} end
23

34
function showterm(io::IO, ::Type{<:StandardBasisPolynomial}, pj::T, var, j, first::Bool, mimetype) where {T}
45

@@ -199,6 +200,22 @@ function integrate(p::P) where {T, X, P <: StandardBasisPolynomial{T, X}}
199200
return Q(as)
200201
end
201202

203+
function integrate(p::P) where {T, X, P <: LaurentBasisPolynomial{T, X}}
204+
R = typeof(constantterm(p)/1)
205+
Q = (P){R,X}
206+
207+
hasnan(p) && return Q([NaN])
208+
iszero(p) && return zero(Q)
209+
210+
∫p = zero(Q)
211+
for (k, pₖ) pairs(p)
212+
iszero(pₖ) && continue
213+
k == -1 && throw(ArgumentError("Can't integrate Laurent polynomial with `x⁻¹` term"))
214+
∫p[k+1] = pₖ/(k+1)
215+
end
216+
∫p
217+
end
218+
202219
function Base.divrem(num::P, den::Q) where {T, P <: StandardBasisPolynomial{T}, S, Q <: StandardBasisPolynomial{S}}
203220

204221
assert_same_variable(num, den)

test/StandardBasis.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,14 @@ end
933933
# Issue with overflow and polyder Issue #159
934934
@test derivative(P(BigInt[0, 1])^100, 100) == P(factorial(big(100)))
935935
end
936+
937+
# Sparse and Laurent test issue #409
938+
pₛ, pₗ = SparsePolynomial(Dict(-1=>1, 1=>1)), LaurentPolynomial([1,0,1], -1)
939+
@test pₛ == pₗ && derivative(pₛ) == derivative(pₗ)
940+
@test_throws ArgumentError integrate(pₛ)
941+
@test_throws ArgumentError integrate(pₗ)
942+
qₛ, qₗ = SparsePolynomial(Dict(-2=>1, 1=>1)), LaurentPolynomial([1,0,0,1], -2)
943+
@test qₛ == qₗ && integrate(qₛ) == integrate(qₗ)
936944
end
937945

938946
@testset "Elementwise Operations" begin

0 commit comments

Comments
 (0)