Array/Vector multiplication for single element arrays

Hi, I’m a long term Matlab user just starting to wade into the world of Julia, so forgive me if my question is naive.

I’m am currently writing some code to perform a number of matrix manipulation tasks. I came across what to me seems like a limitation of the * operator on Arrays. Since I am new to Julia, I think the limitation is probably my understanding, not the language.

Say I have the following function

function double(A::Array{<:Real}, B::Array{<:Real})
    C = A*B
    2*C
end

which I evaluate as follows

julia> A = [1 2;3 4]
2×2 Array{Int64,2}:
 1  2
 3  4

julia> B = [5;6]
2-element Array{Int64,1}:
 5
 6

julia> double(A,B)
2-element Array{Int64,1}:
 34
 78

This all works as expected. Now what if A and B are defined as shown below

julia> A = [1;2]
2-element Array{Int64,1}:
 1
 2

julia> B = [3]
1-element Array{Int64,1}:
 3

julia> double(A,B)
ERROR: MethodError: no method matching *(::Array{Int64,1}, ::Array{Int64,1})

So even though this multiplication is mathematically valid it doesn’t evaluate successfully. I have solved this by extending the the * operator using the following function

function Base.:*(A::Array{<:Number,1}, B::Array{<:Number,1})
    if length(A) == 1
        A[1]*B
    elseif length(B) == 1
        A*B[1]
    else
        error("Array dimensions not suitable for multiplication.")
    end
end

This works fine, however, it feels to me like this is not good practice. I was hoping someone could provide some advice on a more “Julian” way of dong this, or if this is indeed a suitable approach.

Thanks in advance, Will.

So the problem here is you have confused * and .* the first is matrix multiplication. The second is vectorized multiplication which is what you want. In general, to apply an operation element-wise, use f. (the dot goes before for infix functions).

Oscar, thanks for the prompt reply.

Matrix multiplication is indeed what I want, not element-wise multiplication. Specifically, I want to evaluate the multiplication of matrices A and B where A has dimensions n x m and B has dimensions m x 1 (or m x p for that matter). Both n and m can be any positive integer, including 1.

Sincerely, I think this post could have been avoided and your day to be more productive if the change of error message discussed in this post was already implemented. So you would have alternatives already presented to you.

Are you sure that what you want is not:

> A = [1;2]; B = [3];
> A * B'
2×1 Array{Int64,2}:
 3
 6

In other words, this operation is not really defined for vectors (Array{T, 1}), it is defined for matrices (Array{T, 2}). You should use the right type.

Hi there,
Welcome to the Julia community! While Julia might look very familiar to MatLab users, there are some subtle differences. Notice that in your second example, both A and B are column vectors (array with only one dimension) and therefore no multiplication method is defined since it’s unclear whether you want the inner or outer product.
To achieve what you want, you can do A * transpose(B) or A * B' (the latter is actually the adjoint of B, but has the same result). This is mathematically consistent, since what you want is indeed matrix multiplication and transpose(B) or B' can be thought as 1 by 1 matrices.
However, Oscar’s recommendation to broadcast multiplication is probably the most convenient way.

No, my suggestion was wrong if the generalized desired behavior is matrix multiplication.

1 Like

So what about the other case in my original post, when

julia> A = [1 2;3 4];B = [5;6];

julia> A*B'
ERROR: DimensionMismatch("matrix A has dimensions (2,2), matrix B has dimensions (1,2)")

Unsurprisingly, this gives an error as the dimensions don’t agree. So it would appear that this approach is not suitable in general for A with dimensions n x m and B with dimensions m x 1?

Note the types:

> A = [1 2; 3 4]
2×2 Array{Int64,2}:
 1  2
 3  4

> B = [5;6]
2-element Array{Int64,1}:
 5
 6

> A = [1;2]
2-element Array{Int64,1}:
 1
 2

> B = [3]
1-element Array{Int64,1}:
 3

In other words, in the first case, the multiplication works because the two are matrices Array{T, 2} of the right dimensions. In the second case they are not matrices of the right dimensions, for them to be matrices of the right dimensions you need to declare them correctly from start or use the ' operator I used to get the second operand (B) with the right type.

> A = reshape([1, 2], 2, 1)
2×1 Array{Int64,2}:
 1
 2
> B = reshape([3], 1, 1)
1×1 Array{Int64,2}:
 3
> A * B
2×1 Array{Int64,2}:
 3
 6

This gets both A and B with the right types and then matrix multiplication is defined for them.

1 Like

Thank you, Henrique. I wasn’t aware of the reshape() function. That solves my problems.