-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Release Real type constraint on Quaternion #79
Comments
Oh, I was thinking that julia> using ForwardDiff, DualNumbers
julia> ForwardDiff.Dual <: Real
true
julia> DualNumbers.Dual <: Real
false Related issues:
I'm not much familiar with biquaternions, but it seems reasonable to change |
Yeah, both are really purposed for automatic differentiation, but The other thing we could do is make an Then there would also be the option of defining a
Yeah, I'm pretty sure biquaternions just won't work without quite a bit of work (that we shouldn't do), but it would be nice if our types supported someone trying to implement them. |
None of this package's direct dependents use
|
Could you provide an example that
Biquaternion with For the above reasons, I now tend to avoid releasing the type constraint... |
So both DualNumbers and ForwardDiff are not trying to implement dual numbers as a Because ForwardDiff is doing AD, its For |
I see. Thanks for the detailed explanation! |
Here's some code that checks using Quaternions, ForwardDiff
function dualquat_to_quatdual(dq)
q0args = let (; s, v1, v2, v3) = dq.q0
(s, v1, v2, v3)
end
qeargs = let (; s, v1, v2, v3) = dq.qe
(s, v1, v2, v3)
end
return Quaternion(ForwardDiff.Dual.(q0args, qeargs)...)
end
function dual_to_nondual(q::Quaternion{<:ForwardDiff.Dual})
qargs = let (; s, v1, v2, v3) = q
(s, v1, v2, v3)
end
q0 = Quaternion(ForwardDiff.value.(qargs)...)
qe = Quaternion(ForwardDiff.partials.(qargs, 1)...)
return DualQuaternion(q0, qe)
end
function dual_to_nondual(d::ForwardDiff.Dual)
return Quaternions.Dual(ForwardDiff.value(d), ForwardDiff.partials(d, 1))
end
dual_to_nondual(x) = x
unary_functions = [+, -, exp, log, sign, abs, abs2, one, zero, conj, float, inv, sign, sqrt, angle]
binary_functions = [+, -, *, /, ==, ^]
dq1, dq2 = rand(DualQuaternionF64, 2)
# check all implemented functions. Difference should be about 0
map(unary_functions) do f
f => f(dq1) - dual_to_nondual(f(dualquat_to_quatdual(dq1)))
end
map(binary_functions) do f
f => f(dq1, dq2) - dual_to_nondual(f(dualquat_to_quatdual(dq1), dualquat_to_quatdual(dq2)))
end
# check that if we use ForwardDiff, we can still AD through the function
function foo(args)
dq1 = DualQuaternion(Quaternion(args[1:4]...), Quaternion(args[5:8]...))
dq2 = DualQuaternion(Quaternion(args[9:12]...), Quaternion(args[13:16]...))
dq3 = dq1 * dq2
q0 = dq3.q0
qe = dq3.qe
return [q0.s, q0.v1, q0.v2, q0.v3, qe.s, qe.v1, qe.v2, qe.v3]
end
flatten(x::ForwardDiff.Dual) = (ForwardDiff.value(x), ForwardDiff.partials(x, 1))
function foo2(args)
dq1 = Quaternion(ForwardDiff.Dual.(args[1:4], args[5:8])...)
dq2 = Quaternion(ForwardDiff.Dual.(args[9:12], args[13:16])...)
dq = dq1 * dq2
r = (dq.s, dq.v1, dq.v2, dq.v3)
return [ForwardDiff.value.(r)..., ForwardDiff.partials.(r, 1)...]
end
args = randn(16)
foo(args) ≈ foo2(args)
ForwardDiff.jacobian(foo, args) ≈ ForwardDiff.jacobian(foo2, args) Both implementations agree except for I also tested that using |
Closing since we instead opted for #92 |
There are several variations on quaternions that uses non-real numbers with the quaternion multiplication operations, for which most/all of the current defaults can be kept. The two I'm thinking of are biquaternions and dual quaternions.
Currently we implement dual quaternions as 2 quaternions, one being the "primal" and one being corresponding "infinitesimal", but equivalently, it could be implemented as 4
Dual
numbers, tying together the individual primals with infinitesimals. If this latter choice was made,DualQuaternion{T}
could just be an alias forQuaternion{Dual{T}}
, and we may we able to eliminate any special functionality for dual quaternions.The steps would be:
Real
type constraint for theT
inQuaternion{T}
.Quaternion
implementations more generalDualQuaternion
's struct with aconst
, keeping the same tests.These are breaking changes. Note that biquaternions would probably not work so long as we embed the complex numbers in the quaternions #62.
Relates #16 and #8
The text was updated successfully, but these errors were encountered: