# Grouping Rotation objects in a vector

**URL:** <https://discourse.julialang.org/t/grouping-rotation-objects-in-a-vector/61899>\
**Category:** New to Julia\
**Tags:** parametric-types, structtypes\
**Created:** [May 27, 2021, 1:59am UTC](https://discourse.julialang.org/t/grouping-rotation-objects-in-a-vector/61899 "2021-05-27T01:59:46Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![baptnz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baptnz/32/24519_2.png) [@baptnz](https://discourse.julialang.org/u/baptnz)\
**Post date:** [May 27, 2021, 1:59am UTC](https://discourse.julialang.org/t/grouping-rotation-objects-in-a-vector/61899/1 "2021-05-27T01:59:46Z")

</div>

I’m working with 3D rotations, and my current code implements rotation matrices from Euler angles.

I would like to switch to a more general approach that leverages Rotations.jl (or `ReferenceFrameRotations.jl`, but that’s a separate discussion). I like the idea of abstracting away the specific convention that the user may prefer (parametrising with Euler angles, or axis-angle, or quaternions, etc.) but I haven’t been able to adapt my code to work with the supertype common to them all. Here’s what I mean:

```julia
using StaticArrays

# current definition: each object is given 3 Euler angles to describe the rotation
struct current_clust{T}

    angles::Vector{SVector{3,T}}

end

current_clust(SVector.(1:4,2,3))
# current_clust{Int64}(SVector{3, Int64}[[1, 2, 3], [2, 2, 3], [3, 2, 3], [4, 2, 3]])

```

vs my attempt at a new approach:

```julia
using Rotations

# new implementation: each object would be assigned a generic "Rotation" object
struct new_clust{T}

    angles::Vector{Rotation{3,T}}

end

r = rand(RotMatrix{3})
q = UnitQuaternion(r)
e = RotXYZ(0,1,2)
aa = AngleAxis(r)

new_clust([r, q, e, aa])
# ERROR: DimensionMismatch("No precise constructor for Rotation{3, Float64} found. Length of input was 9.")

```

Is my idea flawed (e.g. would the `new_clust` objects be inefficient because of arbitrary types)? Or do I just have the syntax wrong? (e.g I need a different container)?

I don’t really know how to probe the different subtypes – from what is printed they all seem “compatible”, as in

```julia
supertype(typeof(r))
Rotation{3, Float64}

```

etc.

giving me the impression that I could just group them together in a vector. But at the same time I expect that internally they’re stored quite differently (e.g. 3, 4, or maybe 9 elements, etc.). How can I check this kind of thing?

Of course I could coerce everything into 3x3 matrices, but that would seem a bit wasteful.

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [May 27, 2021, 8:03pm UTC](https://discourse.julialang.org/t/grouping-rotation-objects-in-a-vector/61899/2 "2021-05-27T20:03:08Z")

</div>

> [@baptnz](#):
>
> e.g. would the `new_clust` objects be inefficient because of arbitrary types

Your instinct here is correct–`Rotation` is an abstract type, so you’d be running into this performance tip: [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-abstract-container)

If it were me, I would probably skip the generic container entirely and store a `Vector{UnitQuaternion{T}}`. Dealing with collections of differently-typed objects can be tricky, and it’s not actually obvious that you need that here. Since a quaternion is already a nice representation of a rotation, it might make sense to just pick that fundamental type to store.

Note that this doesn’t restrict you at all from _populating_ that vector with whatever type is convenient. You can `push!` to that vector and any element you add will automatically try to `convert` into a quaternion:

```julia
julia> using Rotations

julia> vec = Vector{UnitQuaternion{Float64}}()
UnitQuaternion{Float64}[]

julia> push!(vec, AngleAxis(0, 1, 0, 0))
1-element Vector{UnitQuaternion{Float64}}:
 [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]

julia> push!(vec, RotXYZ(0, 1, 2))
2-element Vector{UnitQuaternion{Float64}}:
 [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
 [-0.22484509536615288 -0.49129549643388193 0.8414709848078966; 0.9092974268256818 -0.41614683654714246 -5.551115123125783e-17; 0.3501754883740148 0.7651474012342927 0.5403023058681398]

julia> vec
2-element Vector{UnitQuaternion{Float64}}:
 [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
 [-0.22484509536615288 -0.49129549643388193 0.8414709848078966; 0.9092974268256818 -0.41614683654714246 -5.551115123125783e-17; 0.3501754883740148 0.7651474012342927 0.5403023058681398]

```

The only reason to actually store the separate rotations as different types is if you actually care about accessing them in their original types later, rather than just as some totally equivalent representation.

---

<div class="post-metadata">

**Author:** ![baptnz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baptnz/32/24519_2.png) [@baptnz](https://discourse.julialang.org/u/baptnz)\
**Post date:** [May 27, 2021, 8:21pm UTC](https://discourse.julialang.org/t/grouping-rotation-objects-in-a-vector/61899/3 "2021-05-27T20:21:24Z")

</div>

Thanks, I think I agree with your points but just two quick clarifications:

> Since a quaternion is already a nice representation of a rotation, it might make sense to just pick that fundamental type to store.

Picking just one type makes sense to me, but I’m not sure this is the best for my use-case. I worry quaternions might get in the way of ForwardDiff (I couldn’t quite make sense of some thread discussing the matter), and they’re also the least-intuitive (to me at least). 3x3 matrices feel like one obvious alternative, but they’re quite wasteful. Euler angles have their own problems (gimbal lock etc.). Maybe I should go with axis-angle; they’re not friendly to combine, but as you say I could always use different formulations beforehand, and coerce into this specific form for convenient storage.

> The only reason to actually store the separate rotations as different types is if you actually care about accessing them in their original types later, rather than just as some totally equivalent representation.

Yes, you make a good point: I was thinking of convenience to generate those rotations (using whichever convention is easier for a given problem, possibly combining various rotations into one, etc.) but those steps don’t need to be tied to the final storage mode: I can just coerce into one format (provided it’s a good one…).

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [May 27, 2021, 8:34pm UTC](https://discourse.julialang.org/t/grouping-rotation-objects-in-a-vector/61899/4 "2021-05-27T20:34:18Z")

</div>

FWIW I’ve done lots of autodiff computation through quaternions, and it certainly can work just fine. You may run into edge cases, but that’s true with any representation, so you might as well pick the one that isn’t a minefield of singularities.

> [@baptnz](#):
>
> Yes, you make a good point: I was thinking of convenience to generate those rotations (using whichever convention is easier for a given problem, possibly combining various rotations into one, etc.) but those steps don’t need to be tied to the final storage mode

Right–that all sounds great, and would make lots of sense as one or more helpful methods for your `new_clust{T}` type.

---

<div class="post-metadata">

**Author:** ![baptnz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baptnz/32/24519_2.png) [@baptnz](https://discourse.julialang.org/u/baptnz)\
**Post date:** [May 27, 2021, 8:50pm UTC](https://discourse.julialang.org/t/grouping-rotation-objects-in-a-vector/61899/5 "2021-05-27T20:50:34Z")

</div>

> [@rdeits](#):
>
> FWIW I’ve done lots of autodiff computation through quaternions, and it certainly can work just fine.

That’s reassuring, thanks! I’ll give them a try then.

---

<div class="post-metadata">

**Author:** ![Orbots](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/orbots/32/3392_2.png) [@Orbots](https://discourse.julialang.org/u/Orbots)\
**Post date:** [May 27, 2021, 9:24pm UTC](https://discourse.julialang.org/t/grouping-rotation-objects-in-a-vector/61899/6 "2021-05-27T21:24:05Z")

</div>

> [@baptnz](#):
>
> they’re also the least-intuitive (to me at least)

Quaternions are actually quite intuitive if you first learn what a bivector is. No hyperspheres needed. Then you also get a very nice connection between angle-axis and quaternions via exponential/log maps as a bonus. `exp(angle_axis*i) = quaternion`.

Any intro to geometric algebra will have a section on quaternions ( they are called rotors in GA ).

This here is pretty easy to follow. Note that quaternions are really the same thing as rotors ( dual ).

[https://marctenbosch.com/quaternions/](https://marctenbosch.com/quaternions/)

---

<div class="post-metadata">

**Author:** ![baptnz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baptnz/32/24519_2.png) [@baptnz](https://discourse.julialang.org/u/baptnz)\
**Post date:** [May 28, 2021, 8:41am UTC](https://discourse.julialang.org/t/grouping-rotation-objects-in-a-vector/61899/7 "2021-05-28T08:41:58Z")

</div>

Thanks – I’ve had geometric algebra books on my reading list for years.

---

<div class="post-metadata">

**Author:** ![baptnz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baptnz/32/24519_2.png) [@baptnz](https://discourse.julialang.org/u/baptnz)\
**Post date:** [May 29, 2021, 12:29am UTC](https://discourse.julialang.org/t/grouping-rotation-objects-in-a-vector/61899/8 "2021-05-29T00:29:18Z")

</div>

For info, I’ve now refactored my code to use Rotations.jl and store the parameters as quaternions. Pretty happy with the change so far, it’s quite convenient to be able to choose the easiest parametrisation for a given geometry. And quaternions do come in handy for composition. I have yet to try ForwardDiff on the code though.

Amusingly, three.js quaternions are stored with a different convention, which tripped me at first.

 ![Screen Shot 2021-05-29 at 12.26.20 PM](https://global.discourse-cdn.com/julialang/original/3X/0/d/0d4df7ed89be165454165f0f6e973363ecd440d8.png)

 ![Screen Shot 2021-05-28 at 8.06.35 PM](https://global.discourse-cdn.com/julialang/original/3X/7/0/70785f50789bd16ceda214b6a69f6425122b0448.png)

---

<div class="post-metadata">

**Author:** ![Orbots](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/orbots/32/3392_2.png) [@Orbots](https://discourse.julialang.org/u/Orbots)\
**Post date:** [June 14, 2021, 5:30pm UTC](https://discourse.julialang.org/t/grouping-rotation-objects-in-a-vector/61899/9 "2021-06-14T17:30:15Z")

</div>

> [@baptnz](#):
>
> Amusingly, three.js quaternions are stored with a different convention, which tripped me at first.

Yeah, you need to read the code when looking at quaternion packages, since conventions differ. There has been some interest in unifying quaternions here. [Taking Quaternions Seriously](https://discourse.julialang.org/t/taking-quaternions-seriously/44834)
