diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index a95c81a807fb9..48cbc52cd04d1 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -83,6 +83,94 @@ end squeeze(A::AbstractArray, dim::Integer) = squeeze(A, (Int(dim),)) +## Transposition ## + +""" + transpose(A::AbstractMatrix) + +The transposition operator (`.'`). + +# Examples +```jldoctest +julia> A = [1 2 3; 4 5 6; 7 8 9] +3×3 Array{Int64,2}: +1 2 3 +4 5 6 +7 8 9 + +julia> transpose(A) +3×3 Array{Int64,2}: +1 4 7 +2 5 8 +3 6 9 +``` +""" +function transpose(A::AbstractMatrix) + ind1, ind2 = indices(A) + B = similar(A, (ind2, ind1)) + transpose!(B, A) +end + +transpose(a::AbstractArray) = error("transpose not defined for $(typeof(a)). Consider using `permutedims` for higher-dimensional arrays.") + +""" + transpose!(dest, src) + +Transpose array `src` and store the result in the preallocated array `dest`, which should +have a size corresponding to `(size(src,2),size(src,1))`. No in-place transposition is +supported and unexpected results will happen if `src` and `dest` have overlapping memory +regions. +""" +transpose!(B::AbstractMatrix, A::AbstractMatrix) = transpose_f!(identity, B, A) + +function transpose!(B::AbstractVector, A::AbstractMatrix) + indices(B,1) == indices(A,2) && indices(A,1) == 1:1 || throw(DimensionMismatch("transpose")) + copy!(B, A) +end +function transpose!(B::AbstractMatrix, A::AbstractVector) + indices(B,2) == indices(A,1) && indices(B,1) == 1:1 || throw(DimensionMismatch("transpose")) + copy!(B, A) +end + +const transposebaselength=64 +function transpose_f!(f, B::AbstractMatrix, A::AbstractMatrix) + inds = indices(A) + indices(B,1) == inds[2] && indices(B,2) == inds[1] || throw(DimensionMismatch(string(f))) + + m, n = length(inds[1]), length(inds[2]) + if m*n<=4*transposebaselength + @inbounds begin + for j = inds[2] + for i = inds[1] + B[j,i] = f(A[i,j]) + end + end + end + else + transposeblock!(f,B,A,m,n,first(inds[1])-1,first(inds[2])-1) + end + return B +end +function transposeblock!(f, B::AbstractMatrix, A::AbstractMatrix, m::Int, n::Int, offseti::Int, offsetj::Int) + if m*n<=transposebaselength + @inbounds begin + for j = offsetj+(1:n) + for i = offseti+(1:m) + B[j,i] = f(A[i,j]) + end + end + end + elseif m>n + newm=m>>1 + transposeblock!(f,B,A,newm,n,offseti,offsetj) + transposeblock!(f,B,A,m-newm,n,offseti+newm,offsetj) + else + newn=n>>1 + transposeblock!(f,B,A,m,newn,offseti,offsetj) + transposeblock!(f,B,A,m,n-newn,offseti,offsetj+newn) + end + return B +end ## Unary operators ## diff --git a/base/linalg/adjoint.jl b/base/linalg/adjoint.jl new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/base/linalg/linalg.jl b/base/linalg/linalg.jl index 09816b9e0a73c..5ec561658a82c 100644 --- a/base/linalg/linalg.jl +++ b/base/linalg/linalg.jl @@ -238,6 +238,31 @@ end copy_oftype(A::AbstractArray{T}, ::Type{T}) where {T} = copy(A) copy_oftype(A::AbstractArray{T,N}, ::Type{S}) where {T,N,S} = convert(AbstractArray{S,N}, A) +function copy_transpose!(B::AbstractVecOrMat, ir_dest::Range{Int}, jr_dest::Range{Int}, + A::AbstractVecOrMat, ir_src::Range{Int}, jr_src::Range{Int}) + if length(ir_dest) != length(jr_src) + throw(ArgumentError(string("source and destination must have same size (got ", + length(jr_src)," and ",length(ir_dest),")"))) + end + if length(jr_dest) != length(ir_src) + throw(ArgumentError(string("source and destination must have same size (got ", + length(ir_src)," and ",length(jr_dest),")"))) + end + @boundscheck checkbounds(B, ir_dest, jr_dest) + @boundscheck checkbounds(A, ir_src, jr_src) + idest = first(ir_dest) + for jsrc in jr_src + jdest = first(jr_dest) + for isrc in ir_src + B[idest,jdest] = A[isrc,jsrc] + jdest += step(jr_dest) + end + idest += step(ir_dest) + end + return B +end + + include("conjarray.jl") include("transpose.jl") include("rowvector.jl") diff --git a/base/linalg/transpose.jl b/base/linalg/transpose.jl index 2d9efbcae5439..10707f08b265b 100644 --- a/base/linalg/transpose.jl +++ b/base/linalg/transpose.jl @@ -1,20 +1,9 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license adjoint(a::AbstractArray) = error("adjoint not defined for $(typeof(a)). Consider using `permutedims` for higher-dimensional arrays.") -transpose(a::AbstractArray) = error("transpose not defined for $(typeof(a)). Consider using `permutedims` for higher-dimensional arrays.") ## Matrix transposition ## -""" - transpose!(dest,src) - -Transpose array `src` and store the result in the preallocated array `dest`, which should -have a size corresponding to `(size(src,2),size(src,1))`. No in-place transposition is -supported and unexpected results will happen if `src` and `dest` have overlapping memory -regions. -""" -transpose!(B::AbstractMatrix, A::AbstractMatrix) = transpose_f!(identity, B, A) - """ adjoint!(dest,src) @@ -24,14 +13,6 @@ is supported and unexpected results will happen if `src` and `dest` have overlap regions. """ adjoint!(B::AbstractMatrix, A::AbstractMatrix) = transpose_f!(adjoint, B, A) -function transpose!(B::AbstractVector, A::AbstractMatrix) - indices(B,1) == indices(A,2) && indices(A,1) == 1:1 || throw(DimensionMismatch("transpose")) - copy!(B, A) -end -function transpose!(B::AbstractMatrix, A::AbstractVector) - indices(B,2) == indices(A,1) && indices(B,1) == 1:1 || throw(DimensionMismatch("transpose")) - copy!(B, A) -end function adjoint!(B::AbstractVector, A::AbstractMatrix) indices(B,1) == indices(A,2) && indices(A,1) == 1:1 || throw(DimensionMismatch("transpose")) adjointcopy!(B, A) @@ -41,46 +22,6 @@ function adjoint!(B::AbstractMatrix, A::AbstractVector) adjointcopy!(B, A) end -const transposebaselength=64 -function transpose_f!(f, B::AbstractMatrix, A::AbstractMatrix) - inds = indices(A) - indices(B,1) == inds[2] && indices(B,2) == inds[1] || throw(DimensionMismatch(string(f))) - - m, n = length(inds[1]), length(inds[2]) - if m*n<=4*transposebaselength - @inbounds begin - for j = inds[2] - for i = inds[1] - B[j,i] = f(A[i,j]) - end - end - end - else - transposeblock!(f,B,A,m,n,first(inds[1])-1,first(inds[2])-1) - end - return B -end -function transposeblock!(f, B::AbstractMatrix, A::AbstractMatrix, m::Int, n::Int, offseti::Int, offsetj::Int) - if m*n<=transposebaselength - @inbounds begin - for j = offsetj+(1:n) - for i = offseti+(1:m) - B[j,i] = f(A[i,j]) - end - end - end - elseif m>n - newm=m>>1 - transposeblock!(f,B,A,newm,n,offseti,offsetj) - transposeblock!(f,B,A,m-newm,n,offseti+newm,offsetj) - else - newn=n>>1 - transposeblock!(f,B,A,m,newn,offseti,offsetj) - transposeblock!(f,B,A,m,n-newn,offseti,offsetj+newn) - end - return B -end - function adjointcopy!(B, A) RB, RA = eachindex(B), eachindex(A) if RB == RA @@ -94,57 +35,9 @@ function adjointcopy!(B, A) end end -""" - transpose(A::AbstractMatrix) - -The transposition operator (`.'`). - -# Examples -```jldoctest -julia> A = [1 2 3; 4 5 6; 7 8 9] -3×3 Array{Int64,2}: - 1 2 3 - 4 5 6 - 7 8 9 - -julia> transpose(A) -3×3 Array{Int64,2}: - 1 4 7 - 2 5 8 - 3 6 9 -``` -""" -function transpose(A::AbstractMatrix) - ind1, ind2 = indices(A) - B = similar(A, (ind2, ind1)) - transpose!(B, A) -end function adjoint(A::AbstractMatrix) ind1, ind2 = indices(A) B = similar(A, adjoint_type(eltype(A)), (ind2, ind1)) adjoint!(B, A) end -function copy_transpose!(B::AbstractVecOrMat, ir_dest::Range{Int}, jr_dest::Range{Int}, - A::AbstractVecOrMat, ir_src::Range{Int}, jr_src::Range{Int}) - if length(ir_dest) != length(jr_src) - throw(ArgumentError(string("source and destination must have same size (got ", - length(jr_src)," and ",length(ir_dest),")"))) - end - if length(jr_dest) != length(ir_src) - throw(ArgumentError(string("source and destination must have same size (got ", - length(ir_src)," and ",length(jr_dest),")"))) - end - @boundscheck checkbounds(B, ir_dest, jr_dest) - @boundscheck checkbounds(A, ir_src, jr_src) - idest = first(ir_dest) - for jsrc in jr_src - jdest = first(jr_dest) - for isrc in ir_src - B[idest,jdest] = A[isrc,jsrc] - jdest += step(jr_dest) - end - idest += step(ir_dest) - end - return B -end diff --git a/test/mappedarray.jl b/test/mappedarray.jl index 85478fb64134e..90c38b8c162f7 100644 --- a/test/mappedarray.jl +++ b/test/mappedarray.jl @@ -9,7 +9,7 @@ b = @inferred(MappedArray(x -> x + 10, a))::MappedArray @test_throws ErrorException b[2] = 20 c = @inferred(MappedArray(x -> x + 10, x -> x - 10, a))::MappedArray @test c[2] === 12 -@test (c[2] = 20; c[2] === 10) -@test (c[3] = 30.0; c[3] === 20) +@test (c[2] = 20; a[2] === 10) +@test (c[3] = 30.0; a[3] === 20) @test Base.IndexStyle(b) === Base.IndexStyle(a) \ No newline at end of file