Skip to content

Commit 1d5524c

Browse files
authored
Fixes to norm and friends (closes #915) (#929)
* various fixes to `norm` & more tests * fix test failure; widen signatures * restrict type-stability tests to v1.2+ * fixes/improvements from code-review * address remaining issue for `_inner_eltype` of empty arrays * use `_inner_eltype(x)` for `_norm_p0` and adjust signature to `AbstractArray` - also fix copying errors from last commit * bump patch version
1 parent 920ff58 commit 1d5524c

File tree

3 files changed

+72
-12
lines changed

3 files changed

+72
-12
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "StaticArrays"
22
uuid = "90137ffa-7385-5640-81b9-e52037218182"
3-
version = "1.2.7"
3+
version = "1.2.8"
44

55
[deps]
66
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

src/linalg.jl

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -208,17 +208,23 @@ end
208208

209209
#--------------------------------------------------
210210
# Norms
211-
@inline LinearAlgebra.norm_sqr(v::StaticVector) = mapreduce(abs2, +, v; init=zero(real(eltype(v))))
211+
_inner_eltype(v::AbstractArray) = isempty(v) ? eltype(v) : _inner_eltype(first(v))
212+
_inner_eltype(x::Number) = typeof(x)
213+
@inline _init_zero(v::StaticArray) = float(norm(zero(_inner_eltype(v))))
214+
215+
@inline function LinearAlgebra.norm_sqr(v::StaticArray)
216+
return mapreduce(LinearAlgebra.norm_sqr, +, v; init=_init_zero(v))
217+
end
212218

213219
@inline norm(a::StaticArray) = _norm(Size(a), a)
214220
@generated function _norm(::Size{S}, a::StaticArray) where {S}
215221
if prod(S) == 0
216-
return :(zero(real(eltype(a))))
222+
return :(_init_zero(a))
217223
end
218224

219-
expr = :(abs2(a[1]))
225+
expr = :(LinearAlgebra.norm_sqr(a[1]))
220226
for j = 2:prod(S)
221-
expr = :($expr + abs2(a[$j]))
227+
expr = :($expr + LinearAlgebra.norm_sqr(a[$j]))
222228
end
223229

224230
return quote
@@ -227,28 +233,31 @@ end
227233
end
228234
end
229235

230-
_norm_p0(x) = x == 0 ? zero(x) : one(x)
236+
function _norm_p0(x)
237+
T = _inner_eltype(x)
238+
return float(norm(iszero(x) ? zero(T) : one(T)))
239+
end
231240

232241
@inline norm(a::StaticArray, p::Real) = _norm(Size(a), a, p)
233242
@generated function _norm(::Size{S}, a::StaticArray, p::Real) where {S}
234243
if prod(S) == 0
235-
return :(zero(real(eltype(a))))
244+
return :(_init_zero(a))
236245
end
237246

238-
expr = :(abs(a[1])^p)
247+
expr = :(norm(a[1])^p)
239248
for j = 2:prod(S)
240-
expr = :($expr + abs(a[$j])^p)
249+
expr = :($expr + norm(a[$j])^p)
241250
end
242251

243-
expr_p1 = :(abs(a[1]))
252+
expr_p1 = :(norm(a[1]))
244253
for j = 2:prod(S)
245-
expr_p1 = :($expr_p1 + abs(a[$j]))
254+
expr_p1 = :($expr_p1 + norm(a[$j]))
246255
end
247256

248257
return quote
249258
$(Expr(:meta, :inline))
250259
if p == Inf
251-
return mapreduce(abs, max, a)
260+
return mapreduce(norm, max, a)
252261
elseif p == 1
253262
@inbounds return $expr_p1
254263
elseif p == 2

test/linalg.jl

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,57 @@ StaticArrays.similar_type(::Union{RotMat2,Type{RotMat2}}) = SMatrix{2,2,Float64,
202202
@test normalize(SVector(1,2,3), 1) normalize([1,2,3], 1)
203203
@test normalize!(MVector(1.,2.,3.)) normalize([1.,2.,3.])
204204
@test normalize!(MVector(1.,2.,3.), 1) normalize([1.,2.,3.], 1)
205+
206+
# nested vectors
207+
a = SA[SA[1, 2], SA[3, 4]]
208+
av = convert(Vector{Vector{Int}}, a)
209+
aa = SA[a,a]
210+
@test norm(a) norm(av)
211+
@test norm(aa) norm([a,a])
212+
@test norm(aa) norm([av,av])
213+
@test norm(SVector{0,Int}()) === norm(Vector{Float64}()) === 0.0
214+
215+
# do not overflow for Int
216+
c = SA[typemax(Int)÷2, typemax(Int)÷3]
217+
@test norm(c) norm(Vector(c))
218+
@test norm(SA[c,c]) norm([Vector(c), Vector(c)])
219+
220+
# 0-norm of vectors w/ zero-vectors
221+
@test norm(SA[0,0], 0) == norm([0,0], 0)
222+
@test norm(SA[[0,0],[1,1]], 0) == norm([[0,0],[1,1]], 0) == 1.0
223+
@test norm(SA[[0,1],[1,1]], 0) == norm([[0,1],[1,1]], 0) == 2.0
224+
225+
# complex numbers
226+
@test norm(SA[1+im, 2+3im]) norm([1+im, 2+3im])
227+
@test norm(SA[22.0+0.1im, 2.0-23.0im]) norm([22.0+0.1im, 2.0-23.0im])
228+
a_c, av_c = a+1im*a, av+1im*av
229+
@test norm(a_c) norm(av_c)
230+
231+
# p-norms for nested vectors
232+
for (x,xv) in ((a,av), (a_c, av_c))
233+
@test norm(x, 2) norm(xv,2)
234+
@test norm(x, Inf) norm(xv, Inf)
235+
@test norm(x, 1) norm(xv, 1)
236+
@test norm(x, 0) norm(xv, 0)
237+
@test norm(SA[Int[], [1,2]], 0) norm([Int[], [1,2]], 0)
238+
end
239+
240+
# type-stability
241+
if VERSION v"1.2"
242+
# only test strict type-stability on v1.2+, since there were Base-related type
243+
# instabilities in `norm` prior to https://github.com/JuliaLang/julia/pull/30481
244+
@test (@inferred norm(a[1])) == (@inferred norm(a[1], 2))
245+
@test (@inferred norm(a)) == (@inferred norm(a, 2))
246+
@test (@inferred norm(aa)) == (@inferred norm(aa, 2))
247+
@test (@inferred norm(float.(aa))) == (@inferred norm(float.(aa), 2))
248+
@test (@inferred norm(SVector{0,Int}())) == (@inferred norm(SVector{0,Int}(), 2))
249+
end
250+
251+
# norm of empty SVector
252+
@test norm(SVector{0,Int}()) isa float(Int)
253+
@test norm(SVector{0,Float64}()) isa Float64
254+
@test norm(SA[SVector{0,Int}(),SVector{0,Int}()]) isa float(Int)
255+
@test norm(SA[SVector{0,Int}(),SVector{0,Int}()]) == norm([Int[], Int[]])
205256
end
206257

207258
@testset "trace" begin

0 commit comments

Comments
 (0)