I have an AbstractVector type x and want to get the type of the 2D version. For example, if I’m passed a x::CuArray{T,1,device}, I’d like to end up with a type CuArray{T,2,device}.
One (type-unstable?) way to do this is to get the type of a reshape.
Do you need it to work for all abstract vectors, or would cuda vectors and julia vectors be enough? If so, you could just dispatch to those two types of vectors
_promote_1D_vector_type(x::CuArray{T,1,M}) where {T,M} = CuArray{T,2,M}
_promote_1D_vector_type(x::Vector{T}) where T = Matrix{T}
Otherwise, I think what you have is going to be best combination of simple and general. I would maybe write it as
Note that the reshaping approach has limitations, because it will often wrap the vector inside a ReshapedArray instead of returning the “true” 2D type, even when that type exists.
Here’s an example:
julia> using SparseArrays
julia> x = spzeros(4)
4-element SparseVector{Float64, Int64} with 0 stored entries
julia> reshape(x, 2, 2)
2×2 reshape(::SparseVector{Float64, Int64}, 2, 2) with eltype Float64:
0.0 0.0
0.0 0.0
julia> typeof(ans) # not a SparseMatrixCSC
Base.ReshapedArray{Float64, 2, SparseVector{Float64, Int64}, Tuple{}}
I think @gdalle’s example illustrates another layer of conplexity hiding in this seemingly simple question: There just might not be a “N+1 D” version of a “N D” type.
So the best course of action is probably to use reshape as a default implementation and add methods for specific types where this does not give a good result (like SparseVector, SparseMatrixCSC,…)
In NDTools.jl we have something called reorient which works for N-d arrays as it uses a Val(d) parameter. However, this is only type stable if the d comes from type e.g. the dimensionality of another array:
Typically you use similar to construct an instance of a (mutable) similar type, e.g. similar(x, 3, 4) makes a 3 \times 4 uninitialized array of a similar type to x, which you can then initialize to desired values.
Is there a reason why you need to construct the type by itself, rather than directly constructing an instance of the type?
Thank you everyone for these insightful comments, I didn’t appreciate these nuances!
I’m pleasantly surprised to be wrong about the type stability, I had assumed that the reshape would cause inference since it is operating on the instance.
Here’s the context: RandomizedPreconditioners.jl takes in a PSD system A (anything that defines mul!) and builds a Nyström sketch by evaluating A on some random vectors. For example, those random vectors could be created together in a CuArray{T,2,device}, leading to a sketch which lives on GPU. The question is how to allow the user to specify where they would like these original random vectors (and thus the preconditioner) to live.
We currently allow the user to specify a type with keyword argument S = Array{Float64,2}, which seems like a reasonable choice. However, in a related package we construct a sketch from A and only have access to a type V <: AbstractVector{T} which could be a CuArray or other. So we need to convert that vector type to the appropriate matrix type. Maybe we should have set up this interface differently?