Vinod
Vinod

Reputation: 4352

Multiply column of a matrix with row of another matrix in Julia

Let

A = rand(3,3);B = rand(3,3)

I can multiply first column of A : A[:,1] with third row of matrix B : B[3,:] by the command:

reshape(A[:,1],3,1)*reshape(B[3,:],1,3)

to make a 3x3 matrix.

The direct computation

A[:,1]*B[3,:]

is giving the error:

ERROR: MethodError: no method matching *(::Vector{Float64}, ::Vector{Float64})
Closest candidates are:
  *(::Any, ::Any, ::Any, ::Any...) at operators.jl:560
  *(::StridedMatrix{T}, ::StridedVector{S}) where {T<:Union{Float32, Float64, ComplexF32, ComplexF64}, S<:Real} at C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\LinearAlgebra\src\matmul.jl:44
  *(::StridedVecOrMat{T} where T, ::LinearAlgebra.Adjoint{var"#s832", var"#s831"} where {var"#s832", var"#s831"<:LinearAlgebra.LQPackedQ}) at C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\LinearAlgebra\src\lq.jl:254
  ...
Stacktrace:
 [1] top-level scope
   @ REPL[2]:1

Is there any other short/clear method to do this operation?

Answer : A[:, 1:1] * B[3:3, :] and A[:, 1] * B[3, :]' from @phipsgabler's reply. Or view(A, :, 1)*view(B, 3, :)' , @views A[:, 1] * B[3, :]' without copying rows or columns.

Upvotes: 1

Views: 374

Answers (1)

phipsgabler
phipsgabler

Reputation: 20980

A[:, 1] and B[3, :] are both Vectors -- rank 1 -- so it is not automatically clear what you want here. The more likely option would be the inner product:

julia> dot(A[:, 1], B[3, :])
0.8875027511646011

julia> A[:, 1]' * B[3, :]
0.8875027511646011

But it seems you want the outer product:

julia> reshape(A[:,1],3,1)*reshape(B[3,:],1,3)
3×3 Matrix{Float64}:
 0.689437  0.246968   0.190616
 0.400674  0.143528   0.110778
 0.197257  0.0706608  0.0545377

julia> A[:, 1:1] * B[3:3, :]
3×3 Matrix{Float64}:
 0.689437  0.246968   0.190616
 0.400674  0.143528   0.110778
 0.197257  0.0706608  0.0545377

julia> A[:, 1] * B[3, :]'
3×3 Matrix{Float64}:
 0.689437  0.246968   0.190616
 0.400674  0.143528   0.110778
 0.197257  0.0706608  0.0545377

To explain: by using a range, 1:1, instead of an index, the result will still be a matrix (just like your reshape approach):

julia> B[3:3, :]
1×3 Matrix{Float64}:
 0.938292  0.336112  0.259419

That way the * is well defined as the matrix product between a one-column matrix and a one-row matrix.

The same holds if you transpose one of the vectors:

julia> B[3, :]'
1×3 adjoint(::Vector{Float64}) with eltype Float64:
 0.938292  0.336112  0.259419

The product between a vector and a covector is also well-defined.

The last option is to use kron; this however vectorizes the result, and you have to reshape the output:

julia> reshape(kron(A[:, 1], B[3, :]), 3, 3)
3×3 Matrix{Float64}:
 0.689437  0.400674  0.197257
 0.246968  0.143528  0.0706608
 0.190616  0.110778  0.0545377

Upvotes: 4

Related Questions