Skip to content

Commit 3d6fa35

Browse files
andyferrisstevengj
authored andcommitted
Introduce RowVector as the transpose of a vector (#19670)
* Moved all array transpose functions to LinAlg Transposition is a concept of linear algebra rather than multidimensional arrays of data. * Introduce `RowVector` as vector transpose `RowVector` is now defined as the `transpose` of any `AbstractVector`. If `v` is an `AbstractVector`, then it obeys the identity that `(v.').' === v` and the matrix multiplication rules follow that `(A * v).' == (v.' * A.')`. `RowVector` is a "view" and maintains the recursive nature of `transpose`. It is a subtype of `AbstractMatrix` and maintains the current shape and broadcast behavior for `v.'. Consequences include: * v'' is a vector, not a matrix * v'*v is a scalar, not a vector * v*v' is the outer produce (returns a matrix) * v*A (for A::AbstractMatrix) is removed, since its puprose was to provide a way of doing the outer product above, and is no longer necessary. Closes #4774
1 parent aa2ea55 commit 3d6fa35

32 files changed

+833
-283
lines changed

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ This section lists changes that do not have deprecation warnings.
9999
`n` and `max_delay`. The previous functionality can be achieved setting
100100
`delays` to `ExponentialBackOff`. ([#19331])
101101

102+
* `transpose(::AbstractVector)` now always returns a `RowVector` view of the input (which is a
103+
special 1×n-sized `AbstractMatrix`), not a `Matrix`, etc. In particular, for
104+
`v::AbstractVector` we now have `(v.').' === v` and `v.' * v` is a scalar. ([#19670])
105+
102106
Library improvements
103107
--------------------
104108

base/abstractarray.jl

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -644,29 +644,6 @@ function copy!{R,S}(B::AbstractVecOrMat{R}, ir_dest::Range{Int}, jr_dest::Range{
644644
return B
645645
end
646646

647-
function copy_transpose!{R,S}(B::AbstractVecOrMat{R}, ir_dest::Range{Int}, jr_dest::Range{Int},
648-
A::AbstractVecOrMat{S}, ir_src::Range{Int}, jr_src::Range{Int})
649-
if length(ir_dest) != length(jr_src)
650-
throw(ArgumentError(string("source and destination must have same size (got ",
651-
length(jr_src)," and ",length(ir_dest),")")))
652-
end
653-
if length(jr_dest) != length(ir_src)
654-
throw(ArgumentError(string("source and destination must have same size (got ",
655-
length(ir_src)," and ",length(jr_dest),")")))
656-
end
657-
@boundscheck checkbounds(B, ir_dest, jr_dest)
658-
@boundscheck checkbounds(A, ir_src, jr_src)
659-
idest = first(ir_dest)
660-
for jsrc in jr_src
661-
jdest = first(jr_dest)
662-
for isrc in ir_src
663-
B[idest,jdest] = A[isrc,jsrc]
664-
jdest += step(jr_dest)
665-
end
666-
idest += step(ir_dest)
667-
end
668-
return B
669-
end
670647

671648
"""
672649
copymutable(a)

base/abstractarraymath.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ isinteger{T<:Integer,n}(x::AbstractArray{T,n}) = true
77
isreal(x::AbstractArray) = all(isreal,x)
88
iszero(x::AbstractArray) = all(iszero,x)
99
isreal{T<:Real,n}(x::AbstractArray{T,n}) = true
10-
ctranspose(a::AbstractArray) = error("ctranspose not implemented for $(typeof(a)). Consider adding parentheses, e.g. A*(B*C') instead of A*B*C' to avoid explicit calculation of the transposed matrix.")
11-
transpose(a::AbstractArray) = error("transpose not implemented for $(typeof(a)). Consider adding parentheses, e.g. A*(B*C.') instead of A*B*C' to avoid explicit calculation of the transposed matrix.")
1210

1311
## Constructors ##
1412

base/arraymath.jl

Lines changed: 0 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -274,130 +274,3 @@ julia> rot180(a,2)
274274
```
275275
"""
276276
rot180(A::AbstractMatrix, k::Integer) = mod(k, 2) == 1 ? rot180(A) : copy(A)
277-
278-
## Transpose ##
279-
280-
"""
281-
transpose!(dest,src)
282-
283-
Transpose array `src` and store the result in the preallocated array `dest`, which should
284-
have a size corresponding to `(size(src,2),size(src,1))`. No in-place transposition is
285-
supported and unexpected results will happen if `src` and `dest` have overlapping memory
286-
regions.
287-
"""
288-
transpose!(B::AbstractMatrix, A::AbstractMatrix) = transpose_f!(transpose, B, A)
289-
290-
"""
291-
ctranspose!(dest,src)
292-
293-
Conjugate transpose array `src` and store the result in the preallocated array `dest`, which
294-
should have a size corresponding to `(size(src,2),size(src,1))`. No in-place transposition
295-
is supported and unexpected results will happen if `src` and `dest` have overlapping memory
296-
regions.
297-
"""
298-
ctranspose!(B::AbstractMatrix, A::AbstractMatrix) = transpose_f!(ctranspose, B, A)
299-
function transpose!(B::AbstractVector, A::AbstractMatrix)
300-
indices(B,1) == indices(A,2) && indices(A,1) == 1:1 || throw(DimensionMismatch("transpose"))
301-
copy!(B, A)
302-
end
303-
function transpose!(B::AbstractMatrix, A::AbstractVector)
304-
indices(B,2) == indices(A,1) && indices(B,1) == 1:1 || throw(DimensionMismatch("transpose"))
305-
copy!(B, A)
306-
end
307-
function ctranspose!(B::AbstractVector, A::AbstractMatrix)
308-
indices(B,1) == indices(A,2) && indices(A,1) == 1:1 || throw(DimensionMismatch("transpose"))
309-
ccopy!(B, A)
310-
end
311-
function ctranspose!(B::AbstractMatrix, A::AbstractVector)
312-
indices(B,2) == indices(A,1) && indices(B,1) == 1:1 || throw(DimensionMismatch("transpose"))
313-
ccopy!(B, A)
314-
end
315-
316-
const transposebaselength=64
317-
function transpose_f!(f,B::AbstractMatrix,A::AbstractMatrix)
318-
inds = indices(A)
319-
indices(B,1) == inds[2] && indices(B,2) == inds[1] || throw(DimensionMismatch(string(f)))
320-
321-
m, n = length(inds[1]), length(inds[2])
322-
if m*n<=4*transposebaselength
323-
@inbounds begin
324-
for j = inds[2]
325-
for i = inds[1]
326-
B[j,i] = f(A[i,j])
327-
end
328-
end
329-
end
330-
else
331-
transposeblock!(f,B,A,m,n,first(inds[1])-1,first(inds[2])-1)
332-
end
333-
return B
334-
end
335-
function transposeblock!(f,B::AbstractMatrix,A::AbstractMatrix,m::Int,n::Int,offseti::Int,offsetj::Int)
336-
if m*n<=transposebaselength
337-
@inbounds begin
338-
for j = offsetj+(1:n)
339-
for i = offseti+(1:m)
340-
B[j,i] = f(A[i,j])
341-
end
342-
end
343-
end
344-
elseif m>n
345-
newm=m>>1
346-
transposeblock!(f,B,A,newm,n,offseti,offsetj)
347-
transposeblock!(f,B,A,m-newm,n,offseti+newm,offsetj)
348-
else
349-
newn=n>>1
350-
transposeblock!(f,B,A,m,newn,offseti,offsetj)
351-
transposeblock!(f,B,A,m,n-newn,offseti,offsetj+newn)
352-
end
353-
return B
354-
end
355-
356-
function ccopy!(B, A)
357-
RB, RA = eachindex(B), eachindex(A)
358-
if RB == RA
359-
for i = RB
360-
B[i] = ctranspose(A[i])
361-
end
362-
else
363-
for (i,j) = zip(RB, RA)
364-
B[i] = ctranspose(A[j])
365-
end
366-
end
367-
end
368-
369-
"""
370-
transpose(A)
371-
372-
The transposition operator (`.'`).
373-
374-
# Example
375-
376-
```jldoctest
377-
julia> A = [1 2 3; 4 5 6; 7 8 9]
378-
3×3 Array{Int64,2}:
379-
1 2 3
380-
4 5 6
381-
7 8 9
382-
383-
julia> transpose(A)
384-
3×3 Array{Int64,2}:
385-
1 4 7
386-
2 5 8
387-
3 6 9
388-
```
389-
"""
390-
function transpose(A::AbstractMatrix)
391-
ind1, ind2 = indices(A)
392-
B = similar(A, (ind2, ind1))
393-
transpose!(B, A)
394-
end
395-
function ctranspose(A::AbstractMatrix)
396-
ind1, ind2 = indices(A)
397-
B = similar(A, (ind2, ind1))
398-
ctranspose!(B, A)
399-
end
400-
ctranspose{T<:Real}(A::AbstractVecOrMat{T}) = transpose(A)
401-
402-
transpose(x::AbstractVector) = [ transpose(v) for i=of_indices(x, OneTo(1)), v in x ]
403-
ctranspose{T}(x::AbstractVector{T}) = T[ ctranspose(v) for i=of_indices(x, OneTo(1)), v in x ]

base/bitarray.jl

Lines changed: 0 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1893,94 +1893,6 @@ function filter(f, Bs::BitArray)
18931893
Bs[boolmap]
18941894
end
18951895

1896-
## Transpose ##
1897-
1898-
transpose(B::BitVector) = reshape(copy(B), 1, length(B))
1899-
1900-
# fast 8x8 bit transpose from Henry S. Warrens's "Hacker's Delight"
1901-
# http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt
1902-
function transpose8x8(x::UInt64)
1903-
y = x
1904-
t = xor(y, y >>> 7) & 0x00aa00aa00aa00aa
1905-
y = xor(y, t, t << 7)
1906-
t = xor(y, y >>> 14) & 0x0000cccc0000cccc
1907-
y = xor(y, t, t << 14)
1908-
t = xor(y, y >>> 28) & 0x00000000f0f0f0f0
1909-
return xor(y, t, t << 28)
1910-
end
1911-
1912-
function form_8x8_chunk(Bc::Vector{UInt64}, i1::Int, i2::Int, m::Int, cgap::Int, cinc::Int, nc::Int, msk8::UInt64)
1913-
x = UInt64(0)
1914-
1915-
k, l = get_chunks_id(i1 + (i2 - 1) * m)
1916-
r = 0
1917-
for j = 1:8
1918-
k > nc && break
1919-
x |= ((Bc[k] >>> l) & msk8) << r
1920-
if l + 8 >= 64 && nc > k
1921-
r0 = 8 - _mod64(l + 8)
1922-
x |= (Bc[k + 1] & (msk8 >>> r0)) << (r + r0)
1923-
end
1924-
k += cgap + (l + cinc >= 64 ? 1 : 0)
1925-
l = _mod64(l + cinc)
1926-
r += 8
1927-
end
1928-
return x
1929-
end
1930-
1931-
# note: assumes B is filled with 0's
1932-
function put_8x8_chunk(Bc::Vector{UInt64}, i1::Int, i2::Int, x::UInt64, m::Int, cgap::Int, cinc::Int, nc::Int, msk8::UInt64)
1933-
k, l = get_chunks_id(i1 + (i2 - 1) * m)
1934-
r = 0
1935-
for j = 1:8
1936-
k > nc && break
1937-
Bc[k] |= ((x >>> r) & msk8) << l
1938-
if l + 8 >= 64 && nc > k
1939-
r0 = 8 - _mod64(l + 8)
1940-
Bc[k + 1] |= ((x >>> (r + r0)) & (msk8 >>> r0))
1941-
end
1942-
k += cgap + (l + cinc >= 64 ? 1 : 0)
1943-
l = _mod64(l + cinc)
1944-
r += 8
1945-
end
1946-
return
1947-
end
1948-
1949-
function transpose(B::BitMatrix)
1950-
l1 = size(B, 1)
1951-
l2 = size(B, 2)
1952-
Bt = falses(l2, l1)
1953-
1954-
cgap1, cinc1 = _div64(l1), _mod64(l1)
1955-
cgap2, cinc2 = _div64(l2), _mod64(l2)
1956-
1957-
Bc = B.chunks
1958-
Btc = Bt.chunks
1959-
1960-
nc = length(Bc)
1961-
1962-
for i = 1:8:l1
1963-
msk8_1 = UInt64(0xff)
1964-
if (l1 < i + 7)
1965-
msk8_1 >>>= i + 7 - l1
1966-
end
1967-
1968-
for j = 1:8:l2
1969-
x = form_8x8_chunk(Bc, i, j, l1, cgap1, cinc1, nc, msk8_1)
1970-
x = transpose8x8(x)
1971-
1972-
msk8_2 = UInt64(0xff)
1973-
if (l2 < j + 7)
1974-
msk8_2 >>>= j + 7 - l2
1975-
end
1976-
1977-
put_8x8_chunk(Btc, j, i, x, l2, cgap2, cinc2, nc, msk8_2)
1978-
end
1979-
end
1980-
return Bt
1981-
end
1982-
1983-
ctranspose(B::BitArray) = transpose(B)
19841896

19851897
## Concatenation ##
19861898

base/docs/basedocs.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,16 @@ kw"'"
281281
1+1im 2+1im
282282
3+1im 4+1im
283283
284+
julia> v = [1,2,3]
285+
3-element Array{Int64,1}:
286+
1
287+
2
288+
3
289+
290+
julia> v.'
291+
1×3 RowVector{Int64,Array{Int64,1}}:
292+
1 2 3
293+
284294
"""
285295
kw".'"
286296

base/exports.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ export
9898
RoundNearestTiesUp,
9999
RoundToZero,
100100
RoundUp,
101+
RowVector,
101102
AbstractSerializer,
102103
SerializationState,
103104
Set,

base/linalg/bidiag.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,15 @@ A_mul_B!(C::AbstractVector, A::BiTri, B::AbstractVector) = A_mul_B_td!(C, A, B)
354354
A_mul_B!(C::AbstractMatrix, A::BiTri, B::AbstractVecOrMat) = A_mul_B_td!(C, A, B)
355355
A_mul_B!(C::AbstractVecOrMat, A::BiTri, B::AbstractVecOrMat) = A_mul_B_td!(C, A, B)
356356

357+
\(::Diagonal, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector"))
358+
\(::Bidiagonal, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector"))
359+
\{TA<:Number,TB<:Number}(::Bidiagonal{TA}, ::RowVector{TB}) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector"))
360+
361+
At_ldiv_B(::Bidiagonal, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector"))
362+
At_ldiv_B{TA<:Number,TB<:Number}(::Bidiagonal{TA}, ::RowVector{TB}) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector"))
363+
364+
Ac_ldiv_B(::Bidiagonal, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector"))
365+
Ac_ldiv_B{TA<:Number,TB<:Number}(::Bidiagonal{TA}, ::RowVector{TB}) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector"))
357366

358367
function check_A_mul_B!_sizes(C, A, B)
359368
nA, mA = size(A)

0 commit comments

Comments
 (0)