Filling Array with 2d function values in Julia - arrays

I am wondering if there is a 1 liner to do this assignment in the array in Julia:
h = .1
L = 1
x = 0:h:L
n = length(x)
discretized = zeros(n,n)
#really any old function
f(x,y) = x*y + cos(x) + sin(y)
for i in 1:n
for j in 1:n
discretized[i, j] = f(x[i], x[j])
end
end
Or do I explicitly have to write out the loops?

You could broadcast the function over an array an its transpose - julia will return the result as a 2d Array:
x = 0:0.1:1
f(x,y) = x*y + cos(x) + sin(y)
A = f.(x,x') # the `.` before the bracket broadcasts the dimensions
# 11×11 Array{Float64,2}
or if have more complicated expressions or functions and don't want to write out lots of dots use the #. macro, e.g:
A = #. f(x,x') + x^2
Once A already exists, you can also do
#. A = f(x,x') + x^2
which uses .= to write the result locally to each element of A, and hence is non-allocating.
Broadcasting goes much further than this easy extension of scalar functions to arrays, allowing "fusion" of multiple calculations into a single fast operation https://julialang.org/blog/2017/01/moredots

You could do:
discretized = [f(i, j) for i in x, j in x]
For more information, see https://docs.julialang.org/en/v1/manual/arrays/#Comprehensions-1
Edit: Based on the comments, here's a brief overview of what the : operator does in indexing:
julia> a = [1, 2, 3]
3-element Array{Int64,1}:
1
2
3
julia> a[:]
3-element Array{Int64,1}:
1
2
3
julia> ans === a
false
julia> a[:] .= [2, 3, 4]
3-element view(::Array{Int64,1}, :) with eltype Int64:
2
3
4
julia> a
3-element Array{Int64,1}:
2
3
4

Related

Julia, use findall to reset a third row in a 3d array

I'm attempting to use findall to get an index of which elements of one 1d array are greater than those of a second 1d array, and then use those indexes to set corresponding values of a third 1d array to 0.
MWE:
# create 3d array
a, b = [3;2;2], [4;3;2];
c = transpose(cat(a,b, dims = 2));
d, e = [1;2;3], [2;3;4];
f = transpose(cat(d,e, dims = 2));
g = cat(c, f, dims = 3);
g
2×3×2 Array{Int64,3}:
[:, :, 1] =
3 2 2
4 3 2
[:, :, 2] =
1 2 3
2 3 4
findall.(g[end,:,1] >= g[end-1,:,1])
and use indexes to reset elements of g[end,:,2] such that I end up with
g
2×3×2 Array{Int64,3}:
[:, :, 1] =
3 2 2
4 3 2
[:, :, 2] =
1 2 3
0 0 4
Thx. J
The code below gives the answer you request. You just have the . in the wrong spot. You want to compare the > operation element by element, and then apply findall to the entire resulting array (not element by element).
julia> g[end, findall(g[end,:,1] .> g[end-1,:,1]), 2] .= 0
2-element view(::Array{Int64,3}, 2, [1, 2], 2) with eltype Int64:
0
0
julia> g
2×3×2 Array{Int64,3}:
[:, :, 1] =
3 2 2
4 3 2
[:, :, 2] =
1 2 3
0 0 4
However, I wouldn't try to compile all your data into one big array like that. It would be easier to use three separate 1D array variables than three dimensions in one variable. Again using your variables above:
julia> e[b .> a] .= 0
2-element view(::Array{Int64,1}, [1, 2]) with eltype Int64:
0
0
julia> e
3-element Array{Int64,1}:
0
0
4

What is the mathematical explanation of adding 2d Array and 1d Array?

I can't seem to replicate this numpy arithmetic. I'm using Julia, but want to know the mathematical explanation for this code. It seems to break what I know about Linear Algebra.
X = np.arange(-5, 5, 0.2).reshape(-1, 1)
X.shape ## (50, 1)
test = np.sum(X**2, 1).reshape(-1, 1) + np.sum(X**2, 1)
test.shape ## (50, 50)
In Julia, I would write
X = reshape(collect(range(-5, stop=5, length=N)), :, 1);
size(X) ## (50, 1)
test = sum(X.^2, dims=2) + vec(sum(X.^2, dims=2));
size(test) ## (50, 1)
I'm trying to think how a 50x50 matrix would be the result of adding two vectors? I know numpy uses a lot of broadcasting under the hood, but it doesn't seem clear to me what this is doing.
What is the mathematical notation or Julia equivalent for what numpy is doing here?
Your are doing a lot of stuff that really obscures your point, which, I believe, concerns how to add arrays of different shapes.
Python:
In [21]: x = np.random.rand(5, 1)
In [22]: x.shape
Out[22]: (5, 1)
In [23]: y = np.random.rand(1, 4)
In [24]: y.shape
Out[24]: (1, 4)
In [25]: (x + y).shape
Out[25]: (5, 4)
Julia:
julia> x = rand(5);
julia> y = rand(1, 4);
julia> x + y
ERROR: DimensionMismatch("dimensions must match")
julia> x .+ y
5×4 Array{Float64,2}:
1.95779 1.31897 1.23345 1.32423
1.78126 1.14244 1.05692 1.14771
1.08306 0.444243 0.35872 0.449509
1.69756 1.05874 0.97322 1.06401
1.18661 0.547789 0.462265 0.553054
julia> size(x .+ y)
(5, 4)
As you can tell, Python broadcasts arrays by default, while Julia requires that you specifically ask for it, by using the dot operator, ..
It is exactly because it does not make sense to add two arrays of different shapes, that Julia does not broadcast by default. Similarly, with multiplication, * and .* differ:
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> B = [4 5; 6 7]
2×2 Array{Int64,2}:
4 5
6 7
julia> A * B
2×2 Array{Int64,2}:
16 19
36 43
julia> A .* B
2×2 Array{Int64,2}:
4 10
18 28
The ordinary * is matrix multiplication, while the latter is elementwise array multiplication.
Another example:
julia> A = [1 2 3; 4 5 6]
2×3 Array{Int64,2}:
1 2 3
4 5 6
julia> b = [7, 8]
2-element Array{Int64,1}:
7
8
julia> A * b
ERROR: DimensionMismatch("matrix A has dimensions (2,3), vector B has length 2")
julia> A .* b
2×3 Array{Int64,2}:
7 14 21
32 40 48

How to zip a 2D and a 1D array row-wise in Julia?

How do I zip a two-dimensional array with a "vector" row-wise in Julia?
This
X = [1 2; 3 4]
ndims(X)
Y = [-1 -2]
ndims(Y)
first(zip(X,Y))
gives (1, -1) while I want to get ([1 2], -1).
If you're ok with using column-vectors for the input and output, then you can use the eachrow function, which iterates over the rows of a matrix and returns the rows as column-vectors:
julia> X = [1 2; 3 4];
julia> Y = [-1, -2];
julia> collect(zip(eachrow(X), Y))
2-element Array{Tuple{Array{Int64,1},Int64},1}:
([1, 2], -1)
([3, 4], -2)
On the other hand, if you need the first elements of your zipped tuples to be row-vectors (as is shown in your question), then you could convert your matrix into a vector of rows and then use zip:
julia> X = [1 2; 3 4];
julia> Y = [-1 -2];
julia> rows = [X[[i], :] for i in 1:size(X, 1)]
2-element Array{Array{Int64,2},1}:
[1 2]
[3 4]
julia> collect(zip(rows, Y))
2-element Array{Tuple{Array{Int64,2},Int64},1}:
([1 2], -1)
([3 4], -2)
Note that I've used X[[i], :] inside the comprehension instead of X[i, :], so that we get an array of rows rather than an array of column-vectors.
Finally, just to be clear, note that Y = [-1 -2] produces a row-vector. We usually represent vectors as column vectors:
julia> Y = [-1, -2]
2-element Array{Int64,1}:
-1
-2
There are iterator builders in Julia: eachrow and eachcol, which work for arrays and are concise (at least in this case):
X = [1 2; 3 4]
Y = [-1 -2]
z = zip(eachrow(X), eachcol(Y))
Then
for el in z
print(el)
end
gives
([1, 2], [-1])
([3, 4], [-2])

How to access elements of 1-D array through some other 1-D array?

I am very new to Julia, even new to programming. Therefore, please excuse me for simple doubts.
consider the below Matlab Example:
A=[10; 20; 30; 40; 50];
B=[1; 3; 5];
The result of A(B)=0 in the matlab shall be [0.0 20 0.0 40 0.0].
How do I achieve the same in Julia for 1-D array??
I have a variable A and B:
julia> A
5×1 Array{Int64,2}:
10
20
30
40
50
julia> B
2-element Array{Int64,1}:
1
3
5
when I execute this A[[B]]
ERROR: ArgumentError: invalid index: Array{Int64,1}[[1, 2]]
HOWEVER, this statement provides this result:
julia> A[[1, 3 ,5]]
3-element Array{Int64,1}:
5
3
1
Please guide me. I know that Julia has the flat array, but how to access them through any other flat array.
You have an extra pair of brackets.
A[B]
A[ [1; 3; 5] ]
A[ [1, 3, 5] ]
A[ [1 3 5] ]
A[ 1:2:5 ]
all work as desired. You can index an array with any valid index or any collection of indices.
However, A[[B]] tries to index A at the location [1;3;5], which is an error.
You can get your desired result by overwriting the elements of A at indices given by B with zeros as follows:
julia> A=[10; 20; 30; 40; 50];
julia> B=[1; 3; 5];
julia> A[B] .= 0;
julia> A
5-element Array{Int64,1}:
0
20
0
40
0
Here, the dot assignment .= indicates to change the elements of A in-place.

Julia's most efficient way to choose longest array in array of arrays?

I have an array of arrays A which is an N-element Array{Array{Int64,1},1} of integers. I am trying to find the largest array in A using Julia.
For example:
A = [[1, 2], [3, 4], [5, 6, 7], [1, 2, 5, 8]]
In Python I would simply do: max(A, key=len) but in Julia I don't know how to do it.
What I did is this:
L = []
for a in A
push!(L, length(a))
end
A[findmax(L)[2]]
Thanks!
#Colin has provided a compact, convenient answer. However, if speed matters (op asked for most efficient way) this should be close to optimum
function findlongest(A)
idx = 0
len = 0
#inbounds for i in 1:length(A)
l = length(A[i])
l > len && (idx = i; len=l)
end
return A[idx]
end
Note that this implementation would (presumably) be a really bad idea in Python :)
Quick benchmark:
julia> using BenchmarkTools
julia> A = [[1,2], [1,2,3,4,5,6], [1,2,3]]
3-element Array{Array{Int64,1},1}:
[1, 2]
[1, 2, 3, 4, 5, 6]
[1, 2, 3]
julia> #btime findlongest(A);
26.880 ns (0 allocations: 0 bytes)
julia> #btime A[indmax(length.(A))];
9.813 μs (25 allocations: 1.14 KiB)
That's a ~365 times speedup for this example.
EDIT: Better benchmark (suggested in the comments)
julia> #btime findlongest($A);
9.813 ns (0 allocations: 0 bytes)
julia> #btime $A[indmax(length.($A))];
41.813 ns (1 allocation: 112 bytes)
The $ signs avoid setup allocations and times. Speedup ~4.
Quick explanation
for loops are fast in Julia, so why not use them
avoid allocation (length.(A) allocates a new array of integers)
a && b is shortcut for "if a then b"
#inbounds avoids bound checks for A[i]
UPDATE: For v1+ you'll need to replace indmax in this answer with argmax.
EDIT: Note, it is also worth checking out the other answer by #crstnbr
Consider the following example code:
julia> A = [[1,2], [1,2,3,4,5,6], [1,2,3]]
3-element Array{Array{Int64,1},1}:
[1, 2]
[1, 2, 3, 4, 5, 6]
[1, 2, 3]
julia> length(A)
3
julia> length.(A)
3-element Array{Int64,1}:
2
6
3
julia> indmax(length.(A))
2
julia> A[indmax(length.(A))]
6-element Array{Int64,1}:
1
2
3
4
5
6
The first call to length gets the length of the outer vector in A, which is not what we want. In the second call, I use the broadcasting operator . so that I instead get the length of each of the inner vectors. In the indmax line, I'm finding the index of largest value in length.(A), ie the index of the longest inner vector. If you instead want to return the longest inner vector, you can just index into A using the result of the indmax line.
indmax is no longer defined in Julia (at least 1.3).
Use argmax instead.
>>> A = [[1,2], [1,2,3]]
2-element Array{Array{Int64,1},1}:
[1, 2]
[1, 2, 3]
>>> length.(A)
2-element Array{Int64,1}:
2
3
>>> argmax(length.(A))
2
>>> A[argmax(length.(A))]
3-element Array{Int64,1}:
1
2
3

Resources