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

Avoid some allocations in mutating methods #347

Merged
merged 23 commits into from
Feb 24, 2024
Merged
Show file tree
Hide file tree
Changes from 14 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
12 changes: 6 additions & 6 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[weakdeps]
IntervalArithmetic = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253"

[extensions]
TaylorSeriesIAExt = "IntervalArithmetic"

[compat]
Aqua = "0.8"
IntervalArithmetic = "0.15, 0.16, 0.17, 0.18, 0.19, 0.20"
Expand All @@ -19,9 +25,6 @@ SparseArrays = "<0.0.1, 1"
Test = "<0.0.1, 1"
julia = "1"

[extensions]
TaylorSeriesIAExt = "IntervalArithmetic"

[extras]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
IntervalArithmetic = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253"
Expand All @@ -31,6 +34,3 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["IntervalArithmetic", "LinearAlgebra", "SparseArrays", "Test", "Aqua"]

[weakdeps]
IntervalArithmetic = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253"
1 change: 0 additions & 1 deletion src/TaylorSeries.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ see also [`HomogeneousPolynomial`](@ref).
"""
module TaylorSeries


using SparseArrays: SparseMatrixCSC
using Markdown

Expand Down
80 changes: 76 additions & 4 deletions src/arithmetic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ end
function mul!(res::Taylor1{TaylorN{T}}, a::Taylor1{TaylorN{T}}, b::Taylor1{TaylorN{T}},
ordT::Int) where {T<:NumberNotSeries}
# Sanity
zero!(res, a, ordT)
zero!(res, ordT)
for k in 0:ordT
@inbounds for ordQ in eachindex(a[ordT])
mul!(res[ordT], a[k], b[ordT-k], ordQ)
Expand Down Expand Up @@ -665,6 +665,19 @@ function /(a::Taylor1{TaylorN{T}}, b::Taylor1{TaylorN{T}}) where {T<:NumberNotSe
return res
end

function /(a::NumberNotSeries, b::Taylor1{TaylorN{T}}) where {T<:NumberNotSeries}
iszero(a) && !iszero(b) && return zero(a)

# order and coefficient of first factorized term
# In this case, since a[k]=0 for k>0, we can simplify to:
# ordfact, cdivfact = 0, a/b[0]

res = Taylor1(a/b[0], b.order)
for ordT in eachindex(res)
div!(res, a, b, ordT)
end
return res
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose the following here to ensure type stability (this is untested)

function /(a::NumberNotSeries, b::Taylor1{TaylorN{T}}) where {T<:NumberNotSeries}
    R = promote_type(typeof(a), TaylorN{T})
    iszero(a) && !iszero(b) && return convert(Taylor1{R}, zero(b))

    # order and coefficient of first factorized term
    # In this case, since a[k]=0 for k>0, we can simplify to:
    # ordfact, cdivfact = 0, a/b[0]

    res = Taylor1(a/b[0], b.order)
    for ordT in eachindex(res)
        div!(res, a, b, ordT)
    end
    return res
end

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that a::NumberNotSeries is perhaps too strong, because it leaves outside a::TaylorN{T}, which is a method worth having too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion! I added the fix for type-stability and widened the type for a to allow for TaylorN{T}


@inline function divfactorization(a1::Taylor1, b1::Taylor1)
# order of first factorized term; a1 and b1 assumed to be of the same order
Expand Down Expand Up @@ -731,8 +744,25 @@ end
return nothing
end

div!(v::Taylor1, b::NumberNotSeries, a::Taylor1, k::Int) =
div!(v::Taylor1, Taylor1(b, a.order), a, k)
@inline function div!(c::Taylor1, a::NumberNotSeries,
b::Taylor1, k::Int)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we should impose c::Taylor1{T} as well as b::Taylor1{T}...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, although I think we can make an extra tweak to avoid some allocations for T<:TaylorN{<:NumberNotSeries}, so I added an extra method for the latter case (will fix it in the next few commits)

iszero(a) && !iszero(b) && zero!(c, k)
# order and coefficient of first factorized term
# In this case, since a[k]=0 for k>0, we can simplify to:
# ordfact, cdivfact = 0, a/b[0]
if k == 0
@inbounds c[0] = a/b[0]
return nothing
end

imin = max(0, k-b.order)
PerezHz marked this conversation as resolved.
Show resolved Hide resolved
@inbounds c[k] = c[imin] * b[k-imin]
@inbounds for i = imin+1:k-1
c[k] += c[i] * b[k-i]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is related to the TODO above. We do have methods that indeed accumulate as mentioned above for TaylorN. I wonder if replacing this line with those methods can provide further improvements. The suggested code is:

        # c[k] += c[i] * b[k-i] # current code
        for ord in eachindex(c[k])
            mul!(c[k], c[i], b[k-i], ord)
        end

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the suggestion, I'll give it a try and see if we can get rid of some more allocations 😄 !

end
@inbounds c[k] = -c[k]/b[0]
return nothing
end

# NOTE: Here `div!` *accumulates* the result of a / b in c[k] (k > 0)
@inline function div!(c::TaylorN, a::TaylorN, b::TaylorN, k::Int)
Expand All @@ -758,7 +788,7 @@ end
@inbounds res[0] = cdivfact
return nothing
end
zero!(res, a, ordT)
zero!(res, ordT)
imin = max(0, ordT+ordfact-b.order)
aux = TaylorN(zero(a[ordT][0][1]), a[ordT].order)
for k in imin:ordT-1
Expand All @@ -783,6 +813,48 @@ end
return nothing
end

@inline function mul!(res::Taylor1{TaylorN{T}}, a::NumberNotSeries,
b::Taylor1{TaylorN{T}}, k::Int) where {T<:NumberNotSeries}
for l in eachindex(b[k])
for m in eachindex(b[k][l])
res[k][l][m] = a*b[k][l][m]
end
end
return nothing
end

mul!(res::Taylor1{TaylorN{T}}, a::Taylor1{TaylorN{T}},
b::NumberNotSeries, k::Int) where {T<:NumberNotSeries} = mul!(res, b, a, k)

@inline function div!(res::Taylor1{TaylorN{T}}, a::Taylor1{TaylorN{T}},
b::NumberNotSeries, k::Int) where {T<:NumberNotSeries}
for l in eachindex(a[k])
for m in eachindex(a[k][l])
res[k][l][m] = a[k][l][m]/b
end
end
return nothing
end

# ### TODO: use non-allocating div!(::TaylorN,::TaylorN,::TaylorN)
# @inline function div!(c::Taylor1{TaylorN{T}}, a::NumberNotSeries,
# b::Taylor1{TaylorN{T}}, k::Int) where {T<:NumberNotSeries}
# # order and coefficient of first factorized term
# # In this case, since a[k]=0 for k>0, we can simplify to:
# # ordfact, cdivfact = 0, a/b[0]
# if k == 0
# @inbounds c[0] = a/b[0]
# return nothing
# end

# imin = max(0, k-b.order)
# @inbounds c[k] = c[imin] * b[k-imin]
# @inbounds for i = imin+1:k-1
# c[k] += c[i] * b[k-i]
# end
# @inbounds c[k] = -c[k]/b[0]
# return nothing
# end



Expand Down
Loading
Loading