`unsqueeze` or `insertdims` not part of Base

Hi!

in Base we have dropdims which effectively calls reshape.
Today, I was confused that we don’t have insertdims being the inverse to the former.

There is already one implementation in MLUtils.jl for a single dim. However, it should be possible to generalize that to tuple of dims.

Is there a reason we don’t have that in Base?

Best,

Felix

1 Like

I tried to implement insertdims similarly to dropdims.

Is that something we should try to add to Base?

insertdims(A; dims) = _insertdims(A, dims)
function _insertdims(A::AbstractArray{T, N}, dims::Tuple{Vararg{Int64, M}}) where {T, N, M}
    for i in eachindex(dims)
        for j = 1:i-1
            dims[j] == dims[i] && throw(ArgumentError("inserted dims must be unique"))
        end
    end 

    # sorted list of dims
    new_dims = _sortedmerge(ntuple(identity, Val(N)), dims)
    for i in 2:length(new_dims)
        new_dims[i-1] == new_dims[i] || new_dims[i-1] + 1 == new_dims[i] ||
            throw(ArgumentError("inserted dims and existing dims must be contiguos"))
    end

    # n is the amount of the dims already inserted
    ax_n = Base._foldoneto(((ds, n), d) -> d in dims ? ((ds..., 1), n+1) : ((ds..., axes(A,d - n)), n), 
                         ((), 0), Val(ndims(A) + length(dims)))
    # we need only the new shape and not n
    reshape(A, ax_n[1])::AbstractArray{T, N + M}
end
_insertdims(A::AbstractArray, dim::Integer) = _insertdims(A, (Int(dim),))


_sortedmerge(::Tuple{}, ::Tuple{}) = ()
_sortedmerge(::Tuple{}, s::Tuple) = s 
_sortedmerge(t::Tuple, s::Tuple{}) = t 
_sortedmerge(t::Tuple, s::Tuple) = (first(s) < first(t) ? (first(s), _sortedmerge(t, Base.tail(s))...) 
                                                        : (first(t), _sortedmerge(Base.tail(t), s)...))