155 lines
4.8 KiB
Julia
155 lines
4.8 KiB
Julia
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||
|
||
ctranspose(a::AbstractArray) = error("ctranspose 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!(transpose, B, A)
|
||
|
||
"""
|
||
ctranspose!(dest,src)
|
||
|
||
Conjugate 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.
|
||
"""
|
||
ctranspose!(B::AbstractMatrix, A::AbstractMatrix) = transpose_f!(ctranspose, 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 ctranspose!(B::AbstractVector, A::AbstractMatrix)
|
||
indices(B,1) == indices(A,2) && indices(A,1) == 1:1 || throw(DimensionMismatch("transpose"))
|
||
ccopy!(B, A)
|
||
end
|
||
function ctranspose!(B::AbstractMatrix, A::AbstractVector)
|
||
indices(B,2) == indices(A,1) && indices(B,1) == 1:1 || throw(DimensionMismatch("transpose"))
|
||
ccopy!(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 ccopy!(B, A)
|
||
RB, RA = eachindex(B), eachindex(A)
|
||
if RB == RA
|
||
for i = RB
|
||
B[i] = ctranspose(A[i])
|
||
end
|
||
else
|
||
for (i,j) = zip(RB, RA)
|
||
B[i] = ctranspose(A[j])
|
||
end
|
||
end
|
||
end
|
||
|
||
"""
|
||
transpose(A::AbstractMatrix)
|
||
|
||
The transposition operator (`.'`).
|
||
|
||
# Example
|
||
|
||
```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 ctranspose(A::AbstractMatrix)
|
||
ind1, ind2 = indices(A)
|
||
B = similar(A, (ind2, ind1))
|
||
ctranspose!(B, A)
|
||
end
|
||
|
||
@inline ctranspose(A::AbstractVector{<:Real}) = transpose(A)
|
||
@inline ctranspose(A::AbstractMatrix{<:Real}) = transpose(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
|