Skip to content
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
24 changes: 20 additions & 4 deletions src/adjtrans.jl
Original file line number Diff line number Diff line change
Expand Up @@ -368,11 +368,27 @@ convert(::Type{Adjoint{T,S}}, A::Adjoint) where {T,S} = Adjoint{T,S}(convert(S,
convert(::Type{Transpose{T,S}}, A::Transpose) where {T,S} = Transpose{T,S}(convert(S, A.parent))::Transpose{T,S}

# Strides and pointer for transposed strided arrays — but only if the elements are actually stored in memory
Base.strides(A::Adjoint{<:Real, <:AbstractVector}) = (stride(A.parent, 2), stride(A.parent, 1))
Base.strides(A::Transpose{<:Any, <:AbstractVector}) = (stride(A.parent, 2), stride(A.parent, 1))
function Base.strides(A::Adjoint{<:Real, <:AbstractVector})
st = strides(A.parent)
isnothing(st) && return nothing
(st[1]*Int(length(A.parent)), st[1])

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

st[1]*Int(length(A.parent)) should match stride(A.parent, 2) since the parent is an abstract vector: https://github.com/JuliaLang/julia/blob/201e056e9ee2398f01ecd2f104f9d8000b04d195/base/abstractarray.jl#L602

JuliaLang/julia#30432 has this return (1, st[1]). The first stride should not get used, so in theory its value shouldn't matter.

end
function Base.strides(A::Transpose{<:Number, <:AbstractVector})
st = strides(A.parent)
isnothing(st) && return nothing
(st[1]*Int(length(A.parent)), st[1])
end
# For matrices it's slightly faster to use reverse and avoid calling stride twice
Base.strides(A::Adjoint{<:Real, <:AbstractMatrix}) = reverse(strides(A.parent))
Base.strides(A::Transpose{<:Any, <:AbstractMatrix}) = reverse(strides(A.parent))
function Base.strides(A::Adjoint{<:Real, <:AbstractMatrix})
st = strides(A.parent)
isnothing(st) && return nothing
reverse(st)
end
function Base.strides(A::Transpose{<:Number, <:AbstractMatrix})
st = strides(A.parent)
isnothing(st) && return nothing
reverse(st)
end

Base.cconvert(::Type{Ptr{T}}, A::Adjoint{<:Real, <:AbstractVecOrMat}) where {T} = Base.cconvert(Ptr{T}, A.parent)
Base.cconvert(::Type{Ptr{T}}, A::Transpose{<:Any, <:AbstractVecOrMat}) where {T} = Base.cconvert(Ptr{T}, A.parent)
Expand Down
12 changes: 10 additions & 2 deletions test/adjtrans.jl
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,14 @@ end
@test repr(transpose([1f0,2f0])) == "transpose(Float32[1.0, 2.0])"
end

function test_no_strides(x)
@test try
strides(x)
catch e
e
end isa Union{MethodError, Nothing}
end

@testset "strided transposes" begin
for t in (Adjoint, Transpose)
@test strides(t(rand(3))) == (3, 1)
Expand All @@ -583,8 +591,8 @@ end
B = rand(3,1)
@test pointer(t(B)) === pointer(B)
end
@test_throws MethodError strides(Adjoint(rand(3) .+ rand(3).*im))
@test_throws MethodError strides(Adjoint(rand(3, 2) .+ rand(3, 2).*im))
test_no_strides(Adjoint(rand(3) .+ rand(3).*im))
test_no_strides(Adjoint(rand(3, 2) .+ rand(3, 2).*im))
@test strides(Transpose(rand(3) .+ rand(3).*im)) == (3, 1)
@test strides(Transpose(rand(3, 2) .+ rand(3, 2).*im)) == (3, 1)

Expand Down
20 changes: 13 additions & 7 deletions test/blas.jl
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,14 @@ Base.cconvert(::Type{Ptr{T}}, A::WrappedArray{T}) where T = Base.cconvert(Ptr{T}
Base.strides(A::WrappedArray) = strides(A.A)
Base.elsize(::Type{WrappedArray{T,N}}) where {T,N} = Base.elsize(Array{T,N})

function test_no_strides(x)
@test try
strides(x)
catch e
e
end isa Union{MethodError, Nothing}
end

@testset "strided interface adjtrans" begin
x = WrappedArray([1, 2, 3, 4])
@test stride(x,1) == 1
Expand All @@ -617,20 +625,18 @@ Base.elsize(::Type{WrappedArray{T,N}}) where {T,N} = Base.elsize(Array{T,N})
y = WrappedArray([1+im, 2, 3, 4])
@test strides(transpose(y)) == (4,1)
@test pointer(transpose(y)) == pointer(y)
@test_throws MethodError strides(y')
test_no_strides(y')
@test_throws ErrorException pointer(y')

B = WrappedArray([1+im 2; 3 4; 5 6])
@test strides(transpose(B)) == (3,1)
@test pointer(transpose(B)) == pointer(B)
@test_throws MethodError strides(B')
test_no_strides(B')
@test_throws ErrorException pointer(B')

@test_throws MethodError stride(1:5,0)
@test_throws MethodError stride(1:5,1)
@test_throws MethodError stride(1:5,2)
@test_throws MethodError strides(transpose(1:5))
@test_throws MethodError strides((1:5)')
test_no_strides(1:5)
test_no_strides(transpose(1:5))
test_no_strides((1:5)')
@test_throws ErrorException pointer(transpose(1:5))
@test_throws ErrorException pointer((1:5)')
end
Expand Down