-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Introduce iscontiguous function or trait #10889
Comments
I can make a PR if people think it is worth it. |
I feel that this should already verified by any implementation of |
There are certain cases where we want to get a ptr, but doesn't require the underlying memory to be contiguous (e.g. The |
The BLAS functions now use a = rand(3, 4)
b = sub(a, 1:2, :)
p = pointer(b) # this is fine, and rightly so However, supplying Hence, being able to get the pointer and testing whether an array is contiguous are two different things, and need to be addressed in different functions. |
DenseArrays are necessarily contiguous, right? So the problem is effectively that there are some parameters that make for contiguous SubArrays and some that don't. I see two other possible ways to handle this:
You might actually want to dispatch on contiguity, e.g. if you are picking between an optimized algorithm from an external library that only supports contiguous arrays and pure Julia code that is slower but can handle anything, so I think I'd prefer one of the above two approaches to |
Adding If we take this approach, we may need some revision of the type hierarchy of arrays. While the |
The current type hierarchy is as follows:
Then, we have a union type Union(SubArray{T,N,A<:DenseArray{T,N},I<:Tuple{Vararg{Union(Int64,Colon,Range{Int64})}},LD},DenseArray{T,N}) |
Related to the discussion JuliaLang/LinearAlgebra.jl#186. |
Another way is to use array traits, as suggested by @timholy type Contiguous end
type NotContiguous end
contiguousness(a::AbstractArray) = NotContiguous()
contiguousness(a::Array) = Contiguous()
contiguousness(a::SubArray) = # more sophisticated stuff
function fastsum(a::StridedArray)
_fastsum(a, contiguousness(a))
end
_fastsum(a::StridedArray, ::Contiguous) = # ... call the underlying C functions |
iscontiguous
function
Lines 396 to 412 in 8f69307
Right now it's intended for internal use in stagedfunctions, but we could change it to return |
Great. I think you may also add iscontiguous{T,N}(::Type{Array{T,N}}) = true
iscontiguous(::Array) = true I think this is useful for interfacing with C libraries, as mentioned above. |
See also the (slightly more general, perhaps, because it doesn't assume the dimesions are sorted in a particular order?) |
There seem to be two conflicting requirements: something that works on types so you can use it during type inference, and something that you can evaluate at runtime and call out to C libraries. This: A = rand(3,5)
B1 = sub(A, :, 2:3) # inference: yes, runtime: yes
B2 = sub(A, 1:2, 2:3) # inference: no, runtime: no
B3 = sub(A, 1:3, 2:3) # inference: no, runtime: yes illustrates the conflict. |
Instead of That way storage does no longer need no longer be reflected in the |
I think using specific types to indicate different memory layout is a good idea. Below is an example that demonstrates how this may be used: # memory layout traits
abstract MemLayout
type Contiguous <: MemLayout end
type UnitStrided <: MemLayout end
type Strided <: MemLayout end
memlayout(a::StridedArray) = Strided
memlayout(a::Array) = Contiguous
memlayout(a::SubArray) = ... # probably need a staged function to figure out
# suppose we have a highly optimized C functions to sum elements
# and we want to port it to Julia, naming it to `fastsum`
fastsum(a::StridedArray{Float64}) = fastsum(a, memlayout(a))
fastsum(a::StridedArray{Float64}, ::Type{Contiguous}) = # call out the C function
# it is possible to write it for general arrays,
# using matrix here to make the illustration simple
function fastsum(a::StridedMatrix{Float64}, ::Type{UnitStrided})
s = 0.0
for i = 1:size(a,2)
s += fastsum(slice(a, :, i), Contiguous)
end
return s
end
# fallbacks to the builtin implementation for other layouts
fastsum{L<:MemLayout}(a::StridedArray, ::Type{L}) = sum(a) |
Sure, we could definitely introduce those types. An alternative approach would be (For the record, the linear indexing traits were introduced before |
The point of using types would be that you could use them like this: abstract MemLayout
abstract Strided <: MemLayout
abstract UnitStrided <: Strided
abstract Contiguous <: UnitStrided (the last one can probably be a |
Works for me. |
Still relevant/necessary? |
I think it is. It would be good to have a storage/memlayout trait, rather than trying to reflect this property in the type hierarchy, which makes it less flexible and more difficult to extend (as in the |
Yes — the |
For anyone who wants to jump on this, it mostly consists of replacing qr(A::StridedArray) = ... with qr(A::AbstractArray) = _qr(MemLayout(A), A)
_qr(::Strided, A) = ... once the MemLayout trait is defined (for which one can mimic the |
The first question to answer here is if adding this is a breaking change in any way. If not, we should move this off of the 1.0 milestone. If not, we should figure out the minimal change we'd need to allow this in the future without breaking anything. |
Still unclear if there's anything breaking here and no one has chimed in since I asked. |
I'm not convinced that traits are needed here. If it is a (And if traits are needed, they can be added on top of that. A trait would not be breaking either.) |
Well, that's the problem. That said, I don't think this is breaking, but it can be hard to think through all the ramifications of changing informal interfaces that get extended by user code. This is really largely an addition of a new feature — the ability to ask an array about its storage type — and a large refactoring of functions in Base to take advantage of that fact. We can follow the pattern that we use for Type-Piracy absolutely can and should be excluded from stability guarantees. Am I missing any other places where this would be breaking? |
@stevengj, you want to have AbstractArray types that endow arrays with all kinds of new properties: you want to reshape them ( |
@StefanKarpinski, the breaking part is that in an ideal world we'd simultaneously ditch |
Eh, it's a fairly harmless typealias. We can always deprecate it alongside the new feature on a minor release (even if it won't be completely removed until 2.0). The important part isn't that it goes away, the important part is that folks start using the alternative. And a deprecation alone is sufficient for that. |
Many C libraries have functions like the following:
These functions assume that the arrays have contiguous memory layout.
Now for safety, packages like
Yeppp
andVML
etc restrict the arguments toArray
. It would be very useful to generalize the fast computation functions there to arbitrary array types with contiguous array layouts (e.g. someSubArray
or array views).A
iscontiguous
function can be useful in such casescc: @timholy @ViralBShah @simonster
The text was updated successfully, but these errors were encountered: