8

Multiplying a row and a column vector, I was expecting the result to be scalar, but it is a 1-dimensional, 1-element Array:

julia> [1 2 3] * [4; 5; 6]
1-element Array{Int64,1}:
 32

Question 1: What is the rationale behind this?

Question 2: Accepting this as a quirk of Julia, I want to convert the 1-element Array into a scalar. Taking the first element with [1] is an option, but not very readable. What is the idiosyncratic way to do this?

4
  • [1 2 3] is a 1x3 2D Array. Therefore multiplying a 2D array by a 1D array gives a 1D array, as a matrix by vector multiply should. As @Chris Rackauckas mentioned using dot() gives a scalar. Commented Aug 22, 2016 at 12:51
  • 1
    \cdot<TAB> will produce the dot operator which is shorthand for dot(...). Thus, the expression in the OP can be written: vec([1 2 3])⋅[4;5;6]. Note [1 2 3] still needs to be turned to a 1D vector. Commented Aug 22, 2016 at 12:56
  • @DanGetz: You're right, it is a 2D Array... so an array output makes sense. I didn't want to use dot, because it takes vectors, so the first argument needs to be converted, as you said. So the efficient version is still to take the first element of the matrix multiplication. Commented Aug 22, 2016 at 15:43
  • 2
    since we're exploring options from an aesthetic point of view, creating the vector via slicing is also an option: [1 2 3][:]⋅[1;2;3] Commented Aug 22, 2016 at 16:11

1 Answer 1

12

Every expression could be acted on, so you can use

([1 2 3] * [4; 5; 6])[1]

to get the first (and only value out).

There are major performance reasons for this: type-stability. Basically, in a compiled language you cannot change your types around without doing a bunch of conversions. Julia is a bit smarter, though if you do a bunch of conversions, then your code will be slower since the compiler will have to keep around a lot of "kruft" just in case you have the wrong type. Thus by ensuring type-stability, the compiler can know in advance what the type will be, and do a lot more optimizations. This is one of the performance tips. Indeed, Julia is fast and reaches C speeds BECAUSE of multiple dispatch and type-stability, and so it should be respected.

Array * Array gives out an array. In order for that to be type-stable, it must always give out an array. Otherwise the compiler needs to put extra code to check if that variable is an array or not... at every place where the output is used! So then you should use * with arrays to get arrays out. If you want to get a scalar out, the easy answer is use the dot function:

dot([1;2;3],[4;5;6])

Of course I could've just said that, but it's good to know the "why" since type-stability is such an important idea for performant code.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks, this answers Question 1. As for Q2, I know that I can just take the first element, it just looks awkward, so I was hoping there is some special convention for this.
Isn't the dot function exactly that "special convention"? It doesn't have an inline operator, but it does what you're looking for. If you need it on a transposed vector, you can roll your own function (just a loop) (though I'd be surprised if Base.dot couldn't handle this?). Remember, in Julia looping is not bad for performance, so you can always roll your own functions with a loop.
Yes and no - with dot I still have to convert the "row vector" into a vector. Maybe there is not much overhead with vec, but still it looks redundant... I guess that's the price of speed :)
I prefer to use [] which in turn reminds me this is a singe-elment array.
FWIW, writing a dot method would be the fastest because you can do it without ever allocating an array. * with [1] will allocate a size 1 array and a number, and when summing will have to keep dereferencing. So I'd prefer to just write a dot function (since the normal dot wants two vectors) with a for loop (and then you can easily multi-thread or parallelize it too if the actual matrices are large enough).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.