Struct containing differently-sized Static Vectors

I want to define a struct for a cluster of particles that each have a position and orientation in space. I would like my representation to work for both 2D and 3D, which is a bit tricky since in 2D I represent orientation as an angle with a SVector{1} and in 3D I need a quaternion, which is a SVector{4}. I would like to have a struct that only contains the dimensionality of space D as a type parameter, but not the number of orientation variables. That is, I would like to have is something that behaves like this:

struct Cluster{D,F<:Real}
    xs::Vector{SVector{D,F}}
    thetas::Vector{SVector{D == 2 ? 1 : 4,F}}
end

which obviously doesnt work since you cannot do arithmetic with typevars.

What would be a solution that gives me the closest behavior to this?

I specifically want to avoid having multiple type parameters, as in

struct Cluster{D,R,F<:Real}
    xs::Vector{SVector{D,F}}
    thetas::Vector{SVector{R,F}}
end

I only way I can think of would be to define an AbstractCluster and then a Cluster2D <: AbstractCluster and Cluster3D <: AbstractCluster, but that doesn’t seem super elegant to me.

Why is this? Typevars are the main way, we can communicate constraints to the compiler. You could set the additional typevar within an inner constructor and you’d never really have to worry about.

And it is basically equivalent to having the extra typevar. The typevar would save you the typing. If you want to have structurally differences than you need multiple concrete types.

So if you really require a single concrete type to do both then I’d suggest either making two fields and using the correct one based on the type or making the field an SVector{4} where all values except the first one are 0 if D==2-

1 Like

Thanks for the quick reply. Maybe there is just a simple thing I am missing: Is there a way to dispatch without writing out all the typevars all the time?

For example, say my full type signature is Cluster{D,R,T<:Integer, F<:AbstractFloat}, where D and R are the dimension of my static vectors.
I will never dispatch on R, so is there a way of not having to write out the full type signature like below?

f(c::Cluster{D,R,T,F}) where {D,R,T,F} = ...

If there is, then just setting R with an inner constructor would be ideal. I just want to avoid having to sprinkle Rs everywhere, basically.

You can partially provide typevars :slight_smile: E.g. Array{Int} really means Array{Int, N} where N.

So put the typevars you want to dispatch on to the left and all the other stuff further to the right :slight_smile:

Edit: Of course you can also always use aliases like

Matrix{T} = Array{T,2} where T

and then dispatch on that.

1 Like

That’s awesome (and I should have thought of that). Thanks a lot! :slight_smile:

1 Like