Skip to content

Commit a654b37

Browse files
committed
invperm: 0-allocation version of Base.invperm
1 parent d67c199 commit a654b37

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed

src/util.jl

+12-6
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,16 @@ TrivialView(a::AbstractArray{T,N}) where {T,N} = TrivialView{typeof(a),T,N}(a)
7474
@inline drop_sdims(a::StaticArrayLike) = TrivialView(a)
7575
@inline drop_sdims(a) = a
7676

77-
Base.@propagate_inbounds function invperm(p::StaticVector)
78-
# in difference to base, this does not check if p is a permutation (every value unique)
79-
ip = similar(p)
80-
ip[p] = 1:length(p)
81-
similar_type(p)(ip)
82-
end
77+
import Base: invperm
8378

79+
# 0-allocation version of Base.invperm
80+
@inline function invperm(p::StaticVector{N,T})::SVector{N,T} where {N,T<:Integer}
81+
r = MVector{N,T}(undef)
82+
r .= 0
83+
@inbounds for i in 1:N
84+
j = p[i]
85+
0 < j <= N && iszero(r[j]) || throw(ArgumentError("p is not a permuation"))
86+
r[j] = i
87+
end
88+
SVector(r)
89+
end

test/qr.jl

+24
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,30 @@ end
146146
@test_throws Union{BoundsError,ArgumentError} invperm(x)
147147
end
148148

149+
@testset "0 allocations" begin
150+
(function()
151+
x = @MVector zeros(5)
152+
X = @MMatrix zeros(5,5)
153+
154+
@allocated sum(invperm(F.p))
155+
@test 0 == @allocated sum(invperm(F.p))
156+
@allocated sum(A * y)
157+
@test 0 == @allocated sum(A * y)
158+
@allocated sum(F \ y)
159+
@test 0 == @allocated sum(F \ y)
160+
@allocated sum(ldiv!(x, F, y))
161+
@test 0 == @allocated sum(ldiv!(x, F, y))
162+
163+
# "SMAtrix * SMatrix" causes allocations, so these all allocate > 0
164+
# @allocated sum(A' * Y)
165+
#a_mult = @allocated sum(A' * Y)
166+
# @allocated sum(F \ Y)
167+
#@test a_mult < @allocated sum(F \ Y) < 2a_mult
168+
# @allocated sum(ldiv!(X, F, Y))
169+
#@test a_mult+32 == @allocated sum(ldiv!(X, F, Y))
170+
end)()
171+
end
172+
149173
@testset "10x faster" begin
150174
time_to_test = @elapsed (function()
151175
y2 = @SVector rand(50)

0 commit comments

Comments
 (0)