convenience variables for quaternions friendly suggestion
iq = Quaternion(0,1,0,0)
jq = Quaternion(0,0,1,0)
kq = Quaternion(0,0,0,1)
Thank you for the suggestion! There was a related issue (#50).
I also think the constants add convenience. To implement the constants, we need to decide the following:
- Which symbols should we use?
iq, jq, kqim_i, im_j, im_kimx, imy, imz- etc.
- Should we update the
Base.show(::IO, q::Quaternion)?-
Yeah, the Base docs indicate that
imis convenient syntactic sugar that is probably best used for convenience in the REPL or for defining constants in the code but in general should not be used.- https://github.com/JuliaGeometry/Quaternions.jl/issues/50#issuecomment-1046042942
- I couldn't find documentation explicitly discouraging the use of
im. Also, some comments in #50 are outdated. (e.g.OctanionandDualQuaternionare no longer provided in this package.)
-
I agree that most of the arguments against including these convenience variables no longer apply, so it's worth reconsidering this.
- I couldn't find documentation explicitly discouraging the use of
im. Also, some comments in Use𝒊, 𝒋, 𝒌as symbols of the basis ofQuaternion? #50 are outdated. (e.g.OctanionandDualQuaternionare no longer provided in this package.)
From https://docs.julialang.org/en/v1/manual/complex-and-rational-numbers/#Complex-Numbers:
The [literal numeric coefficient notation](@ref man-numeric-literal-coefficients) does not work when constructing a complex number
from variables. Instead, the multiplication must be explicitly written out:
```jldoctest
julia> a = 1; b = 2; a + b*im
1 + 2im
```
However, this is *not* recommended. Instead, use the more efficient [`complex`](@ref) function to construct
a complex value directly from its real and imaginary parts:
```jldoctest
julia> a = 1; b = 2; complex(a, b)
1 + 2im
```
This construction avoids the multiplication and addition operations.
i.e. it's safe to use im when a and b are constants, e.g. in the REPL or when defining a constant within a function. But otherwise complex should be used.
Which symbols should we use?
* `iq, jq, kq` * [`im_i, im_j, im_k`](https://github.com/JuliaGeometry/Quaternions.jl/issues/50#issuecomment-1045786440) * [`imx, imy, imz`](https://moble.github.io/Quaternionic.jl/stable/manual/#Quaternionic.imx) * etc.
I don't have a strong preference here. Base uses im instead of i, since i is commonly an index. So I don't think we need to use a variant of im, just something that is unlikely to clash with another namespace. We don't use xyz anywhere else, and this is uncommon with quaternions, so I'd say no. Underscores are insufficiently compact. iq, jq, etc is fine. My only annoyance is that we use v1, v2, etc in the fields of Quaternion. I wouldn't like iq1, iq2, etc though.
The following show implementation is based on Complex's. Because the strings are much longer than Complex's, I think it looks nicer to render the bases as bold (while still keeping the unicode as non-bold):
# use Bool to avoid promoting integer types e.g. Int16 to Int64
const iq = Quaternion(false, true, false, false)
const jq = Quaternion(false, false, true, false)
const kq = Quaternion(false, false, false, true)
function Base.show(io::IO, q::Quaternion)
compact = get(io, :compact, false)::Bool
show(io, q.s)
for (v, sym) in zip((q.v1, q.v2, q.v3), (:iq, :jq, :kq))
if signbit(v) && !isnan(v)
print(io, compact ? "-" : " - ")
if isa(v, Signed) && !isa(v, BigInt) && v == typemin(typeof(v))
show(io, -widen(v))
else
show(io, -v)
end
else
print(io, compact ? "+" : " + ")
show(io, v)
end
printstyled(io, sym; bold=true)
end
end
function Base.show(io::IO, q::Quaternion{Bool})
name = findfirst(Base.Fix2(===, q), (; iq, jq, kq))
if name === nothing
print(io, "Quaternion(", q.s, ',', q.v1, ',', q.v2, ',', q.v3, ")")
else
printstyled(io, name; bold=true)
end
end
julia> iq
iq
julia> jq
jq
julia> kq
kq
julia> 1+3jq
1 + 0iq + 3jq + 0kq
julia> Quaternion(true, true, false, false)
Quaternion(true,true,false,false)
julia> randn(QuaternionF64, 3)
3-element Vector{QuaternionF64}:
0.14029180109916273 - 1.1540872532752005iq + 0.1906721473746647jq + 1.2743183122684032kq
-1.030315293683978 + 0.2523419854373315iq - 0.38537355553418795jq - 1.089803948247486kq
-1.1036492479688396 - 0.3894607415241461iq - 0.1328394303475304jq - 0.5361253909830082kq
julia> randn(QuaternionF64, 3, 2)
3×2 Matrix{QuaternionF64}:
0.389246-0.606827iq+0.704692jq+0.205152kq 0.346844+0.412816iq-0.409325jq+0.0666423kq
0.796425-0.147743iq+0.495668jq-0.237316kq -1.03524+0.672756iq-0.149115jq-0.199047kq
-0.326256+0.346335iq-0.165236jq-0.0462912kq -0.432593+0.138248iq-0.400217jq-0.221615kq