Skip to content

norm of nested StaticArrays throws #915

Closed
@thchr

Description

@thchr

The implementation of norm(a::StaticArray) assumes that the elements of a have an abs2 implementation, i.e. that they are scalars. Unfortunately, that means that if a's elements are also e.g. SVector, it will throw:

julia> a = SVector{2}(SVector{2}(0.0, 0.0), SVector{2}(1.0, 1.0))
2-element SVector{2, SVector{2, Float64}} with indices SOneTo(2):
 [0.0, 0.0]
 [1.0, 1.0]

julia> norm(a)
ERROR: MethodError: no method matching abs2(::SVector{2, Float64})
Closest candidates are:
  abs2(::Bool) at bool.jl:80
  abs2(::Real) at number.jl:151
  abs2(::Complex) at complex.jl:265
  ...
Stacktrace:
 [1] macro expansion
   @ ~/.julia/packages/StaticArrays/rKBnO/src/linalg.jl:225 [inlined]
 [2] _norm
   @ ~/.julia/packages/StaticArrays/rKBnO/src/linalg.jl:213 [inlined]
 [3] norm(a::SVector{2, SVector{2, Float64}})
   @ StaticArrays ~/.julia/packages/StaticArrays/rKBnO/src/linalg.jl:212
  ...

One of the unhappy consequences of this is that things like isapprox breaks for nested StaticArrays.

The norm implementation is here:

@inline norm(a::StaticArray) = _norm(Size(a), a)
@generated function _norm(::Size{S}, a::StaticArray) where {S}
if prod(S) == 0
return :(zero(real(eltype(a))))
end
expr = :(abs2(a[1]))
for j = 2:prod(S)
expr = :($expr + abs2(a[$j]))
end
return quote
$(Expr(:meta, :inline))
@inbounds return sqrt($expr)
end
end

AFAICT LinearAlgebra is avoiding this by calling out to an internal function norm_sqr instead of abs2, which is just abs2 for scalar input, but recursively calls norm otherwise. There's actually a norm_sqr function in StaticArrays too, but it seems unused?

If the suggested fix seems acceptable, I can make a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions