From 7f977eda016e67aa421a59480eadbe6f60650d97 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 2 Feb 2017 21:04:49 -0500 Subject: [PATCH 1/5] re-allow vector*(1-row matrix) and transpose (closes #20389) --- base/linalg/matmul.jl | 1 + base/linalg/rowvector.jl | 3 --- test/linalg/rowvector.jl | 7 ++++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/base/linalg/matmul.jl b/base/linalg/matmul.jl index 4dbd4c8dae817..b7090bfe4e691 100644 --- a/base/linalg/matmul.jl +++ b/base/linalg/matmul.jl @@ -80,6 +80,7 @@ function (*){T,S}(A::AbstractMatrix{T}, x::AbstractVector{S}) TS = promote_op(matprod, T, S) A_mul_B!(similar(x,TS,size(A,1)),A,x) end +(*)(A::AbstractVector, B::AbstractMatrix) = reshape(A,length(A),1)*B A_mul_B!{T<:BlasFloat}(y::StridedVector{T}, A::StridedVecOrMat{T}, x::StridedVector{T}) = gemv!(y, 'N', A, x) for elty in (Float32,Float64) diff --git a/base/linalg/rowvector.jl b/base/linalg/rowvector.jl index c5d2839e19b3c..9b8c873b46cdf 100644 --- a/base/linalg/rowvector.jl +++ b/base/linalg/rowvector.jl @@ -154,12 +154,9 @@ end sum(@inbounds(return rowvec[i]*vec[i]) for i = 1:length(vec)) end @inline *(rowvec::RowVector, mat::AbstractMatrix) = transpose(mat.' * transpose(rowvec)) -*(vec::AbstractVector, mat::AbstractMatrix) = throw(DimensionMismatch( - "Cannot left-multiply a matrix by a vector")) # Should become a deprecation *(::RowVector, ::RowVector) = throw(DimensionMismatch("Cannot multiply two transposed vectors")) @inline *(vec::AbstractVector, rowvec::RowVector) = vec .* rowvec *(vec::AbstractVector, rowvec::AbstractVector) = throw(DimensionMismatch("Cannot multiply two vectors")) -*(mat::AbstractMatrix, rowvec::RowVector) = throw(DimensionMismatch("Cannot right-multiply matrix by transposed vector")) # Transposed forms A_mul_Bt(::RowVector, ::AbstractVector) = throw(DimensionMismatch("Cannot multiply two transposed vectors")) diff --git a/test/linalg/rowvector.jl b/test/linalg/rowvector.jl index 315ec12586f5d..e35a97a0f9c93 100644 --- a/test/linalg/rowvector.jl +++ b/test/linalg/rowvector.jl @@ -104,7 +104,7 @@ end @test (rv*v) === 14 @test (rv*mat)::RowVector == [1 4 9] - @test_throws DimensionMismatch [1]*reshape([1],(1,1)) # no longer permitted + @test [1]*reshape([1],(1,1)) == reshape([1],(1,1)) @test_throws DimensionMismatch rv*rv @test (v*rv)::Matrix == [1 2 3; 2 4 6; 3 6 9] @test_throws DimensionMismatch v*v # Was previously a missing method error, now an error message @@ -238,5 +238,10 @@ end @test_throws DimensionMismatch ut\rv end +# issue #20389 +@testset "1 row/col vec*mat" begin + @test [1,2,3] * ones(1, 4) == [1,2,3] .* ones(1, 4) + @test ones(4,1) * RowVector([1,2,3]) == ones(4,1) .* RowVector([1,2,3]) +end end # @testset "RowVector" From 30f9cd16992d21e189689064452a37f9b27fb175 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 3 Feb 2017 08:53:09 -0500 Subject: [PATCH 2/5] delete more methods that are just there to throw errors on 1 row/col matrices --- base/linalg/rowvector.jl | 12 ------------ test/linalg/rowvector.jl | 16 ++++++++++++---- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/base/linalg/rowvector.jl b/base/linalg/rowvector.jl index 9b8c873b46cdf..9bc908d20f781 100644 --- a/base/linalg/rowvector.jl +++ b/base/linalg/rowvector.jl @@ -161,16 +161,12 @@ end # Transposed forms A_mul_Bt(::RowVector, ::AbstractVector) = throw(DimensionMismatch("Cannot multiply two transposed vectors")) @inline A_mul_Bt(rowvec::RowVector, mat::AbstractMatrix) = transpose(mat * transpose(rowvec)) -A_mul_Bt(vec::AbstractVector, mat::AbstractMatrix) = throw(DimensionMismatch( - "Cannot left-multiply a matrix by a vector")) @inline A_mul_Bt(rowvec1::RowVector, rowvec2::RowVector) = rowvec1*transpose(rowvec2) A_mul_Bt(vec::AbstractVector, rowvec::RowVector) = throw(DimensionMismatch("Cannot multiply two vectors")) @inline A_mul_Bt(vec1::AbstractVector, vec2::AbstractVector) = vec1 * transpose(vec2) @inline A_mul_Bt(mat::AbstractMatrix, rowvec::RowVector) = mat * transpose(rowvec) @inline At_mul_Bt(rowvec::RowVector, vec::AbstractVector) = transpose(rowvec) * transpose(vec) -At_mul_Bt(rowvec::RowVector, mat::AbstractMatrix) = throw(DimensionMismatch( - "Cannot left-multiply matrix by vector")) @inline At_mul_Bt(vec::AbstractVector, mat::AbstractMatrix) = transpose(mat * vec) At_mul_Bt(rowvec1::RowVector, rowvec2::RowVector) = throw(DimensionMismatch("Cannot multiply two vectors")) @inline At_mul_Bt(vec::AbstractVector, rowvec::RowVector) = transpose(vec)*transpose(rowvec) @@ -179,8 +175,6 @@ At_mul_Bt(vec::AbstractVector, rowvec::AbstractVector) = throw(DimensionMismatch @inline At_mul_Bt(mat::AbstractMatrix, rowvec::RowVector) = mat.' * transpose(rowvec) At_mul_B(::RowVector, ::AbstractVector) = throw(DimensionMismatch("Cannot multiply two vectors")) -At_mul_B(rowvec::RowVector, mat::AbstractMatrix) = throw(DimensionMismatch( - "Cannot left-multiply matrix by vector")) @inline At_mul_B(vec::AbstractVector, mat::AbstractMatrix) = transpose(At_mul_B(mat,vec)) @inline At_mul_B(rowvec1::RowVector, rowvec2::RowVector) = transpose(rowvec1) * rowvec2 At_mul_B(vec::AbstractVector, rowvec::RowVector) = throw(DimensionMismatch( @@ -188,20 +182,16 @@ At_mul_B(vec::AbstractVector, rowvec::RowVector) = throw(DimensionMismatch( @inline At_mul_B{T<:Real}(vec1::AbstractVector{T}, vec2::AbstractVector{T}) = reduce(+, map(At_mul_B, vec1, vec2)) # Seems to be overloaded... @inline At_mul_B(vec1::AbstractVector, vec2::AbstractVector) = transpose(vec1) * vec2 -At_mul_B(mat::AbstractMatrix, rowvec::RowVector) = throw(DimensionMismatch( - "Cannot right-multiply matrix by transposed vector")) # Conjugated forms A_mul_Bc(::RowVector, ::AbstractVector) = throw(DimensionMismatch("Cannot multiply two transposed vectors")) @inline A_mul_Bc(rowvec::RowVector, mat::AbstractMatrix) = ctranspose(mat * ctranspose(rowvec)) -A_mul_Bc(vec::AbstractVector, mat::AbstractMatrix) = throw(DimensionMismatch("Cannot left-multiply a matrix by a vector")) @inline A_mul_Bc(rowvec1::RowVector, rowvec2::RowVector) = rowvec1 * ctranspose(rowvec2) A_mul_Bc(vec::AbstractVector, rowvec::RowVector) = throw(DimensionMismatch("Cannot multiply two vectors")) @inline A_mul_Bc(vec1::AbstractVector, vec2::AbstractVector) = vec1 * ctranspose(vec2) @inline A_mul_Bc(mat::AbstractMatrix, rowvec::RowVector) = mat * ctranspose(rowvec) @inline Ac_mul_Bc(rowvec::RowVector, vec::AbstractVector) = ctranspose(rowvec) * ctranspose(vec) -Ac_mul_Bc(rowvec::RowVector, mat::AbstractMatrix) = throw(DimensionMismatch("Cannot left-multiply matrix by vector")) @inline Ac_mul_Bc(vec::AbstractVector, mat::AbstractMatrix) = ctranspose(mat * vec) Ac_mul_Bc(rowvec1::RowVector, rowvec2::RowVector) = throw(DimensionMismatch("Cannot multiply two vectors")) @inline Ac_mul_Bc(vec::AbstractVector, rowvec::RowVector) = ctranspose(vec)*ctranspose(rowvec) @@ -209,12 +199,10 @@ Ac_mul_Bc(vec::AbstractVector, rowvec::AbstractVector) = throw(DimensionMismatch @inline Ac_mul_Bc(mat::AbstractMatrix, rowvec::RowVector) = mat' * ctranspose(rowvec) Ac_mul_B(::RowVector, ::AbstractVector) = throw(DimensionMismatch("Cannot multiply two vectors")) -Ac_mul_B(rowvec::RowVector, mat::AbstractMatrix) = throw(DimensionMismatch("Cannot left-multiply matrix by vector")) @inline Ac_mul_B(vec::AbstractVector, mat::AbstractMatrix) = ctranspose(Ac_mul_B(mat,vec)) @inline Ac_mul_B(rowvec1::RowVector, rowvec2::RowVector) = ctranspose(rowvec1) * rowvec2 Ac_mul_B(vec::AbstractVector, rowvec::RowVector) = throw(DimensionMismatch("Cannot multiply two transposed vectors")) @inline Ac_mul_B(vec1::AbstractVector, vec2::AbstractVector) = ctranspose(vec1)*vec2 -Ac_mul_B(mat::AbstractMatrix, rowvec::RowVector) = throw(DimensionMismatch("Cannot right-multiply matrix by transposed vector")) # Left Division # diff --git a/test/linalg/rowvector.jl b/test/linalg/rowvector.jl index e35a97a0f9c93..e2efb7c189c95 100644 --- a/test/linalg/rowvector.jl +++ b/test/linalg/rowvector.jl @@ -112,7 +112,7 @@ end @test_throws DimensionMismatch rv*v.' @test (rv*mat.')::RowVector == [1 4 9] - @test_throws DimensionMismatch [1]*reshape([1],(1,1)).' # no longer permitted + @test [1]*reshape([1],(1,1)).' == reshape([1],(1,1)) @test rv*rv.' === 14 @test_throws DimensionMismatch v*rv.' @test (v*v.')::Matrix == [1 2 3; 2 4 6; 3 6 9] @@ -142,7 +142,7 @@ end @test_throws DimensionMismatch cz*z' @test (cz*mat')::RowVector == [-2im 4 9] - @test_throws DimensionMismatch [1]*reshape([1],(1,1))' # no longer permitted + @test [1]*reshape([1],(1,1))' == reshape([1],(1,1)) @test cz*cz' === 15 + 0im @test_throws DimensionMismatch z*cz' @test (z*z')::Matrix == [2 2+2im 3+3im; 2-2im 4 6; 3-3im 6 9] @@ -240,8 +240,16 @@ end # issue #20389 @testset "1 row/col vec*mat" begin - @test [1,2,3] * ones(1, 4) == [1,2,3] .* ones(1, 4) - @test ones(4,1) * RowVector([1,2,3]) == ones(4,1) .* RowVector([1,2,3]) + let x=[1,2,3], A=ones(1,4), y=x', B=A', C=x.*A + @test x*A == y'*A == x*B' == y'*B' == C + @test A'*x' == A'*y == B*x' == B*y == C' + end +end +@testset "complex 1 row/col vec*mat" begin + let x=[1,2,3]*im, A=ones(1,4)*im, y=x', B=A', C=x.*A + @test x*A == y'*A == x*B' == y'*B' == C + @test A'*x' == A'*y == B*x' == B*y == C' + end end end # @testset "RowVector" From 9e24fbf538b8aff6ada8937363057a3bc95ce575 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 3 Feb 2017 20:41:13 -0500 Subject: [PATCH 3/5] rm more DimensionMismatch methods for RowVector: diagonal and triangular cases --- base/linalg/diagonal.jl | 7 ------- base/linalg/triangular.jl | 13 ------------- 2 files changed, 20 deletions(-) diff --git a/base/linalg/diagonal.jl b/base/linalg/diagonal.jl index 12d9826bf1219..7ef09ad1508a7 100644 --- a/base/linalg/diagonal.jl +++ b/base/linalg/diagonal.jl @@ -256,16 +256,9 @@ end # Methods to resolve ambiguities with `Diagonal` @inline *(rowvec::RowVector, D::Diagonal) = transpose(D * transpose(rowvec)) -*(::Diagonal, ::RowVector) = throw(DimensionMismatch("Cannot right-multiply matrix by transposed vector")) - @inline A_mul_Bt(D::Diagonal, rowvec::RowVector) = D*transpose(rowvec) - -At_mul_B(rowvec::RowVector, ::Diagonal) = throw(DimensionMismatch("Cannot left-multiply matrix by vector")) - @inline A_mul_Bc(D::Diagonal, rowvec::RowVector) = D*ctranspose(rowvec) -Ac_mul_B(rowvec::RowVector, ::Diagonal) = throw(DimensionMismatch("Cannot left-multiply matrix by vector")) - conj(D::Diagonal) = Diagonal(conj(D.diag)) transpose(D::Diagonal) = D ctranspose(D::Diagonal) = conj(D) diff --git a/base/linalg/triangular.jl b/base/linalg/triangular.jl index 61c8ffe34dc35..de6e75368690f 100644 --- a/base/linalg/triangular.jl +++ b/base/linalg/triangular.jl @@ -1637,25 +1637,12 @@ At_mul_Bt(A::AbstractMatrix, B::AbstractTriangular) = A_mul_Bt(A.', B) # Specializations for RowVector @inline *(rowvec::RowVector, A::AbstractTriangular) = transpose(A * transpose(rowvec)) -*(::AbstractTriangular, ::RowVector) = throw(DimensionMismatch("Cannot right-multiply matrix by transposed vector")) - @inline A_mul_Bt(rowvec::RowVector, A::AbstractTriangular) = transpose(A * transpose(rowvec)) @inline A_mul_Bt(A::AbstractTriangular, rowvec::RowVector) = A * transpose(rowvec) - @inline At_mul_Bt(A::AbstractTriangular, rowvec::RowVector) = A.' * transpose(rowvec) -At_mul_Bt(::RowVector, ::AbstractTriangular) = throw(DimensionMismatch("Cannot left-multiply matrix by vector")) - -At_mul_B(::AbstractTriangular, ::RowVector) = throw(DimensionMismatch("Cannot right-multiply matrix by transposed vector")) -At_mul_B(::RowVector, ::AbstractTriangular) = throw(DimensionMismatch("Cannot left-multiply matrix by vector")) - @inline A_mul_Bc(rowvec::RowVector, A::AbstractTriangular) = ctranspose(A * ctranspose(rowvec)) @inline A_mul_Bc(A::AbstractTriangular, rowvec::RowVector) = A * ctranspose(rowvec) - @inline Ac_mul_Bc(A::AbstractTriangular, rowvec::RowVector) = A' * ctranspose(rowvec) -Ac_mul_Bc(::RowVector, ::AbstractTriangular) = throw(DimensionMismatch("Cannot left-multiply matrix by vector")) - -Ac_mul_B(::AbstractTriangular, ::RowVector) = throw(DimensionMismatch("Cannot right-multiply matrix by transposed vector")) -Ac_mul_B(::RowVector, ::AbstractTriangular) = throw(DimensionMismatch("Cannot left-multiply matrix by vector")) @inline /(rowvec::RowVector, A::Union{UpperTriangular,LowerTriangular}) = transpose(transpose(A) \ transpose(rowvec)) @inline /(rowvec::RowVector, A::Union{UnitUpperTriangular,UnitLowerTriangular}) = transpose(transpose(A) \ transpose(rowvec)) From b799c16e576714307c113fd2b96c07d14a85a78a Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Sat, 4 Feb 2017 11:05:09 -0500 Subject: [PATCH 4/5] add missing vector*matrix fallbacks --- base/linalg/matmul.jl | 8 +++++++- base/linalg/triangular.jl | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/base/linalg/matmul.jl b/base/linalg/matmul.jl index b7090bfe4e691..33040803d6172 100644 --- a/base/linalg/matmul.jl +++ b/base/linalg/matmul.jl @@ -80,7 +80,13 @@ function (*){T,S}(A::AbstractMatrix{T}, x::AbstractVector{S}) TS = promote_op(matprod, T, S) A_mul_B!(similar(x,TS,size(A,1)),A,x) end -(*)(A::AbstractVector, B::AbstractMatrix) = reshape(A,length(A),1)*B + +# these will throw a DimensionMismatch unless B has 1 row (or 1 col for transposed case): +A_mul_B(a::AbstractVector, B::AbstractMatrix) = A_mul_B(reshape(a,length(a),1),B) +A_mul_Bt(a::AbstractVector, B::AbstractMatrix) = A_mul_Bt(reshape(a,length(a),1),B) +A_mul_Bt(A::AbstractMatrix, b::AbstractVector) = A_mul_Bt(A,reshape(b,length(b),1)) +A_mul_Bc(a::AbstractVector, B::AbstractMatrix) = A_mul_Bc(reshape(a,length(a),1),B) +(*)(a::AbstractVector, B::AbstractMatrix) = reshape(a,length(a),1)*B A_mul_B!{T<:BlasFloat}(y::StridedVector{T}, A::StridedVecOrMat{T}, x::StridedVector{T}) = gemv!(y, 'N', A, x) for elty in (Float32,Float64) diff --git a/base/linalg/triangular.jl b/base/linalg/triangular.jl index de6e75368690f..92edda90c269c 100644 --- a/base/linalg/triangular.jl +++ b/base/linalg/triangular.jl @@ -1585,7 +1585,7 @@ for (f, g) in ((:\, :A_ldiv_B!), (:Ac_ldiv_B, :Ac_ldiv_B!), (:At_ldiv_B, :At_ldi end ### Multiplication with triangle to the rigth and hence lhs cannot be transposed. for (f, g) in ((:*, :A_mul_B!), (:A_mul_Bc, :A_mul_Bc!), (:A_mul_Bt, :A_mul_Bt!)) - @eval begin + mat != :AbstractVector && @eval begin function ($f)(A::$mat, B::AbstractTriangular) TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) AA = similar(A, TAB, size(A)) From c7ad5e618a2be45c1c8b4a0745030640a9d63d34 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Sat, 4 Feb 2017 17:19:57 -0500 Subject: [PATCH 5/5] A_mul_B does not exist, added missing A_mul_Bc case --- base/linalg/matmul.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/linalg/matmul.jl b/base/linalg/matmul.jl index 33040803d6172..00db5728b7031 100644 --- a/base/linalg/matmul.jl +++ b/base/linalg/matmul.jl @@ -82,10 +82,10 @@ function (*){T,S}(A::AbstractMatrix{T}, x::AbstractVector{S}) end # these will throw a DimensionMismatch unless B has 1 row (or 1 col for transposed case): -A_mul_B(a::AbstractVector, B::AbstractMatrix) = A_mul_B(reshape(a,length(a),1),B) A_mul_Bt(a::AbstractVector, B::AbstractMatrix) = A_mul_Bt(reshape(a,length(a),1),B) A_mul_Bt(A::AbstractMatrix, b::AbstractVector) = A_mul_Bt(A,reshape(b,length(b),1)) A_mul_Bc(a::AbstractVector, B::AbstractMatrix) = A_mul_Bc(reshape(a,length(a),1),B) +A_mul_Bc(A::AbstractMatrix, b::AbstractVector) = A_mul_Bc(A,reshape(b,length(b),1)) (*)(a::AbstractVector, B::AbstractMatrix) = reshape(a,length(a),1)*B A_mul_B!{T<:BlasFloat}(y::StridedVector{T}, A::StridedVecOrMat{T}, x::StridedVector{T}) = gemv!(y, 'N', A, x)