Defining a multiple-dimensional array of arbitrary dimension in Julia
Asked Answered
U

2

5

Context

This question is related to this one.

In Julia, I wanted to make a 2-dimensional array of 5 x 5 with the (i, j) element having [i,j] like this:

5×5 Matrix{Vector{Int64}}:
 [1, 1]  [1, 2]  [1, 3]  [1, 4]  [1, 5]
 [2, 1]  [2, 2]  [2, 3]  [2, 4]  [2, 5]
 [3, 1]  [3, 2]  [3, 3]  [3, 4]  [3, 5]
 [4, 1]  [4, 2]  [4, 3]  [4, 4]  [4, 5]
 [5, 1]  [5, 2]  [5, 3]  [5, 4]  [5, 5]

I tried this with using array comprehension:

N = 5
L_2 = [[x1,x2] for x1 = 1:N, x2 = 1:N]

What I want to do

I want to generalize this definition for arbitrary dimension D.

L_1 = [[x1] for x1 = 1:N] # 1-dimensional
L_2 = [[x1,x2] for x1 = 1:N, x2 = 1:N] # 2-dimensional
L_3 = [[x1,x2,x3] for x1 = 1:N, x2 = 1:N,x3 = 1:N] # 3-dimensional
...

#L_D = ??? # D-dimensional

How can I define?

It is okay without using array comprehension.

Any information would be appreciated.

Unsecured answered 13/12, 2021 at 11:12 Comment(2)
So what do you want to use this for? If it is for indexing into a previously existing N-D array, X, then you can just do CartesianIndices(X). This works for any dimensionality and size.Scarcity
@Scarcity and to put it another way, CartesianIndices(X) does the same thing as CartesianIndices(size(X)). All this number crunching is only needed if X doesn't already exist and you need a NxNxNx... array of indices.Amphitheater
A
5

It doesn't seem like you want CartesianIndices for this, but for the record, CartesianIndices can take any Tuple of Int (more accurately Dims aka NTuple{N,Int} where N) to represent an Array's size. CartesianIndices((5,5)) for a 5x5, CartesianIndices((2,8,3)) for a 2x8x3, etc. You can make a quick NxNxNx... Tuple representing a size with D dimensions with NtotheD(N,D) = ntuple(i -> N, D).

Amphitheater answered 13/12, 2021 at 11:32 Comment(4)
Thank you. I'm feeling like using this CartesianIndices in my project. However, I need to use index of Float64 for each point of lattice in the future in my project. Is it easy to convert Int64 to Float64?Unsecured
It is very easy to convert Int64 to Float64, but don't you mean to ask about the reverse? I must remind you that CartesianIndex{N} is a wrapper around ONLY NTuple{N,Int}, so NTuple{N,Float64} won't work. If you're indexing like A[3.0], then your getindex method needs to convert 3.0 to 3. Converting Float64 to Int64 is a bit tougher because you'll have to decide how to round to the nearest integer if you do A[3.1].Amphitheater
What I want in the future is to make a "unit" lattice which has 5 x 5 points and divided in regular interval. → unit lattice : 0.2, 0.4, 0.6, 0.8, 1.0 . Is this a job for CartesianIndices?Unsecured
Possibly. CartesianIndex{N} must only contain Int, but you can calculate Float64 from Int on demand. Off the top of my head, you can make a struct that subtypes AbstractArray (see Interfaces page of Julia docs) and simply wraps a CartesianIndices. Your getindex for that struct will index the CartesianIndices to get a CartesianIndex, convert the Int to Float64 values, and return them. Just like CartesianIndices, the lattice values are generated on demand, and no memory needs to be allocated on the heap in advance (though you can collect it to generate all values in one go).Amphitheater
S
5

You can generalize the vcat approach I have posted in the other answer like this:

julia> lattice(N, D) = vcat.((reshape(1:N, ntuple(j -> j == i ? N : 1, D)) for i in 1:D)...)
lattice (generic function with 1 method)

julia> lattice(2, 1)
2-element Vector{Vector{Int64}}:
 [1]
 [2]

julia> lattice(2, 2)
2×2 Matrix{Vector{Int64}}:
 [1, 1]  [1, 2]
 [2, 1]  [2, 2]

julia> lattice(2, 3)
2×2×2 Array{Vector{Int64}, 3}:
[:, :, 1] =
 [1, 1, 1]  [1, 2, 1]
 [2, 1, 1]  [2, 2, 1]

[:, :, 2] =
 [1, 1, 2]  [1, 2, 2]
 [2, 1, 2]  [2, 2, 2]

julia> lattice(2, 4)
2×2×2×2 Array{Vector{Int64}, 4}:
[:, :, 1, 1] =
 [1, 1, 1, 1]  [1, 2, 1, 1]
 [2, 1, 1, 1]  [2, 2, 1, 1]

[:, :, 2, 1] =
 [1, 1, 2, 1]  [1, 2, 2, 1]
 [2, 1, 2, 1]  [2, 2, 2, 1]

[:, :, 1, 2] =
 [1, 1, 1, 2]  [1, 2, 1, 2]
 [2, 1, 1, 2]  [2, 2, 1, 2]

[:, :, 2, 2] =
 [1, 1, 2, 2]  [1, 2, 2, 2]
 [2, 1, 2, 2]  [2, 2, 2, 2]

julia> lattice(2, 5)
2×2×2×2×2 Array{Vector{Int64}, 5}:
[:, :, 1, 1, 1] =
 [1, 1, 1, 1, 1]  [1, 2, 1, 1, 1]
 [2, 1, 1, 1, 1]  [2, 2, 1, 1, 1]

[:, :, 2, 1, 1] =
 [1, 1, 2, 1, 1]  [1, 2, 2, 1, 1]
 [2, 1, 2, 1, 1]  [2, 2, 2, 1, 1]

[:, :, 1, 2, 1] =
 [1, 1, 1, 2, 1]  [1, 2, 1, 2, 1]
 [2, 1, 1, 2, 1]  [2, 2, 1, 2, 1]

[:, :, 2, 2, 1] =
 [1, 1, 2, 2, 1]  [1, 2, 2, 2, 1]
 [2, 1, 2, 2, 1]  [2, 2, 2, 2, 1]

[:, :, 1, 1, 2] =
 [1, 1, 1, 1, 2]  [1, 2, 1, 1, 2]
 [2, 1, 1, 1, 2]  [2, 2, 1, 1, 2]

[:, :, 2, 1, 2] =
 [1, 1, 2, 1, 2]  [1, 2, 2, 1, 2]
 [2, 1, 2, 1, 2]  [2, 2, 2, 1, 2]

[:, :, 1, 2, 2] =
 [1, 1, 1, 2, 2]  [1, 2, 1, 2, 2]
 [2, 1, 1, 2, 2]  [2, 2, 1, 2, 2]

[:, :, 2, 2, 2] =
 [1, 1, 2, 2, 2]  [1, 2, 2, 2, 2]
 [2, 1, 2, 2, 2]  [2, 2, 2, 2, 2]
Sumba answered 13/12, 2021 at 11:21 Comment(1)
Thank you for showing me many examples that made me easy to understand.Unsecured
A
5

It doesn't seem like you want CartesianIndices for this, but for the record, CartesianIndices can take any Tuple of Int (more accurately Dims aka NTuple{N,Int} where N) to represent an Array's size. CartesianIndices((5,5)) for a 5x5, CartesianIndices((2,8,3)) for a 2x8x3, etc. You can make a quick NxNxNx... Tuple representing a size with D dimensions with NtotheD(N,D) = ntuple(i -> N, D).

Amphitheater answered 13/12, 2021 at 11:32 Comment(4)
Thank you. I'm feeling like using this CartesianIndices in my project. However, I need to use index of Float64 for each point of lattice in the future in my project. Is it easy to convert Int64 to Float64?Unsecured
It is very easy to convert Int64 to Float64, but don't you mean to ask about the reverse? I must remind you that CartesianIndex{N} is a wrapper around ONLY NTuple{N,Int}, so NTuple{N,Float64} won't work. If you're indexing like A[3.0], then your getindex method needs to convert 3.0 to 3. Converting Float64 to Int64 is a bit tougher because you'll have to decide how to round to the nearest integer if you do A[3.1].Amphitheater
What I want in the future is to make a "unit" lattice which has 5 x 5 points and divided in regular interval. → unit lattice : 0.2, 0.4, 0.6, 0.8, 1.0 . Is this a job for CartesianIndices?Unsecured
Possibly. CartesianIndex{N} must only contain Int, but you can calculate Float64 from Int on demand. Off the top of my head, you can make a struct that subtypes AbstractArray (see Interfaces page of Julia docs) and simply wraps a CartesianIndices. Your getindex for that struct will index the CartesianIndices to get a CartesianIndex, convert the Int to Float64 values, and return them. Just like CartesianIndices, the lattice values are generated on demand, and no memory needs to be allocated on the heap in advance (though you can collect it to generate all values in one go).Amphitheater

© 2022 - 2024 — McMap. All rights reserved.