From 9fc49b3f5f3ef0cab3a8ca4ed40ba16df5140767 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Fri, 4 Aug 2017 21:52:30 +0200 Subject: [PATCH 1/2] fix deprecations and upgrade to 0.6 --- .travis.yml | 1 - src/DualQuaternion.jl | 200 ++++++++++++++++++++-------------------- src/Octonion.jl | 162 ++++++++++++++++---------------- src/Quaternion.jl | 116 +++++++++++------------ test/runtests.jl | 12 +-- test/test_Quaternion.jl | 82 ++++++++-------- 6 files changed, 286 insertions(+), 287 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1b76d91b..9a12fc41 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ os: - linux - osx julia: - - 0.5 - 0.6 - nightly diff --git a/src/DualQuaternion.jl b/src/DualQuaternion.jl index 4a0a86dc..977f974f 100644 --- a/src/DualQuaternion.jl +++ b/src/DualQuaternion.jl @@ -1,170 +1,170 @@ using DualNumbers -immutable DualQuaternion{T<:Real} <: Number +struct DualQuaternion{T<:Real} <: Number q0::Quaternion{T} qe::Quaternion{T} norm::Bool end -DualQuaternion( q0::Quaternion, qe::Quaternion, n::Bool = false) = - DualQuaternion( promote( q0, qe )..., n ) +DualQuaternion(q0::Quaternion, qe::Quaternion, n::Bool = false) = + DualQuaternion(promote(q0, qe)..., n) -DualQuaternion( d1::Dual, d2::Dual, d3::Dual, d4::Dual, n::Bool = false) = - DualQuaternion( Quaternion( d1.re, d2.re, d3.re, d4.re, n ), - Quaternion( d1.du, d2.du, d3.du, d4.du ), n ) +DualQuaternion(d1::Dual, d2::Dual, d3::Dual, d4::Dual, n::Bool = false) = + DualQuaternion(Quaternion(d1.re, d2.re, d3.re, d4.re, n), + Quaternion(d1.du, d2.du, d3.du, d4.du), n) -DualQuaternion( x::Real ) = DualQuaternion( Quaternion( x ), Quaternion( zero(x) ), abs(x) == one(x) ) +DualQuaternion(x::Real) = DualQuaternion(Quaternion(x), Quaternion(zero(x)), abs(x) == one(x)) -DualQuaternion( d::Dual ) = DualQuaternion( d, zero(d), zero(d), zero(d), abs(d) == one(d.re) ) +DualQuaternion(d::Dual) = DualQuaternion(d, zero(d), zero(d), zero(d), abs(d) == one(d.re)) -DualQuaternion( q::Quaternion ) = DualQuaternion( q, zero(q), q.norm ) +DualQuaternion(q::Quaternion) = DualQuaternion(q, zero(q), q.norm) -DualQuaternion( a::Vector ) = DualQuaternion( zero(Quaternion{typeof(a[1])}), Quaternion( a ) ) +DualQuaternion(a::Vector) = DualQuaternion(zero(Quaternion{typeof(a[1])}), Quaternion(a)) -convert{T}(::Type{DualQuaternion{T}}, x::Real) = - DualQuaternion( convert( Quaternion{T}, x ), convert(Quaternion{T},0) ) +convert(::Type{DualQuaternion{T}}, x::Real) where {T} = + DualQuaternion(convert(Quaternion{T}, x), convert(Quaternion{T}, 0)) -convert{T}(::Type{DualQuaternion{T}}, d::Dual) = - DualQuaternion( convert( Dual{T}, d ), convert( Dual{T}, 0 ), convert( Dual{T}, 0 ), convert( Dual{T}, 0 ) ) +convert(::Type{DualQuaternion{T}}, d::Dual) where {T} = + DualQuaternion(convert(Dual{T}, d), convert(Dual{T}, 0), convert(Dual{T}, 0), convert(Dual{T}, 0)) -convert{T}(::Type{DualQuaternion{T}}, q::Quaternion) = - DualQuaternion( convert( Quaternion{T}, q ), convert( Quaternion{T}, 0 ), q.norm ) +convert(::Type{DualQuaternion{T}}, q::Quaternion) where {T} = + DualQuaternion(convert(Quaternion{T}, q), convert(Quaternion{T}, 0), q.norm) -convert{T<:Real}(::Type{DualQuaternion{T}}, q::DualQuaternion{T}) = q +convert(::Type{DualQuaternion{T}}, q::DualQuaternion{T}) where {T <: Real} = q -convert{T}(::Type{DualQuaternion{T}}, dq::DualQuaternion) = - DualQuaternion( convert( Quaternion{T}, dq.q0 ), convert( Quaternion{T}, dq.qe ), dq.norm ) +convert(::Type{DualQuaternion{T}}, dq::DualQuaternion) where {T} = + DualQuaternion(convert(Quaternion{T}, dq.q0), convert(Quaternion{T}, dq.qe), dq.norm) -promote_rule{T<:Real}(::Type{DualQuaternion{T}}, ::Type{T}) = DualQuaternion{T} -promote_rule{T<:Real}(::Type{DualQuaternion}, ::Type{T}) = DualQuaternion -promote_rule{T<:Real,S<:Real}(::Type{DualQuaternion{T}}, ::Type{S}) = DualQuaternion{promote_type(T,S)} -promote_rule{T<:Real,S<:Real}(::Type{Quaternion{T}}, ::Type{DualQuaternion{S}}) = DualQuaternion{promote_type(T,S)} -promote_rule{T<:Real,S<:Real}(::Type{DualQuaternion{T}}, ::Type{DualQuaternion{S}}) = DualQuaternion{promote_type(T,S)} +promote_rule(::Type{DualQuaternion{T}}, ::Type{T}) where {T <: Real} = DualQuaternion{T} +promote_rule(::Type{DualQuaternion}, ::Type{T}) where {T <: Real} = DualQuaternion +promote_rule(::Type{DualQuaternion{T}}, ::Type{S}) where {T <: Real, S <: Real} = DualQuaternion{promote_type(T, S)} +promote_rule(::Type{Quaternion{T}}, ::Type{DualQuaternion{S}}) where {T <: Real, S <: Real} = DualQuaternion{promote_type(T, S)} +promote_rule(::Type{DualQuaternion{T}}, ::Type{DualQuaternion{S}}) where {T <: Real, S <: Real} = DualQuaternion{promote_type(T, S)} -dualquat( q1, q2, n=false ) = DualQuaternion( q1, q2, n ) -dualquat( d1, d2, d3, d4, n=false ) = DualQuaternion( d1, d2, d3, d4, n ) -dualquat( x ) = DualQuaternion( x ) +dualquat(q1, q2, n=false) = DualQuaternion(q1, q2, n) +dualquat(d1, d2, d3, d4, n=false) = DualQuaternion(d1, d2, d3, d4, n) +dualquat(x) = DualQuaternion(x) function show(io::IO, dq::DualQuaternion) - show( io, dq.q0 ) - print( io, " + ( " ) - show( io, dq.qe ) - print( io, " )du" ) + show(io, dq.q0) + print(io, " + ( ") + show(io, dq.qe) + print(io, " )du") end -Q0( dq::DualQuaternion ) = dq.q0 -Qe( dq::DualQuaternion ) = dq.qe +Q0(dq::DualQuaternion) = dq.q0 +Qe(dq::DualQuaternion) = dq.qe -(/)(dq::DualQuaternion, x::Real) = DualQuaternion( dq.q0 / x, dq.qe / x ) +(/)(dq::DualQuaternion, x::Real) = DualQuaternion(dq.q0 / x, dq.qe / x) (/)(dq::DualQuaternion, d::Dual) = - DualQuaternion( dual( dq.q0.s , dq.qe.s ) / d, - dual( dq.q0.v1, dq.qe.v1 ) / d, - dual( dq.q0.v2, dq.qe.v2 ) / d, - dual( dq.q0.v3, dq.qe.v3 ) / d ) - -abs2( dq::DualQuaternion ) = dq.norm ? dual( one( dq.q0.s ) ) : - dual( abs2( dq.q0 ) , - 2.0 * ( dq.q0.s * dq.qe.s + + DualQuaternion(dual(dq.q0.s, dq.qe.s) / d, + dual(dq.q0.v1, dq.qe.v1) / d, + dual(dq.q0.v2, dq.qe.v2) / d, + dual(dq.q0.v3, dq.qe.v3) / d) + +abs2(dq::DualQuaternion) = dq.norm ? dual(one(dq.q0.s)) : + dual(abs2(dq.q0), + 2.0 * (dq.q0.s * dq.qe.s + dq.q0.v1 * dq.qe.v1 + dq.q0.v2 * dq.qe.v2 + - dq.q0.v3 * dq.qe.v3 ) ) + dq.q0.v3 * dq.qe.v3)) -abs( dq::DualQuaternion ) = dq.norm ? dual( one( dq.q0.s ) ) : sqrt( abs2( dq ) ) +abs(dq::DualQuaternion) = dq.norm ? dual(one(dq.q0.s)) : sqrt(abs2(dq)) -conj( dq::DualQuaternion ) = DualQuaternion( conj( dq.q0 ), conj( dq.qe ), dq.norm ) -dconj( dq::DualQuaternion ) = DualQuaternion( dq.q0, -dq.qe, dq.norm ) +conj(dq::DualQuaternion) = DualQuaternion(conj(dq.q0), conj(dq.qe), dq.norm) +dconj(dq::DualQuaternion) = DualQuaternion(dq.q0, -dq.qe, dq.norm) -inv( dq::DualQuaternion ) = dq.norm ? conj( dq ) : conj( dq ) / abs2( dq ) +inv(dq::DualQuaternion) = dq.norm ? conj(dq) : conj(dq) / abs2(dq) -function normalize( dq::DualQuaternion ) - if ( dq.norm ) +function normalize(dq::DualQuaternion) + if (dq.norm) return dq end - a = abs( dq ) - if abs( a ) > 0 + a = abs(dq) + if abs(a) > 0 qa = dq / a - dualquat( qa.q0, qa.qe, true ) + dualquat(qa.q0, qa.qe, true) else dq end end -function normalizea( dq::DualQuaternion ) - if ( dq.norm ) - return ( dq, one( dual ) ) +function normalizea(dq::DualQuaternion) + if (dq.norm) + return (dq, one(dual)) end - a = abs( dq ) - if abs( a ) > 0 + a = abs(dq) + if abs(a) > 0 qa = dq / a - dualquat( qa.q0, qa.qe, true ), a + dualquat(qa.q0, qa.qe, true), a else - dq, zero( dual ) + dq, zero(dual) end end -(-)(dq::DualQuaternion) = DualQuaternion( -dq.q0, -dq.qe, dq.norm) +(-)(dq::DualQuaternion) = DualQuaternion(-dq.q0, -dq.qe, dq.norm) -(+)(dq::DualQuaternion, dw::DualQuaternion) = DualQuaternion( dq.q0 + dw.q0, dq.qe + dw.qe ) -(-)(dq::DualQuaternion, dw::DualQuaternion) = DualQuaternion( dq.q0 - dw.q0, dq.qe - dw.qe ) -(*)(dq::DualQuaternion, dw::DualQuaternion) = DualQuaternion( dq.q0 * dw.q0, +(+)(dq::DualQuaternion, dw::DualQuaternion) = DualQuaternion(dq.q0 + dw.q0, dq.qe + dw.qe) +(-)(dq::DualQuaternion, dw::DualQuaternion) = DualQuaternion(dq.q0 - dw.q0, dq.qe - dw.qe) +(*)(dq::DualQuaternion, dw::DualQuaternion) = DualQuaternion(dq.q0 * dw.q0, dq.q0 * dw.qe + dq.qe * dw.q0, - dq.norm && dw.norm ) -(/)(dq::DualQuaternion, dw::DualQuaternion) = dq*inv(dw) + dq.norm && dw.norm) +(/)(dq::DualQuaternion, dw::DualQuaternion) = dq * inv(dw) -function angleaxis( dq::DualQuaternion ) - tq = dq.qe * conj( dq.q0 ) - t = [ 2.0 * tq.v1, 2.0 * tq.v2, 2.0 * tq.v3 ] +function angleaxis(dq::DualQuaternion) + tq = dq.qe * conj(dq.q0) + t = [2.0 * tq.v1, 2.0 * tq.v2, 2.0 * tq.v3] q0s = dq.q0.s - th0, s0 = angleaxis( dq.q0 ) - sq0 = quat( 0.0, s0 ) - if abs( abs( q0s ) - one( q0s ) ) == 0 - th = dual( th0, 0.5 * abs( quat( 0, t ) ) ) - th, dualquat( sq0 ) + th0, s0 = angleaxis(dq.q0) + sq0 = quat(0.0, s0) + if abs(abs(q0s) - one(q0s)) == 0 + th = dual(th0, 0.5 * abs(quat(0, t))) + th, dualquat(sq0) else - th = dual( th0, 0.5 * dot( t, s0 ) ) - s0c1 = cross( s0, t ) - tanth = tan( th0 ) - s0c2 = ( s0c1 / tanth + t ) * 0.5 - sqev = cross( s0c2, s0 ) - th, dualquat( sq0, quat( 0.0, sqev ) ) + th = dual(th0, 0.5 * dot(t, s0)) + s0c1 = cross(s0, t) + tanth = tan(th0) + s0c2 = (s0c1 / tanth + t) * 0.5 + sqev = cross(s0c2, s0) + th, dualquat(sq0, quat(0.0, sqev)) end end -function angle( dq::DualQuaternion ) - th, ax = angleaxis( dq ) +function angle(dq::DualQuaternion) + th, ax = angleaxis(dq) th end -function axis( dq::DualQuaternion ) - th, ax = angleaxis( dq ) +function axis(dq::DualQuaternion) + th, ax = angleaxis(dq) ax end -function exp( dq::DualQuaternion ) - se = dual( dq.q0.s, dq.qe.s ) - se = exp( se ) - dq = dualquat( quat( 0.0, imag( dq.q0 ) ), quat( 0.0, imag( dq.qe ) ) ) - dq, th = normalizea( dq ) +function exp(dq::DualQuaternion) + se = dual(dq.q0.s, dq.qe.s) + se = exp(se) + dq = dualquat(quat(0.0, imag(dq.q0)), quat(0.0, imag(dq.qe))) + dq, th = normalizea(dq) if dq.norm - dualquat( se ) * ( dualquat( cos( th ) ) + dq * dualquat( sin( th ) ) ) + dualquat(se) * (dualquat(cos(th)) + dq * dualquat(sin(th))) else - dualquat( se ) + dualquat(se) end end -function log( dq::DualQuaternion ) - dq, a = normalizea( dq ) - sl = log( a ) - th, s = angleaxis( dq ) - s * dualquat( th ) + dualquat( sl ) +function log(dq::DualQuaternion) + dq, a = normalizea(dq) + sl = log(a) + th, s = angleaxis(dq) + s * dualquat(th) + dualquat(sl) end -(^)(dq::DualQuaternion, dw::DualQuaternion) = exp( dw * log( dq ) ) +(^)(dq::DualQuaternion, dw::DualQuaternion) = exp(dw * log(dq)) -function sqrt( dq::DualQuaternion ) - exp( 0.5 * log( dq ) ) +function sqrt(dq::DualQuaternion) + exp(0.5 * log(dq)) end -dualquatrand() = dualquat( quatrand(), quatrand() ) -ndualquatrand() = normalize( dualquatrand() ) +dualquatrand() = dualquat(quatrand(), quatrand()) +ndualquatrand() = normalize(dualquatrand()) diff --git a/src/Octonion.jl b/src/Octonion.jl index dd89da77..4afab97e 100644 --- a/src/Octonion.jl +++ b/src/Octonion.jl @@ -1,4 +1,4 @@ -immutable Octonion{T<:Real} <: Number +struct Octonion{T<:Real} <: Number s::T v1::T v2::T @@ -10,117 +10,117 @@ immutable Octonion{T<:Real} <: Number norm::Bool end -Octonion( s::Real, v1::Real, v2::Real, v3::Real, v4::Real, v5::Real, v6::Real, v7::Real, n::Bool = false) = - Octonion( promote( s, v1, v2, v3, v4, v5, v6, v7 )..., n ) -Octonion( x::Real ) = Octonion( x, zero(x), zero(x), zero(x), zero(x), zero(x), zero(x), zero(x), abs(x) == one(x) ) -Octonion( z::Complex ) = Octonion( z.re, z.im, zero(z.re), zero(z.re), zero(z.re), zero(z.re), zero(z.re), zero(z.re), abs(z) == one(z.re) ) -Octonion( q::Quaternion ) = Octonion( q.s, q.v1, q.v2, q.v3, zero(q.s), zero(q.s), zero(q.s), zero(q.s), q.norm ) -Octonion( s::Real, a::Vector ) = Octonion( s, a[1], a[2], a[3], a[4], a[5], a[6], a[7] ) -Octonion( a::Vector ) = Octonion( 0, a[1], a[2], a[3], a[4], a[5], a[6], a[7] ) - -convert{T}(::Type{Octonion{T}}, x::Real) = - Octonion(convert(T,x), convert(T,0), convert(T,0), convert(T,0), convert(T,0), convert(T,0), convert(T,0), convert(T,0)) -convert{T}(::Type{Octonion{T}}, z::Complex) = - Octonion(convert(T,real(z)), convert(T,imag(z)), convert(T,0), convert(T,0), convert(T,0), convert(T,0), convert(T,0), convert(T,0)) -convert{T}(::Type{Octonion{T}}, q::Quaternion) = - Octonion(convert(T,real(z)), convert(T,q.v1), convert(T,q.v2), convert(T,q.v3), convert(T,0), convert(T,0), convert(T,0), convert(T,0)) -convert{T<:Real}(::Type{Octonion{T}}, o::Octonion{T}) = o -convert{T}(::Type{Octonion{T}}, o::Octonion) = - Octonion(convert(T,o.s), convert(T,o.v1), convert(T,o.v2), convert(T,o.v3), convert(T,o.v4), convert(T,o.v5), convert(T,o.v6), convert(T,o.v7), o.norm) - -promote_rule{T<:Real}(::Type{Octonion{T}}, ::Type{T}) = Octonion{T} -promote_rule{T<:Real}(::Type{Octonion}, ::Type{T}) = Octonion -promote_rule{T<:Real,S<:Real}(::Type{Octonion{T}}, ::Type{S}) = Octonion{promote_type(T,S)} -promote_rule{T<:Real,S<:Real}(::Type{Complex{T}}, ::Type{Octonion{S}}) = Octonion{promote_type(T,S)} -promote_rule{T<:Real,S<:Real}(::Type{Quaternion{T}}, ::Type{Octonion{S}}) = Octonion{promote_type(T,S)} -promote_rule{T<:Real,S<:Real}(::Type{Octonion{T}}, ::Type{Octonion{S}}) = Octonion{promote_type(T,S)} - -octo( p, v1, v2, v3, v4, v5, v6, v7, n = false ) = Octonion( p, v1, v2, v3, v4, v5, v6, v7, n ) -octo( x ) = Octonion( x ) -octo( s, a ) = Octonion( s, a ) +Octonion(s::Real, v1::Real, v2::Real, v3::Real, v4::Real, v5::Real, v6::Real, v7::Real, n::Bool = false) = + Octonion(promote(s, v1, v2, v3, v4, v5, v6, v7)..., n) +Octonion(x::Real) = Octonion(x, zero(x), zero(x), zero(x), zero(x), zero(x), zero(x), zero(x), abs(x) == one(x)) +Octonion(z::Complex) = Octonion(z.re, z.im, zero(z.re), zero(z.re), zero(z.re), zero(z.re), zero(z.re), zero(z.re), abs(z) == one(z.re)) +Octonion(q::Quaternion) = Octonion(q.s, q.v1, q.v2, q.v3, zero(q.s), zero(q.s), zero(q.s), zero(q.s), q.norm) +Octonion(s::Real, a::Vector) = Octonion(s, a[1], a[2], a[3], a[4], a[5], a[6], a[7]) +Octonion(a::Vector) = Octonion(0, a[1], a[2], a[3], a[4], a[5], a[6], a[7]) + +convert(::Type{Octonion{T}}, x::Real) where {T} = + Octonion(convert(T, x), convert(T, 0), convert(T, 0), convert(T, 0), convert(T, 0), convert(T, 0), convert(T, 0), convert(T, 0)) +convert(::Type{Octonion{T}}, z::Complex) where {T} = + Octonion(convert(T, real(z)), convert(T, imag(z)), convert(T, 0), convert(T, 0), convert(T, 0), convert(T, 0), convert(T, 0), convert(T, 0)) +convert(::Type{Octonion{T}}, q::Quaternion) where {T} = + Octonion(convert(T, real(z)), convert(T, q.v1), convert(T, q.v2), convert(T, q.v3), convert(T, 0), convert(T, 0), convert(T, 0), convert(T, 0)) +convert(::Type{Octonion{T}}, o::Octonion{T}) where {T <: Real} = o +convert(::Type{Octonion{T}}, o::Octonion) where {T} = + Octonion(convert(T, o.s), convert(T, o.v1), convert(T, o.v2), convert(T, o.v3), convert(T, o.v4), convert(T, o.v5), convert(T, o.v6), convert(T, o.v7), o.norm) + +promote_rule(::Type{Octonion{T}}, ::Type{T}) where {T <: Real} = Octonion{T} +promote_rule(::Type{Octonion}, ::Type{T}) where {T <: Real} = Octonion +promote_rule(::Type{Octonion{T}}, ::Type{S}) where {T <: Real, S <: Real} = Octonion{promote_type(T, S)} +promote_rule(::Type{Complex{T}}, ::Type{Octonion{S}}) where {T <: Real, S <: Real} = Octonion{promote_type(T, S)} +promote_rule(::Type{Quaternion{T}}, ::Type{Octonion{S}}) where {T <: Real, S <: Real} = Octonion{promote_type(T, S)} +promote_rule(::Type{Octonion{T}}, ::Type{Octonion{S}}) where {T <: Real, S <: Real} = Octonion{promote_type(T, S)} + +octo(p, v1, v2, v3, v4, v5, v6, v7, n = false) = Octonion(p, v1, v2, v3, v4, v5, v6, v7, n) +octo(x) = Octonion(x) +octo(s, a) = Octonion(s, a) function show(io::IO, o::Octonion) pm(x) = x < 0 ? " - $(-x)" : " + $x" print(io, o.s, pm(o.v1), "im", pm(o.v2), "jm", pm(o.v3), "km", pm(o.v4), "ilm", pm(o.v5), "jlm", pm(o.v6), "klm", pm(o.v7), "lm") end -real( o::Octonion ) = o.s -imag( o::Octonion ) = [ o.v1, o.v2, o.v3, o.v4, o.v5, o.v6, o.v7 ] +real(o::Octonion) = o.s +imag(o::Octonion) = [o.v1, o.v2, o.v3, o.v4, o.v5, o.v6, o.v7] -(/)( o::Octonion, x::Real ) = Octonion( o.s/x, o.v1/x, o.v2/x, o.v3/x, o.v4/x, o.v5/x, o.v6/x, o.v7/x ) +(/)(o::Octonion, x::Real) = Octonion(o.s / x, o.v1 / x, o.v2 / x, o.v3 / x, o.v4 / x, o.v5 / x, o.v6 / x, o.v7 / x) -conj( o::Octonion ) = Octonion( o.s, -o.v1, -o.v2, -o.v3, -o.v4, -o.v5, -o.v6, -o.v7, o.norm ) -abs( o::Octonion ) = sqrt(o.s*o.s + o.v1*o.v1 + o.v2*o.v2 + o.v3*o.v3 + o.v4*o.v4 + o.v5*o.v5 + o.v6*o.v6 + o.v7*o.v7 ) -abs2( o::Octonion ) = o.s*o.s + o.v1*o.v1 + o.v2*o.v2 + o.v3*o.v3 + o.v4*o.v4 + o.v5*o.v5 + o.v6*o.v6 + o.v7*o.v7 -inv( o::Octonion ) = o.norm ? conj(o) : conj(o)/abs2(o) +conj(o::Octonion) = Octonion(o.s, -o.v1, -o.v2, -o.v3, -o.v4, -o.v5, -o.v6, -o.v7, o.norm) +abs(o::Octonion) = sqrt(o.s * o.s + o.v1 * o.v1 + o.v2 * o.v2 + o.v3 * o.v3 + o.v4 * o.v4 + o.v5 * o.v5 + o.v6 * o.v6 + o.v7 * o.v7) +abs2(o::Octonion) = o.s * o.s + o.v1 * o.v1 + o.v2 * o.v2 + o.v3 * o.v3 + o.v4 * o.v4 + o.v5 * o.v5 + o.v6 * o.v6 + o.v7 * o.v7 +inv(o::Octonion) = o.norm ? conj(o) : conj(o) / abs2(o) -function normalize( o::Octonion ) - if ( o.norm ) +function normalize(o::Octonion) + if (o.norm) return o end - o = o / abs( o ) - Octonion( o.s, o.v1, o.v2, o.v3, o.v4, o.v5, o.v6, o.v7, true ) + o = o / abs(o) + Octonion(o.s, o.v1, o.v2, o.v3, o.v4, o.v5, o.v6, o.v7, true) end -function normalizea( o::Octonion ) - if ( o.norm ) - return ( o, one( o.s ) ) +function normalizea(o::Octonion) + if (o.norm) + return (o, one(o.s)) end - a = abs( o ) + a = abs(o) o = o / a - ( Octonion( o.s, o.v1, o.v2, o.v3, o.v4, o.v5, o.v6, o.v7, true ), a ) + (Octonion(o.s, o.v1, o.v2, o.v3, o.v4, o.v5, o.v6, o.v7, true), a) end -(-)( o::Octonion) = Octonion( -o.s, -o.v1, -o.v2, -o.v3, -o.v4, -o.v5, -o.v6, -o.v7, o.norm ) +(-)(o::Octonion) = Octonion(-o.s, -o.v1, -o.v2, -o.v3, -o.v4, -o.v5, -o.v6, -o.v7, o.norm) -(+)( o::Octonion, w::Octonion ) = Octonion( o.s + w.s, +(+)(o::Octonion, w::Octonion) = Octonion(o.s + w.s, o.v1 + w.v1, o.v2 + w.v2, o.v3 + w.v3, o.v4 + w.v4, o.v5 + w.v5, o.v6 + w.v6, - o.v7 + w.v7 ) + o.v7 + w.v7) -(-)( o::Octonion, w::Octonion ) = Octonion( o.s - w.s, +(-)(o::Octonion, w::Octonion) = Octonion(o.s - w.s, o.v1 - w.v1, o.v2 - w.v2, o.v3 - w.v3, o.v4 - w.v4, o.v5 - w.v5, o.v6 - w.v6, - o.v7 - w.v7 ) + o.v7 - w.v7) -macro ocmul( i, j ) - si = @compat Symbol( "v$i" ) - sj = @compat Symbol( "v$j" ) - esc( :( o.$si * w.$sj - o.$sj * w.$si ) ) +macro ocmul(i, j) + si = @compat Symbol("v$i") + sj = @compat Symbol("v$j") + esc(:(o.$si * w.$sj - o.$sj * w.$si)) end -(*)( o::Octonion, w::Octonion ) = +(*)(o::Octonion, w::Octonion) = Octonion( - o.s*w.s - o.v1*w.v1 - o.v2*w.v2 - o.v3*w.v3 - o.v4*w.v4 - o.v5*w.v5 - o.v6*w.v6 - o.v7*w.v7, - o.s*w.v1 + o.v1*w.s + @ocmul( 2, 3 ) + @ocmul( 6, 5 ) + @ocmul( 7, 4 ), - o.s*w.v2 + o.v2*w.s + @ocmul( 3, 1 ) + @ocmul( 4, 6 ) + @ocmul( 7, 5 ), - o.s*w.v3 + o.v3*w.s + @ocmul( 1, 2 ) + @ocmul( 5, 4 ) + @ocmul( 7, 6 ), - o.s*w.v4 + o.v4*w.s + @ocmul( 1, 7 ) + @ocmul( 3, 5 ) + @ocmul( 6, 2 ), - o.s*w.v5 + o.v5*w.s + @ocmul( 1, 6 ) + @ocmul( 2, 7 ) + @ocmul( 4, 3 ), - o.s*w.v6 + o.v6*w.s + @ocmul( 2, 4 ) + @ocmul( 3, 7 ) + @ocmul( 5, 1 ), - o.s*w.v7 + o.v7*w.s + @ocmul( 4, 1 ) + @ocmul( 5, 2 ) + @ocmul( 6, 3 ) + o.s * w.s - o.v1 * w.v1 - o.v2 * w.v2 - o.v3 * w.v3 - o.v4 * w.v4 - o.v5 * w.v5 - o.v6 * w.v6 - o.v7 * w.v7, + o.s * w.v1 + o.v1 * w.s + @ocmul( 2, 3 ) + @ocmul( 6, 5 ) + @ocmul( 7, 4 ), + o.s * w.v2 + o.v2 * w.s + @ocmul( 3, 1 ) + @ocmul( 4, 6 ) + @ocmul( 7, 5 ), + o.s * w.v3 + o.v3 * w.s + @ocmul( 1, 2 ) + @ocmul( 5, 4 ) + @ocmul( 7, 6 ), + o.s * w.v4 + o.v4 * w.s + @ocmul( 1, 7 ) + @ocmul( 3, 5 ) + @ocmul( 6, 2 ), + o.s * w.v5 + o.v5 * w.s + @ocmul( 1, 6 ) + @ocmul( 2, 7 ) + @ocmul( 4, 3 ), + o.s * w.v6 + o.v6 * w.s + @ocmul( 2, 4 ) + @ocmul( 3, 7 ) + @ocmul( 5, 1 ), + o.s * w.v7 + o.v7 * w.s + @ocmul( 4, 1 ) + @ocmul( 5, 2 ) + @ocmul( 6, 3 ) ) -(/)( o::Octonion, w::Octonion ) = o * inv(w) +(/)(o::Octonion, w::Octonion) = o * inv(w) -function exp( o::Octonion ) +function exp(o::Octonion) s = o.s - se = exp( s ) + se = exp(s) scale = se - th = abs( Octonion( imag( o) ) ) + th = abs(Octonion(imag(o))) if th > 0 - scale *= sin( th ) / th + scale *= sin(th) / th end - Octonion( se * cos( th ), + Octonion(se * cos(th), scale * o.v1, scale * o.v2, scale * o.v3, @@ -128,33 +128,33 @@ function exp( o::Octonion ) scale * o.v5, scale * o.v6, scale * o.v7, - abs( s ) == 0 ) + abs(s) == 0) end -function log( o::Octonion ) - o, a = normalizea( o ) +function log(o::Octonion) + o, a = normalizea(o) s = o.s - M = abs( Octonion( imag( o ) ) ) - th = atan2( M, s ) + M = abs(Octonion(imag(o))) + th = atan2(M, s) if M > 0 M = th / M - return Octonion( log( a ), + return Octonion(log(a), o.v1 * M, o.v2 * M, o.v3 * M, o.v4 * M, o.v5 * M, o.v6 * M, - o.v7 * M ) + o.v7 * M) else - return Octonion( log( a ), th , 0.0, 0.0 ) + return Octonion(log(a), th, 0.0, 0.0) end end -(^)(o::Octonion, w::Octonion) = exp( w * log( o ) ) +(^)(o::Octonion, w::Octonion) = exp(w * log(o)) -function sqrt( o::Octonion ) - exp( 0.5 * log( o ) ) +function sqrt(o::Octonion) + exp(0.5 * log(o)) end -octorand() = octo( randn(), randn(), randn(), randn(), randn(), randn(), randn(), randn() ) +octorand() = octo(randn(), randn(), randn(), randn(), randn(), randn(), randn(), randn()) diff --git a/src/Quaternion.jl b/src/Quaternion.jl index 8abc97d5..622d8917 100644 --- a/src/Quaternion.jl +++ b/src/Quaternion.jl @@ -1,4 +1,4 @@ -immutable Quaternion{T<:Real} <: Number +struct Quaternion{T<:Real} <: Number s::T v1::T v2::T @@ -7,25 +7,25 @@ immutable Quaternion{T<:Real} <: Number end Quaternion(s::Real, v1::Real, v2::Real, v3::Real, n::Bool = false) = - Quaternion( promote(s, v1, v2, v3)..., n) + Quaternion(promote(s, v1, v2, v3)..., n) Quaternion(x::Real) = Quaternion(x, zero(x), zero(x), zero(x), abs(x) == one(x)) Quaternion(z::Complex) = Quaternion(z.re, z.im, zero(z.re), zero(z.re), abs(z) == one(z.re)) Quaternion(s::Real, a::Vector) = Quaternion(s, a[1], a[2], a[3]) Quaternion(a::Vector) = Quaternion(0, a[1], a[2], a[3]) -convert{T}(::Type{Quaternion{T}}, x::Real) = - Quaternion(convert(T,x), convert(T,0), convert(T,0), convert(T,0)) -convert{T}(::Type{Quaternion{T}}, z::Complex) = - Quaternion(convert(T,real(z)), convert(T,imag(z)), convert(T,0), convert(T,0)) -convert{T<:Real}(::Type{Quaternion{T}}, q::Quaternion{T}) = q -convert{T}(::Type{Quaternion{T}}, q::Quaternion) = - Quaternion(convert(T,q.s), convert(T,q.v1), convert(T,q.v2), convert(T,q.v3), q.norm) +convert(::Type{Quaternion{T}}, x::Real) where {T} = + Quaternion(convert(T, x), convert(T, 0), convert(T, 0), convert(T, 0)) +convert(::Type{Quaternion{T}}, z::Complex) where {T} = + Quaternion(convert(T, real(z)), convert(T, imag(z)), convert(T, 0), convert(T, 0)) +convert(::Type{Quaternion{T}}, q::Quaternion{T}) where {T <: Real} = q +convert(::Type{Quaternion{T}}, q::Quaternion) where {T} = + Quaternion(convert(T, q.s), convert(T, q.v1), convert(T, q.v2), convert(T, q.v3), q.norm) -promote_rule{T<:Real}(::Type{Quaternion{T}}, ::Type{T}) = Quaternion{T} -promote_rule{T<:Real}(::Type{Quaternion}, ::Type{T}) = Quaternion -promote_rule{T<:Real,S<:Real}(::Type{Quaternion{T}}, ::Type{S}) = Quaternion{promote_type(T,S)} -promote_rule{T<:Real,S<:Real}(::Type{Complex{T}}, ::Type{Quaternion{S}}) = Quaternion{promote_type(T,S)} -promote_rule{T<:Real,S<:Real}(::Type{Quaternion{T}}, ::Type{Quaternion{S}}) = Quaternion{promote_type(T,S)} +promote_rule(::Type{Quaternion{T}}, ::Type{T}) where {T <: Real} = Quaternion{T} +promote_rule(::Type{Quaternion}, ::Type{T}) where {T <: Real} = Quaternion +promote_rule(::Type{Quaternion{T}}, ::Type{S}) where {T <: Real, S <: Real} = Quaternion{promote_type(T, S)} +promote_rule(::Type{Complex{T}}, ::Type{Quaternion{S}}) where {T <: Real, S <: Real} = Quaternion{promote_type(T, S)} +promote_rule(::Type{Quaternion{T}}, ::Type{Quaternion{S}}) where {T <: Real, S <: Real} = Quaternion{promote_type(T, S)} quat(p, v1, v2, v3, n = false) = Quaternion(p, v1, v2, v3, n) quat(x) = Quaternion(x) @@ -36,17 +36,17 @@ function show(io::IO, q::Quaternion) print(io, q.s, pm(q.v1), "im", pm(q.v2), "jm", pm(q.v3), "km") end -real{T}(::Type{Quaternion{T}}) = T +real(::Type{Quaternion{T}}) where {T} = T real(q::Quaternion) = q.s imag(q::Quaternion) = [q.v1, q.v2, q.v3] -(/)(q::Quaternion, x::Real) = Quaternion(q.s/x, q.v1/x, q.v2/x, q.v3/x) +(/)(q::Quaternion, x::Real) = Quaternion(q.s / x, q.v1 / x, q.v2 / x, q.v3 / x) conj(q::Quaternion) = Quaternion(q.s, -q.v1, -q.v2, -q.v3, q.norm) -abs(q::Quaternion) = sqrt(q.s*q.s + q.v1*q.v1 + q.v2*q.v2 + q.v3*q.v3) -abs_imag(q::Quaternion) = sqrt(q.v1*q.v1 + q.v2*q.v2 + q.v3*q.v3) -abs2(q::Quaternion) = q.s*q.s + q.v1*q.v1 + q.v2*q.v2 + q.v3*q.v3 -inv(q::Quaternion) = q.norm ? conj(q) : conj(q)/abs2(q) +abs(q::Quaternion) = sqrt(q.s * q.s + q.v1 * q.v1 + q.v2 * q.v2 + q.v3 * q.v3) +abs_imag(q::Quaternion) = sqrt(q.v1 * q.v1 + q.v2 * q.v2 + q.v3 * q.v3) +abs2(q::Quaternion) = q.s * q.s + q.v1 * q.v1 + q.v2 * q.v2 + q.v3 * q.v3 +inv(q::Quaternion) = q.norm ? conj(q) : conj(q) / abs2(q) isfinite(q::Quaternion) = q.norm ? true : (isfinite(q.s) && isfinite(q.v1) && isfinite(q.v2) && isfinite(q.v3)) @@ -60,7 +60,7 @@ end function normalizea(q::Quaternion) if (q.norm) - return (q,one(q.s)) + return (q, one(q.s)) end a = abs(q) q = q / a @@ -85,21 +85,21 @@ end (-)(q::Quaternion, w::Quaternion) = Quaternion(q.s - w.s, q.v1 - w.v1, q.v2 - w.v2, q.v3 - w.v3) -(*)(q::Quaternion, w::Quaternion) = Quaternion(q.s*w.s - q.v1*w.v1 - q.v2*w.v2 - q.v3*w.v3, - q.s*w.v1 + q.v1*w.s + q.v2*w.v3 - q.v3*w.v2, - q.s*w.v2 - q.v1*w.v3 + q.v2*w.s + q.v3*w.v1, - q.s*w.v3 + q.v1*w.v2 - q.v2*w.v1 + q.v3*w.s, +(*)(q::Quaternion, w::Quaternion) = Quaternion(q.s * w.s - q.v1 * w.v1 - q.v2 * w.v2 - q.v3 * w.v3, + q.s * w.v1 + q.v1 * w.s + q.v2 * w.v3 - q.v3 * w.v2, + q.s * w.v2 - q.v1 * w.v3 + q.v2 * w.s + q.v3 * w.v1, + q.s * w.v3 + q.v1 * w.v2 - q.v2 * w.v1 + q.v3 * w.s, q.norm && w.norm) (/)(q::Quaternion, w::Quaternion) = q * inv(w) angleaxis(q::Quaternion) = angle(q), axis(q) -angle(q::Quaternion) = 2*atan2(√(q.v1^2 + q.v2^2 + q.v3^2), q.s) +angle(q::Quaternion) = 2 * atan2(√(q.v1^2 + q.v2^2 + q.v3^2), q.s) function axis(q::Quaternion) q = normalize(q) s = sin(angle(q) / 2) - abs(s) > 0 ? + abs(s) > 0 ? [q.v1, q.v2, q.v3] / s : [1.0, 0.0, 0.0] end @@ -114,7 +114,7 @@ function exp(q::Quaternion) if th > 0 scale *= sin(th) / th end - Quaternion(se*cos(th), scale*q.v1, scale*q.v2, scale*q.v3, abs(s) < eps(typeof(s))) + Quaternion(se * cos(th), scale * q.v1, scale * q.v2, scale * q.v3, abs(s) < eps(typeof(s))) end function log(q::Quaternion) @@ -124,25 +124,25 @@ function log(q::Quaternion) th = atan2(M, s) if M > 0 M = th / M - return Quaternion(log(a), q.v1*M, q.v2*M, q.v3*M) + return Quaternion(log(a), q.v1 * M, q.v2 * M, q.v3 * M) else - return Quaternion(log(a), th , 0.0, 0.0) + return Quaternion(log(a), th, 0.0, 0.0) end end function sin(q::Quaternion) L = argq(q) - return (exp(L*q) - exp(-L*q))/(2*L) + return (exp(L * q) - exp(-L * q)) / (2 * L) end function cos(q::Quaternion) L = argq(q) - return (exp(L*q) + exp(-L*q)) / 2 + return (exp(L * q) + exp(-L * q)) / 2 end -(^)(q::Quaternion, w::Quaternion) = exp(w*log(q)) +(^)(q::Quaternion, w::Quaternion) = exp(w * log(q)) -sqrt(q::Quaternion) = exp(0.5*log(q)) +sqrt(q::Quaternion) = exp(0.5 * log(q)) function linpol(p::Quaternion, q::Quaternion, t::Real) p = normalize(p) @@ -156,23 +156,23 @@ function linpol(p::Quaternion, q::Quaternion, t::Real) if c < 1.0 o = acos(c) s = sin(o) - sp = sin((1 - t)*o)/s - sq = sin(t*o)/s + sp = sin((1 - t) * o) / s + sq = sin(t * o) / s else sp = 1 - t sq = t end - Quaternion(sp*p.s + sq*q.s, - sp*p.v1 + sq*q.v1, - sp*p.v2 + sq*q.v2, - sp*p.v3 + sq*q.v3, true) + Quaternion(sp * p.s + sq * q.s, + sp * p.v1 + sq * q.v1, + sp * p.v2 + sq * q.v2, + sp * p.v3 + sq * q.v3, true) else s = p.v3 v1 = -p.v2 v2 = p.v1 v3 = -p.s - sp = sin((0.5 - t)*pi) - sq = sin(t*pi) + sp = sin((0.5 - t) * pi) + sq = sin(t * pi) Quaternion(s, sp * p.v1 + sq * v1, sp * p.v2 + sq * v2, @@ -185,25 +185,25 @@ nquatrand() = normalize(quatrand()) ## Rotations -function qrotation{T<:Real}(axis::Vector{T}, theta) +function qrotation(axis::Vector{T}, theta) where {T <: Real} if length(axis) != 3 error("Must be a 3-vector") end u = normalize(axis) thetaT = convert(eltype(u), theta) - s = sin(thetaT/2) - Quaternion(cos(thetaT/2), s*u[1], s*u[2], s*u[3], true) + s = sin(thetaT / 2) + Quaternion(cos(thetaT / 2), s * u[1], s * u[2], s * u[3], true) end # Variant of the above where norm(rotvec) encodes theta -function qrotation{T<:Real}(rotvec::Vector{T}) +function qrotation(rotvec::Vector{T}) where {T <: Real} if length(rotvec) != 3 error("Must be a 3-vector") end theta = norm(rotvec) if theta > 0 - s = sin(theta/2)/theta # divide by theta to make rotvec a unit vector - return Quaternion(cos(theta/2), s*rotvec[1], s*rotvec[2], s*rotvec[3], true) + s = sin(theta / 2) / theta # divide by theta to make rotvec a unit vector + return Quaternion(cos(theta / 2), s * rotvec[1], s * rotvec[2], s * rotvec[3], true) end Quaternion(one(T), zero(T), zero(T), zero(T), true) end @@ -212,24 +212,24 @@ end rotationmatrix(q::Quaternion) = rotationmatrix_normalized(normalize(q)) function rotationmatrix_normalized(q::Quaternion) - sx, sy, sz = 2q.s*q.v1, 2q.s*q.v2, 2q.s*q.v3 - xx, xy, xz = 2q.v1^2, 2q.v1*q.v2, 2q.v1*q.v3 - yy, yz, zz = 2q.v2^2, 2q.v2*q.v3, 2q.v3^2 - [1-(yy+zz) xy-sz xz+sy; - xy+sz 1-(xx+zz) yz-sx; - xz-sy yz+sx 1-(xx+yy)] + sx, sy, sz = 2q.s * q.v1, 2q.s * q.v2, 2q.s * q.v3 + xx, xy, xz = 2q.v1^2, 2q.v1 * q.v2, 2q.v1 * q.v3 + yy, yz, zz = 2q.v2^2, 2q.v2 * q.v3, 2q.v3^2 + [1 - (yy + zz) xy - sz xz + sy; + xy + sz 1 - (xx + zz) yz - sx; + xz - sy yz + sx 1 - (xx + yy)] end -function normalize{T}(v::Vector{T}) +function normalize(v::Vector{T}) where {T} nv = norm(v) if nv > 0 - return v/nv + return v / nv end - zeros(promote_type(T,typeof(nv)), length(v)) + zeros(promote_type(T, typeof(nv)), length(v)) end -function slerp{T}(qa::Quaternion{T}, qb::Quaternion{T}, t::T) +function slerp(qa::Quaternion{T}, qb::Quaternion{T}, t::T) where {T} # http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ coshalftheta = qa.s * qb.s + qa.v1 * qb.v1 + qa.v2 * qb.v2 + qa.v3 * qb.v3; diff --git a/test/runtests.jl b/test/runtests.jl index 2dc209a5..a4eb73ca 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,12 +1,12 @@ using Base.Test using Quaternions -test_associative(x, y, z, ⊗) = @test (x⊗y)⊗z ≈ x⊗(y⊗z) -test_commutative(x, y, ⊗) = @test x⊗y ≈ y⊗x -test_inverse(x, eins, ⊗, inv) = (@test x⊗inv(x) ≈ eins; @test inv(x)⊗x ≈ eins) -test_neutral(x, eins, ⊗) = (@test x⊗eins ≈ x; @test eins⊗x ≈ x) +test_associative(x, y, z, ⊗) = @test (x ⊗ y) ⊗ z ≈ x ⊗ (y ⊗ z) +test_commutative(x, y, ⊗) = @test x ⊗ y ≈ y ⊗ x +test_inverse(x, eins, ⊗, inv) = (@test x ⊗ inv(x) ≈ eins; @test inv(x) ⊗ x ≈ eins) +test_neutral(x, eins, ⊗) = (@test x ⊗ eins ≈ x; @test eins ⊗ x ≈ x) test_monoid(x, y, z, ⊗, eins) = (test_associative(x, y, z, ⊗); test_neutral(x, eins, ⊗)) -test_group(x, y, z, ⊗, eins, inv) = (test_monoid(x,y,z, ⊗, eins);test_inverse(x, eins, ⊗, inv)) -test_multiplicative(x,y,⊗, f) = @test f(x⊗y) ≈ f(x) ⊗ f(y) +test_group(x, y, z, ⊗, eins, inv) = (test_monoid(x, y, z, ⊗, eins);test_inverse(x, eins, ⊗, inv)) +test_multiplicative(x, y, ⊗, f) = @test f(x ⊗ y) ≈ f(x) ⊗ f(y) include("test_Quaternion.jl") diff --git a/test/test_Quaternion.jl b/test/test_Quaternion.jl index bd053d25..c688455f 100644 --- a/test/test_Quaternion.jl +++ b/test/test_Quaternion.jl @@ -2,59 +2,59 @@ import Quaternions.argq # creating random examples -sample{T <: Integer}(QT::Type{Quaternion{T}}) = QT(rand(-100:100,4)..., false) -sample{T <: AbstractFloat}(QT::Type{Quaternion{T}}) = QT(rand(Bool)? quatrand() : nquatrand()) -sample{T <: Integer}(CT::Type{Complex{T}}) = CT(rand(-100:100,2)...) -sample{T <: AbstractFloat}(CT::Type{Complex{T}}) = CT(randn(2)...) +sample(QT::Type{Quaternion{T}}) where {T <: Integer} = QT(rand(-100:100, 4)..., false) +sample(QT::Type{Quaternion{T}}) where {T <: AbstractFloat} = QT(rand(Bool) ? quatrand() : nquatrand()) +sample(CT::Type{Complex{T}}) where {T <: Integer} = CT(rand(-100:100, 2)...) +sample(CT::Type{Complex{T}}) where {T <: AbstractFloat} = CT(randn(2)...) sample(T, n) = T[sample(T) for _ in 1:n] # test algebraic properties of quaternions for _ in 1:10, T in (Float32, Float64, Int32, Int64) - q,q1,q2,q3 = sample(Quaternion{T}, 4) + q, q1, q2, q3 = sample(Quaternion{T}, 4) # skewfield - test_group(q1,q2,q3, +, zero(q), -) - test_group(q1,q2,q3, *, one(q), inv) - test_multiplicative(q1,q2,*,norm) + test_group(q1, q2, q3, +, zero(q), -) + test_group(q1, q2, q3, *, one(q), inv) + test_multiplicative(q1, q2, *, norm) # complex embedding c1, c2 = sample(Complex{T}, 2) - test_multiplicative(c1,c2,*, Quaternion) - test_multiplicative(c1,c2,+, Quaternion) + test_multiplicative(c1, c2, *, Quaternion) + test_multiplicative(c1, c2, +, Quaternion) end let # test rotations - qx = qrotation([1,0,0], pi/4) - @test qx*qx ≈ qrotation([1,0,0], pi/2) - @test qx^2 ≈ qrotation([1,0,0], pi/2) - theta = pi/8 - qx = qrotation([1,0,0], theta) + qx = qrotation([1, 0, 0], pi / 4) + @test qx * qx ≈ qrotation([1, 0, 0], pi / 2) + @test qx^2 ≈ qrotation([1, 0, 0], pi / 2) + theta = pi / 8 + qx = qrotation([1, 0, 0], theta) c = cos(theta); s = sin(theta) Rx = [1 0 0; 0 c -s; 0 s c] @test rotationmatrix(qx) ≈ Rx - theta = pi/6 - qy = qrotation([0,1,0], theta) + theta = pi / 6 + qy = qrotation([0, 1, 0], theta) c = cos(theta); s = sin(theta) Ry = [c 0 s; 0 1 0; -s 0 c] @test rotationmatrix(qy) ≈ Ry - theta = 4pi/3 - qz = qrotation([0,0,1], theta) + theta = 4pi / 3 + qz = qrotation([0, 0, 1], theta) c = cos(theta); s = sin(theta) Rz = [c -s 0; s c 0; 0 0 1] @test rotationmatrix(qz) ≈ Rz - @test rotationmatrix(qx*qy*qz) ≈ Rx*Ry*Rz - @test rotationmatrix(qy*qx*qz) ≈ Ry*Rx*Rz - @test rotationmatrix(qz*qx*qy) ≈ Rz*Rx*Ry + @test rotationmatrix(qx * qy * qz) ≈ Rx * Ry * Rz + @test rotationmatrix(qy * qx * qz) ≈ Ry * Rx * Rz + @test rotationmatrix(qz * qx * qy) ≈ Rz * Rx * Ry - a, b = qrotation([0,0,1], deg2rad(0)), qrotation([0,0,1], deg2rad(180)) - @test slerp(a,b,0.0) ≈ a - @test slerp(a,b,1.0) ≈ b - @test slerp(a,b,0.5) ≈ qrotation([0,0,1], deg2rad(90)) + a, b = qrotation([0, 0, 1], deg2rad(0)), qrotation([0, 0, 1], deg2rad(180)) + @test slerp(a, b, 0.0) ≈ a + @test slerp(a, b, 1.0) ≈ b + @test slerp(a, b, 0.5) ≈ qrotation([0, 0, 1], deg2rad(90)) - @test angle(qrotation([1,0,0], 0)) ≈ 0 - @test angle(qrotation([0,1,0], pi/4)) ≈ pi/4 - @test angle(qrotation([0,0,1], pi/2)) ≈ pi/2 + @test angle(qrotation([1, 0, 0], 0)) ≈ 0 + @test angle(qrotation([0, 1, 0], pi / 4)) ≈ pi / 4 + @test angle(qrotation([0, 0, 1], pi / 2)) ≈ pi / 2 let # test numerical stability of angle ax = randn(3) @@ -68,13 +68,13 @@ end for _ in 1:100 let # test specialfunctions c = Complex(randn(2)...) - q,q2 = sample(Quaternion{Float64}, 4) + q, q2 = sample(Quaternion{Float64}, 4) unary_funs = [exp, log, sin, cos, sqrt, inv, conj, abs2, norm] # since every quaternion is conjugate to a complex number, # one can establish correctness as follows: for fun in unary_funs @test fun(Quaternion(c)) ≈ Quaternion(fun(c)) - @test q2*fun(q)*inv(q2) ≈ fun(q2*q*inv(q2)) + @test q2 * fun(q) * inv(q2) ≈ fun(q2 * q * inv(q2)) end @test exp(log(q)) ≈ q @@ -82,7 +82,7 @@ for _ in 1:100 end let # test qrotation and angleaxis inverse - ax = randn(3); ax = ax/norm(ax) + ax = randn(3); ax = ax / norm(ax) Θ = π * rand() q = qrotation(ax, Θ) @test angle(q) ≈ Θ @@ -92,10 +92,10 @@ for _ in 1:100 end let # test argq - q,q2 = sample(Quaternion{Float64}, 2) - @test q2*argq(q)*inv(q2) ≈ argq(q2*q*inv(q2)) + q, q2 = sample(Quaternion{Float64}, 2) + @test q2 * argq(q) * inv(q2) ≈ argq(q2 * q * inv(q2)) v = Quaternion(0, randn(3)...) - @test argq(v)*norm(v) ≈ v + @test argq(v) * norm(v) ≈ v end let # test normalize @@ -109,24 +109,24 @@ for _ in 1:100 end let # test slerp and linpol if q1 = 1 - q1 = quat(1,0,0,0.) + q1 = quat(1, 0, 0, 0.) # there are numerical stability issues with slerp atm - θ = clamp(rand() * 3.5, deg2rad(5e-1) ,π) + θ = clamp(rand() * 3.5, deg2rad(5e-1), π) ax = randn(3) q2 = qrotation(ax, θ) t = rand() slerp(q1, q2, 0.) ≈ q1 @test slerp(q1, q2, 0.) ≈ q1 @test slerp(q1, q2, 1.) ≈ q2 - @test slerp(q1, q2, t) ≈ qrotation(ax, t*θ) + @test slerp(q1, q2, t) ≈ qrotation(ax, t * θ) @test norm(slerp(q1, q2, t)) ≈ 1 - @test slerp(q1, q2, 0.5) ≈ qrotation(ax, 0.5*θ) - @test linpol(q1, q2, 0.5) ≈ qrotation(ax, 0.5*θ) + @test slerp(q1, q2, 0.5) ≈ qrotation(ax, 0.5 * θ) + @test linpol(q1, q2, 0.5) ≈ qrotation(ax, 0.5 * θ) end let # test conjugation invariance q, q1, q2 = sample(Quaternion{Float64}, 3) - ⊗(s, t) = s*t*inv(s) + ⊗(s, t) = s * t * inv(s) t = rand() @test q ⊗ slerp(q1, q2, t) ≈ slerp(q ⊗ q1, q ⊗ q2, t) @test q ⊗ linpol(q1, q2, t) ≈ linpol(q ⊗ q1, q ⊗ q2, t) From b320e5e1639632c808bd4081fce54e28bc43c34b Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Fri, 4 Aug 2017 21:52:46 +0200 Subject: [PATCH 2/2] fix typo --- src/Octonion.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Octonion.jl b/src/Octonion.jl index 4afab97e..5e04ceba 100644 --- a/src/Octonion.jl +++ b/src/Octonion.jl @@ -23,7 +23,7 @@ convert(::Type{Octonion{T}}, x::Real) where {T} = convert(::Type{Octonion{T}}, z::Complex) where {T} = Octonion(convert(T, real(z)), convert(T, imag(z)), convert(T, 0), convert(T, 0), convert(T, 0), convert(T, 0), convert(T, 0), convert(T, 0)) convert(::Type{Octonion{T}}, q::Quaternion) where {T} = - Octonion(convert(T, real(z)), convert(T, q.v1), convert(T, q.v2), convert(T, q.v3), convert(T, 0), convert(T, 0), convert(T, 0), convert(T, 0)) + Octonion(convert(T, real(q)), convert(T, q.v1), convert(T, q.v2), convert(T, q.v3), convert(T, 0), convert(T, 0), convert(T, 0), convert(T, 0)) convert(::Type{Octonion{T}}, o::Octonion{T}) where {T <: Real} = o convert(::Type{Octonion{T}}, o::Octonion) where {T} = Octonion(convert(T, o.s), convert(T, o.v1), convert(T, o.v2), convert(T, o.v3), convert(T, o.v4), convert(T, o.v5), convert(T, o.v6), convert(T, o.v7), o.norm)