-
Notifications
You must be signed in to change notification settings - Fork 36
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
Added some methods to help support LoopVectorization.jl #61
Changes from all commits
9a41d08
597606b
2513045
791cffa
6c36e69
8af5986
87e8bd1
53929ad
572fccc
874fee8
358a93c
0ca96b8
9b09212
3417ba0
944fd93
a8567db
bd55e33
0862eb6
a3ac561
2f92c61
9778d47
ab02af4
7cfd029
39f414b
9f852da
94eb2a7
973a01c
6e9207b
00d0a00
5120651
d6130f8
a88c692
910a42a
6ad4ec5
28404dc
1f08ae0
00c9112
5f1f14f
dd7b0ed
726691e
895f9b7
a59e05a
7d17247
18b954b
09515fe
0ef7653
33b8433
efe40e1
e72cfc8
42258b5
090dab9
ac8033a
21f7d48
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ | |
*.jl.mem | ||
deps/deps.jl | ||
Manifest.toml | ||
*~ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,8 +33,9 @@ If `length` of an instance of type `T` is known at compile time, return it. | |
Otherwise, return `nothing`. | ||
""" | ||
known_length(x) = known_length(typeof(x)) | ||
known_length(::Type{<:NTuple{N,<:Any}}) where {N} = N | ||
known_length(::Type{<:NamedTuple{L}}) where {L} = length(L) | ||
known_length(::Type{T}) where {T<:Base.Slice} = known_length(parent_type(T)) | ||
known_length(::Type{<:Tuple{Vararg{Any,N}}}) where {N} = N | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We probably don't need There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll remove the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we don't have this defined for tuples then the method would return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The julia> NTuple{1423} <: Tuple{Vararg{Any,1423}}
true There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I misunderstood. I thought the final idea was to remove both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To expand a little on Chris' answer, in case you didn't know: julia> (1, 'd') isa NTuple{2,<:Any}
false
julia> (1, 'd') isa NTuple{2,Any}
true |
||
known_length(::Type{<:Number}) = 1 | ||
function known_length(::Type{T}) where {T} | ||
if parent_type(T) <: T | ||
|
@@ -52,7 +53,7 @@ _known_length(x::Tuple{Vararg{Int}}) = prod(x) | |
""" | ||
can_change_size(::Type{T}) -> Bool | ||
|
||
Returns `true` if the size of `T` can change, in which case operations | ||
Returns `true` if the Base.size of `T` can change, in which case operations | ||
such as `pop!` and `popfirst!` are available for collections of type `T`. | ||
""" | ||
can_change_size(x) = can_change_size(typeof(x)) | ||
|
@@ -102,7 +103,7 @@ function Base.setindex(x::AbstractVector,v,i::Int) | |
end | ||
|
||
function Base.setindex(x::AbstractMatrix,v,i::Int,j::Int) | ||
n,m = size(x) | ||
n,m = Base.size(x) | ||
x .* (i .!== 1:n) .* (j .!== i:m)' .+ v .* (i .== 1:n) .* (j .== i:m)' | ||
end | ||
|
||
|
@@ -202,7 +203,7 @@ Return: (I,J) #indexable objects | |
Find sparsity pattern of special matrices, the same as the first two elements of findnz(::SparseMatrixCSC) | ||
""" | ||
function findstructralnz(x::Diagonal) | ||
n=size(x,1) | ||
n = Base.size(x,1) | ||
(1:n,1:n) | ||
end | ||
|
||
|
@@ -412,15 +413,15 @@ function Base.getindex(ind::BandedBlockBandedMatrixIndex,i::Int) | |
end | ||
|
||
function findstructralnz(x::Bidiagonal) | ||
n=size(x,1) | ||
n= Base.size(x,1) | ||
isup= x.uplo=='U' ? true : false | ||
rowind=BidiagonalIndex(n+n-1,isup) | ||
colind=BidiagonalIndex(n+n-1,!isup) | ||
(rowind,colind) | ||
end | ||
|
||
function findstructralnz(x::Union{Tridiagonal,SymTridiagonal}) | ||
n=size(x,1) | ||
n= Base.size(x,1) | ||
rowind=TridiagonalIndex(n+n-1+n-1,n,true) | ||
colind=TridiagonalIndex(n+n-1+n-1,n,false) | ||
(rowind,colind) | ||
|
@@ -447,26 +448,26 @@ fast_matrix_colors(A::Type{<:Union{Diagonal,Bidiagonal,Tridiagonal,SymTridiagona | |
matrix_colors(A::Union{Array,UpperTriangular,LowerTriangular}) | ||
|
||
The color vector for dense matrix and triangular matrix is simply | ||
`[1,2,3,...,size(A,2)]` | ||
`[1,2,3,..., Base.size(A,2)]` | ||
""" | ||
function matrix_colors(A::Union{Array,UpperTriangular,LowerTriangular}) | ||
eachindex(1:size(A,2)) # Vector size matches number of rows | ||
eachindex(1:Base.size(A,2)) # Vector Base.size matches number of rows | ||
end | ||
|
||
function _cycle(repetend,len) | ||
repeat(repetend,div(len,length(repetend))+1)[1:len] | ||
end | ||
|
||
function matrix_colors(A::Diagonal) | ||
fill(1,size(A,2)) | ||
fill(1, Base.size(A,2)) | ||
end | ||
|
||
function matrix_colors(A::Bidiagonal) | ||
_cycle(1:2,size(A,2)) | ||
_cycle(1:2, Base.size(A,2)) | ||
end | ||
|
||
function matrix_colors(A::Union{Tridiagonal,SymTridiagonal}) | ||
_cycle(1:3,size(A,2)) | ||
_cycle(1:3, Base.size(A,2)) | ||
end | ||
|
||
""" | ||
|
@@ -540,9 +541,64 @@ function restructure(x,y) | |
end | ||
|
||
function restructure(x::Array,y) | ||
reshape(convert(Array,y),size(x)...) | ||
reshape(convert(Array,y), Base.size(x)...) | ||
end | ||
|
||
abstract type AbstractDevice end | ||
abstract type AbstractCPU <: AbstractDevice end | ||
struct CPUPointer <: AbstractCPU end | ||
struct CheckParent end | ||
struct CPUIndex <: AbstractCPU end | ||
struct GPU <: AbstractDevice end | ||
""" | ||
device(::Type{T}) | ||
|
||
Indicates the most efficient way to access elements from the collection in low level code. | ||
For `GPUArrays`, will return `ArrayInterface.GPU()`. | ||
For `AbstractArray` supporting a `pointer` method, returns `ArrayInterface.CPUPointer()`. | ||
For other `AbstractArray`s and `Tuple`s, returns `ArrayInterface.CPUIndex()`. | ||
Otherwise, returns `nothing`. | ||
""" | ||
device(A) = device(typeof(A)) | ||
device(::Type) = nothing | ||
device(::Type{<:Tuple}) = CPUIndex() | ||
# Relies on overloading for GPUArrays that have subtyped `StridedArray`. | ||
device(::Type{<:StridedArray}) = CPUPointer() | ||
function device(::Type{T}) where {T <: AbstractArray} | ||
P = parent_type(T) | ||
T === P ? CPUIndex() : device(P) | ||
end | ||
|
||
|
||
""" | ||
defines_strides(::Type{T}) -> Bool | ||
|
||
Is strides(::T) defined? | ||
""" | ||
defines_strides(::Type) = false | ||
defines_strides(x) = defines_strides(typeof(x)) | ||
defines_strides(::Type{<:StridedArray}) = true | ||
defines_strides(::Type{A}) where {A <: Union{<:Transpose,<:Adjoint,<:SubArray,<:PermutedDimsArray}} = defines_strides(parent_type(A)) | ||
|
||
""" | ||
can_avx(f) | ||
|
||
Returns `true` if the function `f` is guaranteed to be compatible with `LoopVectorization.@avx` for supported element and array types. | ||
While a return value of `false` does not indicate the function isn't supported, this allows a library to conservatively apply `@avx` | ||
only when it is known to be safe to do so. | ||
|
||
```julia | ||
function mymap!(f, y, args...) | ||
if can_avx(f) | ||
@avx @. y = f(args...) | ||
else | ||
@. y = f(args...) | ||
end | ||
end | ||
``` | ||
""" | ||
can_avx(::Any) = false | ||
|
||
""" | ||
insert(collection, index, item) | ||
|
||
|
@@ -654,6 +710,7 @@ function __init__() | |
ismutable(::Type{<:StaticArrays.StaticArray}) = false | ||
can_setindex(::Type{<:StaticArrays.StaticArray}) = false | ||
ismutable(::Type{<:StaticArrays.MArray}) = true | ||
ismutable(::Type{<:StaticArrays.SizedArray}) = true | ||
|
||
function lu_instance(_A::StaticArrays.StaticMatrix{N,N}) where {N} | ||
A = StaticArrays.SArray(_A) | ||
|
@@ -675,6 +732,26 @@ function __init__() | |
known_last(::Type{StaticArrays.SOneTo{N}}) where {N} = N | ||
known_length(::Type{StaticArrays.SOneTo{N}}) where {N} = N | ||
|
||
device(::Type{<:StaticArrays.MArray}) = CPUPointer() | ||
contiguous_axis(::Type{<:StaticArrays.StaticArray}) = Contiguous{1}() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This whole part will have to be revisited after merging JuliaArrays/StaticArrays.jl#783. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Preferably it'd define a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, I've added |
||
contiguous_batch_size(::Type{<:StaticArrays.StaticArray}) = ContiguousBatch{0}() | ||
stride_rank(::Type{T}) where {N, T <: StaticArrays.StaticArray{<:Any,<:Any,N}} = StrideRank{ntuple(identity, Val{N}())}() | ||
dense_dims(::Type{<:StaticArrays.StaticArray{S,T,N}}) where {S,T,N} = DenseDims{ntuple(_ -> true, Val(N))}() | ||
defines_strides(::Type{<:StaticArrays.MArray}) = true | ||
@generated function size(A::StaticArrays.StaticArray{S}) where {S} | ||
t = Expr(:tuple); Sp = S.parameters | ||
for n in 1:length(Sp) | ||
push!(t.args, Expr(:call, Expr(:curly, :StaticInt, Sp[n]))) | ||
end | ||
t | ||
end | ||
@generated function strides(A::StaticArrays.StaticArray{S}) where {S} | ||
t = Expr(:tuple, Expr(:call, Expr(:curly, :StaticInt, 1))); Sp = S.parameters; x = 1 | ||
for n in 1:length(Sp)-1 | ||
push!(t.args, Expr(:call, Expr(:curly, :StaticInt, (x *= Sp[n])))) | ||
end | ||
t | ||
end | ||
@require Adapt="79e6a3ab-5dfb-504d-930d-738a2a938a0e" begin | ||
function Adapt.adapt_storage(::Type{<:StaticArrays.SArray{S}},xs::Array) where S | ||
StaticArrays.SArray{S}(xs) | ||
|
@@ -694,7 +771,7 @@ function __init__() | |
aos_to_soa(x::AbstractArray{<:Tracker.TrackedReal,N}) where N = Tracker.collect(x) | ||
end | ||
|
||
@require CuArrays="3a865a2d-5b23-5a0f-bc46-62713ec82fae" begin | ||
@require CuArrays="3a865a2d-5b23-5a0f-bc46-62713ec82fae" begin | ||
@require Adapt="79e6a3ab-5dfb-504d-930d-738a2a938a0e" begin | ||
include("cuarrays.jl") | ||
end | ||
|
@@ -717,7 +794,7 @@ function __init__() | |
@require BandedMatrices="aae01518-5342-5314-be14-df237901396f" begin | ||
function findstructralnz(x::BandedMatrices.BandedMatrix) | ||
l,u=BandedMatrices.bandwidths(x) | ||
rowsize,colsize=size(x) | ||
rowsize,colsize= Base.size(x) | ||
rowind=BandedMatrixIndex(rowsize,colsize,l,u,true) | ||
colind=BandedMatrixIndex(rowsize,colsize,l,u,false) | ||
(rowind,colind) | ||
|
@@ -730,7 +807,7 @@ function __init__() | |
function matrix_colors(A::BandedMatrices.BandedMatrix) | ||
l,u=BandedMatrices.bandwidths(A) | ||
width=u+l+1 | ||
_cycle(1:width,size(A,2)) | ||
_cycle(1:width, Base.size(A,2)) | ||
end | ||
|
||
end | ||
|
@@ -794,9 +871,19 @@ function __init__() | |
end | ||
end | ||
end | ||
@require OffsetArrays="6fe1bfb0-de20-5000-8ca7-80f57d26f881" begin | ||
size(A::OffsetArrays.OffsetArray) = size(parent(A)) | ||
strides(A::OffsetArrays.OffsetArray) = strides(parent(A)) | ||
# offsets(A::OffsetArrays.OffsetArray) = map(+, A.offsets, offsets(parent(A))) | ||
device(::OffsetArrays.OffsetArray) = CheckParent() | ||
contiguous_axis(A::OffsetArrays.OffsetArray) = contiguous_axis(parent(A)) | ||
contiguous_batch_size(A::OffsetArrays.OffsetArray) = contiguous_batch_size(parent(A)) | ||
stride_rank(A::OffsetArrays.OffsetArray) = stride_rank(parent(A)) | ||
end | ||
end | ||
|
||
include("static.jl") | ||
include("ranges.jl") | ||
include("stridelayout.jl") | ||
|
||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking a bit about
Base.Slice
in the context ofHybridArrays
and my general conclusion was to treat is the same way asColon
. IIRC there was a case where a statically-known axis ended up being a slice withBase.OneTo
instead ofSOneTo
. Are there any benefits of using this method instead?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are treating them as traversing the entire axis, so a
Base.Slice
preserves density.SOneTo
is preferable, so I'd recommend getting that case to return aBase.Slice(SOneTo(N))
instead.Using which method instead of which alternative?
Currently,
known_length
takes a type and returnsnothing
(if length unknown, e.g. forBase.Array
s), or returns the known length.A problem is that we can't really use this within
@generated
functions, lest we face world age issues / defeat the entire purpose of providing an interface others can extend (I just checked and realize I have to fix_sdsize
).I'm considering a breaking change where
known_length
will return theStatic
numbers introduced in this PR, which will make it easier to "wrap"@generated
functions (i.e., the wrapper can safely callknown_length
and friends, and withStatic
, it can pass the information on to the@generated
function).Although this works:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I'll keep that in mind.
In HybridArrays I take into account both array type and types of indices to figure out whether a certain access pattern is statically-sized or not. In some places for example
Colon
has to be special-cased, so the same special-casing can be used forSlice
, like I did here for example: https://github.com/JuliaArrays/StaticArrays.jl/pull/783/files#diff-c1a2ec8ab9a030d018ed5124a63d38a4R193 . I don't see in what circumstancesknown_length(::Type{<:Base.Slice})
would be used that don't treatColon
in a special way as well.I support this change. Generated functions that need static size information should get that information as an argument. That's what
StaticArray
does in many places. The downside main I think is potentially increasing compilation times.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a small reminder that you haven't fixed
_sdsize
yet: https://github.com/SciML/ArrayInterface.jl/pull/61/files#diff-b8b78add44fe2319a1282ed26bc78610R284There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, that slipped my mind. Fixed.