I want to have a type (or maybe another container) that contains matrices of different dimensions and be able to do operations (like summing them), but I’m having trouble doing this in a type stable way. Something like:
type Container
mat#::?
end
function mysum(c::Container)
s = 0.0
for m in c.mat
s += sum(m)
end
s
end
c = Container([rand(10,10),rand(10)])
@code_warntype mysum(c)
Doesn’t work because [rand(10,10),rand(10)] is not homogeneous (can’t declare it as Array{Array{Float64,N},1} for a fixed N).
Using a recursive definition of mysum improves things a bit but the top function remains unstable:
mysum2(c::Container) = mysum2((c.mat...))
mysum2(args) = mysum2(0.0,args...)
mysum2(out::Float64,mat::Array{Float64},rest...) = out + mysum2(sum(mat),rest...)
mysum2(out::Float64,mat::Array{Float64}) = out + sum(mat)
@code_warntype mysum2( (c.mat...) ) #type stable, but
@code_warntype mysum2( c ) #type unstable
I could generate a collection of types of the sort:
type Container2{N1,N2}
m1::Array{Float64,N1}
m2::Array{Float64,N2}
end
But that’s not very elegant.
Am I missing something obvious here ? Is there a pattern to solve this kind of issues ?
Yes but we are speaking about using tuples instead of custom types here. I mean you can overwrite show for some tuples of arrays, but that’s not exactly ideal.
When you try to write something a bit more involved than sum it also quickly gets complicated (admittedly I’m not used to work with tuples, maybe it gets easier with practice).
If your real-world data is going to have dimensions larger than 10 by 10, I would ignore type stability for summing over the container and just use a Vector{Array{Float64}}, then assert the result type if I know it to prevent type instability from propagating. For large data, the cost of dynamic dispatch to vectorized container operations is probably negligible.