How to use comprehensions on linspace to create matrix - julia

I would like to produce an n x 3 matrix where n is the number of pixels (width * height).
x = linspace(-1, 1, width)
y = linspace(-1, 1, height)
r = 1.0
viewDirections = [[i j 1.0] for i in x for j in y]
However, when I run this I get a:
16-element Array{Array{Float64,2},1}
and not my desired a 16x3 Array{Float64,2}. I am obviously not using comprehensions properly to construct matrices. I tried using comprehensions to create an array of tuples, but I can't then convert those tuples into a matrix.

The problem here is array comprehension will give us a nested array instead of a Matrix. This is the right behavior of comprehension, it won't do extra guesswork for us, so we need to convert the nested array to matrix manually, which can be done using vcat with splating operator(...):
julia> vcat(viewDirections...)
6×3 Array{Float64,2}:
-1.0 -1.0 1.0
-1.0 1.0 1.0
0.0 -1.0 1.0
0.0 1.0 1.0
1.0 -1.0 1.0
1.0 1.0 1.0
It seems like you're constructing homogeneous coordinates from 2D Euclidean space. Using Base.Iterators.product is a more concise and robust way to create the iterator:
julia> w = linspace(-1,1,3)
-1.0:1.0:1.0
julia> h = linspace(-1,1,2)
-1.0:2.0:1.0
julia> r = 1.0
1.0
julia> viewDirections = [collect(i) for i in Iterators.product(w, h, r)]
3×2 Array{Array{Float64,1},2}:
[-1.0, -1.0, 1.0] [-1.0, 1.0, 1.0]
[0.0, -1.0, 1.0] [0.0, 1.0, 1.0]
[1.0, -1.0, 1.0] [1.0, 1.0, 1.0]
julia> hcat(viewDirections...).'
6×3 Array{Float64,2}:
-1.0 -1.0 1.0
0.0 -1.0 1.0
1.0 -1.0 1.0
-1.0 1.0 1.0
0.0 1.0 1.0
1.0 1.0 1.0
Note that, the order of coordinates is different from your original version, that's because Julia is column-major, Iterators.product will iterate the rightest dimension "outestly" i.e. [[i j r] for j in y for i in x ]. If the order is important in your use case, just pay attention to it.
Here are some benchmark results when width/height goes large:
julia> w = linspace(-1,1,300)
-1.0:0.006688963210702341:1.0
julia> h = linspace(-1,1,200)
-1.0:0.010050251256281407:1.0
julia> foo(w,h,r) = hcat([collect(i) for i in Iterators.product(w, h, r)]...).'
julia> bar(w,h,r) = vcat([[i j r] for i in w for j in h]...)
julia> #btime foo($w,$h,$r);
6.172 ms (60018 allocations: 10.99 MiB)
julia> #btime bar($w,$h,$r);
11.294 ms (360028 allocations: 17.02 MiB)

Related

How to use nested list comprehension in julia

How do I make the following code into nested list comprehension?
node_x = 5
node_y = 5
node_z = 5
xyz = Matrix(undef, node_x*node_y*node_z,3)
ii = 0
dx = 1.0
for k in 0:node_z-1
for j in 0:node_y-1
for i in 0:node_x-1
x = i * dx
y = j * dx
z = k * dx
ii += 1
#println([x, y, z])
xyz[ii, 1] = x
xyz[ii, 2] = y
xyz[ii, 3] = z
end
end
end
In python and numpy, I can write such as following codes.
xyz = np.array([[i*dx, j*dx, k*dx] for k in range(node_z) for j in range(node_y) for i in range(node_x)])
Comprehensions can be nested just the same, it's just range that is a bit different, but in your case there is the start:end syntactic sugar:
julia> [[i*dx, j*dx, k*dx] for k in 1:node_z for j in 1:node_y for i in 1:node_x]
125-element Vector{Vector{Float64}}:
[1.0, 1.0, 1.0]
[2.0, 1.0, 1.0]
⋮
[4.0, 5.0, 5.0]
[5.0, 5.0, 5.0]
To get the same array as your Python example, you'd have to permute the dimensions of the 3-element vectors and concatenate the list:
julia> vcat(([i*dx j*dx k*dx] for k in 1:node_z for j in 1:node_y for i in 1:node_x)...)
125×3 Matrix{Float64}:
1.0 1.0 1.0
2.0 1.0 1.0
⋮
4.0 5.0 5.0
5.0 5.0 5.0

What is the Julia way to dot product over desired dimensions

I have a xy-grid with two vector fields u and v. I represent vector fields as Array{Float64, 3} with dimensions nx × ny × 2.
I would like to have dot product u.v as a scalar field (Array{Float64,2} with dimensions nx×ny). What is the best way to achieve that?
It would be perfect to have something like dot(u,v,3), where 3 is the dimension over which the dot product is taken.
nx, ny = 3, 4
u = Array{Float64,3}(rand(0:1, nx, ny, 2))
#[0.0 1.0 0.0 1.0; 1.0 0.0 1.0 0.0; 1.0 0.0 1.0 0.0]
#[1.0 0.0 1.0 0.0; 1.0 0.0 0.0 1.0; 1.0 0.0 1.0 1.0]
v = Array{Float64,3}(rand(0:1, nx, ny, 2))
#[1.0 1.0 1.0 1.0; 0.0 1.0 0.0 0.0; 0.0 1.0 1.0 0.0]
#[1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 1.0 1.0 1.0 0.0]
[dot(u[i,j,:], v[i,j,:]) for i in 1:nx, j in 1:ny]
3×4 Array{Float64,2}:
1.0 1.0 0.0 1.0
0.0 0.0 0.0 0.0
1.0 0.0 2.0 0.0
sum(u.*v,3) is both (reasonably) fast and short.
To explicity get a matrix you can squeeze the third dimension like so squeeze(sum(u.*v,3), 3)
Update: Of course, this has allocations and is not the best answer if speed is everything. In this case, see #DNF's direct loop implementation which is basically as fast as you can get it.
squeeze(sum(u .* v, 3), 3) is clean and simple, but if you need more speed, this is approximately 20x times faster on my pc:
a = fill(zero(eltype(u)), nx, ny)
#inbounds for k in indices(u, 3)
for j in indices(u, 2)
for i in indices(u, 1)
a[i, j] += u[i, j, k] * v[i, j, k]
end
end
end
Edit: For easier benchmarking comparison, this try this code:
function dotsum3(u, v)
a = fill(zero(eltype(u)), size(u, 1), size(u, 2))
#inbounds for k in indices(u, 3)
for j in indices(u, 2)
for i in indices(u, 1)
a[i, j] += u[i, j, k] * v[i, j, k]
end
end
end
return a
end
Also note that, if using #inbounds, one should probably explicitely check that the sizes of u and v are compatible.
Another version is
a = copy(view(u,:,:,1))
a .*= view(v,:,:,1)
a .+= #views u[:,:,2].*v[:,:,2]
Which is easily extensible to arbitrary 3rd dimension length. The benchmarks from my machine:
julia> using BenchmarkTools
julia> function f1(u,v)
a = fill(zero(eltype(u)), nx, ny)
#inbounds for k in indices(u, 3)
for j in indices(u, 2)
for i in indices(u, 1)
a[i, j] += u[i, j, k] * v[i, j, k]
end
end
end
return a
end
f1 (generic function with 1 method)
julia> f2(u,v) = squeeze(sum(u .* v, 3), 3)
f2 (generic function with 1 method)
julia> function f3(u,v)
a = copy(view(u,:,:,1))
a .*= view(v,:,:,1)
a .+= #views u[:,:,2].*v[:,:,2]
return a
end
f3 (generic function with 1 method)
julia> nx, ny = 3, 4
(3, 4)
julia> u = Array{Float64,3}(rand(0:1, nx, ny, 2));
julia> v = Array{Float64,3}(rand(0:1, nx, ny, 2));
Timing results:
julia> #btime f1($u,$v); # DNF suggestion
1.016 μs (1 allocation: 176 bytes)
julia> #btime f2($u,$v); # original answer
1.263 μs (14 allocations: 816 bytes)
julia> #btime f3($u,$v); # this answer
168.591 ns (5 allocations: 432 bytes)
The suggested version is faster (which is logical considering memory ordering of Julia Arrays).

Cos, Acos with complex numbers

In Matlab I can write:
real(cos(kron(acos(-1.25),[0:4])))
and get:
1.0000 -1.2506 2.1282 -4.0725 8.0583
How to do the same in Julia. acos does not work with numbers less than -1.0. Even if I write:
r = max(-1.25,-1)
v = collect(0:4).';
cc =kron(acos(r),v)
I get only this:
1.0 -1.0 1.0 -1.0 1.0
It seems that I need to make cos/acos work with complex numbers.
Is this what you are looking for?
julia> real(cos.(kron(acos(complex(-1.25)),(0:4)')))
1×5 RowVector{Float64,Array{Float64,1}}:
1.0 -1.25 2.125 -4.0625 8.03125
or
julia> real(cos.(kron(acos(complex(-1.25)),0:4)))
5-element Array{Float64,1}:
1.0
-1.25
2.125
-4.0625
8.03125
Looks like Julia's acos requires a complex argument for a complex output.

Concatenate array of arrays

I have an array of arrays in Julia and am trying to find a way to concatenate all of the elements together. If I create the arrays and feed them each individually into hcat(), it performs exactly as I would want. But, if I create the arrays and then feed the array of arrays into hcat(), it fails. I could just write a loop to successfully concatenate one array to another, but I am wondering if there is a better way.
a = ones(2,2);
b = ones(2,2);
c = ones(2,2);
hcat(a,b,c) ## Does what I want by creating a single array. would be impracticable though for large number of objects.
d = Array(Array{Float64,2}, 3);
d[1] = a;
d[2] = b;
d[3] = c;
hcat(d) ## Still leaves me with an array of arrays, like before
[a b c] ## also does what I want
[f for f in d] ## Still leaves me with an array of arrays
julia> hcat(d)
3x1 Array{Array{Float64,2},2}:
2x2 Array{Float64,2}:
1.0 1.0
1.0 1.0
2x2 Array{Float64,2}:
1.0 1.0
1.0 1.0
2x2 Array{Float64,2}:
1.0 1.0
1.0 1.0
julia> hcat(d...)
2x6 Array{Float64,2}:
1.0 1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0 1.0

Assign blocks of multi-dimensional array

Imagine you have a 3 dimensonal Julia Array A of type Float64 where size(A) = (2, 3, 3).
How could you assign blocks of this array at a time using 2-dimensional arrays? For example, say I wanted A[1, :, :] to be the identity matrix. I would think of doing something like this:
A = Array(Float64, 2, 3, 3)
A[1, :, :] = eye(3)
When I do this I get the following error:
ERROR: argument dimensions must match
in setindex! at array.jl:592
I know it is because size(A[1, :, :]) = (1, 3, 3), but I can't figure out how to either 1) get this slice to be just (3, 3) so eye(3) fits or 2) make eye(3) also be (1, 3, 3) to conform to the shape of the slice of A.
Any suggestions?
EDIT 12:51 AM PST 8-13-13
I learned two new things:
If I take a slice of A along either of the other two dimensions, the result is a 2-dimensional array instead of a 3-d array with the leading dimension being 1.
I found a temporary fix to my specific problem by doing A[1, :, :] = reshape(eye(3), (1, 3, 3)). This is sub-optimal and I am hoping for a better fix.
You may be looking for slice:
julia> sA = slice(A, 1, :, :)
3x3 SubArray of 2x3x3 Float64 Array:
0.0 0.0 0.0
0.0 0.0 0.0
0.0 0.0 0.0
julia> sA[:] = eye(3)
3x3 Float64 Array:
1.0 0.0 0.0
0.0 1.0 0.0
0.0 0.0 1.0
julia> A
2x3x3 Float64 Array:
[:, :, 1] =
1.0 0.0 0.0
0.0 0.0 0.0
[:, :, 2] =
0.0 1.0 0.0
0.0 0.0 0.0
[:, :, 3] =
0.0 0.0 1.0
0.0 0.0 0.0

Resources