I am building a custom array type to emulate indexing in a special-case multidimensional sparse tensor.
My type is backed by a SparseMatrixCSC and exposes a Nsum
-dimensional interface, where the dimensions are in 2 groups, Npre
, Npost
:
struct SparseSynapses{Npre,Npost,Nsum} <: AbstractArray{Int8,Nsum}
data::SparseMatrixCSC{Int8,Int}
preDims::NTuple{Npre,Int}
postDims::NTuple{Npost,Int}
# Translate cartesian to linear indices
preLinIdx::LinearIndices{Npre}
postLinIdx::LinearIndices{Npre}
function SparseSynapses{Npre,Npost,Nsum}(data,preDims,postDims) where {Npre,Npost,Nsum}
Npre+Npost == Nsum || error("Nsum must be Npre+Npost")
preLinIdx= LinearIndices(preDims)
postLinIdx= LinearIndices(postDims)
new{Npre,Npost,Nsum}(data,preDims,postDims,preLinIdx,postLinIdx);
end
end
I would like to be able to index into this array like so:
synapses= SparseSynapses((4,5),(2,3))
synapses[2:3,1:3,:,2]
My first solution (works) is to simply overwrite the scalar getindex, with a cartesian-to-linear transform:
function Base.getindex(S::SparseSynapses{Npre,Npost}, I::Vararg{Int,N}) where {Npre,Npost,N}
pre= S.preLinIdx[CartesianIndex(I[1:Npre])]
post= S.postLinIdx[CartesianIndex(I[Npre+1:Npre+Npost])]
S.data[pre,post]
end
However, this scalar access pattern of the LinearIndices arrays should be very inefficient. If I want to consolidate these accesses, which function should I extend?
Base.getindex(A, I...)
, Base.to_indices(A, I::Tuple)
or something else?
PS. My access pattern looks a bit similar to how SubArrays work, maybe that can help me?