Assign blocks of multi-dimensional array - julia

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

Related

How to create two nested for loops in a single line in Julia

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

typedef myFLOAT Float64 / BigFloat

in C(++) I can do in a header file myFLOAT.h
typedef myFLOAT double;
// typedef myFLOAT BigFloat; // with the correct lib
Then I can write code based on the type myFLOAT
and switch very easily for the code between double and BigFloat
by just uncomment/comment the corresponding line
in the header file.
How do I do the same in Julia?
I tried
abstract type myFLOAT <: Float64 end
#abstract type myFLOAT <: BigFloat end
but I get
ERROR: invalid subtyping in definition of myFLOAT
I add the following comment after the answer from #clbieganek
My simulation code generally looks like
init = initSimulation(args);
result = doSimulation(init);
Plotting(result);
I agree that I can/should use AbstractFloat "everywhere" in doSimulation().
But with
const myFLOAT = Float64 # thanks
I want to guarantee that every myFLOAT in 'struct init' is a Float64 or BigFloat depending on the use case. This way 'doSimulation(init)' will choose
the correct Float type.
In Julia, concrete types cannot be sub-typed. Float64 and BigFloat are both concrete types, which is why you are getting the invalid sub-typing error. The direct translation of what you are trying to do is to create a type alias:
const MyType = Float64
However, the Julian approach is to define your types and methods using the most generic types possible. In your case, you could use AbstractFloat. Then your code will work with both Float64 and BigFloat. For example,
julia> struct A
x::AbstractFloat
end
julia> function foo(a::A, x::AbstractFloat)
return a.x + x
end
foo (generic function with 1 method)
julia> a1 = A(4.5)
A(4.5)
julia> foo(a1, 5.2)
9.7
julia> a2 = A(BigFloat(4.5))
A(4.5)
julia> foo(a2, BigFloat(5.2))
9.70000000000000017763568394002504646778106689453125
The Julia type hierarchy for numbers can be viewed here.
You can use the where syntax for the functions, and use syntax like T, then, for either:
julia> function f(a::T) where T <: Number
ret = zeros(T, 5, 5)
ret
end
f (generic function with 1 method)
julia> x = 1.0
1.0
julia> f(x)
5×5 Array{Float64,2}:
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
julia> y = BigFloat(1.0)
1.0
julia> f(y)
5×5 Array{BigFloat,2}:
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
julia>

Julia - console behaving differently than include("myfile.jl")

I would like to execute the following code, which works perfectly well when I type every line into my Julia console on Windows 10, but throws an error because of the mismatching type LinearAlgebra.Adjoint{Float64,Array{Float64,2}} (my subsequent code expects Array{Float64,2}).
This is the code:
x = [0.2, 0.1, 0.2]
y = [-0.5 0.0 0.5]
fx = x * y
fy = fx'
return fx::Array{Float64,2}, fy::Array{Float64,2}
There is a TypeError, because fy seems to be of type LinearAlgebra.Adjoint{Float64,Array{Float64,2}} instead of Array{Float64,2}.
How can I do a transpose and get a "normal" Array{Float64,2} object ?
And why does this work when I type every line into my Julia console, but does not when I run the file via include("myfile.jl") ?
Use collect to have a copy of actual data rather than a transformed view of the original (note that this rule applies to many other similar situations):
julia> x = [0.2, 0.1, 0.2];
julia> y = [-0.5 0.0 0.5];
julia> fx = x * y
3×3 Array{Float64,2}:
-0.1 0.0 0.1
-0.05 0.0 0.05
-0.1 0.0 0.1
julia> fy = fx'
3×3 LinearAlgebra.Adjoint{Float64,Array{Float64,2}}:
-0.1 -0.05 -0.1
0.0 0.0 0.0
0.1 0.05 0.1
julia> fy = collect(fx')
3×3 Array{Float64,2}:
-0.1 -0.05 -0.1
0.0 0.0 0.0
0.1 0.05 0.1
To get a normal Matrix{Float64} use:
fy = permutedims(fx)
or
fy = Matrix(fx')
Those two are not 100% equivalent in general as fx' is a recursive adjoint operation (conjugate transpose), while permutedims is a non-recursive transpose, but in your case they will give the same result.
What does recursive adjoint mean exactly?
recursive: the conjugate transpose is applied recursively to all entries of the array (in your case you have array of numbers and transpose of a number is the same number so this does not change anything);
adjoint: if you would have complex numbers then the operation would return their complex conjugates (in your case you have real numbers so this does not change anything);
Here is an example when both things matter:
julia> x = [[im, -im], [1-im 1+im]]
2-element Array{Array{Complex{Int64},N} where N,1}:
[0+1im, 0-1im]
[1-1im 1+1im]
julia> permutedims(x)
1×2 Array{Array{Complex{Int64},N} where N,2}:
[0+1im, 0-1im] [1-1im 1+1im]
julia> Matrix(x')
1×2 Array{AbstractArray{Complex{Int64},N} where N,2}:
[0-1im 0+1im] [1+1im; 1-1im]
However, unless you really need to you do not have to do it if you really need to get a conjugate transpose of your data. It is enough to change type assertion to
return fx::Array{Float64,2}, fy::AbstractArray{Float64,2}
or
return fx::Matrix{Float64}, fy::AbstractMatrix{Float64}
Conjugate transpose was designed to avoid unnecessary allocation of data and most of the time this will be more efficient for you (especially with large matrices).
Finally the line:
return fx::Array{Float64,2}, fy::Array{Float64,2}
throws an error also in the Julia command line (not only when run from a script).

How to use comprehensions on linspace to create matrix

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)

How to append a vector to Julia matrix as a row?

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

Resources