From 034e2f6ddfef325f3f013d5fd0d7bf4d547376d6 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 20 Nov 2021 12:51:09 +0900 Subject: [PATCH 01/29] add infinitesimal rotations --- src/Rotations.jl | 7 ++ src/infinitesimal.jl | 249 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 src/infinitesimal.jl diff --git a/src/Rotations.jl b/src/Rotations.jl index e2583790..d225f07a 100644 --- a/src/Rotations.jl +++ b/src/Rotations.jl @@ -24,6 +24,7 @@ include("principal_value.jl") include("rodrigues_params.jl") include("error_maps.jl") include("rotation_error.jl") +include("infinitesimal.jl") include("log.jl") include("eigen.jl") include("deprecated.jl") @@ -42,6 +43,12 @@ export # Deprecated, but export for compatibility UnitQuaternion, + # infinitesimal rotations + InfinitesimalRotation, + InfinitesimalRotMatrix, + InfinitesimalAngle2d, + InfinitesimalRotationVec, + # Quaternion math ops logm, expm, ⊖, ⊕, diff --git a/src/infinitesimal.jl b/src/infinitesimal.jl new file mode 100644 index 00000000..ef0f4d8b --- /dev/null +++ b/src/infinitesimal.jl @@ -0,0 +1,249 @@ +""" + abstract type InfinitesimalRotation{N,T} <: StaticMatrix{N,N,T} + +An abstract type representing `N`-dimensional infinitesimal rotations. More abstractly, they represent +skew-symmetric real `N`×`N` matrices. +""" +abstract type InfinitesimalRotation{N,T} <: StaticMatrix{N,N,T} end + +Base.@pure StaticArrays.Size(::Type{InfinitesimalRotation{N}}) where {N} = Size(N,N) +Base.@pure StaticArrays.Size(::Type{InfinitesimalRotation{N,T}}) where {N,T} = Size(N,N) +Base.@pure StaticArrays.Size(::Type{R}) where {R<:InfinitesimalRotation} = Size(supertype(R)) +Base.adjoint(r::InfinitesimalRotation) = -r +Base.transpose(r::InfinitesimalRotation{N,T}) where {N,T<:Real} = -r + +# Generate identity-matrix with SMatrix +# Note that zeros(InfinitesimalRotation3,dims...) is not Array{<:InfinitesimalRotation} but Array{<:StaticMatrix{3,3}} +Base.one(::InfinitesimalRotation{N,T}) where {N,T} = @SMatrix ones(T,N,N) +Base.one(::Type{InfinitesimalRotation}) = error("The dimension of rotation is not specified.") +Base.one(::Type{<:InfinitesimalRotation{N}}) where N = @SMatrix ones(N,N) +Base.one(::Type{<:InfinitesimalRotation{N,T}}) where {N,T} = @SMatrix ones(T,N,N) +Base.ones(::Type{R}) where {R<:InfinitesimalRotation} = ones(R, ()) # avoid StaticArray constructor +Base.ones(::Type{R}, dims::Base.DimOrInd...) where {R<:InfinitesimalRotation} = ones(typeof(one(R)),dims...) +Base.ones(::Type{R}, dims::NTuple{N, Integer}) where {R<:InfinitesimalRotation, N} = ones(typeof(one(R)),dims) + +# `convert` goes through the constructors, similar to e.g. `Number` +Base.convert(::Type{R}, rot::InfinitesimalRotation{N}) where {N,R<:InfinitesimalRotation{N}} = R(rot) + +# InfinitesimalRotation matrices should be orthoginal/unitary. Only the operations we define, +# like multiplication, will stay as InfinitesimalRotations, otherwise users will get an +# SMatrix{3,3} (e.g. rot1 + rot2 -> SMatrix) +Base.@pure StaticArrays.similar_type(::Union{R,Type{R}}) where {R <: InfinitesimalRotation} = SMatrix{size(R)..., eltype(R), prod(size(R))} +Base.@pure StaticArrays.similar_type(::Union{R,Type{R}}, ::Type{T}) where {R <: InfinitesimalRotation, T} = SMatrix{size(R)..., T, prod(size(R))} + +# Useful for converting arrays of rotations to another rotation eltype, for instance. +# Only works because parameters of all the rotations are of a similar form +# Would need to be more sophisticated if we have arbitrary dimensions, etc +@inline function Base.promote_op(::Type{R1}, ::Type{R2}) where {R1 <: InfinitesimalRotation, R2 <: InfinitesimalRotation} + size(R1) == size(R2) || throw(DimensionMismatch("cannot promote rotations of $(size(R1)[1]) and $(size(R2)[1]) dimensions")) + if isleaftype(R1) + return R1 + else + return R1{eltype(R2)} + end +end + +################################################################################ +################################################################################ +""" + struct InfinitesimalRotMatrix{N,T} <: InfinitesimalRotation{N,T} + +A statically-sized, N×N skew-symmetric matrix. + +Note: the skew-symmetricity of the input matrix is *not* checked by the constructor. +""" +struct InfinitesimalRotMatrix{N,T,L} <: InfinitesimalRotation{N,T} # which is <: AbstractMatrix{T} + mat::SMatrix{N, N, T, L} # The final parameter to SMatrix is the "length" of the matrix, 3 × 3 = 9 + InfinitesimalRotMatrix{N,T,L}(x::AbstractArray) where {N,T,L} = new{N,T,L}(convert(SMatrix{N,N,T,L}, x)) + # fixes #49 ambiguity introduced in StaticArrays 0.6.5 + InfinitesimalRotMatrix{N,T,L}(x::StaticArray) where {N,T,L} = new{N,T,L}(convert(SMatrix{N,N,T,L}, x)) +end +InfinitesimalRotMatrix(x::SMatrix{N,N,T,L}) where {N,T,L} = InfinitesimalRotMatrix{N,T,L}(x) + +Base.zero(::Type{InfinitesimalRotMatrix}) = error("The dimension of rotation is not specified.") + +# These functions (plus size) are enough to satisfy the entire StaticArrays interface: +for N = 2:3 + L = N*N + InfinitesimalRotMatrixN = Symbol(:InfinitesimalRotMatrix, N) + @eval begin + @inline InfinitesimalRotMatrix(t::NTuple{$L}) = InfinitesimalRotMatrix(SMatrix{$N,$N}(t)) + @inline (::Type{InfinitesimalRotMatrix{$N}})(t::NTuple{$L}) = InfinitesimalRotMatrix(SMatrix{$N,$N}(t)) + @inline InfinitesimalRotMatrix{$N,T}(t::NTuple{$L}) where {T} = InfinitesimalRotMatrix(SMatrix{$N,$N,T}(t)) + @inline InfinitesimalRotMatrix{$N,T,$L}(t::NTuple{$L}) where {T} = InfinitesimalRotMatrix(SMatrix{$N,$N,T}(t)) + const $InfinitesimalRotMatrixN{T} = InfinitesimalRotMatrix{$N, T, $L} + end +end +Base.@propagate_inbounds Base.getindex(r::InfinitesimalRotMatrix, i::Int) = r.mat[i] +@inline Base.Tuple(r::InfinitesimalRotMatrix) = Tuple(r.mat) + +@inline InfinitesimalRotMatrix(θ::Real) = InfinitesimalRotMatrix{2}(θ) +@inline function (::Type{InfinitesimalRotMatrix{2}})(θ::Real) + InfinitesimalRotMatrix(@SMatrix [zero(θ) -θ; θ zero(θ)]) +end +@inline function InfinitesimalRotMatrix{2,T}(θ::Real) where T + InfinitesimalRotMatrix(@SMatrix T[zero(θ) -θ; θ zero(θ)]) +end + +Base.one(::Type{R}) where {N,R<:InfinitesimalRotMatrix{N}} = R(I) + +# A rotation is more-or-less defined as being an orthogonal (or unitary) matrix +Base.:-(r::InfinitesimalRotMatrix) = InfinitesimalRotMatrix(-r.mat) + +# By default, composition of rotations will go through InfinitesimalRotMatrix, unless overridden +@inline Base.:+(r1::InfinitesimalRotation, r2::InfinitesimalRotation) = InfinitesimalRotMatrix(r1) + InfinitesimalRotMatrix(r2) +@inline Base.:+(r1::InfinitesimalRotMatrix, r2::InfinitesimalRotation) = r1 + InfinitesimalRotMatrix(r2) +@inline Base.:+(r1::InfinitesimalRotation, r2::InfinitesimalRotMatrix) = InfinitesimalRotMatrix(r1) + r2 +@inline Base.:+(r1::InfinitesimalRotMatrix, r2::InfinitesimalRotMatrix) = InfinitesimalRotMatrix(r1.mat + r2.mat) + +# Special case multiplication of 2×2 rotation matrices: speedup using skew-symmetricity +@inline function Base.:+(r1::InfinitesimalRotMatrix{2}, r2::InfinitesimalRotMatrix{2}) + s12 = r1[2,1]+r2[2,1] + s = @SMatrix [0 s12 -s31 + -s12 0 s23 + s31 -s23 0] + return InfinitesimalRotMatrix(s) +end + +# Special case multiplication of 3×3 rotation matrices: speedup using skew-symmetricity +@inline function Base.:+(r1::InfinitesimalRotMatrix{3}, r2::InfinitesimalRotMatrix{3}) + x = r1[6]+r2[6] + y = r1[7]+r2[7] + z = r1[2]+r2[2] + s = @SMatrix [ 0 -z y + z 0 -x + -y x 0] + + return InfinitesimalRotMatrix(s) +end + +""" + struct InfinitesimalAngle2d{T} <: InfinitesimalRotation{2,T} + v::T + end + +A 2×2 infinitesimal rotation matrix (i.e. skew-symmetric matrix). +[ 0 -v + v 0 ] +""" +struct InfinitesimalAngle2d{T} <: InfinitesimalRotation{2,T} + v::T + InfinitesimalAngle2d{T}(r) where T = new{T}(r) +end + +@inline function InfinitesimalAngle2d(r::T) where T <: Number + InfinitesimalAngle2d{T}(r) +end + +@inline InfinitesimalAngle2d(r::InfinitesimalRotation{2}) = InfinitesimalAngle2d(r[2,1]) +@inline InfinitesimalAngle2d{T}(r::InfinitesimalRotation{2}) where {T} = InfinitesimalAngle2d{T}(r[2,1]) + +@inline Base.zero(::Type{A}) where {A<: InfinitesimalAngle2d} = A(0) + +@inline Base.:+(r1::InfinitesimalAngle2d, r2::InfinitesimalAngle2d) = InfinitesimalAngle2d(r1.v + r2.v) +@inline Base.:-(r1::InfinitesimalAngle2d, r2::InfinitesimalAngle2d) = InfinitesimalAngle2d(r1.v - r2.v) +@inline Base.:*(t::Number, r::InfinitesimalAngle2d) = InfinitesimalAngle2d(t*r.v) +@inline Base.:*(r::InfinitesimalAngle2d, t::Number) = t*r +@inline Base.:-(r::InfinitesimalAngle2d) = InfinitesimalAngle2d(-r.v) + +@inline function Base.getindex(r::InfinitesimalAngle2d{T}, i::Int) where T + if i == 1 + zero(T) + elseif i == 2 + r.v + elseif i == 3 + -r.v + elseif i == 4 + zero(T) + else + throw(BoundsError(r,i)) + end +end + + +""" + struct InfinitesimalRotationVec{T} <: InfinitesimalRotation{2,T} + x::T + y::T + z::T + end + +A 3×3 infinitesimal rotation matrix (i.e. skew-symmetric matrix). +[ 0 -z y + z 0 -x + -y x 0] +""" +struct InfinitesimalRotationVec{T} <: InfinitesimalRotation{3,T} + x::T + y::T + z::T + InfinitesimalRotationVec{T}(x,y,z) where T = new{T}(x,y,z) +end + +@inline function InfinitesimalRotationVec(x::X,y::Y,z::Z) where {X<:Number, Y<:Number, Z<:Number} + InfinitesimalRotationVec{promote_type(X,Y,Z)}(x, y, z) +end + +@inline InfinitesimalRotationVec(r::InfinitesimalRotation{3}) = InfinitesimalRotationVec(r[6], r[7], r[2]) +@inline InfinitesimalRotationVec{T}(r::InfinitesimalRotation{3}) where {T} = InfinitesimalRotationVec{T}(r[6], r[7], r[x]) + +@inline Base.zero(::Type{A}) where {A<: InfinitesimalRotationVec} = A(0) + +@inline Base.:+(r1::InfinitesimalRotationVec, r2::InfinitesimalRotationVec) = InfinitesimalRotationVec(r1.x + r2.x, r1.y + r2.y, r1.z + r2.z) +@inline Base.:-(r1::InfinitesimalRotationVec, r2::InfinitesimalRotationVec) = InfinitesimalRotationVec(r1.x - r2.x, r1.y - r2.y, r1.z - r2.z) +@inline Base.:*(t::Number, r::InfinitesimalRotationVec) = InfinitesimalRotationVec(t*r.x, t*r.y, t*r.z) +@inline Base.:*(r::InfinitesimalRotationVec, t::Number) = t*r +@inline Base.:-(r::InfinitesimalRotationVec) = InfinitesimalRotationVec(-r.x, -r.y, -r.z) + +@inline function Base.getindex(r::InfinitesimalRotationVec{T}, i::Int) where T + if i == 1 + zero(T) + elseif i == 2 + r.z + elseif i == 3 + -r.y + elseif i == 4 + -r.z + elseif i == 5 + zero(T) + elseif i == 6 + r.x + elseif i == 7 + r.y + elseif i == 8 + -r.x + elseif i == 9 + zero(T) + else + throw(BoundsError(r,i)) + end +end + + +################################################################################ +################################################################################ + + +# A simplification and specialization of the Base.show function for AbstractArray makes +# everything sensible at the REPL. +function Base.show(io::IO, ::MIME"text/plain", X::InfinitesimalRotation) + if !haskey(io, :compact) + io = IOContext(io, :compact => true) + end + summary(io, X) + if !isa(X, InfinitesimalRotMatrix) + n_fields = length(fieldnames(typeof(X))) + print(io, "(") + for i = 1:n_fields + print(io, getfield(X, i)) + if i < n_fields + print(io, ", ") + end + end + print(io, ")") + end + print(io, ":") + println(io) + io = IOContext(io, :typeinfo => eltype(X)) + Base.print_array(io, X) +end From 0c52741c981b088c69d87d5f873e19bc0468f207 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sun, 14 Nov 2021 12:37:00 +0900 Subject: [PATCH 02/29] update log with InfinitesimalRotation --- src/log.jl | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/log.jl b/src/log.jl index 9a87a0e9..718d9cd6 100644 --- a/src/log.jl +++ b/src/log.jl @@ -1,9 +1,8 @@ +## log # 3d function Base.log(R::RotationVec) x, y, z = params(R) - return @SMatrix [0 -z y - z 0 -x - -y x 0] + return InfinitesimalRotationVec(x,y,z) end function Base.log(R::Rotation{3}) @@ -14,10 +13,30 @@ end # 2d function Base.log(R::Angle2d) θ, = params(R) - return @SMatrix [0 -θ - θ 0] + return InfinitesimalAngle2d(θ) end function Base.log(R::Rotation{2}) log(Angle2d(R)) end + + +## exp +# 3d +function Base.exp(R::InfinitesimalRotationVec) + return RotationVec(R.x,R.y,R.z) +end + +function Base.exp(R::InfinitesimalRotation{3}) + exp(InfinitesimalRotationVec(R)) +end + + +# 2d +function Base.exp(R::InfinitesimalAngle2d) + return Angle2d(R.v) +end + +function Base.exp(R::InfinitesimalRotation{2}) + exp(InfinitesimalAngle2d(R)) +end From 498cb1cd75c0f2c0a7478a1a09e867c3729b9ccd Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 20 Nov 2021 12:53:06 +0900 Subject: [PATCH 03/29] rename log.jl to logexp.jl, and fix tests --- src/Rotations.jl | 2 +- src/{log.jl => logexp.jl} | 0 test/{log.jl => logexp.jl} | 3 ++- test/runtests.jl | 2 +- test/unitquat.jl | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) rename src/{log.jl => logexp.jl} (100%) rename test/{log.jl => logexp.jl} (85%) diff --git a/src/Rotations.jl b/src/Rotations.jl index d225f07a..552cfddf 100644 --- a/src/Rotations.jl +++ b/src/Rotations.jl @@ -25,7 +25,7 @@ include("rodrigues_params.jl") include("error_maps.jl") include("rotation_error.jl") include("infinitesimal.jl") -include("log.jl") +include("logexp.jl") include("eigen.jl") include("deprecated.jl") diff --git a/src/log.jl b/src/logexp.jl similarity index 100% rename from src/log.jl rename to src/logexp.jl diff --git a/test/log.jl b/test/logexp.jl similarity index 85% rename from test/log.jl rename to test/logexp.jl index 85853030..ff488ad3 100644 --- a/test/log.jl +++ b/test/logexp.jl @@ -10,6 +10,7 @@ @testset "$(T)" for T in all_types, F in (one, rand) R = F(T) @test R ≈ exp(log(R)) - @test log(R) isa SMatrix + @test log(R) isa InfinitesimalRotation + @test exp(log(R)) isa Rotation end end diff --git a/test/runtests.jl b/test/runtests.jl index 62da0178..a231086d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -28,8 +28,8 @@ include("quatmaps.jl") include("rotation_error.jl") include("distribution_tests.jl") include("eigen.jl") -include("log.jl") include("nearest_rotation.jl") +include("logexp.jl") include("deprecated.jl") include(joinpath(@__DIR__, "..", "perf", "runbenchmarks.jl")) diff --git a/test/unitquat.jl b/test/unitquat.jl index 972255d7..cef14206 100644 --- a/test/unitquat.jl +++ b/test/unitquat.jl @@ -129,7 +129,7 @@ import Rotations: vmat, rmult, lmult, hmat, tmat q32 = rand(QuatRotation{Float32}) @test Rotations._log_as_quat(q32) isa Quaternion{Float32} - @test log(q32) isa SMatrix + @test log(q32) isa InfinitesimalRotation{3} @test eltype(logm(q32)) == Float32 @test expm(logm(q32)) ≈ q32 From b3d226879cf1b92702e898eb634217bfa8b27250 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 20 Nov 2021 16:48:26 +0900 Subject: [PATCH 04/29] update infinitesimal --- src/infinitesimal.jl | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/infinitesimal.jl b/src/infinitesimal.jl index ef0f4d8b..cbb1a806 100644 --- a/src/infinitesimal.jl +++ b/src/infinitesimal.jl @@ -14,13 +14,16 @@ Base.transpose(r::InfinitesimalRotation{N,T}) where {N,T<:Real} = -r # Generate identity-matrix with SMatrix # Note that zeros(InfinitesimalRotation3,dims...) is not Array{<:InfinitesimalRotation} but Array{<:StaticMatrix{3,3}} -Base.one(::InfinitesimalRotation{N,T}) where {N,T} = @SMatrix ones(T,N,N) +Base.one(::InfinitesimalRotation{N,T}) where {N,T} = one(SMatrix{N,N,T}) Base.one(::Type{InfinitesimalRotation}) = error("The dimension of rotation is not specified.") -Base.one(::Type{<:InfinitesimalRotation{N}}) where N = @SMatrix ones(N,N) -Base.one(::Type{<:InfinitesimalRotation{N,T}}) where {N,T} = @SMatrix ones(T,N,N) +Base.one(::Type{<:InfinitesimalRotation{N}}) where N = one(SMatrix{N,N}) +Base.one(::Type{<:InfinitesimalRotation{N,T}}) where {N,T} = one(SMatrix{N,N,T}) Base.ones(::Type{R}) where {R<:InfinitesimalRotation} = ones(R, ()) # avoid StaticArray constructor -Base.ones(::Type{R}, dims::Base.DimOrInd...) where {R<:InfinitesimalRotation} = ones(typeof(one(R)),dims...) -Base.ones(::Type{R}, dims::NTuple{N, Integer}) where {R<:InfinitesimalRotation, N} = ones(typeof(one(R)),dims) +# Base.ones(::Type{R}, dims::Base.DimOrInd...) where {R<:InfinitesimalRotation} = ones(typeof(one(R)),dims...) +# Base.ones(::Type{R}, dims::NTuple{N, Integer}) where {R<:InfinitesimalRotation, N} = ones(typeof(one(R)),dims) + +# Generate identity rotation matrix +Base.zero(r::InfinitesimalRotation) = zero(typeof(r)) # `convert` goes through the constructors, similar to e.g. `Number` Base.convert(::Type{R}, rot::InfinitesimalRotation{N}) where {N,R<:InfinitesimalRotation{N}} = R(rot) @@ -85,8 +88,6 @@ end InfinitesimalRotMatrix(@SMatrix T[zero(θ) -θ; θ zero(θ)]) end -Base.one(::Type{R}) where {N,R<:InfinitesimalRotMatrix{N}} = R(I) - # A rotation is more-or-less defined as being an orthogonal (or unitary) matrix Base.:-(r::InfinitesimalRotMatrix) = InfinitesimalRotMatrix(-r.mat) @@ -98,10 +99,9 @@ Base.:-(r::InfinitesimalRotMatrix) = InfinitesimalRotMatrix(-r.mat) # Special case multiplication of 2×2 rotation matrices: speedup using skew-symmetricity @inline function Base.:+(r1::InfinitesimalRotMatrix{2}, r2::InfinitesimalRotMatrix{2}) - s12 = r1[2,1]+r2[2,1] - s = @SMatrix [0 s12 -s31 - -s12 0 s23 - s31 -s23 0] + v = r1[2,1]+r2[2,1] + s = @SMatrix [0 -v + v 0] return InfinitesimalRotMatrix(s) end @@ -138,7 +138,7 @@ end @inline InfinitesimalAngle2d(r::InfinitesimalRotation{2}) = InfinitesimalAngle2d(r[2,1]) @inline InfinitesimalAngle2d{T}(r::InfinitesimalRotation{2}) where {T} = InfinitesimalAngle2d{T}(r[2,1]) -@inline Base.zero(::Type{A}) where {A<: InfinitesimalAngle2d} = A(0) +@inline Base.zero(::Type{A}) where {A<: InfinitesimalAngle2d} = A(0.0) @inline Base.:+(r1::InfinitesimalAngle2d, r2::InfinitesimalAngle2d) = InfinitesimalAngle2d(r1.v + r2.v) @inline Base.:-(r1::InfinitesimalAngle2d, r2::InfinitesimalAngle2d) = InfinitesimalAngle2d(r1.v - r2.v) @@ -187,7 +187,7 @@ end @inline InfinitesimalRotationVec(r::InfinitesimalRotation{3}) = InfinitesimalRotationVec(r[6], r[7], r[2]) @inline InfinitesimalRotationVec{T}(r::InfinitesimalRotation{3}) where {T} = InfinitesimalRotationVec{T}(r[6], r[7], r[x]) -@inline Base.zero(::Type{A}) where {A<: InfinitesimalRotationVec} = A(0) +@inline Base.zero(::Type{R}) where {R<: InfinitesimalRotationVec} = R(0.0,0.0,0.0) @inline Base.:+(r1::InfinitesimalRotationVec, r2::InfinitesimalRotationVec) = InfinitesimalRotationVec(r1.x + r2.x, r1.y + r2.y, r1.z + r2.z) @inline Base.:-(r1::InfinitesimalRotationVec, r2::InfinitesimalRotationVec) = InfinitesimalRotationVec(r1.x - r2.x, r1.y - r2.y, r1.z - r2.z) From 20a53e0ae9ccd3f55fa53587dce84eae42a8d228 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 20 Nov 2021 16:48:56 +0900 Subject: [PATCH 05/29] add tests for infinitesimal rotations --- test/infinitesimal.jl | 40 ++++++++++++++++++++++++++++++++++++++++ test/logexp.jl | 11 +++++++++++ test/runtests.jl | 1 + 3 files changed, 52 insertions(+) create mode 100644 test/infinitesimal.jl diff --git a/test/infinitesimal.jl b/test/infinitesimal.jl new file mode 100644 index 00000000..920d7e99 --- /dev/null +++ b/test/infinitesimal.jl @@ -0,0 +1,40 @@ +@testset "infinitesimal" begin + all_types = (InfinitesimalRotMatrix{3}, InfinitesimalRotationVec, + InfinitesimalRotMatrix{2}, InfinitesimalAngle2d) + types_2d = (InfinitesimalRotMatrix{2}, InfinitesimalAngle2d) + types_3d = (InfinitesimalRotMatrix{3}, InfinitesimalRotationVec) + + @testset "zero" begin + for T in all_types + r = zero(T) + @test r isa InfinitesimalRotation + @test r === zero(r) + + end + end + + @testset "one" begin + for T in all_types + r = one(T) + @test r isa SMatrix + @test r == one(r) + end + end + + @testset "minus" begin + for T in all_types + r = T(log(rand(typeof(exp(zero(T)))))) + @test r isa T + @test -r isa T + @test r' isa T + @test transpose(r) isa T + + @test -r == -SMatrix(r) + @test r' == SMatrix(r)' + @test transpose(r) == transpose(SMatrix(r)) + + @test r-r == r+(-r) == zero(r) + @test -r == r' == transpose(r) + end + end +end diff --git a/test/logexp.jl b/test/logexp.jl index ff488ad3..2978e9b2 100644 --- a/test/logexp.jl +++ b/test/logexp.jl @@ -14,3 +14,14 @@ @test exp(log(R)) isa Rotation end end + +@testset "exp(zero)" begin + all_types = (InfinitesimalRotMatrix{3}, InfinitesimalRotationVec, + InfinitesimalRotMatrix{2}, InfinitesimalAngle2d) + + @testset "$(T)" for T in all_types + r = zero(T) + @test one(exp(r)) ≈ exp(r) + @test exp(r) isa Rotation + end +end diff --git a/test/runtests.jl b/test/runtests.jl index a231086d..f94a7e3f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -29,6 +29,7 @@ include("rotation_error.jl") include("distribution_tests.jl") include("eigen.jl") include("nearest_rotation.jl") +include("infinitesimal.jl") include("logexp.jl") include("deprecated.jl") From bda9f38816f08a4bfdc35f3bbbf224646a9784ac Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 20 Nov 2021 17:12:55 +0900 Subject: [PATCH 06/29] update tests for infinitesimal --- test/infinitesimal.jl | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/infinitesimal.jl b/test/infinitesimal.jl index 920d7e99..c599b3a7 100644 --- a/test/infinitesimal.jl +++ b/test/infinitesimal.jl @@ -37,4 +37,19 @@ @test -r == r' == transpose(r) end end + + @testset "multiply" begin + for T in all_types + r = T(log(rand(typeof(exp(zero(T)))))) + a = 4.2 + @test r isa T + @test r*1 isa T + @test 1*r isa T + @test a*r isa T + + @test r*1 == 1*r == r + @test r*2 == 2*r == r+r + @test r*a == a*r == a*SMatrix(r) + end + end end From f19e191f60b6f0058502b8eb4d7b864e7f0d74a1 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 20 Nov 2021 17:13:12 +0900 Subject: [PATCH 07/29] update src for infinitesimal --- src/infinitesimal.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/infinitesimal.jl b/src/infinitesimal.jl index cbb1a806..4fb6e7fe 100644 --- a/src/infinitesimal.jl +++ b/src/infinitesimal.jl @@ -97,6 +97,9 @@ Base.:-(r::InfinitesimalRotMatrix) = InfinitesimalRotMatrix(-r.mat) @inline Base.:+(r1::InfinitesimalRotation, r2::InfinitesimalRotMatrix) = InfinitesimalRotMatrix(r1) + r2 @inline Base.:+(r1::InfinitesimalRotMatrix, r2::InfinitesimalRotMatrix) = InfinitesimalRotMatrix(r1.mat + r2.mat) +@inline Base.:*(t::Number, r::InfinitesimalRotMatrix) = InfinitesimalRotMatrix(t*r.mat) +@inline Base.:*(r::InfinitesimalRotMatrix, t::Number) = t*r + # Special case multiplication of 2×2 rotation matrices: speedup using skew-symmetricity @inline function Base.:+(r1::InfinitesimalRotMatrix{2}, r2::InfinitesimalRotMatrix{2}) v = r1[2,1]+r2[2,1] From 6106e070c7d089900564a6bada3e0e0571c8d02c Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 20 Nov 2021 18:36:05 +0900 Subject: [PATCH 08/29] fix typo --- src/infinitesimal.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/infinitesimal.jl b/src/infinitesimal.jl index 4fb6e7fe..ff181388 100644 --- a/src/infinitesimal.jl +++ b/src/infinitesimal.jl @@ -188,7 +188,7 @@ end end @inline InfinitesimalRotationVec(r::InfinitesimalRotation{3}) = InfinitesimalRotationVec(r[6], r[7], r[2]) -@inline InfinitesimalRotationVec{T}(r::InfinitesimalRotation{3}) where {T} = InfinitesimalRotationVec{T}(r[6], r[7], r[x]) +@inline InfinitesimalRotationVec{T}(r::InfinitesimalRotation{3}) where {T} = InfinitesimalRotationVec{T}(r[6], r[7], r[2]) @inline Base.zero(::Type{R}) where {R<: InfinitesimalRotationVec} = R(0.0,0.0,0.0) From 6e0e14931612bb37ac9f8f12d44ae8b7d9a4cc3b Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 20 Nov 2021 21:09:20 +0900 Subject: [PATCH 09/29] add tests for error --- test/infinitesimal.jl | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/infinitesimal.jl b/test/infinitesimal.jl index c599b3a7..35509936 100644 --- a/test/infinitesimal.jl +++ b/test/infinitesimal.jl @@ -52,4 +52,20 @@ @test r*a == a*r == a*SMatrix(r) end end + + @testset "error case" begin + for T in types_2d + @test_throws BoundsError zero(InfinitesimalAngle2d)[5] + @test_throws BoundsError zero(InfinitesimalAngle2d)[2,3] + @test_throws BoundsError zero(InfinitesimalAngle2d)[3,1] + end + + for T in types_3d + @test_throws BoundsError zero(InfinitesimalAngle2d)[10] + @test_throws BoundsError zero(InfinitesimalAngle2d)[2,4] + @test_throws BoundsError zero(InfinitesimalAngle2d)[4,1] + end + + @test_throws DimensionMismatch InfinitesimalAngle2d(1) + InfinitesimalRotationVec(2,3,4) + end end From fa141fb11c32a8d6de21c0b1012eb7d47e11d2e5 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 20 Nov 2021 21:33:34 +0900 Subject: [PATCH 10/29] update Base.:- --- src/infinitesimal.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/infinitesimal.jl b/src/infinitesimal.jl index ff181388..b2fe096c 100644 --- a/src/infinitesimal.jl +++ b/src/infinitesimal.jl @@ -25,6 +25,9 @@ Base.ones(::Type{R}) where {R<:InfinitesimalRotation} = ones(R, ()) # avoid Stat # Generate identity rotation matrix Base.zero(r::InfinitesimalRotation) = zero(typeof(r)) +# difference +Base.:-(r1::InfinitesimalRotation, r2::InfinitesimalRotation) = r1 + (-r2) + # `convert` goes through the constructors, similar to e.g. `Number` Base.convert(::Type{R}, rot::InfinitesimalRotation{N}) where {N,R<:InfinitesimalRotation{N}} = R(rot) From 2c22177687b40f128b28d6299abb29c07a87a512 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 20 Nov 2021 21:34:00 +0900 Subject: [PATCH 11/29] add tests for type promotion --- test/infinitesimal.jl | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/infinitesimal.jl b/test/infinitesimal.jl index 35509936..e7f345fd 100644 --- a/test/infinitesimal.jl +++ b/test/infinitesimal.jl @@ -68,4 +68,22 @@ @test_throws DimensionMismatch InfinitesimalAngle2d(1) + InfinitesimalRotationVec(2,3,4) end + + @testset "type promotion" begin + for (T, N) in ((InfinitesimalAngle2d, 2), (InfinitesimalRotationVec, 3)) + R = InfinitesimalRotMatrix + + @test zero(T) + zero(R{N}) isa R{N, Float64} + @test zero(T{Int}) + zero(R{N,Int}) isa R{N, Int} + @test zero(T{Int}) + zero(T{BigFloat}) isa T{BigFloat} + + @test zero(T) - zero(R{N}) isa R{N, Float64} + @test zero(T{Int}) - zero(R{N,Int}) isa R{N, Int} + @test zero(T{Int}) - zero(T{BigFloat}) isa T{BigFloat} + + @test 42 * zero(T) isa T{Float64} + @test 42 * zero(T{Int}) isa T{Int} + @test 1.2 * zero(T{Int}) isa T{Float64} + end + end end From c6bd6589c054a656e6d12677dfae8d5d77884a99 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 20 Nov 2021 22:03:52 +0900 Subject: [PATCH 12/29] update tests --- test/infinitesimal.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/infinitesimal.jl b/test/infinitesimal.jl index e7f345fd..26ab111e 100644 --- a/test/infinitesimal.jl +++ b/test/infinitesimal.jl @@ -9,7 +9,7 @@ r = zero(T) @test r isa InfinitesimalRotation @test r === zero(r) - + @test zeros(T,2,3) == [zero(T) for i in 1:2, j in 1:3] end end @@ -18,6 +18,7 @@ r = one(T) @test r isa SMatrix @test r == one(r) + @test ones(T,2,3) == [one(T) for i in 1:2, j in 1:3] end end @@ -66,6 +67,9 @@ @test_throws BoundsError zero(InfinitesimalAngle2d)[4,1] end + @test_throws ErrorException zero(InfinitesimalRotation) + @test_throws ErrorException one(InfinitesimalRotation) + @test_throws DimensionMismatch InfinitesimalAngle2d(1) + InfinitesimalRotationVec(2,3,4) end From 95bcb18067d317106c9e20cb7c97ede88c76ee7c Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 20 Nov 2021 22:04:09 +0900 Subject: [PATCH 13/29] update Base.ones --- src/infinitesimal.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/infinitesimal.jl b/src/infinitesimal.jl index b2fe096c..015fa38d 100644 --- a/src/infinitesimal.jl +++ b/src/infinitesimal.jl @@ -19,8 +19,8 @@ Base.one(::Type{InfinitesimalRotation}) = error("The dimension of rotation is no Base.one(::Type{<:InfinitesimalRotation{N}}) where N = one(SMatrix{N,N}) Base.one(::Type{<:InfinitesimalRotation{N,T}}) where {N,T} = one(SMatrix{N,N,T}) Base.ones(::Type{R}) where {R<:InfinitesimalRotation} = ones(R, ()) # avoid StaticArray constructor -# Base.ones(::Type{R}, dims::Base.DimOrInd...) where {R<:InfinitesimalRotation} = ones(typeof(one(R)),dims...) -# Base.ones(::Type{R}, dims::NTuple{N, Integer}) where {R<:InfinitesimalRotation, N} = ones(typeof(one(R)),dims) +Base.ones(::Type{R}, dims::Base.DimOrInd...) where {R<:InfinitesimalRotation} = ones(typeof(one(R)),dims...) +Base.ones(::Type{R}, dims::NTuple{N, Integer}) where {R<:InfinitesimalRotation, N} = ones(typeof(one(R)),dims) # Generate identity rotation matrix Base.zero(r::InfinitesimalRotation) = zero(typeof(r)) From 500a2d9f3dc6fe51ba8e4692b15edc9a8a504870 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 20 Nov 2021 22:09:56 +0900 Subject: [PATCH 14/29] update tests --- test/infinitesimal.jl | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/test/infinitesimal.jl b/test/infinitesimal.jl index 26ab111e..db499afd 100644 --- a/test/infinitesimal.jl +++ b/test/infinitesimal.jl @@ -77,13 +77,19 @@ for (T, N) in ((InfinitesimalAngle2d, 2), (InfinitesimalRotationVec, 3)) R = InfinitesimalRotMatrix - @test zero(T) + zero(R{N}) isa R{N, Float64} - @test zero(T{Int}) + zero(R{N,Int}) isa R{N, Int} - @test zero(T{Int}) + zero(T{BigFloat}) isa T{BigFloat} + @test zero(T) + zero(R{N}) isa R{N, Float64} + @test zero(R{T}) + zero(T) isa R{N, Float64} + @test zero(T{Int}) + zero(R{N,Int}) isa R{N, Int} + @test zero(R{N,Int}) + zero(T{Int}) isa R{N, Int} + @test zero(T{Int}) + zero(T{BigFloat}) isa T{BigFloat} + @test zero(T{BigFloat}) + zero(T{Int}) isa T{BigFloat} - @test zero(T) - zero(R{N}) isa R{N, Float64} - @test zero(T{Int}) - zero(R{N,Int}) isa R{N, Int} - @test zero(T{Int}) - zero(T{BigFloat}) isa T{BigFloat} + @test zero(T) - zero(R{N}) isa R{N, Float64} + @test zero(R{T}) - zero(T) isa R{N, Float64} + @test zero(T{Int}) - zero(R{N,Int}) isa R{N, Int} + @test zero(R{N,Int}) - zero(T{Int}) isa R{N, Int} + @test zero(T{Int}) - zero(T{BigFloat}) isa T{BigFloat} + @test zero(T{BigFloat}) - zero(T{Int}) isa T{BigFloat} @test 42 * zero(T) isa T{Float64} @test 42 * zero(T{Int}) isa T{Int} From b3aa8c0d4453fbfe3c50bd8c0076d574eff9944e Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 20 Nov 2021 22:19:35 +0900 Subject: [PATCH 15/29] update comments --- src/infinitesimal.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/infinitesimal.jl b/src/infinitesimal.jl index 015fa38d..19bddac7 100644 --- a/src/infinitesimal.jl +++ b/src/infinitesimal.jl @@ -13,7 +13,7 @@ Base.adjoint(r::InfinitesimalRotation) = -r Base.transpose(r::InfinitesimalRotation{N,T}) where {N,T<:Real} = -r # Generate identity-matrix with SMatrix -# Note that zeros(InfinitesimalRotation3,dims...) is not Array{<:InfinitesimalRotation} but Array{<:StaticMatrix{3,3}} +# Note that ones(InfinitesimalRotation3,dims...) is not Array{<:InfinitesimalRotation} but Array{<:StaticMatrix{3,3}} Base.one(::InfinitesimalRotation{N,T}) where {N,T} = one(SMatrix{N,N,T}) Base.one(::Type{InfinitesimalRotation}) = error("The dimension of rotation is not specified.") Base.one(::Type{<:InfinitesimalRotation{N}}) where N = one(SMatrix{N,N}) @@ -31,9 +31,9 @@ Base.:-(r1::InfinitesimalRotation, r2::InfinitesimalRotation) = r1 + (-r2) # `convert` goes through the constructors, similar to e.g. `Number` Base.convert(::Type{R}, rot::InfinitesimalRotation{N}) where {N,R<:InfinitesimalRotation{N}} = R(rot) -# InfinitesimalRotation matrices should be orthoginal/unitary. Only the operations we define, -# like multiplication, will stay as InfinitesimalRotations, otherwise users will get an -# SMatrix{3,3} (e.g. rot1 + rot2 -> SMatrix) +# InfinitesimalRotation matrices should be skew-symmetric. Only the operations we define, +# like addition, will stay as InfinitesimalRotations, otherwise users will get an +# SMatrix{3,3} (e.g. rot1 * rot2 -> SMatrix) Base.@pure StaticArrays.similar_type(::Union{R,Type{R}}) where {R <: InfinitesimalRotation} = SMatrix{size(R)..., eltype(R), prod(size(R))} Base.@pure StaticArrays.similar_type(::Union{R,Type{R}}, ::Type{T}) where {R <: InfinitesimalRotation, T} = SMatrix{size(R)..., T, prod(size(R))} From faa2b8a3db99e5bb4d38e44ae3505d77fd262ee2 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sat, 20 Nov 2021 22:21:11 +0900 Subject: [PATCH 16/29] update export --- src/Rotations.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Rotations.jl b/src/Rotations.jl index 552cfddf..af662516 100644 --- a/src/Rotations.jl +++ b/src/Rotations.jl @@ -46,6 +46,8 @@ export # infinitesimal rotations InfinitesimalRotation, InfinitesimalRotMatrix, + InfinitesimalRotMatrix2, + InfinitesimalRotMatrix3, InfinitesimalAngle2d, InfinitesimalRotationVec, From 377294d642b02539fd8ed9fb460c9821301d5abc Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sun, 21 Nov 2021 00:54:59 +0900 Subject: [PATCH 17/29] fix type parameter in test --- test/infinitesimal.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/infinitesimal.jl b/test/infinitesimal.jl index db499afd..63cd18dc 100644 --- a/test/infinitesimal.jl +++ b/test/infinitesimal.jl @@ -78,14 +78,14 @@ R = InfinitesimalRotMatrix @test zero(T) + zero(R{N}) isa R{N, Float64} - @test zero(R{T}) + zero(T) isa R{N, Float64} + @test zero(R{N}) + zero(T) isa R{N, Float64} @test zero(T{Int}) + zero(R{N,Int}) isa R{N, Int} @test zero(R{N,Int}) + zero(T{Int}) isa R{N, Int} @test zero(T{Int}) + zero(T{BigFloat}) isa T{BigFloat} @test zero(T{BigFloat}) + zero(T{Int}) isa T{BigFloat} @test zero(T) - zero(R{N}) isa R{N, Float64} - @test zero(R{T}) - zero(T) isa R{N, Float64} + @test zero(R{N}) - zero(T) isa R{N, Float64} @test zero(T{Int}) - zero(R{N,Int}) isa R{N, Int} @test zero(R{N,Int}) - zero(T{Int}) isa R{N, Int} @test zero(T{Int}) - zero(T{BigFloat}) isa T{BigFloat} From 173c282f733724569e2e0cc1fd2cb0b1c727f944 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sun, 21 Nov 2021 01:48:24 +0900 Subject: [PATCH 18/29] update tests --- test/infinitesimal.jl | 65 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/test/infinitesimal.jl b/test/infinitesimal.jl index 63cd18dc..550a032a 100644 --- a/test/infinitesimal.jl +++ b/test/infinitesimal.jl @@ -4,12 +4,23 @@ types_2d = (InfinitesimalRotMatrix{2}, InfinitesimalAngle2d) types_3d = (InfinitesimalRotMatrix{3}, InfinitesimalRotationVec) + @testset "constructor" begin + m = rand(3,3) + s1 = InfinitesimalRotMatrix{3}(m - m') + s2 = InfinitesimalRotMatrix{3, BigFloat}(m - m') + @test s1 isa InfinitesimalRotMatrix{3, Float64} + @test s2 isa InfinitesimalRotMatrix{3, BigFloat} + end + @testset "zero" begin for T in all_types r = zero(T) @test r isa InfinitesimalRotation @test r === zero(r) @test zeros(T,2,3) == [zero(T) for i in 1:2, j in 1:3] + @test zeros(T{BigFloat},2,3) == [zero(T{BigFloat}) for i in 1:2, j in 1:3] + @test zeros(T,(2,3)) == [zero(T) for i in 1:2, j in 1:3] + @test zeros(T{BigFloat},(2,3)) == [zero(T{BigFloat}) for i in 1:2, j in 1:3] end end @@ -19,6 +30,19 @@ @test r isa SMatrix @test r == one(r) @test ones(T,2,3) == [one(T) for i in 1:2, j in 1:3] + @test ones(T{BigFloat},2,3) == [one(T{BigFloat}) for i in 1:2, j in 1:3] + @test ones(T,(2,3)) == [one(T) for i in 1:2, j in 1:3] + @test ones(T{BigFloat},(2,3)) == [one(T{BigFloat}) for i in 1:2, j in 1:3] + end + + for T in types_2d + r = one(T{BigFloat}) + @test r isa SMatrix{2,2,BigFloat} + end + + for T in types_3d + r = one(T{BigFloat}) + @test r isa SMatrix{3,3,BigFloat} end end @@ -54,6 +78,30 @@ end end + @testset "division" begin + for T in all_types + r = T(log(rand(typeof(exp(zero(T)))))) + a = 4.2 + @test r isa T + @test r/1 isa T + @test r/a isa T + + @test r/1 == r + @test r/2 + r/2 ≈ r + @test r/a == SMatrix(r)/a + end + end + + @testset "matrix multiplication" begin + for T in all_types + r = T(log(rand(typeof(exp(zero(T)))))) + @test r isa T + @test r*r isa SMatrix + @test r/r isa SMatrix + @test r^2 isa SMatrix + end + end + @testset "error case" begin for T in types_2d @test_throws BoundsError zero(InfinitesimalAngle2d)[5] @@ -96,4 +144,21 @@ @test 1.2 * zero(T{Int}) isa T{Float64} end end + + @testset "Testing show" begin + io = IOBuffer() + r = zero(InfinitesimalRotMatrix{2}) + show(io, MIME("text/plain"), r) + str = String(take!(io)) + if VERSION ≥ v"1.6" + @test startswith(str, "2×2 InfinitesimalRotMatrix2{Float64}") + else + @test startswith(str, "2×2 InfinitesimalRotMatrix{2,Float64,4}") + end + + rvec = InfinitesimalRotationVec(1.0, 2.0, 3.0) + show(io, MIME("text/plain"), rvec) + str = String(take!(io)) + @test startswith(str, "3×3 InfinitesimalRotationVec{Float64}") && occursin("(1.0, 2.0, 3.0):", str) + end end From 71de499d70b23d1b4c3eaf95cbba13985857bf4b Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sun, 21 Nov 2021 01:49:14 +0900 Subject: [PATCH 19/29] add Base.:/(r::InfinitesimalRotation, t::Number) --- src/infinitesimal.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/infinitesimal.jl b/src/infinitesimal.jl index 19bddac7..da435063 100644 --- a/src/infinitesimal.jl +++ b/src/infinitesimal.jl @@ -102,6 +102,7 @@ Base.:-(r::InfinitesimalRotMatrix) = InfinitesimalRotMatrix(-r.mat) @inline Base.:*(t::Number, r::InfinitesimalRotMatrix) = InfinitesimalRotMatrix(t*r.mat) @inline Base.:*(r::InfinitesimalRotMatrix, t::Number) = t*r +@inline Base.:/(r::InfinitesimalRotMatrix, t::Number) = InfinitesimalRotMatrix(r.mat/t) # Special case multiplication of 2×2 rotation matrices: speedup using skew-symmetricity @inline function Base.:+(r1::InfinitesimalRotMatrix{2}, r2::InfinitesimalRotMatrix{2}) @@ -150,6 +151,7 @@ end @inline Base.:-(r1::InfinitesimalAngle2d, r2::InfinitesimalAngle2d) = InfinitesimalAngle2d(r1.v - r2.v) @inline Base.:*(t::Number, r::InfinitesimalAngle2d) = InfinitesimalAngle2d(t*r.v) @inline Base.:*(r::InfinitesimalAngle2d, t::Number) = t*r +@inline Base.:/(r::InfinitesimalAngle2d, t::Number) = InfinitesimalAngle2d(r.v/t) @inline Base.:-(r::InfinitesimalAngle2d) = InfinitesimalAngle2d(-r.v) @inline function Base.getindex(r::InfinitesimalAngle2d{T}, i::Int) where T @@ -199,6 +201,7 @@ end @inline Base.:-(r1::InfinitesimalRotationVec, r2::InfinitesimalRotationVec) = InfinitesimalRotationVec(r1.x - r2.x, r1.y - r2.y, r1.z - r2.z) @inline Base.:*(t::Number, r::InfinitesimalRotationVec) = InfinitesimalRotationVec(t*r.x, t*r.y, t*r.z) @inline Base.:*(r::InfinitesimalRotationVec, t::Number) = t*r +@inline Base.:/(r::InfinitesimalRotationVec, t::Number) = InfinitesimalRotationVec(r.x/t, r.y/t, r.z/t) @inline Base.:-(r::InfinitesimalRotationVec) = InfinitesimalRotationVec(-r.x, -r.y, -r.z) @inline function Base.getindex(r::InfinitesimalRotationVec{T}, i::Int) where T From a859beb2cc36e5c8b9e8a6f7a389dcaef893521f Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sun, 21 Nov 2021 01:55:22 +0900 Subject: [PATCH 20/29] update comments --- test/infinitesimal.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/infinitesimal.jl b/test/infinitesimal.jl index 550a032a..03147fcc 100644 --- a/test/infinitesimal.jl +++ b/test/infinitesimal.jl @@ -48,6 +48,7 @@ @testset "minus" begin for T in all_types + # TODO: add rand method for InfinitesimalRotation r = T(log(rand(typeof(exp(zero(T)))))) @test r isa T @test -r isa T @@ -65,6 +66,7 @@ @testset "multiply" begin for T in all_types + # TODO: add rand method for InfinitesimalRotation r = T(log(rand(typeof(exp(zero(T)))))) a = 4.2 @test r isa T @@ -80,6 +82,7 @@ @testset "division" begin for T in all_types + # TODO: add rand method for InfinitesimalRotation r = T(log(rand(typeof(exp(zero(T)))))) a = 4.2 @test r isa T @@ -94,6 +97,7 @@ @testset "matrix multiplication" begin for T in all_types + # TODO: add rand method for InfinitesimalRotation r = T(log(rand(typeof(exp(zero(T)))))) @test r isa T @test r*r isa SMatrix From c6ce5cbdaa5c344ac093212419ebe8e0474860ba Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sun, 21 Nov 2021 02:07:37 +0900 Subject: [PATCH 21/29] update 2d infinitesimal rotation --- src/infinitesimal.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/infinitesimal.jl b/src/infinitesimal.jl index da435063..0d59f609 100644 --- a/src/infinitesimal.jl +++ b/src/infinitesimal.jl @@ -83,12 +83,12 @@ end Base.@propagate_inbounds Base.getindex(r::InfinitesimalRotMatrix, i::Int) = r.mat[i] @inline Base.Tuple(r::InfinitesimalRotMatrix) = Tuple(r.mat) -@inline InfinitesimalRotMatrix(θ::Real) = InfinitesimalRotMatrix{2}(θ) -@inline function (::Type{InfinitesimalRotMatrix{2}})(θ::Real) - InfinitesimalRotMatrix(@SMatrix [zero(θ) -θ; θ zero(θ)]) +@inline InfinitesimalRotMatrix(v::Number) = InfinitesimalRotMatrix{2}(v) +@inline function (::Type{InfinitesimalRotMatrix{2}})(v::Number) + InfinitesimalRotMatrix(@SMatrix [zero(v) -v; v zero(v)]) end -@inline function InfinitesimalRotMatrix{2,T}(θ::Real) where T - InfinitesimalRotMatrix(@SMatrix T[zero(θ) -θ; θ zero(θ)]) +@inline function InfinitesimalRotMatrix{2,T}(v::Number) where T + InfinitesimalRotMatrix(@SMatrix T[zero(v) -v; v zero(v)]) end # A rotation is more-or-less defined as being an orthogonal (or unitary) matrix From af3f7b26901fa49b3e270affc5a38c2c5cba4e61 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sun, 21 Nov 2021 02:20:22 +0900 Subject: [PATCH 22/29] update tests --- test/infinitesimal.jl | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/test/infinitesimal.jl b/test/infinitesimal.jl index 03147fcc..a3ffaa8c 100644 --- a/test/infinitesimal.jl +++ b/test/infinitesimal.jl @@ -4,7 +4,29 @@ types_2d = (InfinitesimalRotMatrix{2}, InfinitesimalAngle2d) types_3d = (InfinitesimalRotMatrix{3}, InfinitesimalRotationVec) - @testset "constructor" begin + @testset "constructor-2d" begin + m = rand(2,2) + s1 = InfinitesimalRotMatrix{2}(m - m') + s2 = InfinitesimalRotMatrix{2, BigFloat}(m - m') + s3 = InfinitesimalRotMatrix{2}(0) + s4 = InfinitesimalRotMatrix{2, BigFloat}(0) + s5 = InfinitesimalRotMatrix(0) + s6 = InfinitesimalRotMatrix(BigFloat(0)) + s7 = InfinitesimalAngle2d(0) + s8 = InfinitesimalAngle2d(BigFloat(0)) + s9 = InfinitesimalAngle2d{BigFloat}(0) + @test s1 isa InfinitesimalRotMatrix{2, Float64} + @test s2 isa InfinitesimalRotMatrix{2, BigFloat} + @test s3 isa InfinitesimalRotMatrix{2, Int} + @test s4 isa InfinitesimalRotMatrix{2, BigFloat} + @test s5 isa InfinitesimalRotMatrix{2, Int} + @test s6 isa InfinitesimalRotMatrix{2, BigFloat} + @test s7 isa InfinitesimalAngle2d{Int} + @test s8 isa InfinitesimalAngle2d{BigFloat} + @test s9 isa InfinitesimalAngle2d{BigFloat} + end + + @testset "constructor-3d" begin m = rand(3,3) s1 = InfinitesimalRotMatrix{3}(m - m') s2 = InfinitesimalRotMatrix{3, BigFloat}(m - m') @@ -121,6 +143,8 @@ @test_throws ErrorException zero(InfinitesimalRotation) @test_throws ErrorException one(InfinitesimalRotation) + @test_throws ErrorException zero(InfinitesimalRotMatrix) + @test_throws ErrorException one(InfinitesimalRotMatrix) @test_throws DimensionMismatch InfinitesimalAngle2d(1) + InfinitesimalRotationVec(2,3,4) end From 4faa47377b75289afe4747a6b32ab93df43279ee Mon Sep 17 00:00:00 2001 From: hyrodium Date: Sun, 21 Nov 2021 03:04:23 +0900 Subject: [PATCH 23/29] update tests --- test/infinitesimal.jl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/infinitesimal.jl b/test/infinitesimal.jl index a3ffaa8c..7a7f079a 100644 --- a/test/infinitesimal.jl +++ b/test/infinitesimal.jl @@ -66,6 +66,11 @@ r = one(T{BigFloat}) @test r isa SMatrix{3,3,BigFloat} end + + @test one(InfinitesimalRotation{2}) isa SMatrix{2, 2, Float64} + @test one(InfinitesimalRotation{2,BigFloat}) isa SMatrix{2, 2, BigFloat} + @test one(InfinitesimalRotation{3}) isa SMatrix{3, 3, Float64} + @test one(InfinitesimalRotation{3,BigFloat}) isa SMatrix{3, 3, BigFloat} end @testset "minus" begin From 50e98b345083fbbf67c6b9f2666923e6a93cd86e Mon Sep 17 00:00:00 2001 From: hyrodium Date: Mon, 22 Nov 2021 10:32:30 +0900 Subject: [PATCH 24/29] rename InfinitesimalRotation to RotationGenerator --- src/Rotations.jl | 12 +-- src/infinitesimal.jl | 184 +++++++++++++++++++++--------------------- src/logexp.jl | 16 ++-- test/infinitesimal.jl | 108 ++++++++++++------------- test/logexp.jl | 6 +- test/unitquat.jl | 2 +- 6 files changed, 164 insertions(+), 164 deletions(-) diff --git a/src/Rotations.jl b/src/Rotations.jl index af662516..742c5a77 100644 --- a/src/Rotations.jl +++ b/src/Rotations.jl @@ -44,12 +44,12 @@ export UnitQuaternion, # infinitesimal rotations - InfinitesimalRotation, - InfinitesimalRotMatrix, - InfinitesimalRotMatrix2, - InfinitesimalRotMatrix3, - InfinitesimalAngle2d, - InfinitesimalRotationVec, + RotationGenerator, + RotMatrixGenerator, + RotMatrixGenerator2, + RotMatrixGenerator3, + Angle2dGenerator, + RotationVecGenerator, # Quaternion math ops logm, expm, ⊖, ⊕, diff --git a/src/infinitesimal.jl b/src/infinitesimal.jl index 0d59f609..7f6698e9 100644 --- a/src/infinitesimal.jl +++ b/src/infinitesimal.jl @@ -1,46 +1,46 @@ """ - abstract type InfinitesimalRotation{N,T} <: StaticMatrix{N,N,T} + abstract type RotationGenerator{N,T} <: StaticMatrix{N,N,T} -An abstract type representing `N`-dimensional infinitesimal rotations. More abstractly, they represent +An abstract type representing `N`-dimensional rotation generator. More abstractly, they represent skew-symmetric real `N`×`N` matrices. """ -abstract type InfinitesimalRotation{N,T} <: StaticMatrix{N,N,T} end +abstract type RotationGenerator{N,T} <: StaticMatrix{N,N,T} end -Base.@pure StaticArrays.Size(::Type{InfinitesimalRotation{N}}) where {N} = Size(N,N) -Base.@pure StaticArrays.Size(::Type{InfinitesimalRotation{N,T}}) where {N,T} = Size(N,N) -Base.@pure StaticArrays.Size(::Type{R}) where {R<:InfinitesimalRotation} = Size(supertype(R)) -Base.adjoint(r::InfinitesimalRotation) = -r -Base.transpose(r::InfinitesimalRotation{N,T}) where {N,T<:Real} = -r +Base.@pure StaticArrays.Size(::Type{RotationGenerator{N}}) where {N} = Size(N,N) +Base.@pure StaticArrays.Size(::Type{RotationGenerator{N,T}}) where {N,T} = Size(N,N) +Base.@pure StaticArrays.Size(::Type{R}) where {R<:RotationGenerator} = Size(supertype(R)) +Base.adjoint(r::RotationGenerator) = -r +Base.transpose(r::RotationGenerator{N,T}) where {N,T<:Real} = -r # Generate identity-matrix with SMatrix -# Note that ones(InfinitesimalRotation3,dims...) is not Array{<:InfinitesimalRotation} but Array{<:StaticMatrix{3,3}} -Base.one(::InfinitesimalRotation{N,T}) where {N,T} = one(SMatrix{N,N,T}) -Base.one(::Type{InfinitesimalRotation}) = error("The dimension of rotation is not specified.") -Base.one(::Type{<:InfinitesimalRotation{N}}) where N = one(SMatrix{N,N}) -Base.one(::Type{<:InfinitesimalRotation{N,T}}) where {N,T} = one(SMatrix{N,N,T}) -Base.ones(::Type{R}) where {R<:InfinitesimalRotation} = ones(R, ()) # avoid StaticArray constructor -Base.ones(::Type{R}, dims::Base.DimOrInd...) where {R<:InfinitesimalRotation} = ones(typeof(one(R)),dims...) -Base.ones(::Type{R}, dims::NTuple{N, Integer}) where {R<:InfinitesimalRotation, N} = ones(typeof(one(R)),dims) - -# Generate identity rotation matrix -Base.zero(r::InfinitesimalRotation) = zero(typeof(r)) +# Note that ones(RotationGenerator3,dims...) is not Array{<:RotationGenerator} but Array{<:StaticMatrix{3,3}} +Base.one(::RotationGenerator{N,T}) where {N,T} = one(SMatrix{N,N,T}) +Base.one(::Type{RotationGenerator}) = error("The dimension of rotation is not specified.") +Base.one(::Type{<:RotationGenerator{N}}) where N = one(SMatrix{N,N}) +Base.one(::Type{<:RotationGenerator{N,T}}) where {N,T} = one(SMatrix{N,N,T}) +Base.ones(::Type{R}) where {R<:RotationGenerator} = ones(R, ()) # avoid StaticArray constructor +Base.ones(::Type{R}, dims::Base.DimOrInd...) where {R<:RotationGenerator} = ones(typeof(one(R)),dims...) +Base.ones(::Type{R}, dims::NTuple{N, Integer}) where {R<:RotationGenerator, N} = ones(typeof(one(R)),dims) + +# Generate zero rotation matrix +Base.zero(r::RotationGenerator) = zero(typeof(r)) # difference -Base.:-(r1::InfinitesimalRotation, r2::InfinitesimalRotation) = r1 + (-r2) +Base.:-(r1::RotationGenerator, r2::RotationGenerator) = r1 + (-r2) # `convert` goes through the constructors, similar to e.g. `Number` -Base.convert(::Type{R}, rot::InfinitesimalRotation{N}) where {N,R<:InfinitesimalRotation{N}} = R(rot) +Base.convert(::Type{R}, rot::RotationGenerator{N}) where {N,R<:RotationGenerator{N}} = R(rot) -# InfinitesimalRotation matrices should be skew-symmetric. Only the operations we define, -# like addition, will stay as InfinitesimalRotations, otherwise users will get an +# RotationGenerator matrices should be skew-symmetric. Only the operations we define, +# like addition, will stay as RotationGenerators, otherwise users will get an # SMatrix{3,3} (e.g. rot1 * rot2 -> SMatrix) -Base.@pure StaticArrays.similar_type(::Union{R,Type{R}}) where {R <: InfinitesimalRotation} = SMatrix{size(R)..., eltype(R), prod(size(R))} -Base.@pure StaticArrays.similar_type(::Union{R,Type{R}}, ::Type{T}) where {R <: InfinitesimalRotation, T} = SMatrix{size(R)..., T, prod(size(R))} +Base.@pure StaticArrays.similar_type(::Union{R,Type{R}}) where {R <: RotationGenerator} = SMatrix{size(R)..., eltype(R), prod(size(R))} +Base.@pure StaticArrays.similar_type(::Union{R,Type{R}}, ::Type{T}) where {R <: RotationGenerator, T} = SMatrix{size(R)..., T, prod(size(R))} # Useful for converting arrays of rotations to another rotation eltype, for instance. # Only works because parameters of all the rotations are of a similar form # Would need to be more sophisticated if we have arbitrary dimensions, etc -@inline function Base.promote_op(::Type{R1}, ::Type{R2}) where {R1 <: InfinitesimalRotation, R2 <: InfinitesimalRotation} +@inline function Base.promote_op(::Type{R1}, ::Type{R2}) where {R1 <: RotationGenerator, R2 <: RotationGenerator} size(R1) == size(R2) || throw(DimensionMismatch("cannot promote rotations of $(size(R1)[1]) and $(size(R2)[1]) dimensions")) if isleaftype(R1) return R1 @@ -52,68 +52,68 @@ end ################################################################################ ################################################################################ """ - struct InfinitesimalRotMatrix{N,T} <: InfinitesimalRotation{N,T} + struct RotMatrixGenerator{N,T} <: RotationGenerator{N,T} A statically-sized, N×N skew-symmetric matrix. Note: the skew-symmetricity of the input matrix is *not* checked by the constructor. """ -struct InfinitesimalRotMatrix{N,T,L} <: InfinitesimalRotation{N,T} # which is <: AbstractMatrix{T} +struct RotMatrixGenerator{N,T,L} <: RotationGenerator{N,T} # which is <: AbstractMatrix{T} mat::SMatrix{N, N, T, L} # The final parameter to SMatrix is the "length" of the matrix, 3 × 3 = 9 - InfinitesimalRotMatrix{N,T,L}(x::AbstractArray) where {N,T,L} = new{N,T,L}(convert(SMatrix{N,N,T,L}, x)) + RotMatrixGenerator{N,T,L}(x::AbstractArray) where {N,T,L} = new{N,T,L}(convert(SMatrix{N,N,T,L}, x)) # fixes #49 ambiguity introduced in StaticArrays 0.6.5 - InfinitesimalRotMatrix{N,T,L}(x::StaticArray) where {N,T,L} = new{N,T,L}(convert(SMatrix{N,N,T,L}, x)) + RotMatrixGenerator{N,T,L}(x::StaticArray) where {N,T,L} = new{N,T,L}(convert(SMatrix{N,N,T,L}, x)) end -InfinitesimalRotMatrix(x::SMatrix{N,N,T,L}) where {N,T,L} = InfinitesimalRotMatrix{N,T,L}(x) +RotMatrixGenerator(x::SMatrix{N,N,T,L}) where {N,T,L} = RotMatrixGenerator{N,T,L}(x) -Base.zero(::Type{InfinitesimalRotMatrix}) = error("The dimension of rotation is not specified.") +Base.zero(::Type{RotMatrixGenerator}) = error("The dimension of rotation is not specified.") # These functions (plus size) are enough to satisfy the entire StaticArrays interface: for N = 2:3 L = N*N - InfinitesimalRotMatrixN = Symbol(:InfinitesimalRotMatrix, N) + RotMatrixGeneratorN = Symbol(:RotMatrixGenerator, N) @eval begin - @inline InfinitesimalRotMatrix(t::NTuple{$L}) = InfinitesimalRotMatrix(SMatrix{$N,$N}(t)) - @inline (::Type{InfinitesimalRotMatrix{$N}})(t::NTuple{$L}) = InfinitesimalRotMatrix(SMatrix{$N,$N}(t)) - @inline InfinitesimalRotMatrix{$N,T}(t::NTuple{$L}) where {T} = InfinitesimalRotMatrix(SMatrix{$N,$N,T}(t)) - @inline InfinitesimalRotMatrix{$N,T,$L}(t::NTuple{$L}) where {T} = InfinitesimalRotMatrix(SMatrix{$N,$N,T}(t)) - const $InfinitesimalRotMatrixN{T} = InfinitesimalRotMatrix{$N, T, $L} + @inline RotMatrixGenerator(t::NTuple{$L}) = RotMatrixGenerator(SMatrix{$N,$N}(t)) + @inline (::Type{RotMatrixGenerator{$N}})(t::NTuple{$L}) = RotMatrixGenerator(SMatrix{$N,$N}(t)) + @inline RotMatrixGenerator{$N,T}(t::NTuple{$L}) where {T} = RotMatrixGenerator(SMatrix{$N,$N,T}(t)) + @inline RotMatrixGenerator{$N,T,$L}(t::NTuple{$L}) where {T} = RotMatrixGenerator(SMatrix{$N,$N,T}(t)) + const $RotMatrixGeneratorN{T} = RotMatrixGenerator{$N, T, $L} end end -Base.@propagate_inbounds Base.getindex(r::InfinitesimalRotMatrix, i::Int) = r.mat[i] -@inline Base.Tuple(r::InfinitesimalRotMatrix) = Tuple(r.mat) +Base.@propagate_inbounds Base.getindex(r::RotMatrixGenerator, i::Int) = r.mat[i] +@inline Base.Tuple(r::RotMatrixGenerator) = Tuple(r.mat) -@inline InfinitesimalRotMatrix(v::Number) = InfinitesimalRotMatrix{2}(v) -@inline function (::Type{InfinitesimalRotMatrix{2}})(v::Number) - InfinitesimalRotMatrix(@SMatrix [zero(v) -v; v zero(v)]) +@inline RotMatrixGenerator(v::Number) = RotMatrixGenerator{2}(v) +@inline function (::Type{RotMatrixGenerator{2}})(v::Number) + RotMatrixGenerator(@SMatrix [zero(v) -v; v zero(v)]) end -@inline function InfinitesimalRotMatrix{2,T}(v::Number) where T - InfinitesimalRotMatrix(@SMatrix T[zero(v) -v; v zero(v)]) +@inline function RotMatrixGenerator{2,T}(v::Number) where T + RotMatrixGenerator(@SMatrix T[zero(v) -v; v zero(v)]) end # A rotation is more-or-less defined as being an orthogonal (or unitary) matrix -Base.:-(r::InfinitesimalRotMatrix) = InfinitesimalRotMatrix(-r.mat) +Base.:-(r::RotMatrixGenerator) = RotMatrixGenerator(-r.mat) -# By default, composition of rotations will go through InfinitesimalRotMatrix, unless overridden -@inline Base.:+(r1::InfinitesimalRotation, r2::InfinitesimalRotation) = InfinitesimalRotMatrix(r1) + InfinitesimalRotMatrix(r2) -@inline Base.:+(r1::InfinitesimalRotMatrix, r2::InfinitesimalRotation) = r1 + InfinitesimalRotMatrix(r2) -@inline Base.:+(r1::InfinitesimalRotation, r2::InfinitesimalRotMatrix) = InfinitesimalRotMatrix(r1) + r2 -@inline Base.:+(r1::InfinitesimalRotMatrix, r2::InfinitesimalRotMatrix) = InfinitesimalRotMatrix(r1.mat + r2.mat) +# By default, composition of rotations will go through RotMatrixGenerator, unless overridden +@inline Base.:+(r1::RotationGenerator, r2::RotationGenerator) = RotMatrixGenerator(r1) + RotMatrixGenerator(r2) +@inline Base.:+(r1::RotMatrixGenerator, r2::RotationGenerator) = r1 + RotMatrixGenerator(r2) +@inline Base.:+(r1::RotationGenerator, r2::RotMatrixGenerator) = RotMatrixGenerator(r1) + r2 +@inline Base.:+(r1::RotMatrixGenerator, r2::RotMatrixGenerator) = RotMatrixGenerator(r1.mat + r2.mat) -@inline Base.:*(t::Number, r::InfinitesimalRotMatrix) = InfinitesimalRotMatrix(t*r.mat) -@inline Base.:*(r::InfinitesimalRotMatrix, t::Number) = t*r -@inline Base.:/(r::InfinitesimalRotMatrix, t::Number) = InfinitesimalRotMatrix(r.mat/t) +@inline Base.:*(t::Number, r::RotMatrixGenerator) = RotMatrixGenerator(t*r.mat) +@inline Base.:*(r::RotMatrixGenerator, t::Number) = t*r +@inline Base.:/(r::RotMatrixGenerator, t::Number) = RotMatrixGenerator(r.mat/t) # Special case multiplication of 2×2 rotation matrices: speedup using skew-symmetricity -@inline function Base.:+(r1::InfinitesimalRotMatrix{2}, r2::InfinitesimalRotMatrix{2}) +@inline function Base.:+(r1::RotMatrixGenerator{2}, r2::RotMatrixGenerator{2}) v = r1[2,1]+r2[2,1] s = @SMatrix [0 -v v 0] - return InfinitesimalRotMatrix(s) + return RotMatrixGenerator(s) end # Special case multiplication of 3×3 rotation matrices: speedup using skew-symmetricity -@inline function Base.:+(r1::InfinitesimalRotMatrix{3}, r2::InfinitesimalRotMatrix{3}) +@inline function Base.:+(r1::RotMatrixGenerator{3}, r2::RotMatrixGenerator{3}) x = r1[6]+r2[6] y = r1[7]+r2[7] z = r1[2]+r2[2] @@ -121,40 +121,40 @@ end z 0 -x -y x 0] - return InfinitesimalRotMatrix(s) + return RotMatrixGenerator(s) end """ - struct InfinitesimalAngle2d{T} <: InfinitesimalRotation{2,T} + struct Angle2dGenerator{T} <: RotationGenerator{2,T} v::T end -A 2×2 infinitesimal rotation matrix (i.e. skew-symmetric matrix). +A 2×2 rotation generator matrix (i.e. skew-symmetric matrix). [ 0 -v v 0 ] """ -struct InfinitesimalAngle2d{T} <: InfinitesimalRotation{2,T} +struct Angle2dGenerator{T} <: RotationGenerator{2,T} v::T - InfinitesimalAngle2d{T}(r) where T = new{T}(r) + Angle2dGenerator{T}(r) where T = new{T}(r) end -@inline function InfinitesimalAngle2d(r::T) where T <: Number - InfinitesimalAngle2d{T}(r) +@inline function Angle2dGenerator(r::T) where T <: Number + Angle2dGenerator{T}(r) end -@inline InfinitesimalAngle2d(r::InfinitesimalRotation{2}) = InfinitesimalAngle2d(r[2,1]) -@inline InfinitesimalAngle2d{T}(r::InfinitesimalRotation{2}) where {T} = InfinitesimalAngle2d{T}(r[2,1]) +@inline Angle2dGenerator(r::RotationGenerator{2}) = Angle2dGenerator(r[2,1]) +@inline Angle2dGenerator{T}(r::RotationGenerator{2}) where {T} = Angle2dGenerator{T}(r[2,1]) -@inline Base.zero(::Type{A}) where {A<: InfinitesimalAngle2d} = A(0.0) +@inline Base.zero(::Type{A}) where {A<: Angle2dGenerator} = A(0.0) -@inline Base.:+(r1::InfinitesimalAngle2d, r2::InfinitesimalAngle2d) = InfinitesimalAngle2d(r1.v + r2.v) -@inline Base.:-(r1::InfinitesimalAngle2d, r2::InfinitesimalAngle2d) = InfinitesimalAngle2d(r1.v - r2.v) -@inline Base.:*(t::Number, r::InfinitesimalAngle2d) = InfinitesimalAngle2d(t*r.v) -@inline Base.:*(r::InfinitesimalAngle2d, t::Number) = t*r -@inline Base.:/(r::InfinitesimalAngle2d, t::Number) = InfinitesimalAngle2d(r.v/t) -@inline Base.:-(r::InfinitesimalAngle2d) = InfinitesimalAngle2d(-r.v) +@inline Base.:+(r1::Angle2dGenerator, r2::Angle2dGenerator) = Angle2dGenerator(r1.v + r2.v) +@inline Base.:-(r1::Angle2dGenerator, r2::Angle2dGenerator) = Angle2dGenerator(r1.v - r2.v) +@inline Base.:*(t::Number, r::Angle2dGenerator) = Angle2dGenerator(t*r.v) +@inline Base.:*(r::Angle2dGenerator, t::Number) = t*r +@inline Base.:/(r::Angle2dGenerator, t::Number) = Angle2dGenerator(r.v/t) +@inline Base.:-(r::Angle2dGenerator) = Angle2dGenerator(-r.v) -@inline function Base.getindex(r::InfinitesimalAngle2d{T}, i::Int) where T +@inline function Base.getindex(r::Angle2dGenerator{T}, i::Int) where T if i == 1 zero(T) elseif i == 2 @@ -170,41 +170,41 @@ end """ - struct InfinitesimalRotationVec{T} <: InfinitesimalRotation{2,T} + struct RotationVecGenerator{T} <: RotationGenerator{2,T} x::T y::T z::T end -A 3×3 infinitesimal rotation matrix (i.e. skew-symmetric matrix). +A 3×3 rotation generator matrix (i.e. skew-symmetric matrix). [ 0 -z y z 0 -x -y x 0] """ -struct InfinitesimalRotationVec{T} <: InfinitesimalRotation{3,T} +struct RotationVecGenerator{T} <: RotationGenerator{3,T} x::T y::T z::T - InfinitesimalRotationVec{T}(x,y,z) where T = new{T}(x,y,z) + RotationVecGenerator{T}(x,y,z) where T = new{T}(x,y,z) end -@inline function InfinitesimalRotationVec(x::X,y::Y,z::Z) where {X<:Number, Y<:Number, Z<:Number} - InfinitesimalRotationVec{promote_type(X,Y,Z)}(x, y, z) +@inline function RotationVecGenerator(x::X,y::Y,z::Z) where {X<:Number, Y<:Number, Z<:Number} + RotationVecGenerator{promote_type(X,Y,Z)}(x, y, z) end -@inline InfinitesimalRotationVec(r::InfinitesimalRotation{3}) = InfinitesimalRotationVec(r[6], r[7], r[2]) -@inline InfinitesimalRotationVec{T}(r::InfinitesimalRotation{3}) where {T} = InfinitesimalRotationVec{T}(r[6], r[7], r[2]) +@inline RotationVecGenerator(r::RotationGenerator{3}) = RotationVecGenerator(r[6], r[7], r[2]) +@inline RotationVecGenerator{T}(r::RotationGenerator{3}) where {T} = RotationVecGenerator{T}(r[6], r[7], r[2]) -@inline Base.zero(::Type{R}) where {R<: InfinitesimalRotationVec} = R(0.0,0.0,0.0) +@inline Base.zero(::Type{R}) where {R<: RotationVecGenerator} = R(0.0,0.0,0.0) -@inline Base.:+(r1::InfinitesimalRotationVec, r2::InfinitesimalRotationVec) = InfinitesimalRotationVec(r1.x + r2.x, r1.y + r2.y, r1.z + r2.z) -@inline Base.:-(r1::InfinitesimalRotationVec, r2::InfinitesimalRotationVec) = InfinitesimalRotationVec(r1.x - r2.x, r1.y - r2.y, r1.z - r2.z) -@inline Base.:*(t::Number, r::InfinitesimalRotationVec) = InfinitesimalRotationVec(t*r.x, t*r.y, t*r.z) -@inline Base.:*(r::InfinitesimalRotationVec, t::Number) = t*r -@inline Base.:/(r::InfinitesimalRotationVec, t::Number) = InfinitesimalRotationVec(r.x/t, r.y/t, r.z/t) -@inline Base.:-(r::InfinitesimalRotationVec) = InfinitesimalRotationVec(-r.x, -r.y, -r.z) +@inline Base.:+(r1::RotationVecGenerator, r2::RotationVecGenerator) = RotationVecGenerator(r1.x + r2.x, r1.y + r2.y, r1.z + r2.z) +@inline Base.:-(r1::RotationVecGenerator, r2::RotationVecGenerator) = RotationVecGenerator(r1.x - r2.x, r1.y - r2.y, r1.z - r2.z) +@inline Base.:*(t::Number, r::RotationVecGenerator) = RotationVecGenerator(t*r.x, t*r.y, t*r.z) +@inline Base.:*(r::RotationVecGenerator, t::Number) = t*r +@inline Base.:/(r::RotationVecGenerator, t::Number) = RotationVecGenerator(r.x/t, r.y/t, r.z/t) +@inline Base.:-(r::RotationVecGenerator) = RotationVecGenerator(-r.x, -r.y, -r.z) -@inline function Base.getindex(r::InfinitesimalRotationVec{T}, i::Int) where T +@inline function Base.getindex(r::RotationVecGenerator{T}, i::Int) where T if i == 1 zero(T) elseif i == 2 @@ -235,12 +235,12 @@ end # A simplification and specialization of the Base.show function for AbstractArray makes # everything sensible at the REPL. -function Base.show(io::IO, ::MIME"text/plain", X::InfinitesimalRotation) +function Base.show(io::IO, ::MIME"text/plain", X::RotationGenerator) if !haskey(io, :compact) io = IOContext(io, :compact => true) end summary(io, X) - if !isa(X, InfinitesimalRotMatrix) + if !isa(X, RotMatrixGenerator) n_fields = length(fieldnames(typeof(X))) print(io, "(") for i = 1:n_fields diff --git a/src/logexp.jl b/src/logexp.jl index 718d9cd6..a2e68921 100644 --- a/src/logexp.jl +++ b/src/logexp.jl @@ -2,7 +2,7 @@ # 3d function Base.log(R::RotationVec) x, y, z = params(R) - return InfinitesimalRotationVec(x,y,z) + return RotationVecGenerator(x,y,z) end function Base.log(R::Rotation{3}) @@ -13,7 +13,7 @@ end # 2d function Base.log(R::Angle2d) θ, = params(R) - return InfinitesimalAngle2d(θ) + return Angle2dGenerator(θ) end function Base.log(R::Rotation{2}) @@ -23,20 +23,20 @@ end ## exp # 3d -function Base.exp(R::InfinitesimalRotationVec) +function Base.exp(R::RotationVecGenerator) return RotationVec(R.x,R.y,R.z) end -function Base.exp(R::InfinitesimalRotation{3}) - exp(InfinitesimalRotationVec(R)) +function Base.exp(R::RotationGenerator{3}) + exp(RotationVecGenerator(R)) end # 2d -function Base.exp(R::InfinitesimalAngle2d) +function Base.exp(R::Angle2dGenerator) return Angle2d(R.v) end -function Base.exp(R::InfinitesimalRotation{2}) - exp(InfinitesimalAngle2d(R)) +function Base.exp(R::RotationGenerator{2}) + exp(Angle2dGenerator(R)) end diff --git a/test/infinitesimal.jl b/test/infinitesimal.jl index 7a7f079a..71356dd0 100644 --- a/test/infinitesimal.jl +++ b/test/infinitesimal.jl @@ -1,43 +1,43 @@ -@testset "infinitesimal" begin - all_types = (InfinitesimalRotMatrix{3}, InfinitesimalRotationVec, - InfinitesimalRotMatrix{2}, InfinitesimalAngle2d) - types_2d = (InfinitesimalRotMatrix{2}, InfinitesimalAngle2d) - types_3d = (InfinitesimalRotMatrix{3}, InfinitesimalRotationVec) +@testset "rotation generator" begin + all_types = (RotMatrixGenerator{3}, RotationVecGenerator, + RotMatrixGenerator{2}, Angle2dGenerator) + types_2d = (RotMatrixGenerator{2}, Angle2dGenerator) + types_3d = (RotMatrixGenerator{3}, RotationVecGenerator) @testset "constructor-2d" begin m = rand(2,2) - s1 = InfinitesimalRotMatrix{2}(m - m') - s2 = InfinitesimalRotMatrix{2, BigFloat}(m - m') - s3 = InfinitesimalRotMatrix{2}(0) - s4 = InfinitesimalRotMatrix{2, BigFloat}(0) - s5 = InfinitesimalRotMatrix(0) - s6 = InfinitesimalRotMatrix(BigFloat(0)) - s7 = InfinitesimalAngle2d(0) - s8 = InfinitesimalAngle2d(BigFloat(0)) - s9 = InfinitesimalAngle2d{BigFloat}(0) - @test s1 isa InfinitesimalRotMatrix{2, Float64} - @test s2 isa InfinitesimalRotMatrix{2, BigFloat} - @test s3 isa InfinitesimalRotMatrix{2, Int} - @test s4 isa InfinitesimalRotMatrix{2, BigFloat} - @test s5 isa InfinitesimalRotMatrix{2, Int} - @test s6 isa InfinitesimalRotMatrix{2, BigFloat} - @test s7 isa InfinitesimalAngle2d{Int} - @test s8 isa InfinitesimalAngle2d{BigFloat} - @test s9 isa InfinitesimalAngle2d{BigFloat} + s1 = RotMatrixGenerator{2}(m - m') + s2 = RotMatrixGenerator{2, BigFloat}(m - m') + s3 = RotMatrixGenerator{2}(0) + s4 = RotMatrixGenerator{2, BigFloat}(0) + s5 = RotMatrixGenerator(0) + s6 = RotMatrixGenerator(BigFloat(0)) + s7 = Angle2dGenerator(0) + s8 = Angle2dGenerator(BigFloat(0)) + s9 = Angle2dGenerator{BigFloat}(0) + @test s1 isa RotMatrixGenerator{2, Float64} + @test s2 isa RotMatrixGenerator{2, BigFloat} + @test s3 isa RotMatrixGenerator{2, Int} + @test s4 isa RotMatrixGenerator{2, BigFloat} + @test s5 isa RotMatrixGenerator{2, Int} + @test s6 isa RotMatrixGenerator{2, BigFloat} + @test s7 isa Angle2dGenerator{Int} + @test s8 isa Angle2dGenerator{BigFloat} + @test s9 isa Angle2dGenerator{BigFloat} end @testset "constructor-3d" begin m = rand(3,3) - s1 = InfinitesimalRotMatrix{3}(m - m') - s2 = InfinitesimalRotMatrix{3, BigFloat}(m - m') - @test s1 isa InfinitesimalRotMatrix{3, Float64} - @test s2 isa InfinitesimalRotMatrix{3, BigFloat} + s1 = RotMatrixGenerator{3}(m - m') + s2 = RotMatrixGenerator{3, BigFloat}(m - m') + @test s1 isa RotMatrixGenerator{3, Float64} + @test s2 isa RotMatrixGenerator{3, BigFloat} end @testset "zero" begin for T in all_types r = zero(T) - @test r isa InfinitesimalRotation + @test r isa RotationGenerator @test r === zero(r) @test zeros(T,2,3) == [zero(T) for i in 1:2, j in 1:3] @test zeros(T{BigFloat},2,3) == [zero(T{BigFloat}) for i in 1:2, j in 1:3] @@ -67,15 +67,15 @@ @test r isa SMatrix{3,3,BigFloat} end - @test one(InfinitesimalRotation{2}) isa SMatrix{2, 2, Float64} - @test one(InfinitesimalRotation{2,BigFloat}) isa SMatrix{2, 2, BigFloat} - @test one(InfinitesimalRotation{3}) isa SMatrix{3, 3, Float64} - @test one(InfinitesimalRotation{3,BigFloat}) isa SMatrix{3, 3, BigFloat} + @test one(RotationGenerator{2}) isa SMatrix{2, 2, Float64} + @test one(RotationGenerator{2,BigFloat}) isa SMatrix{2, 2, BigFloat} + @test one(RotationGenerator{3}) isa SMatrix{3, 3, Float64} + @test one(RotationGenerator{3,BigFloat}) isa SMatrix{3, 3, BigFloat} end @testset "minus" begin for T in all_types - # TODO: add rand method for InfinitesimalRotation + # TODO: add rand method for RotationGenerator r = T(log(rand(typeof(exp(zero(T)))))) @test r isa T @test -r isa T @@ -93,7 +93,7 @@ @testset "multiply" begin for T in all_types - # TODO: add rand method for InfinitesimalRotation + # TODO: add rand method for RotationGenerator r = T(log(rand(typeof(exp(zero(T)))))) a = 4.2 @test r isa T @@ -109,7 +109,7 @@ @testset "division" begin for T in all_types - # TODO: add rand method for InfinitesimalRotation + # TODO: add rand method for RotationGenerator r = T(log(rand(typeof(exp(zero(T)))))) a = 4.2 @test r isa T @@ -124,7 +124,7 @@ @testset "matrix multiplication" begin for T in all_types - # TODO: add rand method for InfinitesimalRotation + # TODO: add rand method for RotationGenerator r = T(log(rand(typeof(exp(zero(T)))))) @test r isa T @test r*r isa SMatrix @@ -135,28 +135,28 @@ @testset "error case" begin for T in types_2d - @test_throws BoundsError zero(InfinitesimalAngle2d)[5] - @test_throws BoundsError zero(InfinitesimalAngle2d)[2,3] - @test_throws BoundsError zero(InfinitesimalAngle2d)[3,1] + @test_throws BoundsError zero(Angle2dGenerator)[5] + @test_throws BoundsError zero(Angle2dGenerator)[2,3] + @test_throws BoundsError zero(Angle2dGenerator)[3,1] end for T in types_3d - @test_throws BoundsError zero(InfinitesimalAngle2d)[10] - @test_throws BoundsError zero(InfinitesimalAngle2d)[2,4] - @test_throws BoundsError zero(InfinitesimalAngle2d)[4,1] + @test_throws BoundsError zero(Angle2dGenerator)[10] + @test_throws BoundsError zero(Angle2dGenerator)[2,4] + @test_throws BoundsError zero(Angle2dGenerator)[4,1] end - @test_throws ErrorException zero(InfinitesimalRotation) - @test_throws ErrorException one(InfinitesimalRotation) - @test_throws ErrorException zero(InfinitesimalRotMatrix) - @test_throws ErrorException one(InfinitesimalRotMatrix) + @test_throws ErrorException zero(RotationGenerator) + @test_throws ErrorException one(RotationGenerator) + @test_throws ErrorException zero(RotMatrixGenerator) + @test_throws ErrorException one(RotMatrixGenerator) - @test_throws DimensionMismatch InfinitesimalAngle2d(1) + InfinitesimalRotationVec(2,3,4) + @test_throws DimensionMismatch Angle2dGenerator(1) + RotationVecGenerator(2,3,4) end @testset "type promotion" begin - for (T, N) in ((InfinitesimalAngle2d, 2), (InfinitesimalRotationVec, 3)) - R = InfinitesimalRotMatrix + for (T, N) in ((Angle2dGenerator, 2), (RotationVecGenerator, 3)) + R = RotMatrixGenerator @test zero(T) + zero(R{N}) isa R{N, Float64} @test zero(R{N}) + zero(T) isa R{N, Float64} @@ -180,18 +180,18 @@ @testset "Testing show" begin io = IOBuffer() - r = zero(InfinitesimalRotMatrix{2}) + r = zero(RotMatrixGenerator{2}) show(io, MIME("text/plain"), r) str = String(take!(io)) if VERSION ≥ v"1.6" - @test startswith(str, "2×2 InfinitesimalRotMatrix2{Float64}") + @test startswith(str, "2×2 RotMatrixGenerator2{Float64}") else - @test startswith(str, "2×2 InfinitesimalRotMatrix{2,Float64,4}") + @test startswith(str, "2×2 RotMatrixGenerator{2,Float64,4}") end - rvec = InfinitesimalRotationVec(1.0, 2.0, 3.0) + rvec = RotationVecGenerator(1.0, 2.0, 3.0) show(io, MIME("text/plain"), rvec) str = String(take!(io)) - @test startswith(str, "3×3 InfinitesimalRotationVec{Float64}") && occursin("(1.0, 2.0, 3.0):", str) + @test startswith(str, "3×3 RotationVecGenerator{Float64}") && occursin("(1.0, 2.0, 3.0):", str) end end diff --git a/test/logexp.jl b/test/logexp.jl index 2978e9b2..569e06fa 100644 --- a/test/logexp.jl +++ b/test/logexp.jl @@ -10,14 +10,14 @@ @testset "$(T)" for T in all_types, F in (one, rand) R = F(T) @test R ≈ exp(log(R)) - @test log(R) isa InfinitesimalRotation + @test log(R) isa RotationGenerator @test exp(log(R)) isa Rotation end end @testset "exp(zero)" begin - all_types = (InfinitesimalRotMatrix{3}, InfinitesimalRotationVec, - InfinitesimalRotMatrix{2}, InfinitesimalAngle2d) + all_types = (RotMatrixGenerator{3}, RotationVecGenerator, + RotMatrixGenerator{2}, Angle2dGenerator) @testset "$(T)" for T in all_types r = zero(T) diff --git a/test/unitquat.jl b/test/unitquat.jl index cef14206..99d64fd1 100644 --- a/test/unitquat.jl +++ b/test/unitquat.jl @@ -129,7 +129,7 @@ import Rotations: vmat, rmult, lmult, hmat, tmat q32 = rand(QuatRotation{Float32}) @test Rotations._log_as_quat(q32) isa Quaternion{Float32} - @test log(q32) isa InfinitesimalRotation{3} + @test log(q32) isa RotationGenerator{3} @test eltype(logm(q32)) == Float32 @test expm(logm(q32)) ≈ q32 From 77b10f157cace8f55346e205252fb12af10ebf88 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Mon, 22 Nov 2021 10:33:51 +0900 Subject: [PATCH 25/29] rename files --- src/Rotations.jl | 4 ++-- src/{infinitesimal.jl => rotation_generator.jl} | 0 test/{infinitesimal.jl => rotation_generator.jl} | 0 test/runtests.jl | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename src/{infinitesimal.jl => rotation_generator.jl} (100%) rename test/{infinitesimal.jl => rotation_generator.jl} (100%) diff --git a/src/Rotations.jl b/src/Rotations.jl index 742c5a77..455ce6e6 100644 --- a/src/Rotations.jl +++ b/src/Rotations.jl @@ -24,7 +24,7 @@ include("principal_value.jl") include("rodrigues_params.jl") include("error_maps.jl") include("rotation_error.jl") -include("infinitesimal.jl") +include("rotation_generator.jl") include("logexp.jl") include("eigen.jl") include("deprecated.jl") @@ -43,7 +43,7 @@ export # Deprecated, but export for compatibility UnitQuaternion, - # infinitesimal rotations + # rotation generators RotationGenerator, RotMatrixGenerator, RotMatrixGenerator2, diff --git a/src/infinitesimal.jl b/src/rotation_generator.jl similarity index 100% rename from src/infinitesimal.jl rename to src/rotation_generator.jl diff --git a/test/infinitesimal.jl b/test/rotation_generator.jl similarity index 100% rename from test/infinitesimal.jl rename to test/rotation_generator.jl diff --git a/test/runtests.jl b/test/runtests.jl index f94a7e3f..8bea58ef 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -29,7 +29,7 @@ include("rotation_error.jl") include("distribution_tests.jl") include("eigen.jl") include("nearest_rotation.jl") -include("infinitesimal.jl") +include("rotation_generator.jl") include("logexp.jl") include("deprecated.jl") From aaf529d11b9d16b3d06d41df34583d7870f5a8f0 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Mon, 22 Nov 2021 13:15:50 +0900 Subject: [PATCH 26/29] add test fot exp(::RotMatrixGenerator)::RotMatrix --- test/logexp.jl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/logexp.jl b/test/logexp.jl index 569e06fa..5f81f54c 100644 --- a/test/logexp.jl +++ b/test/logexp.jl @@ -25,3 +25,11 @@ end @test exp(r) isa Rotation end end + +@testset "exp(::RotMatrixGenerator)" begin + for N in 2:3 + r = zero(RotMatrixGenerator{N}) + @test r isa RotMatrixGenerator{N} + @test exp(r) isa RotMatrix{N} + end +end From c133d835787f7f37a2191fb293af2fa9048a9c45 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Mon, 22 Nov 2021 13:17:19 +0900 Subject: [PATCH 27/29] fix for exp(::RotMatrixGenerator)::RotMatrix --- src/logexp.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/logexp.jl b/src/logexp.jl index a2e68921..4cec11f3 100644 --- a/src/logexp.jl +++ b/src/logexp.jl @@ -31,6 +31,9 @@ function Base.exp(R::RotationGenerator{3}) exp(RotationVecGenerator(R)) end +function Base.exp(R::RotMatrixGenerator{3}) + RotMatrix(exp(RotationVecGenerator(R))) +end # 2d function Base.exp(R::Angle2dGenerator) @@ -40,3 +43,7 @@ end function Base.exp(R::RotationGenerator{2}) exp(Angle2dGenerator(R)) end + +function Base.exp(R::RotMatrixGenerator{2}) + RotMatrix(exp(Angle2dGenerator(R))) +end From 89d6a3902cc17c66016c6d8cd71171dea1266543 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Mon, 22 Nov 2021 13:18:00 +0900 Subject: [PATCH 28/29] update tests to remove rand method --- test/rotation_generator.jl | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/test/rotation_generator.jl b/test/rotation_generator.jl index 71356dd0..95305a1a 100644 --- a/test/rotation_generator.jl +++ b/test/rotation_generator.jl @@ -75,8 +75,12 @@ @testset "minus" begin for T in all_types - # TODO: add rand method for RotationGenerator - r = T(log(rand(typeof(exp(zero(T)))))) + # TODO: These should be replaced with `r = rand(T)` + if T in types_2d + r = T(Angle2dGenerator(1.2)) + elseif T in types_3d + r = T(RotationVecGenerator(1.2,-0.8,0.1)) + end @test r isa T @test -r isa T @test r' isa T @@ -93,8 +97,12 @@ @testset "multiply" begin for T in all_types - # TODO: add rand method for RotationGenerator - r = T(log(rand(typeof(exp(zero(T)))))) + # TODO: These should be replaced with `r = rand(T)` + if T in types_2d + r = T(Angle2dGenerator(1.2)) + elseif T in types_3d + r = T(RotationVecGenerator(1.2,-0.8,0.1)) + end a = 4.2 @test r isa T @test r*1 isa T @@ -109,8 +117,12 @@ @testset "division" begin for T in all_types - # TODO: add rand method for RotationGenerator - r = T(log(rand(typeof(exp(zero(T)))))) + # TODO: These should be replaced with `r = rand(T)` + if T in types_2d + r = T(Angle2dGenerator(1.2)) + elseif T in types_3d + r = T(RotationVecGenerator(1.2,-0.8,0.1)) + end a = 4.2 @test r isa T @test r/1 isa T @@ -124,8 +136,12 @@ @testset "matrix multiplication" begin for T in all_types - # TODO: add rand method for RotationGenerator - r = T(log(rand(typeof(exp(zero(T)))))) + # TODO: These should be replaced with `r = rand(T)` + if T in types_2d + r = T(Angle2dGenerator(1.2)) + elseif T in types_3d + r = T(RotationVecGenerator(1.2,-0.8,0.1)) + end @test r isa T @test r*r isa SMatrix @test r/r isa SMatrix From b55c9eefc827ab3c3babdc77aa090e2f67656db4 Mon Sep 17 00:00:00 2001 From: hyrodium Date: Mon, 22 Nov 2021 22:39:46 +0900 Subject: [PATCH 29/29] remove unnecessary Base.promote_op method --- src/core_types.jl | 12 ------------ src/rotation_generator.jl | 12 ------------ 2 files changed, 24 deletions(-) diff --git a/src/core_types.jl b/src/core_types.jl index 3e0e274d..b39cd343 100644 --- a/src/core_types.jl +++ b/src/core_types.jl @@ -62,18 +62,6 @@ function Random.rand(rng::AbstractRNG, ::Random.SamplerType{R}) where R <: Rotat return R(q) end -# Useful for converting arrays of rotations to another rotation eltype, for instance. -# Only works because parameters of all the rotations are of a similar form -# Would need to be more sophisticated if we have arbitrary dimensions, etc -@inline function Base.promote_op(::Type{R1}, ::Type{R2}) where {R1 <: Rotation, R2 <: Rotation} - size(R1) == size(R2) || throw(DimensionMismatch("cannot promote rotations of $(size(R1)[1]) and $(size(R2)[1]) dimensions")) - if isleaftype(R1) - return R1 - else - return R1{eltype(R2)} - end -end - @inline function Base.:/(r1::Rotation, r2::Rotation) r1 * inv(r2) end diff --git a/src/rotation_generator.jl b/src/rotation_generator.jl index 7f6698e9..164ddd44 100644 --- a/src/rotation_generator.jl +++ b/src/rotation_generator.jl @@ -37,18 +37,6 @@ Base.convert(::Type{R}, rot::RotationGenerator{N}) where {N,R<:RotationGenerator Base.@pure StaticArrays.similar_type(::Union{R,Type{R}}) where {R <: RotationGenerator} = SMatrix{size(R)..., eltype(R), prod(size(R))} Base.@pure StaticArrays.similar_type(::Union{R,Type{R}}, ::Type{T}) where {R <: RotationGenerator, T} = SMatrix{size(R)..., T, prod(size(R))} -# Useful for converting arrays of rotations to another rotation eltype, for instance. -# Only works because parameters of all the rotations are of a similar form -# Would need to be more sophisticated if we have arbitrary dimensions, etc -@inline function Base.promote_op(::Type{R1}, ::Type{R2}) where {R1 <: RotationGenerator, R2 <: RotationGenerator} - size(R1) == size(R2) || throw(DimensionMismatch("cannot promote rotations of $(size(R1)[1]) and $(size(R2)[1]) dimensions")) - if isleaftype(R1) - return R1 - else - return R1{eltype(R2)} - end -end - ################################################################################ ################################################################################ """