Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Add ArrayLike #34196

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
381 changes: 196 additions & 185 deletions base/abstractarray.jl

Large diffs are not rendered by default.

56 changes: 28 additions & 28 deletions base/abstractarraymath.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

## Basic functions ##

isreal(x::AbstractArray) = all(isreal,x)
iszero(x::AbstractArray) = all(iszero,x)
isreal(x::ArrayLike) = all(isreal,x)
iszero(x::ArrayLike) = all(iszero,x)
isreal(x::AbstractArray{<:Real}) = true

## Constructors ##

"""
vec(a::AbstractArray) -> AbstractVector
vec(a::ArrayLike) -> ArrayLike{1}

Reshape the array `a` as a one-dimensional column vector. Return `a` if it is
already an `AbstractVector`. The resulting array
already an `ArrayLike{1}`. The resulting array
shares the same underlying data as `a`, so it will only be mutable if `a` is
mutable, in which case modifying one will also modify the other.

Expand All @@ -38,8 +38,8 @@ julia> vec(1:3)

See also [`reshape`](@ref).
"""
vec(a::AbstractArray) = reshape(a,length(a))
vec(a::AbstractVector) = a
vec(a::ArrayLike) = reshape(a,length(a))
vec(a::ArrayLike{1}) = a

_sub(::Tuple{}, ::Tuple{}) = ()
_sub(t::Tuple, ::Tuple{}) = t
Expand Down Expand Up @@ -68,7 +68,7 @@ julia> dropdims(a; dims=3)
```
"""
dropdims(A; dims) = _dropdims(A, dims)
function _dropdims(A::AbstractArray, dims::Dims)
function _dropdims(A::ArrayLike, dims::Dims)
for i in eachindex(dims)
1 <= dims[i] <= ndims(A) || throw(ArgumentError("dropped dims must be in range 1:ndims(A)"))
length(axes(A, dims[i])) == 1 || throw(ArgumentError("dropped dims must all be size 1"))
Expand All @@ -84,7 +84,7 @@ function _dropdims(A::AbstractArray, dims::Dims)
end
reshape(A, d::typeof(_sub(axes(A), dims)))
end
_dropdims(A::AbstractArray, dim::Integer) = _dropdims(A, (Int(dim),))
_dropdims(A::ArrayLike, dim::Integer) = _dropdims(A, (Int(dim),))

## Unary operators ##

Expand Down Expand Up @@ -119,7 +119,7 @@ julia> selectdim(A, 2, 3)
7
```
"""
@inline selectdim(A::AbstractArray, d::Integer, i) = _selectdim(A, d, i, _setindex(i, d, map(Slice, axes(A))...))
@inline selectdim(A::ArrayLike, d::Integer, i) = _selectdim(A, d, i, _setindex(i, d, map(Slice, axes(A))...))
@noinline function _selectdim(A, d, i, idxs)
d >= 1 || throw(ArgumentError("dimension must be ≥ 1, got $d"))
nd = ndims(A)
Expand All @@ -145,7 +145,7 @@ julia> reverse(b, dims=2)
4 3
```
"""
function reverse(A::AbstractArray; dims::Integer)
function reverse(A::ArrayLike; dims::Integer)
nd = ndims(A); d = dims
1 ≤ d ≤ nd || throw(ArgumentError("dimension $d is not 1 ≤ $d ≤ $nd"))
if isempty(A)
Expand Down Expand Up @@ -177,10 +177,10 @@ function reverse(A::AbstractArray; dims::Integer)
return B
end

function circshift(a::AbstractArray, shiftamt::Real)
function circshift(a::ArrayLike, shiftamt::Real)
circshift!(similar(a), a, (Integer(shiftamt),))
end
circshift(a::AbstractArray, shiftamt::DimsInteger) = circshift!(similar(a), a, shiftamt)
circshift(a::ArrayLike, shiftamt::DimsInteger) = circshift!(similar(a), a, shiftamt)
"""
circshift(A, shifts)

Expand Down Expand Up @@ -238,14 +238,14 @@ julia> circshift(a, -1)

See also [`circshift!`](@ref).
"""
function circshift(a::AbstractArray, shiftamt)
function circshift(a::ArrayLike, shiftamt)
circshift!(similar(a), a, map(Integer, (shiftamt...,)))
end

## Other array functions ##

"""
repeat(A::AbstractArray, counts::Integer...)
repeat(A::ArrayLike, counts::Integer...)

Construct an array by repeating array `A` a given number of times in each dimension, specified by `counts`.

Expand All @@ -270,9 +270,9 @@ julia> repeat([1, 2, 3], 2, 3)
3 3 3
```
"""
repeat(a::AbstractArray, counts::Integer...) = repeat(a, outer = counts)
repeat(a::ArrayLike, counts::Integer...) = repeat(a, outer = counts)

function repeat(a::AbstractVecOrMat, m::Integer, n::Integer=1)
function repeat(a::VectorOrMatrixLike, m::Integer, n::Integer=1)
o, p = size(a,1), size(a,2)
b = similar(a, o*m, p*n)
for j=1:n
Expand All @@ -286,7 +286,7 @@ function repeat(a::AbstractVecOrMat, m::Integer, n::Integer=1)
return b
end

function repeat(a::AbstractVector, m::Integer)
function repeat(a::ArrayLike{1}, m::Integer)
o = length(a)
b = similar(a, o*m)
for i=1:m
Expand All @@ -297,7 +297,7 @@ function repeat(a::AbstractVector, m::Integer)
end

"""
repeat(A::AbstractArray; inner=ntuple(x->1, ndims(A)), outer=ntuple(x->1, ndims(A)))
repeat(A::ArrayLike; inner=ntuple(x->1, ndims(A)), outer=ntuple(x->1, ndims(A)))

Construct an array by repeating the entries of `A`. The i-th element of `inner` specifies
the number of times that the individual entries of the i-th dimension of `A` should be
Expand Down Expand Up @@ -329,13 +329,13 @@ julia> repeat([1 2; 3 4], inner=(2, 1), outer=(1, 3))
3 4 3 4 3 4
```
"""
function repeat(A::AbstractArray; inner = nothing, outer = nothing)
function repeat(A::ArrayLike; inner = nothing, outer = nothing)
return _repeat_inner_outer(A, inner, outer)
end

# we have optimized implementations of these cases above
_repeat_inner_outer(A::AbstractVecOrMat, ::Nothing, r::Union{Tuple{Integer},Tuple{Integer,Integer}}) = repeat(A, r...)
_repeat_inner_outer(A::AbstractVecOrMat, ::Nothing, r::Integer) = repeat(A, r)
_repeat_inner_outer(A::VectorOrMatrixLike, ::Nothing, r::Union{Tuple{Integer},Tuple{Integer,Integer}}) = repeat(A, r...)
_repeat_inner_outer(A::VectorOrMatrixLike, ::Nothing, r::Integer) = repeat(A, r)

_repeat_inner_outer(A, ::Nothing, ::Nothing) = A
_repeat_inner_outer(A, ::Nothing, outer) = _repeat(A, ntuple(n->1, Val(ndims(A))), rep_kw2tup(outer))
Expand Down Expand Up @@ -366,7 +366,7 @@ _rshps(shp, shp_i, sz, i, ::Tuple{}) =
_reperr(s, n, N) = throw(ArgumentError("number of " * s * " repetitions " *
"($n) cannot be less than number of dimensions of input ($N)"))

@noinline function _repeat(A::AbstractArray, inner, outer)
@noinline function _repeat(A::ArrayLike, inner, outer)
shape, inner_shape = rep_shapes(A, inner, outer)

R = similar(A, shape)
Expand Down Expand Up @@ -408,7 +408,7 @@ _reperr(s, n, N) = throw(ArgumentError("number of " * s * " repetitions " *
end

"""
eachrow(A::AbstractVecOrMat)
eachrow(A::VectorOrMatrixLike)

Create a generator that iterates over the first dimension of vector or matrix `A`,
returning the rows as views.
Expand All @@ -418,11 +418,11 @@ See also [`eachcol`](@ref) and [`eachslice`](@ref).
!!! compat "Julia 1.1"
This function requires at least Julia 1.1.
"""
eachrow(A::AbstractVecOrMat) = (view(A, i, :) for i in axes(A, 1))
eachrow(A::VectorOrMatrixLike) = (view(A, i, :) for i in axes(A, 1))


"""
eachcol(A::AbstractVecOrMat)
eachcol(A::VectorOrMatrixLike)

Create a generator that iterates over the second dimension of matrix `A`, returning the
columns as views.
Expand All @@ -432,10 +432,10 @@ See also [`eachrow`](@ref) and [`eachslice`](@ref).
!!! compat "Julia 1.1"
This function requires at least Julia 1.1.
"""
eachcol(A::AbstractVecOrMat) = (view(A, :, i) for i in axes(A, 2))
eachcol(A::VectorOrMatrixLike) = (view(A, :, i) for i in axes(A, 2))

"""
eachslice(A::AbstractArray; dims)
eachslice(A::ArrayLike; dims)

Create a generator that iterates over dimensions `dims` of `A`, returning views that select all
the data from the other dimensions in `A`.
Expand All @@ -448,7 +448,7 @@ See also [`eachrow`](@ref), [`eachcol`](@ref), and [`selectdim`](@ref).
!!! compat "Julia 1.1"
This function requires at least Julia 1.1.
"""
@inline function eachslice(A::AbstractArray; dims)
@inline function eachslice(A::ArrayLike; dims)
length(dims) == 1 || throw(ArgumentError("only single dimensions are supported"))
dim = first(dims)
dim <= ndims(A) || throw(DimensionMismatch("A doesn't have $dim dimensions"))
Expand Down
6 changes: 3 additions & 3 deletions base/abstractset.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ union(s::AbstractSet) = copy(s)
const ∪ = union

"""
union!(s::Union{AbstractSet,AbstractVector}, itrs...)
union!(s::Union{AbstractSet,ArrayLike{1}}, itrs...)

Construct the union of passed in sets and overwrite `s` with the result.
Maintain order with arrays.
Expand Down Expand Up @@ -124,7 +124,7 @@ intersect(s::AbstractSet, itr) = mapfilter(_in(s), push!, itr, emptymutable(s))
const ∩ = intersect

"""
intersect!(s::Union{AbstractSet,AbstractVector}, itrs...)
intersect!(s::Union{AbstractSet,ArrayLike{1}}, itrs...)

Intersect all passed in sets and overwrite `s` with the result.
Maintain order with arrays.
Expand Down Expand Up @@ -215,7 +215,7 @@ symdiff(s, sets...) = symdiff!(emptymutable(s, promote_eltype(s, sets...)), s, s
symdiff(s) = symdiff!(copy(s))

"""
symdiff!(s::Union{AbstractSet,AbstractVector}, itrs...)
symdiff!(s::Union{AbstractSet,ArrayLike{1}}, itrs...)

Construct the symmetric difference of the passed in sets, and overwrite `s` with the result.
When `s` is an array, the order is maintained.
Expand Down
37 changes: 19 additions & 18 deletions base/accumulate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# stable in certain situations (e.g. sums).
# it does double the number of operations compared to accumulate,
# though for cheap operations like + this does not have much impact (20%)
function _accumulate_pairwise!(op::Op, c::AbstractVector{T}, v::AbstractVector, s, i1, n)::T where {T,Op}
function _accumulate_pairwise!(op::Op, c::AbstractVector{T}, v::ArrayLike{1}, s, i1, n)::T where {T,Op}
@inbounds if n < 128
s_ = v[i1]
c[i1] = op(s, s_)
Expand All @@ -20,7 +20,7 @@ function _accumulate_pairwise!(op::Op, c::AbstractVector{T}, v::AbstractVector,
return s_
end

function accumulate_pairwise!(op::Op, result::AbstractVector, v::AbstractVector) where Op
function accumulate_pairwise!(op::Op, result::ArrayLike{1}, v::ArrayLike{1}) where Op
li = LinearIndices(v)
li != LinearIndices(result) && throw(DimensionMismatch("input and output array sizes and indices must match"))
n = length(li)
Expand All @@ -43,21 +43,21 @@ end

Cumulative sum of `A` along the dimension `dims`, storing the result in `B`. See also [`cumsum`](@ref).
"""
cumsum!(B::AbstractArray{T}, A; dims::Integer) where {T} =
cumsum!(B::ArrayLike, A; dims::Integer) =
accumulate!(add_sum, B, A, dims=dims)

function cumsum!(out::AbstractArray, v::AbstractVector; dims::Integer=1)
function cumsum!(out::ArrayLike, v::ArrayLike{1}; dims::Integer=1)
# we dispatch on the possibility of numerical stability issues
_cumsum!(out, v, dims, ArithmeticStyle(eltype(out)))
end

function _cumsum!(out::AbstractArray{T}, v, dim, ::ArithmeticRounds) where {T}
function _cumsum!(out::ArrayLike, v, dim, ::ArithmeticRounds)
dim == 1 ? accumulate_pairwise!(add_sum, out, v) : copyto!(out, v)
end
function _cumsum!(out::AbstractArray, v, dim, ::ArithmeticUnknown)
function _cumsum!(out::ArrayLike, v, dim, ::ArithmeticUnknown)
_cumsum!(out, v, dim, ArithmeticRounds())
end
function _cumsum!(out::AbstractArray{T}, v, dim, ::ArithmeticStyle) where {T}
function _cumsum!(out::ArrayLike, v, dim, ::ArithmeticStyle)
dim == 1 ? accumulate!(add_sum, out, v) : copyto!(out, v)
end

Expand Down Expand Up @@ -92,7 +92,7 @@ function cumsum(A::AbstractArray{T}; dims::Integer) where T
end

"""
cumsum(x::AbstractVector)
cumsum(x::ArrayLike{1})

Cumulative sum a vector. See also [`cumsum!`](@ref)
to use a preallocated output array, both for performance and to control the precision of the
Expand All @@ -113,7 +113,8 @@ julia> cumsum([fill(1, 2) for i in 1:3])
[3, 3]
```
"""
cumsum(x::AbstractVector) = cumsum(x, dims=1)
cumsum(x::ArrayLike{1}) = cumsum(x, dims=1)
cumsum(x::AbstractVector) = cumsum(x, dims = 1) # disambiguation


"""
Expand All @@ -122,16 +123,16 @@ cumsum(x::AbstractVector) = cumsum(x, dims=1)
Cumulative product of `A` along the dimension `dims`, storing the result in `B`.
See also [`cumprod`](@ref).
"""
cumprod!(B::AbstractArray{T}, A; dims::Integer) where {T} =
cumprod!(B::ArrayLike, A; dims::Integer) =
accumulate!(mul_prod, B, A, dims=dims)

"""
cumprod!(y::AbstractVector, x::AbstractVector)
cumprod!(y::ArrayLike{1}, x::ArrayLike{1})

Cumulative product of a vector `x`, storing the result in `y`.
See also [`cumprod`](@ref).
"""
cumprod!(y::AbstractVector, x::AbstractVector) = cumprod!(y, x, dims=1)
cumprod!(y::ArrayLike{1}, x::ArrayLike{1}) = cumprod!(y, x, dims=1)

"""
cumprod(A; dims::Integer)
Expand All @@ -158,12 +159,12 @@ julia> cumprod(a, dims=2)
4 20 120
```
"""
function cumprod(A::AbstractArray; dims::Integer)
function cumprod(A::ArrayLike; dims::Integer)
return accumulate(mul_prod, A, dims=dims)
end

"""
cumprod(x::AbstractVector)
cumprod(x::ArrayLike{1})

Cumulative product of a vector. See also
[`cumprod!`](@ref) to use a preallocated output array, both for performance and
Expand All @@ -184,7 +185,7 @@ julia> cumprod([fill(1//3, 2, 2) for i in 1:3])
[4//27 4//27; 4//27 4//27]
```
"""
cumprod(x::AbstractVector) = cumprod(x, dims=1)
cumprod(x::ArrayLike{1}) = cumprod(x, dims=1)


"""
Expand Down Expand Up @@ -304,13 +305,13 @@ function _accumulate!(op, B, A, dims::Nothing, init::Union{Nothing, Some})
throw(ArgumentError("Keyword argument dims must be provided for multidimensional arrays"))
end

function _accumulate!(op, B, A::AbstractVector, dims::Nothing, init::Nothing)
function _accumulate!(op, B, A::ArrayLike{1}, dims::Nothing, init::Nothing)
isempty(A) && return B
v1 = reduce_first(op, first(A))
_accumulate1!(op, B, v1, A, 1)
end

function _accumulate!(op, B, A::AbstractVector, dims::Nothing, init::Some)
function _accumulate!(op, B, A::ArrayLike{1}, dims::Nothing, init::Some)
isempty(A) && return B
v1 = op(something(init), first(A))
_accumulate1!(op, B, v1, A, 1)
Expand Down Expand Up @@ -372,7 +373,7 @@ end
B
end

function _accumulate1!(op, B, v1, A::AbstractVector, dim::Integer)
function _accumulate1!(op, B, v1, A::ArrayLike{1}, dim::Integer)
dim > 0 || throw(ArgumentError("dim must be a positive integer"))
inds = LinearIndices(A)
inds == LinearIndices(B) || throw(DimensionMismatch("LinearIndices of A and B don't match"))
Expand Down
Loading