What is wrong with [1.] * [1.]?

The following example shows that * performs matrix-matrix multiplication and matrix-vector multiplication but throws an error if the size of the operands is 1-by-1. I can get away with this error if I use elementwise multiplication .* in case of 1-by-1 operands. But I do not want check the sizes of the operands each time. Any ideas about getting rid of this error without size check each time?


julia> a  = [1. 2.; 3. 4.]
2×2 Array{Float64,2}:
 1.0  2.0
 3.0  4.0

julia> b  = [5., 6.]
2-element Array{Float64,1}:
 5.0
 6.0

julia> c  = [7. 8. 9.; 10. 11. 12.]
2×3 Array{Float64,2}:
  7.0   8.0   9.0
 10.0  11.0  12.0

julia> d = [1.]
1-element Array{Float64,1}:
 1.0

julia> a * b  # Matrix vector multiplication
2-element Array{Float64,1}:
 17.0
 39.0

julia> a * c  # Matrix matrix multiplication
2×3 Array{Float64,2}:
 27.0  30.0  33.0
 61.0  68.0  75.0

julia> d  * d
ERROR: MethodError: no method matching *(::Array{Float64,1}, ::Array{Float64,1})
Closest candidates are:
  *(::Any, ::Any, ::Any, ::Any...) at operators.jl:502
  *(::Adjoint{#s549,#s548} where #s548<:Union{DenseArray{T<:Union{Complex{Float32}, Complex{Float64}, Float32, Float64},2}, ReinterpretArray{T<:Union{Complex{Float32}, Complex{Float64}, Float32, Float64},2,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Tuple{AbstractUnitRange,Vararg{Any,N}where N} where A<:DenseArray where N where T, DenseArray}, ReshapedArray{T<:Union{Complex{Float32}, Complex{Float64}, Float32, Float64},2,A,MI} where MI<:Tuple{Vararg{SignedMultiplicativeInverse{Int64},N} where N} where A<:Union{ReinterpretArray{T,N,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Tuple{AbstractUnitRange,Vararg{Any,N} where N} where A<:DenseArray where N where T, DenseArray} where N where T, SubArray{T,N,A,I,true} where I<:Tuple{AbstractUnitRange,Vararg{Any,N} where N} where A<:DenseArray where N where T, DenseArray}, SubArray{T<:Union{Complex{Float32}, Complex{Float64}, Float32, Float64},2,A,I,L} where L where I<:Tuple{Vararg{Union{Int64, AbstractRange{Int64}, AbstractCartesianIndex},N} where N} where A<:Union{ReinterpretArray{T,N,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Tuple{AbstractUnitRange,Vararg{Any,N} where N} where A<:DenseArray where N where T, DenseArray} where N where T, ReshapedArray{T,N,A,MI} where MI<:Tuple{Vararg{SignedMultiplicativeInverse{Int64},N} where N} where A<:Union{ReinterpretArray{T,N,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Tuple{AbstractUnitRange,Vararg{Any,N} where N} where A<:DenseArray where N where T, DenseArray} where N where T, SubArray{T,N,A,I,true} where I<:Tuple{AbstractUnitRange,Vararg{Any,N} where N} where A<:DenseArray where N where T, DenseArray} where N where T, DenseArray}} where #s549, ::Union{DenseArray{S,1}, ReinterpretArray{S,1,S,A} where S where A<:Union{SubArray{T,N,A,I,true} whereI<:Tuple{AbstractUnitRange,Vararg{Any,N} where N} where A<:DenseArray where N where T, DenseArray}, ReshapedArray{S,1,A,MI} where MI<:Tuple{Vararg{SignedMultiplicativeInverse{Int64},N} where N} where A<:Union{ReinterpretArray{T,N,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Tuple{AbstractUnitRange,Vararg{Any,N} where N} where A<:DenseArray where N where T, DenseArray} where N where T, SubArray{T,N,A,I,true} where I<:Tuple{AbstractUnitRange,Vararg{Any,N} where N} where A<:DenseArray where N where T, DenseArray}, SubArray{S,1,A,I,L} where L where I<:Tuple{Vararg{Union{Int64, AbstractRange{Int64}, AbstractCartesianIndex},N} where N} where A<:Union{ReinterpretArray{T,N,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Tuple{AbstractUnitRange,Vararg{Any,N} where N} where A<:DenseArray where N where T, DenseArray} where N where T, ReshapedArray{T,N,A,MI} where MI<:Tuple{Vararg{SignedMultiplicativeInverse{Int64},N} where N} where A<:Union{ReinterpretArray{T,N,S,A} where S where A<:Union{SubArray{T,N,A,I,true} where I<:Tuple{AbstractUnitRange,Vararg{Any,N} where N} where A<:DenseArray where N where T, DenseArray} where N where T, SubArray{T,N,A,I,true} where I<:Tuple{AbstractUnitRange,Vararg{Any,N} where N} where A<:DenseArray where N where T, DenseArray} where N where T, DenseArray}}) where {T<:Union{Complex{Float32}, Complex{Float64}, Float32, Float64}, S} at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.0/LinearAlgebra/src/matmul.jl:97
  *(::Adjoint{#s549,#s548} where #s548<:LinearAlgebra.AbstractTriangular where #s549, ::AbstractArray{T,1} where T) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.0/LinearAlgebra/src/triangular.jl:1805
  ...
Stacktrace:
 [1] top-level scope at none:0

I think the problem is d is of type Vector and these is no vector-vector multiplication (not mentioning vector cross product but cross product is for vectors having length greater or equal to three) mathematically. Just element-wise multiplication of two vectors is possible. Anyway,as the * does not have vector-vector multiplication method, are there any functions that can be used for 1-by-1 matrix multiplication.

Maybe helpful: there are 1-element Vectors v = [2.5] and one element matrices

julia> A = fill(2.5,1,1)
1×1 Array{Float64,2}:
 2.5

julia> A*A
1×1 Array{Float64,2}:
 6.25

and these are not the same. . fill is a bit clumsy way to create them. Using these, the 1x1 case does not need to be special cased.

1 Like

Thank you for the reply @mschauer. But the problem is that I need to process the arrays instead of creating them.

I thought multiple dispatch can be used here as follows.


julia> mul(a::Matrix, b::VecOrMat) = a * b
mul (generic function with 1 method)

julia> mul(a::Vector, b::Vector) = length(a) == length(b) == 1 ? [a[1] * b[1]] :
           error("Vector lengths are greater than 1.")
mul (generic function with 2 methods)

julia> a = [1. 2.; 3. 4.];

julia> b = [5.; 6.];

julia> c = [7. 8. 9.; 10. 11. 12.];

julia> d = [1.];

julia> mul(a, b)
2-element Array{Float64,1}:
 17.0
 39.0

julia> mul(a, c)
2×3 Array{Float64,2}:
 27.0  30.0  33.0
 61.0  68.0  75.0

julia> mul(d, d)
1-element Array{Float64,1}:
 1.0

julia> mul(b, b)
ERROR: Vector lengths are greater than 1.
Stacktrace:
 [1] mul(::Array{Float64,1}, ::Array{Float64,1}) at ./none:1
 [2] top-level scope at none:0

julia>

1x1 matrix multiplication works fine. Why do you want to multiply length-1 vectors?

If you want to multiply vectors with each other, you should use element-wise multiplication: .*. Why special-case length-1 vectors, in that case?

1 Like

I am trying to solve a differential equation in the form of xdot = A * x + B * u(t). where A, B are the system parameters, x is the state vector and t is the time and u is the input function. Then the right hand side function corresponding to the differential equation problem is

f(dx, x, u, t) = (dx .= A * x + B * u(t))

Thus if dx = [0.], x=[1.], A=[-1.], B=[1.], u = t -> t and I try to call f(dx, x, u, t) I get the error explained in the previous posts.

I do not want to use element-wise multiplication in order not to loosen the restriction for the multiplication of vectors having lengths greater than 1 since I am having the problem with just length one vector.

It looks to me like A and B should be 1x1 matrices. And it also seems like u should return a vector.

The problem now seems to be that the types in the equation do not make sense.

Or maybe just use scalars?

It works if you transpose one of the 1-element arrays:

julia> [1.]'*[1.]
1.0

(Note the single quote following the first array, which transposes that array)

1 Like

Yes, A should be defined as A = fill(1, 1, 1) as you and @mschauer offered. This prevents A to be vector and makes it a matrix. Then since A is a matrix and x=[1.] is a vector, no problem occurs in A * x.

1 Like