-
Notifications
You must be signed in to change notification settings - Fork 149
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
norm of StaticArray inaccurate #913
Comments
OK, so looking at For smaller Also it would be helpful if you posted an example vector with the two results in the OP. |
I added a simple example to the OP where the static version fails |
Oh that one. We could just port the “unhappy path” from What do other users think? This will introduce a calculation of the maximum value, a branch, divisions, etc. It might be a significant slowdown and we’ve previously made different choices of speed vs accuracy to Base. I’m not sure this issue is so relevant for computer graphics or geography/geodesy or robotics or other fields I’m aware of this package being quite useful. If someone wants to run some benchmarks (I’d recommend finding the norms of a Vector of SVectors) that would inform the discussion. |
The issue occured in a robotics context, where the vector was used to represent rotations. Using differentiating a function with this calculation with ForwardDiff produced NaNs due to RigidBodyDynamics.jl have a very similar implementation of |
This PR is mostly a FYI regarding JuliaArrays/StaticArrays.jl#913 Depending on whether or not that issue is closed, you may want to switch to explicitly calling `generic_norm2` on static vectors to circumvent the accuracy issue. The issue arises when combining static arrays with ForwardDiff, in our case it occured in `exp(::SkewSymmetric)`. I did some benchmarking, and `generic_norm2` is faster than `norm` for all standard arrays up to at least length 9. For static arrays, it appears to do okay as well, while avoiding the accuracy issue. ```julia julia> a 3-element SVector{3, Int64} with indices SOneTo(3): 1 2 3 julia> @Btime norm($(Ref(a))[]) # standard norm of static array 5.135 ns (0 allocations: 0 bytes) 3.74166 julia> @Btime norm($(Ref(Vector(a)))[]) # standard norm of array 8.545 ns (0 allocations: 0 bytes) 3.74166 julia> @Btime LinearAlgebra.generic_norm2($(Ref((a)))[]) # generic_norm2 of static array 4.490 ns (0 allocations: 0 bytes) 3.74166 julia> @Btime LinearAlgebra.generic_norm2($(Ref(Vector(a)))[]) # generic_norm2 of array 7.671 ns (0 allocations: 0 bytes) 3.74166 ```
I see, you represent the rotation in the Lie algebra (not the group a la Rotations.jl) and thus it can be small. (Also worth noting that for this test the 1-norm or infinite-norm would also suffice). |
I recently opened two issues, JuliaDiff/ForwardDiff.jl#547 and #963, which I think are related to this. |
This PR is mostly a FYI regarding JuliaArrays/StaticArrays.jl#913 Depending on whether or not that issue is closed, you may want to switch to explicitly calling `generic_norm2` on static vectors to circumvent the accuracy issue. The issue arises when combining static arrays with ForwardDiff, in our case it occured in `exp(::SkewSymmetric)`. I did some benchmarking, and `generic_norm2` is faster than `norm` for all standard arrays up to at least length 9. For static arrays, it appears to do okay as well, while avoiding the accuracy issue. ```julia julia> a 3-element SVector{3, Int64} with indices SOneTo(3): 1 2 3 julia> @Btime norm($(Ref(a))[]) # standard norm of static array 5.135 ns (0 allocations: 0 bytes) 3.74166 julia> @Btime norm($(Ref(Vector(a)))[]) # standard norm of array 8.545 ns (0 allocations: 0 bytes) 3.74166 julia> @Btime LinearAlgebra.generic_norm2($(Ref((a)))[]) # generic_norm2 of static array 4.490 ns (0 allocations: 0 bytes) 3.74166 julia> @Btime LinearAlgebra.generic_norm2($(Ref(Vector(a)))[]) # generic_norm2 of array 7.671 ns (0 allocations: 0 bytes) 3.74166 ```
This PR is mostly a FYI regarding JuliaArrays/StaticArrays.jl#913 Depending on whether or not that issue is closed, you may want to switch to explicitly calling `generic_norm2` on static vectors to circumvent the accuracy issue. The issue arises when combining static arrays with ForwardDiff, in our case it occured in `exp(::SkewSymmetric)`. I did some benchmarking, and `generic_norm2` is faster than `norm` for all standard arrays up to at least length 9. For static arrays, it appears to do okay as well, while avoiding the accuracy issue. ```julia julia> a 3-element SVector{3, Int64} with indices SOneTo(3): 1 2 3 julia> @Btime norm($(Ref(a))[]) # standard norm of static array 5.135 ns (0 allocations: 0 bytes) 3.74166 julia> @Btime norm($(Ref(Vector(a)))[]) # standard norm of array 8.545 ns (0 allocations: 0 bytes) 3.74166 julia> @Btime LinearAlgebra.generic_norm2($(Ref((a)))[]) # generic_norm2 of static array 4.490 ns (0 allocations: 0 bytes) 3.74166 julia> @Btime LinearAlgebra.generic_norm2($(Ref(Vector(a)))[]) # generic_norm2 of array 7.671 ns (0 allocations: 0 bytes) 3.74166 ```
This PR is mostly a FYI regarding JuliaArrays/StaticArrays.jl#913 Depending on whether or not that issue is closed, you may want to switch to explicitly calling `generic_norm2` on static vectors to circumvent the accuracy issue. The issue arises when combining static arrays with ForwardDiff, in our case it occured in `exp(::SkewSymmetric)`. I did some benchmarking, and `generic_norm2` is faster than `norm` for all standard arrays up to at least length 9. For static arrays, it appears to do okay as well, while avoiding the accuracy issue. ```julia julia> a 3-element SVector{3, Int64} with indices SOneTo(3): 1 2 3 julia> @Btime norm($(Ref(a))[]) # standard norm of static array 5.135 ns (0 allocations: 0 bytes) 3.74166 julia> @Btime norm($(Ref(Vector(a)))[]) # standard norm of array 8.545 ns (0 allocations: 0 bytes) 3.74166 julia> @Btime LinearAlgebra.generic_norm2($(Ref((a)))[]) # generic_norm2 of static array 4.490 ns (0 allocations: 0 bytes) 3.74166 julia> @Btime LinearAlgebra.generic_norm2($(Ref(Vector(a)))[]) # generic_norm2 of array 7.671 ns (0 allocations: 0 bytes) 3.74166 ```
I have traced a bug in my code to the fact that
norm(::StaticArray)
is considerably less accurate thannorm(::Array)
. In code working with rotations, the norm of a small vector, length 2-4, is often used required to very high precision.To verify that the problem is the naive implementation of norm for static arrays, I modified the norm function like so
after which the problem goes away.
Would it be feasible to have an implementation of norm that is more accurate, at least for small vectors?
MWE:
The text was updated successfully, but these errors were encountered: