Vectorized multiplication: Multiply two vectors in Julia, element-wise - arrays

I decided to dive into Julia and hitting the wall; fast.
I am trying to replicate a simple operation, which would like as follows in python numpy
a = numpy.array([1,2,3])
b = numpy.array([1,2,3])
a*b
[output]: [1,4,9]
In other words "[1,4,9]" is the output I expect.
I tried in Julia the following:
a = [1,2,3]
b = [1,2,3]
a*b
[output]: MethodError: no method matching *(::Array{Int64,1}, ::Array{Int64,1})
or after trying to wise up:
a = [1,2,3]
b = [1,2,3]'
a*b
[output]: 3×3 Array{Int64,2}:
1 2 3
2 4 6
3 6 9
I am aware that this seems like a basic question, but my Googling does not seem my finest today and/or stackoverflow could use this question & answer ;)
Thanks for any help and pointers!
Best

Julia needs a . in front of the operator or function call to indicate you want elementwise multiplication and not an operation on the vector as a unit. This is called broadcasting the array:
julia> a = [1,2,3]
3-element Array{Int64,1}:
1
2
3
julia> b = [1,2,3]
3-element Array{Int64,1}:
1
2
3
julia> a .* b
3-element Array{Int64,1}:
1
4
9

I just found a solution, although surely not optimal as it will generate a dot product and then select the diagonals.... to much calc!\
use LinearAlgebra
a = [1,2,3]
b = [1,2,3]
c = a * b'
diag(c)
I am pretty sure that there is a better solution.

Related

Julia accessing specific Matrix elements using vectors as indexes

Suppose I have a 4*2 matrix as follows:
a = [1 2; 3 4; 5 6; 7 8]
4×2 Matrix{Int64}:
1 2
3 4
5 6
7 8
I want to access the matrix using a vector specifying which element I want to access in each column. In NumPy from python, I would do the following command:
a[[1,3], [1,2]]
# expected output:
1×2 Matrix{Int64}:
1(as a[1,1]) 6(as a[3,2])
but in Julia, I got the following matrix:
2×2 Matrix{Int64}:
1 2
5 6
How can I do it in an julia way?
UPDATE: Inspired by DNF answer:
julia> a[CartesianIndex.([1 3], [1 2])]
1×2 Matrix{Int64}:
1 6
seems to me the right balance of clarity and similarity to OP.
ORIGINAL answer:
Maybe not the optimal way, but:
[a[x...] for x in [[[1,1]] [[3,2]]]]
works.
Note that this returns a row vector, like in the OP. In Julia there is a difference between a vector and a matrix. A matrix with one row or one column is not the same as a vector.
The [[]] notation is to let hcat handle vector elements correctly. If a vector output is good enough, then: [[1,1],[3,2]] is enough.
The syntax a[i, j] is syntax sugar for getindex(a, i, j). You can broadcast getindex to get the desired behavior (unfortunately, you cannot broadcast the [] syntax itself):
getindex.(Ref(a), [1,3], [1,2])
You must protect a itself against being broadcasted, by wrapping it in a Ref.

Simple calculation for all combination (brute force) of elements in two arrays, for better performance, in Julia

I am new to Julia (some experience with Python). The main reason I am starting to use Julia is better performance for large scale data processing.
I want to get differences of values (int) of all possible combinations in two arrays.
Say I have two arrays.
a = [5,4]
b = [2,1,3]
Then I want to have differences of all combinations like
a[1] - b[1], a[1] - b[2] ..... a[3] - b[1], a[3] - b[2]
The result will be 3 x2 array [3 2; 4 3; 2 1]
Then something I came up is
a = [5,4]
b = [2,1,3]
diff_matrix = zeros(Int8, size(b)[1], size(a)[1])
for ia in eachindex(a)
for ib in eachindex(b)
diff_matrix[ib,ia]= a[ia] - b[ib]
end
end
println(diff_matrix)
It works but it uses iteration inside of iteration and I assume the performance will not be great. In real application, length of array will be long (like a few hundreds), and this process needs to be done for millions of combinations of arrays.
Is there any better (better performance, simpler code) approach for this task ?
If you wrapped the code in a function your code would be already reasonably fast.
This is exactly the power of Julia that loops are fast. The only thing you need to avoid is using global variables in computations (as they lead to code that is not type stable).
I write the code would be "reasonably fast", as it could be made faster by some low-level tricks. However, in this case you could just write:
julia> a = [5,4]
2-element Vector{Int64}:
5
4
julia> b = [2,1,3]
3-element Vector{Int64}:
2
1
3
julia> permutedims(a) .- b
3×2 Matrix{Int64}:
3 2
4 3
2 1
and this code will be fast (and much simpler as a bonus).

Multiplying arrays of matrices in MATLAB

I have a data set that consists of two 1800 x 900 x 3 x 3 arrays, which should each be interpreted as a 1800x900 array of 3x3 matrices. As part of the analysis, at one point I need to create another such array by, at each point of the 1800x900 array, multiplying the corresponding 3x3 matrices together.
There seem to be two ways to do this that I can think of. The obvious way is
C = zeros(size(A))
for i = 1:900
for j = 1:1800
C(i,j,:,:) = A(i,j,:,:)*B(i,j,:,:)
end
end
But that's quite a long loop and doesn't really take advantage of MATLAB's vectorization. The other way is
C = zeros(size(A))
for i = 1:3
for j = 1:3
for k = 1:3
C(:,:,i,j) = C(:,:,i,j) + A(:,:,i,k).*B(:,:,k,j)
end
end
end
where the large dimensions are getting vectorized and I'm basically using the for loops to implement the Einstein summation convention. This seems really inelegant, though, which makes me think there should be a better way. Is there?
Perfect job for bsxfun with permute:
C = permute(sum(bsxfun(#times, A, permute(B, [1 2 5 3 4])), 4), [1 2 3 5 4]);
In R2016b onwards you can avoid bsxfun thanks to implicit singleton expansion:
C = permute(sum(A .* permute(B, [1 2 5 3 4]), 4), [1 2 3 5 4]);

Error when adding 2-D array and 2-D subarray of 3-D array in Julia

Why does Julia throw an error when I run the following code?
After all, A[1,:,:] is logically a 2-D array.
If I remember correctly, similar code would have worked in MATLAB.
julia> A = reshape(1:8, 2, 2, 2)
2x2x2 Array{Int64,3}:
[:, :, 1] =
1 3
2 4
[:, :, 2] =
5 7
6 8
julia> B = reshape(1:4, 2, 2)
2x2 Array{Int64,2}:
1 3
2 4
julia> B + A[1,:,:]
ERROR: dimensions must match
in promote_shape at operators.jl:211
in promote_shape at operators.jl:207
in + at array.jl:723
Using A and B as defined in your question, note that:
ndims(B)
ndims(A[1,:,:])
returns 2 and 3 respectively. So a sum operation fails because B is a matrix while A[1,:,:] is a 3-dimensional array. Specifically, A[1,:,:] is 1x2x2. The solution is to squeeze the first dimension like so:
B + squeeze(A[1,:,:], 1)
I can see the source of the confusion here. I'm guessing you noticed that:
B[1, :]
returns type Vector, and you assumed the same principle of automatic squeezing would apply to a higher-dimensional array. The github issues page where the questions surrounding this kind of behaviour were settled is here. Interesting read.

Julia Reverse N-dimensional arrays

In Python, Numpy arrays can be reversed using the standard [::-1] i.e.
A = np.diag(np.arange(1,3))
A[::, ::-1]
A[::-1]
A[::-1, ::-1]
Julia does not support [::-1] and the reverse method only works on 1D arrays and only 1D columns (where as rows are 2D by default).
Is there an alternative I'm missing?
Try the following, which is essentially the same as the numpy version:
julia> X = rand(3,3)
3x3 Array{Float64,2}:
0.782622 0.996359 0.335781
0.719058 0.188848 0.985693
0.455355 0.910717 0.870187
julia> X[end:-1:1,end:-1:1]
3x3 Array{Float64,2}:
0.870187 0.910717 0.455355
0.985693 0.188848 0.719058
0.335781 0.996359 0.782622
In Julia 1.0, to reverse a (column) vector:
julia> reverse([1, 2, 3])
3-element Array{Int64,1}:
3
2
1
For reversing rows, just state that you want to flip the second dimension:
julia> reverse([1 2 3], dims=2)
1×3 Array{Int64,2}:
3 2 1
EDIT: Alternatively, you can also index in reverse using end:-1:1, and that way also allows you to request a view instead of a copy:
julia> a = reshape(randperm(9), 3, 3)
3×3 Matrix{Int64}:
4 7 9
5 2 1
3 6 8
julia> #view a[:, end:-1:1]
3×3 view(::Matrix{Int64}, :, 3:-1:1) with eltype Int64:
9 7 4
1 2 5
8 6 3
Following up #IainDunning's answer, an important difference between numpy and Julia here is that X[:,end:-1:1] in Julia returns a copy and in numpy X[:,::-1] will return a view of the same data (no copy is made).
I'm just learning Julia myself, but it seems like you can accomplish something similar in Julia using sub(X, :, size(X)[2]:-1:1), which returns Julia's equivalent of a view (SubArray). Interestingly, you can't use the end keyword in this construct as far as I can see, and instead you must pass in the actual end index in the dimension.
You can use the function flipdim(mat, d).
Ref: http://docs.julialang.org/en/release-0.4/stdlib/arrays/
Try this set of functions:
function reverser(x::AbstractArray, dims::AbstractVector{<:Integer})
y = copy(x)
for d in dims
y = reverse(y, dims=d)
end
return y
end
reverser(x::AbstractArray) = reverser(x, 1:ndims(x)) # all dimensions
reverser(x::AbstractArray, d::Integer) = reverser(x, [1])
Julia 1.6 supports reversing any or all of the dimensions of an arbitrary multidimensional array (implemented here). To reverse all of the dimensions, you can simply do reverse(X).

Resources