Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use comprehensions on linspace to create matrix

Tags:

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.

like image 970
Robert F. Dickerson Avatar asked Oct 30 '22 00:10

Robert F. Dickerson


1 Answers

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)
like image 166
Gnimuc Avatar answered Nov 29 '22 19:11

Gnimuc