Mixing GPU/CPU in struct definition

I use big structs in my code with lots of different vectors of integers and floats like so:

mutable struct Bodies
    a:: Vector{StaticArrays.SVector{3,Float64}}
    b:: Int
    c:: Vector{StaticArrays.SVector{3,Int}}
    d:: Int
    e:: Vector{StaticArrays.SVector{4,Int}}
    f:: Int
    g:: Int
    h:: Vector{Int}
    i:: Vector{Union{ StaticArrays.SVector{3,Int},StaticArrays.SVector{4,Int} }}
    j:: Vector{Vector{Int}}

Right now this code is running on the CPU. An older version without structs ran on the GPU and now I want to port this one to be CPU/GPU runnable.
How would you guys recommend I do that? Do I need to have 2 structs definitions, one using CuArrays and one with Vectors or is there a more elegant way to do this?
Thanks a lot!

You can use a single struct definition, with type parameters

1 Like

How does that work with Vectors and CuArrays?
I tried this:

 mutable struct Bodies{V}
           a :: V{StaticArrays.SVector{3,Float64}}
           nPoints :: Int
           c :: V{StaticArrays.SVector{3,Int}}

and it doesn’t work.
Thanks a lot!

Yep, that doesn’t work. The error such a definition throws (I use Dict instead of StaticArray to not need using a package):

julia> struct A{V}
ERROR: TypeError: in Type{...} expression, expected UnionAll, got a value of type TypeVar
 [1] top-level scope
   @ REPL[1]:1

is a bit cryptic. But it boils down to that types need to be fully defined within the type-def (i.e. a UnionAll and not a TypeVar). This means that you cannot do “type calculations” within the type-def. For instance this is not possible either:

julia> struct B{N}
       a::Array{Int, N+1}
ERROR: MethodError: no method matching +(::TypeVar, ::Int64)

What you can do is:

julia> struct D{V<:U where U<:AbstractVector{D} where D<:Dict{Int,Int}}

julia> D([Dict(1=>1)], [Dict(2=>2)])
D{Vector{Dict{Int64, Int64}}}([Dict(1 => 1)], [Dict(2 => 2)])

or equivalently

julia> struct E{V<:AbstractVector{<:Dict{Int,Int}}}

julia> E([Dict(1=>1)], [Dict(2=>2)])
E{Vector{Dict{Int64, Int64}}}([Dict(1 => 1)], [Dict(2 => 2)])

However, for your case this approach may not be that useful as the types of your fields all seem a bit different. So, probably you just give each a type parameter (without any fancy & verbose constraints) and be done with it.

Ok, this is getting complicated. I think I might define two structs, as I don’t want the definitions to be super messy.
Thanks a lot!

Yes, that is probably best, as too many type parameters are bad (e.g. really annoying in error messages). You can use something like this to avoid repetition:

julia> for (n,V) in zip([:CPUstuct, :GPUstruct], [:Vector, :CuVector])
       struct $n


1 Like