@@ -156,22 +156,139 @@ Base.:(/)(a::MyReal, b::Real) = a.val / b
156156# this used to throw an error
157157@test qrotation ([1 , 0 , 0 ], MyReal (1.5 )) == qrotation ([1 , 0 , 0 ], 1.5 )
158158
159- for _ in 1 : 100
160- let # test specialfunctions
161- c = Complex ( randn ( 2 ) ... )
162- q, q2 = sample (Quaternion{Float64}, 4 )
163- unary_funs = [exp, log, sin, cos, sqrt, inv, conj, abs2, norm]
164- # since every quaternion is conjugate to a complex number,
165- # one can establish correctness as follows:
166- for fun in unary_funs
167- @test fun (Quaternion (c)) ≈ Quaternion ( fun (c) )
159+ @testset " non-analytic functions " begin
160+ q, q2 = randn (Quaternion{Float64}, 2 )
161+ unary_funs = [conj, abs, abs2, norm, sign]
162+ # since every quaternion is conjugate to a complex number,
163+ # one can establish correctness as follows:
164+ @testset for fun in unary_funs
165+ for _ in 1 : 100
166+ c = randn (ComplexF64)
167+ @test fun (Quaternion (c)) ≈ fun (c)
168168 @test q2 * fun (q) * inv (q2) ≈ fun (q2 * q * inv (q2))
169169 end
170+ end
171+ end
172+
173+ @testset " extended complex analytic functions" begin
174+ # all complex analytic functions can be extended to the quaternions
175+ unary_funs = [
176+ sqrt, inv, exp, exp2, exp10, expm1, log, log2, log10, log1p, cis,
177+ sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh,
178+ csc, sec, cot, acsc, asec, acot, csch, sech, coth, acsch, asech, acoth,
179+ sinpi, cospi,
180+ ]
181+ # since every quaternion is conjugate to a complex number,
182+ # one can establish correctness as follows:
183+ @testset for fun in unary_funs
184+ q, q2 = randn (QuaternionF64, 2 )
185+ for _ in 1 : 100
186+ c = randn (ComplexF64)
187+ fun != = cis && @test fun (Quaternion (c)) ≈ fun (c)
188+ @test q2 * fun (q) * inv (q2) ≈ fun (q2 * q * inv (q2))
189+ end
190+ end
170191
171- @test exp (log (q)) ≈ q
172- @test exp (zero (q)) ≈ one (q)
192+ @testset " identities" begin
193+ for _ in 1 : 100
194+ q = randn (QuaternionF64)
195+ @test inv (q) * q ≈ q * inv (q) ≈ one (q)
196+ @test sqrt (q) * sqrt (q) ≈ q
197+ @test exp (log (q)) ≈ q
198+ @test exp (zero (q)) ≈ one (q)
199+ @test log (one (q)) ≈ zero (q)
200+ @test exp2 (log2 (q)) ≈ q
201+ @test exp10 (log10 (q)) ≈ q
202+ @test expm1 (log1p (q)) ≈ q
203+ @test sinpi (q) ≈ sin (π * q)
204+ @test cospi (q) ≈ cos (π * q)
205+ @test all (sincos (q) .≈ (sin (q), cos (q)))
206+ @test all (sincos (zero (q)) .≈ (sin (zero (q)), cos (zero (q))))
207+ if VERSION ≥ v " 1.6"
208+ @test all (sincospi (q) .≈ (sinpi (q), cospi (q)))
209+ @test all (sincospi (zero (q)) .≈ (sinpi (zero (q)), cospi (zero (q))))
210+ end
211+ @test tan (q) ≈ cos (q) \ sin (q) ≈ sin (q) / cos (q)
212+ @test tanh (q) ≈ cosh (q) \ sinh (q) ≈ sinh (q) / cosh (q)
213+ @testset for (f, finv) in [(sin, csc), (cos, sec), (tan, cot), (sinh, csch), (cosh, sech), (tanh, coth)]
214+ @test f (q) ≈ inv (finv (q))
215+ end
216+ @testset for (f, finv) in [(asin, acsc), (acos, asec), (atan, acot), (asinh, acsch), (acosh, asech), (atanh, acoth)]
217+ @test f (q) ≈ finv (inv (q))
218+ end
219+ @test cis (q) ≈ exp (normalize (q - real (q)) * q)
220+ VERSION ≥ v " 1.6" && @test cispi (q) ≈ cis (π * q)
221+ end
173222 end
174223
224+ @testset " additional properties" begin
225+ @testset " log" begin
226+ @test log (zero (QuaternionF64)) === Quaternion (- Inf , 0 , 0 , 0 )
227+ end
228+
229+ @testset " exp" begin
230+ @test exp (Quaternion (0 , 0 , 0 , 0 )) === Quaternion (1. , 0. , 0. , 0. , true )
231+ @test exp (Quaternion (2 , 0 , 0 , 0 )) === Quaternion (exp (2 ), 0 , 0 , 0 , false )
232+ @test exp (Quaternion (0 , 2 , 0 , 0 )) === Quaternion (cos (2 ), sin (2 ), 0 , 0 , true )
233+ @test exp (Quaternion (0 , 0 , 2 , 0 )) === Quaternion (cos (2 ), 0 , sin (2 ), 0 , true )
234+ @test exp (Quaternion (0 , 0 , 0 , 2 )) === Quaternion (cos (2 ), 0 , 0 , sin (2 ), true )
235+
236+ @test norm (exp (Quaternion (0 , 0 , 0 , 0 ))) ≈ 1
237+ @test norm (exp (Quaternion (2 , 0 , 0 , 0 ))) ≠ 1
238+ @test norm (exp (Quaternion (0 , 2 , 0 , 0 ))) ≈ 1
239+ @test norm (exp (Quaternion (0 , 0 , 2 , 0 ))) ≈ 1
240+ @test norm (exp (Quaternion (0 , 0 , 0 , 2 ))) ≈ 1
241+
242+ @test exp (Quaternion (0. , 0. , 0. , 0. )) === Quaternion (1. , 0. , 0. , 0. , true )
243+ @test exp (Quaternion (2. , 0. , 0. , 0. )) === Quaternion (exp (2 ), 0 , 0 , 0 , false )
244+ @test exp (Quaternion (0. , 2. , 0. , 0. )) === Quaternion (cos (2 ), sin (2 ), 0 , 0 , true )
245+ @test exp (Quaternion (0. , 0. , 2. , 0. )) === Quaternion (cos (2 ), 0 , sin (2 ), 0 , true )
246+ @test exp (Quaternion (0. , 0. , 0. , 2. )) === Quaternion (cos (2 ), 0 , 0 , sin (2 ), true )
247+
248+ @test norm (exp (Quaternion (0. , 0. , 0. , 0. ))) ≈ 1
249+ @test norm (exp (Quaternion (2. , 0. , 0. , 0. ))) ≠ 1
250+ @test norm (exp (Quaternion (0. , 2. , 0. , 0. ))) ≈ 1
251+ @test norm (exp (Quaternion (0. , 0. , 2. , 0. ))) ≈ 1
252+ @test norm (exp (Quaternion (0. , 0. , 0. , 2. ))) ≈ 1
253+
254+ @test exp (Quaternion (0 ,0 ,0 ,0 )) isa Quaternion{Float64}
255+ @test exp (Quaternion (0. ,0 ,0 ,0 )) isa Quaternion{Float64}
256+ @test exp (Quaternion (0 // 1 ,0 ,0 ,0 )) isa Quaternion{Float64}
257+ @test exp (Quaternion (BigFloat (0 ),0 ,0 ,0 )) isa Quaternion{BigFloat}
258+
259+ # https://github.com/JuliaGeometry/Quaternions.jl/issues/39
260+ @testset " exp(::Quaternion{Int})" begin
261+ @test exp (Quaternion (1 ,1 ,1 ,1 )) ≈ exp (Quaternion (1.0 ,1.0 ,1.0 ,1.0 ))
262+ end
263+ end
264+ end
265+ end
266+
267+ @testset " ^" begin
268+ @testset " ^(::Quaternion, ::Real)" begin
269+ for _ in 1 : 100
270+ q = randn (QuaternionF64)
271+ @test q^ 2.0 ≈ q * q
272+ @test q^ 1.0 ≈ q
273+ @test q^- 1.0 ≈ inv (q)
274+ @test q^ 1.3 ≈ exp (1.3 * log (q))
275+ @test q^ 7.8 ≈ exp (7.8 * log (q))
276+ @test q^ 1.3f0 ≈ exp (1.3f0 * log (q))
277+ @test q^ 7.8f0 ≈ exp (7.8f0 * log (q))
278+ end
279+ end
280+ @testset " ^(::Quaternion, ::Quaternion)" begin
281+ @test Quaternion (ℯ,0 ,0 ,0 )^ Quaternion (0 ,0 ,π/ 2 ,0 ) ≈ Quaternion (0 ,0 ,1 ,0 )
282+ @test Quaternion (3.5 ,0 ,0 ,2.3 )^ Quaternion (0.2 ,0 ,0 ,1.7 ) ≈
283+ Quaternion (real ((3.5 + 2.3im )^ (0.2 + 1.7im )),0 ,0 ,imag ((3.5 + 2.3im )^ (0.2 + 1.7im )))
284+ for _ in 1 : 100
285+ q, p = randn (QuaternionF64, 2 )
286+ @test q^ p ≈ exp (p * log (q))
287+ end
288+ end
289+ end
290+
291+ for _ in 1 : 100
175292 let # test qrotation and angleaxis inverse
176293 ax = randn (3 ); ax = ax / norm (ax)
177294 Θ = π * rand ()
@@ -230,37 +347,6 @@ for _ in 1:100
230347 end
231348end
232349
233- @testset " exp" begin
234- @test exp (Quaternion (0 , 0 , 0 , 0 )) === Quaternion (1. , 0. , 0. , 0. , true )
235- @test exp (Quaternion (2 , 0 , 0 , 0 )) === Quaternion (exp (2 ), 0 , 0 , 0 , false )
236- @test exp (Quaternion (0 , 2 , 0 , 0 )) === Quaternion (cos (2 ), sin (2 ), 0 , 0 , true )
237- @test exp (Quaternion (0 , 0 , 2 , 0 )) === Quaternion (cos (2 ), 0 , sin (2 ), 0 , true )
238- @test exp (Quaternion (0 , 0 , 0 , 2 )) === Quaternion (cos (2 ), 0 , 0 , sin (2 ), true )
239-
240- @test norm (exp (Quaternion (0 , 0 , 0 , 0 ))) ≈ 1
241- @test norm (exp (Quaternion (2 , 0 , 0 , 0 ))) ≠ 1
242- @test norm (exp (Quaternion (0 , 2 , 0 , 0 ))) ≈ 1
243- @test norm (exp (Quaternion (0 , 0 , 2 , 0 ))) ≈ 1
244- @test norm (exp (Quaternion (0 , 0 , 0 , 2 ))) ≈ 1
245-
246- @test exp (Quaternion (0. , 0. , 0. , 0. )) === Quaternion (1. , 0. , 0. , 0. , true )
247- @test exp (Quaternion (2. , 0. , 0. , 0. )) === Quaternion (exp (2 ), 0 , 0 , 0 , false )
248- @test exp (Quaternion (0. , 2. , 0. , 0. )) === Quaternion (cos (2 ), sin (2 ), 0 , 0 , true )
249- @test exp (Quaternion (0. , 0. , 2. , 0. )) === Quaternion (cos (2 ), 0 , sin (2 ), 0 , true )
250- @test exp (Quaternion (0. , 0. , 0. , 2. )) === Quaternion (cos (2 ), 0 , 0 , sin (2 ), true )
251-
252- @test norm (exp (Quaternion (0. , 0. , 0. , 0. ))) ≈ 1
253- @test norm (exp (Quaternion (2. , 0. , 0. , 0. ))) ≠ 1
254- @test norm (exp (Quaternion (0. , 2. , 0. , 0. ))) ≈ 1
255- @test norm (exp (Quaternion (0. , 0. , 2. , 0. ))) ≈ 1
256- @test norm (exp (Quaternion (0. , 0. , 0. , 2. ))) ≈ 1
257-
258- @test exp (Quaternion (0 ,0 ,0 ,0 )) isa Quaternion{Float64}
259- @test exp (Quaternion (0. ,0 ,0 ,0 )) isa Quaternion{Float64}
260- @test exp (Quaternion (0 // 1 ,0 ,0 ,0 )) isa Quaternion{Float64}
261- @test exp (Quaternion (BigFloat (0 ),0 ,0 ,0 )) isa Quaternion{BigFloat}
262- end
263-
264350@testset " random quaternions" begin
265351 @testset " quatrand" begin
266352 rng = Random. MersenneTwister (42 )
0 commit comments