diff --git a/NEWS.md b/NEWS.md index 0fe173063bc5d..3cf69a0495924 100644 --- a/NEWS.md +++ b/NEWS.md @@ -172,6 +172,14 @@ This section lists changes that do not have deprecation warnings. of the output was shrunk to fit the union of the type of each element in the input. ([#22696]) + * `transpose` and `transpose!` no longer recursively transpose the elements of the + container. Similarly, `RowVector` no longer provides a transposed view of the elements. + Transposition now simply rearranges the elements of containers of data, such as arrays + of strings. Note that the renamed `adjoint` method (formerly `ctranspose`) does still + act in a recursive manner, and that (very occassionally) `conj(adjoint(...))` will be + preferrable to `transpose` for linear algebra problems using nested arrays as "block + matrices". ([#23424]) + Library improvements -------------------- diff --git a/base/linalg/conjarray.jl b/base/linalg/conjarray.jl index 0bc835ce60cd4..22cb5d5ddd2df 100644 --- a/base/linalg/conjarray.jl +++ b/base/linalg/conjarray.jl @@ -55,12 +55,6 @@ IndexStyle(::Type{CA}) where {CA<:ConjArray} = IndexStyle(parent_type(CA)) @inline conj(a::ConjArray) = parent(a) @inline adjoint(a::ConjArray) = ConjAdjointArray(parent(a)) -# Helper functions, currently used by RowVector -@inline _conj(a::AbstractArray) = ConjArray(a) -@inline _conj(a::AbstractArray{T}) where {T<:Real} = a -@inline _conj(a::ConjArray) = parent(a) -@inline _conj(a::ConjArray{T}) where {T<:Real} = parent(a) - """ AdjointArray(array) @@ -116,14 +110,6 @@ IndexStyle(::Type{AA}) where {AA<:AdjointArray} = IndexStyle(parent_type(AA)) @inline adjoint(a::AdjointArray) = parent(a) @inline conj(a::AdjointArray) = ConjAdjointArray(parent(a)) -# Helper functions, currently used by RowVector -@inline _adjoint(a::AbstractArray) = AdjointArray(a) -@inline _adjoint(a::AbstractArray{T}) where {T<:Real} = a -@inline _adjoint(a::AbstractArray{T}) where {T<:Number} = conj(a) -@inline _adjoint(a::AdjointArray) = parent(a) -@inline _adjoint(a::AdjointArray{T}) where {T<:Real} = parent(a) -@inline _adjoint(a::AdjointArray{T}) where {T<:Number} = parent(a) - """ ConjAdjointArray(array) @@ -180,7 +166,22 @@ IndexStyle(::Type{A}) where {A<:ConjAdjointArray} = IndexStyle(parent_type(A)) @inline conj(a::ConjAdjointArray) = AdjointArray(parent(a)) # Helper functions, currently used by RowVector -@inline _conjadjoint(a::AbstractArray) = ConjAdjointArray(a) -@inline _conjadjoint(a::AbstractArray{T}) where {T<:Number} = conj(a) -@inline _conjadjoint(a::AdjointArray) = parent(a) -@inline _conjadjoint(a::ConjAdjointArray{T}) where {T<:Number} = parent(a) +# (some of these are simplify types that would not typically occur) +@inline _conj(a::AbstractArray) = ConjArray(a) +@inline _conj(a::AbstractArray{<:Real}) = a +@inline _conj(a::ConjArray) = parent(a) +@inline _conj(a::AdjointArray) = ConjAdjointArray(parent(a)) +@inline _conj(a::AdjointArray{<:Number}) = parent(a) +@inline _conj(a::ConjAdjointArray) = AdjointArray(parent(a)) +@inline _conj(a::ConjAdjointArray{<:Real}) = parent(a) +@inline _conj(a::ConjAdjointArray{<:Number}) = ConjArray(parent(a)) + +@inline _adjoint(a::AbstractArray) = AdjointArray(a) +@inline _adjoint(a::AbstractArray{<:Real}) = a +@inline _adjoint(a::AbstractArray{<:Number}) = ConjArray(a) +@inline _adjoint(a::AdjointArray) = parent(a) +@inline _adjoint(a::ConjArray) = ConjAdjointArray(parent(a)) +@inline _adjoint(a::ConjArray{<:Number}) = parent(a) +@inline _adjoint(a::ConjAdjointArray) = ConjArray(parent(a)) +@inline _adjoint(a::ConjAdjointArray{<:Real}) = parent(a) +@inline _adjoint(a::ConjAdjointArray{<:Number}) = ConjArray(parent(a)) diff --git a/base/linalg/rowvector.jl b/base/linalg/rowvector.jl index 68125f2d89460..4fa92fb1a86d3 100644 --- a/base/linalg/rowvector.jl +++ b/base/linalg/rowvector.jl @@ -70,10 +70,14 @@ julia> transpose(v) @inline transpose(vec::AbstractVector) = RowVector(vec) @inline adjoint(vec::AbstractVector) = RowVector(_adjoint(vec)) +# For the moment, we remove the ConjArray wrapper from any raw vector of numbers, to allow for BLAS specializations @inline transpose(rowvec::RowVector) = parent(rowvec) -@inline transpose(rowvec::ConjRowVector) = copy(parent(rowvec)) # remove the ConjArray wrapper from any raw vector -@inline adjoint(rowvec::RowVector) = conj(parent(rowvec)) +@inline transpose(rowvec::ConjRowVector{<:Number}) = copy(parent(rowvec)) + @inline adjoint(rowvec::RowVector{<:Real}) = parent(rowvec) +@inline adjoint(rowvec::RowVector{<:Number}) = conj(parent(rowvec)) +@inline adjoint(rowvec::ConjRowVector{<:Number}) = parent(rowvec) +@inline adjoint(rowvec::RowVector) = _adjoint(parent(rowvec)) """ conj(v::RowVector) @@ -131,16 +135,17 @@ end @inline check_tail_indices(i1, i2, i3, is...) = i3 == 1 ? check_tail_indices(i1, i2, is...) : false # helper function for below -@inline to_vec(rowvec::RowVector) = map(transpose, transpose(rowvec)) +@inline to_vec(rowvec::RowVector) = parent(rowvec) @inline to_vec(x::Number) = x @inline to_vecs(rowvecs...) = (map(to_vec, rowvecs)...) # map: Preserve the RowVector by un-wrapping and re-wrapping -@inline map(f, rowvecs::RowVector...) = RowVector(map(f, to_vec(rowvecs...)...)) +@inline map(f, rowvecs::RowVector...) = RowVector(map(f, to_vecs(rowvecs...)...)) # broacast (other combinations default to higher-dimensional array) +# (in future, should use broadcast infrastructure to manage this?) @inline broadcast(f, rowvecs::Union{Number,RowVector}...) = - RowVector(broadcast(f, to_vec(rowvecs...)...)) + RowVector(broadcast(f, to_vecs(rowvecs...)...)) # Horizontal concatenation # diff --git a/test/linalg/rowvector.jl b/test/linalg/rowvector.jl index 4fbcd8cc8b621..ffc6d7b7d9b2d 100644 --- a/test/linalg/rowvector.jl +++ b/test/linalg/rowvector.jl @@ -4,7 +4,7 @@ v = [1,2,3] z = [1+im,2,3] - @test RowVector(v) == [1 2 3] + @test RowVector(v)::RowVector == [1 2 3] @test RowVector{Int}(v) == [1 2 3] @test size(RowVector{Int}(3)) === (1,3) @test size(RowVector{Int}(1,3)) === (1,3) @@ -15,7 +15,9 @@ @test (v.')::RowVector == [1 2 3] @test (v')::RowVector == [1 2 3] @test (z.')::RowVector == [1+im 2 3] + @test parent(z.') isa Vector @test (z')::RowVector == [1-im 2 3] + @test parent(z') isa Base.LinAlg.ConjVector rv = v.' tz = z.' @@ -51,6 +53,40 @@ @test sum(abs2, imag.(diag(y .+ y'))) < 1e-20 end +@testset "Nested arrays" begin + v = [[1, 2]] + + @test v'::RowVector == reshape([[1 2]], (1,1)) + @test parent(v') isa Base.LinAlg.AdjointArray{<:RowVector} + @test conj(v')::RowVector == reshape([[1 2]], (1,1)) + @test parent(conj(v')) isa Base.LinAlg.AdjointArray{<:RowVector} + @test (v').'::Vector == [[1 2]] + @test (v')' === v + + @test v.'::RowVector == [[1, 2]] + @test parent(v.') isa Vector + @test conj(v.')::RowVector == [[1, 2]] + @test parent(conj(v.')) isa Vector{Int} + @test (v.').' === v + @test (v.')'::Vector == [[1 2]] + + z = [[1+im, 2]] + + @test z'::RowVector == reshape([[1-im 2]], (1,1)) + @test parent(z') isa Base.LinAlg.AdjointArray{<:RowVector} + @test conj(z')::RowVector == reshape([[1+im 2]], (1,1)) + @test parent(conj(z')) isa Base.LinAlg.ConjAdjointArray{<:RowVector} + @test (z').'::Vector{<:RowVector} == [[1-im 2]] + @test (z')' === z + + @test z.'::RowVector == [[1+im, 2]] + @test parent(z.') isa Vector + @test conj(z.')::RowVector == [[1-im, 2]] + @test parent(conj(z.')) isa ConjArray{<:Vector} + @test (z.').' === z + @test (z.')'::Vector{<:RowVector} == [[1-im 2]] +end + @testset "Diagonal ambiguity methods" begin d = Diagonal([1,2,3]) v = [2,3,4]