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
Related
I have seen it a few times where someone has a situation where they want to put two for loops on the same line nested in one another.
Just to confirm, is this possible in Julia and if so what does it look like? Thanks!
Correct, Julia allows you to tersely express nested for loops.
As an example, consider filling in a 3x3 matrix in column order:
julia> xs = zeros(3,3)
3×3 Array{Float64,2}:
0.0 0.0 0.0
0.0 0.0 0.0
0.0 0.0 0.0
julia> let a = 1
for j in 1:3, i in 1:3
xs[i,j] = a
a += 1
end
end
julia> xs
3×3 Array{Float64,2}:
1.0 4.0 7.0
2.0 5.0 8.0
3.0 6.0 9.0
The above loop is equivalent to this more verbose version:
julia> let a = 1
for j in 1:3
for i in 1:3
xs[i,j] = a
a += 1
end
end
end
This syntax is even supported for higher dimensions(!):
julia> for k in 1:3, j in 1:3, i in 1:3
#show (i, j, k)
end
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)
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.
Suppose that I have a 1D array like so:
julia> myarray = ones(6)
6-element Array{Float64,1}:
1.0
1.0
1.0
1.0
1.0
1.0
I make a mask that will select some elements, the first and second element in this example:
julia> mymask = [true; true; false; false; false; false;]
6-element Array{Bool,1}:
true
true
false
false
false
false
Now I want to multiply only the first and second elements by random numbers drawn from the same distribution, and save the result over the old array. But this will multiply them by the same value:
julia> myarray[mymask] = myarray[mymask] * rand(Normal(20,5))
julia> myarray
6-element Array{Float64,1}:
16.5642
16.5642
1.0
1.0
1.0
1.0
My next thought was to try myarray[mymask] = myarray[mymask] * rand(Normal(20,5),2) but it gives an error.
You can make your multiplication explicitly elementwise:
julia> myarray[mymask] .*= rand(Normal(20,5), size(myarray[mymask]));
julia> myarray
6-element Array{Float64,1}:
24.1747
12.6375
1.0
1.0
1.0
1.0
At the cost of more lines, the following works:
function mularray!(myarray,mymask)
maskpos = find(mymask)
myrand = rand(Normal(20,5),length(maskpos))
for i=1:length(maskpos)
myarray[maskpos[i]] *= myrand[i]
end
end
With the required operation done by
julia> mularray!(myarray,mymask)
julia> myarray
6-element Array{Float64,1}:
22.1761
20.836
1.0
1.0
1.0
1.0
The advantage is in speed (benchmarked at more than 2x the shorter solution), perhaps readability (for some readers), but probably flexibility for other mutating operations.
Because the value of the mask is bool, following method can be used
for i in eachindex(arr)
mask[i] && (arr[i] *= rand(Normal(20,5)))
end
It is equivalent to
for i in eachindex(arr)
if mask[i]
arr[i] *= rand(Normal(20, 5))
end
end
With this method, you can avoid allocation of arr[mask]
I have an empty matrix initially:
m = Matrix(0, 3)
and a row that I want to add:
v = [2,3]
I try to do this:
[m v]
But I get an error
ERROR: ArgumentError: number of rows of each array must match
What's the proper way to do this?
That is because your matrix sizes don't match. Specifically v does not contain enough columns to match m. And its transposed
So this doesnt work
m = Matrix(0, 3)
v = [2,3]
m = cat(1, m, v) # or a = [m; v]
>> ERROR: DimensionMismatch("mismatch in dimension 2 (expected 3 got 1)")
whereas this does
m = Matrix(0, 3)
v = [2 3 4]
m = cat(1, m, v) # or m = [m; v]
>> 1x3 Array{Any,2}:
>> 2 3 4
and if you run it again it creates another row
m = cat(1, m, v) # or m = [m; v]
>> 2x3 Array{Any,2}:
>> 2 3 4
>> 2 3 4
Use the vcat (concatenate vertically) function:
help?> vcat
search: vcat hvcat VecOrMat DenseVecOrMat StridedVecOrMat AbstractVecOrMat levicivita is_valid_char #vectorize_2arg
vcat(A...)
Concatenate along dimension 1
Notice you have to transpose the vector v, ie. v', else you get a DimensionMismatch error:
julia> v = zeros(3)
3-element Array{Float64,1}:
0.0
0.0
0.0
julia> m = ones(3, 3)
3x3 Array{Float64,2}:
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0
julia> vcat(m, v') # '
4x3 Array{Float64,2}:
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0
0.0 0.0 0.0
julia> v' # '
1x3 Array{Float64,2}:
0.0 0.0 0.0
julia> vcat(m, v)
ERROR: DimensionMismatch("mismatch in dimension 2 (expected 3 got 1)")
in cat_t at abstractarray.jl:850
in vcat at abstractarray.jl:887
Note: the comments; # ' are there just to make syntax highlighting work well.
Isn't that Matrix creates a two-dimensional array in Julia? If you try with m =[0, 3], which creates a one-dimensional Vector for you, you can append it by [m; v].
I think using [m v] is create a two-dimensional array as well, from the Julia Document