From aa59d8fc16e8d07f142621b7818b6c05d072e184 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 23 Oct 2021 23:44:08 +0900 Subject: [PATCH 01/11] add support for eigen values and eigen vectors --- src/Rotations.jl | 1 + src/eigen.jl | 14 ++++++++++++++ test/eigen.jl | 15 +++++++++++++++ test/runtests.jl | 1 + 4 files changed, 31 insertions(+) create mode 100644 src/eigen.jl create mode 100644 test/eigen.jl diff --git a/src/Rotations.jl b/src/Rotations.jl index 8455832c..3d19b373 100644 --- a/src/Rotations.jl +++ b/src/Rotations.jl @@ -22,6 +22,7 @@ include("principal_value.jl") include("rodrigues_params.jl") include("error_maps.jl") include("rotation_error.jl") +include("eigen.jl") include("deprecated.jl") export diff --git a/src/eigen.jl b/src/eigen.jl new file mode 100644 index 00000000..828df82d --- /dev/null +++ b/src/eigen.jl @@ -0,0 +1,14 @@ +function LinearAlgebra.eigvals(R::Rotation{3}) + θ = rotation_angle(R) + return SVector(exp(θ*im), exp(-θ*im), 1) +end + +function LinearAlgebra.eigvecs(R::Rotation{3}) + n3 = normalize(rotation_axis(R)) + n1 = normalize(perpendicular_vector(n3)) + n2 = normalize(n3×n1) + v1 = n1*im + n2 + v2 = n1 + n2*im + v3 = n3 + return hcat(v1,v2,v3) +end diff --git a/test/eigen.jl b/test/eigen.jl new file mode 100644 index 00000000..fafcd2f4 --- /dev/null +++ b/test/eigen.jl @@ -0,0 +1,15 @@ +@testset "Eigen" begin + all_types = (RotMatrix{3}, AngleAxis, RotationVec, + UnitQuaternion, RodriguesParam, MRP, + RotXYZ, RotYZX, RotZXY, RotXZY, RotYXZ, RotZYX, + RotXYX, RotYZY, RotZXZ, RotXZX, RotYXY, RotZYZ, + RotX, RotY, RotZ, + RotXY, RotYZ, RotZX, RotXZ, RotYX, RotZY) + + for type in all_types + R = rand(type) + λs = eigvals(R) + vs = eigvecs(R) + @test R * vs ≈ transpose(λs) .* vs + end +end diff --git a/test/runtests.jl b/test/runtests.jl index 967e52fd..33904e2f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -28,6 +28,7 @@ include("rodrigues_params.jl") include("quatmaps.jl") include("rotation_error.jl") include("distribution_tests.jl") +include("eigen.jl") include("deprecated.jl") include(joinpath(@__DIR__, "..", "perf", "runbenchmarks.jl")) From b3cc7f09b70a2596c3bd0a2e0290948523902584 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 23 Oct 2021 23:56:47 +0900 Subject: [PATCH 02/11] update methods for eigen --- src/eigen.jl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/eigen.jl b/src/eigen.jl index 828df82d..695912c9 100644 --- a/src/eigen.jl +++ b/src/eigen.jl @@ -7,8 +7,14 @@ function LinearAlgebra.eigvecs(R::Rotation{3}) n3 = normalize(rotation_axis(R)) n1 = normalize(perpendicular_vector(n3)) n2 = normalize(n3×n1) - v1 = n1*im + n2 - v2 = n1 + n2*im + v1 = normalize(n1*im + n2) + v2 = normalize(n1 + n2*im) v3 = n3 return hcat(v1,v2,v3) end + +function LinearAlgebra.eigen(R::Rotation{3}) + λs = eigvals(R) + vs = eigvecs(R) + return Eigen(λs, vs) +end From 6d5bbf43dc622bfa4af3ac99db2efbe127dda555 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 23 Oct 2021 23:57:13 +0900 Subject: [PATCH 03/11] update tests for eigen --- test/eigen.jl | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/eigen.jl b/test/eigen.jl index fafcd2f4..521181b7 100644 --- a/test/eigen.jl +++ b/test/eigen.jl @@ -6,10 +6,19 @@ RotX, RotY, RotZ, RotXY, RotYZ, RotZX, RotXZ, RotYX, RotZY) - for type in all_types - R = rand(type) + for T in all_types, F in (one, rand) + R = F(T) λs = eigvals(R) vs = eigvecs(R) + E = eigen(R) + v1 = vs[:,1] + v2 = vs[:,2] + v3 = vs[:,3] @test R * vs ≈ transpose(λs) .* vs + @test norm(v1) ≈ 1 + @test norm(v2) ≈ 1 + @test norm(v3) ≈ 1 + @test E.values == λs + @test E.vectors == vs end end From b12554cb1046c2c9f599a48b182c8ff382902684 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Mon, 25 Oct 2021 23:51:06 +0900 Subject: [PATCH 04/11] update 3d eigen --- src/eigen.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/eigen.jl b/src/eigen.jl index 695912c9..64525c91 100644 --- a/src/eigen.jl +++ b/src/eigen.jl @@ -1,14 +1,15 @@ +# 3D function LinearAlgebra.eigvals(R::Rotation{3}) θ = rotation_angle(R) - return SVector(exp(θ*im), exp(-θ*im), 1) + return SVector(exp(-θ*im), exp(θ*im), 1) end function LinearAlgebra.eigvecs(R::Rotation{3}) n3 = normalize(rotation_axis(R)) n1 = normalize(perpendicular_vector(n3)) n2 = normalize(n3×n1) - v1 = normalize(n1*im + n2) - v2 = normalize(n1 + n2*im) + v1 = normalize(n1 + n2*im) + v2 = normalize(n1*im + n2) v3 = n3 return hcat(v1,v2,v3) end From 3b42712a1353c47005c1357a092af225cecb033c Mon Sep 17 00:00:00 2001 From: hyrodium Date: Mon, 25 Oct 2021 23:51:47 +0900 Subject: [PATCH 05/11] add eigen methods for 2d --- src/eigen.jl | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/eigen.jl b/src/eigen.jl index 64525c91..4e4e27c0 100644 --- a/src/eigen.jl +++ b/src/eigen.jl @@ -19,3 +19,20 @@ function LinearAlgebra.eigen(R::Rotation{3}) vs = eigvecs(R) return Eigen(λs, vs) end + + +# 2D +function LinearAlgebra.eigvals(R::Rotation{2}) + θ = rotation_angle(R) + return SVector(exp(-θ*im), exp(θ*im)) +end + +function LinearAlgebra.eigvecs(R::Rotation{2}) + return @SMatrix [1/√2 1/√2;im/√2 -im/√2] +end + +function LinearAlgebra.eigen(R::Rotation{2}) + λs = eigvals(R) + vs = eigvecs(R) + return Eigen(λs, vs) +end From 8f6bc9388920f335879e76d8a4bf68023c38ff3b Mon Sep 17 00:00:00 2001 From: hyrodium Date: Mon, 25 Oct 2021 23:52:16 +0900 Subject: [PATCH 06/11] update tests for eigen --- test/eigen.jl | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/test/eigen.jl b/test/eigen.jl index 521181b7..d84ca09e 100644 --- a/test/eigen.jl +++ b/test/eigen.jl @@ -1,12 +1,13 @@ -@testset "Eigen" begin +@testset "Eigen_3D" begin all_types = (RotMatrix{3}, AngleAxis, RotationVec, UnitQuaternion, RodriguesParam, MRP, RotXYZ, RotYZX, RotZXY, RotXZY, RotYXZ, RotZYX, RotXYX, RotYZY, RotZXZ, RotXZX, RotYXY, RotZYZ, RotX, RotY, RotZ, RotXY, RotYZ, RotZX, RotXZ, RotYX, RotZY) + oneaxis_types = (RotX, RotY, RotZ) - for T in all_types, F in (one, rand) + @testset "$(T)" for T in all_types, F in (one, rand) R = F(T) λs = eigvals(R) vs = eigvecs(R) @@ -20,5 +21,29 @@ @test norm(v3) ≈ 1 @test E.values == λs @test E.vectors == vs + if !(T in oneaxis_types) + # If the rotation angle is in [0°, 180°], then the eigvals will be equal. + # Note that the randomized RotX (and etc.) have rotation angle in [0°, 360°]. + @test eigvals(R) ≈ eigvals(collect(R)) + end + end +end + +@testset "Eigen_2D" begin + all_types = (RotMatrix{2}, Angle2d) + + @testset "$(T)" for T in all_types, F in (one, rand) + R = F(T) + λs = eigvals(R) + vs = eigvecs(R) + E = eigen(R) + v1 = vs[:,1] + v2 = vs[:,2] + @test R * vs ≈ transpose(λs) .* vs + @test norm(v1) ≈ 1 + @test norm(v2) ≈ 1 + @test E.values == λs + @test E.vectors == vs + @test eigvals(R) ≈ eigvals(collect(R)) end end From 2ff7b115a262a70e1e05f2c72e540abd00f3d717 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Tue, 26 Oct 2021 00:05:41 +0900 Subject: [PATCH 07/11] update tests for Julia 1.0 --- test/eigen.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/eigen.jl b/test/eigen.jl index d84ca09e..ebbd3e26 100644 --- a/test/eigen.jl +++ b/test/eigen.jl @@ -21,9 +21,11 @@ @test norm(v3) ≈ 1 @test E.values == λs @test E.vectors == vs - if !(T in oneaxis_types) + if !(T in oneaxis_types) && VERSION ≥ v"1.2" # If the rotation angle is in [0°, 180°], then the eigvals will be equal. # Note that the randomized RotX (and etc.) have rotation angle in [0°, 360°]. + # This needs Julia(≥1.2) to get sorted eigenvalues in a canonical order + # See https://github.com/JuliaLang/julia/pull/21598 @test eigvals(R) ≈ eigvals(collect(R)) end end From e0f04c4faaad05415a80e8b8ae9e378b56fc12c5 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Tue, 26 Oct 2021 00:14:45 +0900 Subject: [PATCH 08/11] update tests for Julia 1.0 --- test/eigen.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/eigen.jl b/test/eigen.jl index ebbd3e26..69121286 100644 --- a/test/eigen.jl +++ b/test/eigen.jl @@ -46,6 +46,10 @@ end @test norm(v2) ≈ 1 @test E.values == λs @test E.vectors == vs - @test eigvals(R) ≈ eigvals(collect(R)) + if !(T in oneaxis_types) && VERSION ≥ v"1.2" + # This needs Julia(≥1.2) to get sorted eigenvalues in a canonical order + # See https://github.com/JuliaLang/julia/pull/21598 + @test eigvals(R) ≈ eigvals(collect(R)) + end end end From ca3d8708bfd1e206abbfa422a7f3ed9aabf35be2 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Tue, 26 Oct 2021 00:21:27 +0900 Subject: [PATCH 09/11] fix bug in eigen test --- test/eigen.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/eigen.jl b/test/eigen.jl index 69121286..d9c3ffcb 100644 --- a/test/eigen.jl +++ b/test/eigen.jl @@ -46,7 +46,7 @@ end @test norm(v2) ≈ 1 @test E.values == λs @test E.vectors == vs - if !(T in oneaxis_types) && VERSION ≥ v"1.2" + if VERSION ≥ v"1.2" # This needs Julia(≥1.2) to get sorted eigenvalues in a canonical order # See https://github.com/JuliaLang/julia/pull/21598 @test eigvals(R) ≈ eigvals(collect(R)) From 4014fc8108ef0627405dc3bcdc5f5622d705adc1 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Tue, 26 Oct 2021 00:38:57 +0900 Subject: [PATCH 10/11] fix bug in eigen test --- test/eigen.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/eigen.jl b/test/eigen.jl index d9c3ffcb..2caa7fe2 100644 --- a/test/eigen.jl +++ b/test/eigen.jl @@ -34,8 +34,8 @@ end @testset "Eigen_2D" begin all_types = (RotMatrix{2}, Angle2d) - @testset "$(T)" for T in all_types, F in (one, rand) - R = F(T) + @testset "$(T)" for T in all_types, θ in 0.0:0.1:π + R = T(Angle2d(θ)) λs = eigvals(R) vs = eigvecs(R) E = eigen(R) @@ -47,6 +47,8 @@ end @test E.values == λs @test E.vectors == vs if VERSION ≥ v"1.2" + # If the rotation angle θ is in [0°, 180°], then the eigvals will be equal. + # Note that the randomized RotX (and etc.) have rotation angle in [0°, 360°]. # This needs Julia(≥1.2) to get sorted eigenvalues in a canonical order # See https://github.com/JuliaLang/julia/pull/21598 @test eigvals(R) ≈ eigvals(collect(R)) From 143f9aa8786429bfc7fe70daae9cce32b70c7bda Mon Sep 17 00:00:00 2001 From: hyrodium Date: Tue, 26 Oct 2021 13:01:12 +0900 Subject: [PATCH 11/11] update performance --- src/eigen.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/eigen.jl b/src/eigen.jl index 4e4e27c0..56622162 100644 --- a/src/eigen.jl +++ b/src/eigen.jl @@ -15,6 +15,10 @@ function LinearAlgebra.eigvecs(R::Rotation{3}) end function LinearAlgebra.eigen(R::Rotation{3}) + return eigen(AngleAxis(R)) +end + +function LinearAlgebra.eigen(R::AngleAxis) λs = eigvals(R) vs = eigvecs(R) return Eigen(λs, vs)