How to Code Outer Product of a Set of Elements in Julia?

106 Views Asked by At

Permutations of a Set of Elements

I have a Julia snippet which generates all possible 4-tuples with 3 possible elements in each slot:

julia> collect(Iterators.product(ntuple(_ -> 1:3, 4)...))
3×3×3×3 Array{NTuple{4, Int64}, 4}:
[:, :, 1, 1] =
 (1, 1, 1, 1)  (1, 2, 1, 1)  (1, 3, 1, 1)
 (2, 1, 1, 1)  (2, 2, 1, 1)  (2, 3, 1, 1)
 (3, 1, 1, 1)  (3, 2, 1, 1)  (3, 3, 1, 1)

[:, :, 2, 1] =
 (1, 1, 2, 1)  (1, 2, 2, 1)  (1, 3, 2, 1)
 (2, 1, 2, 1)  (2, 2, 2, 1)  (2, 3, 2, 1)
 (3, 1, 2, 1)  (3, 2, 2, 1)  (3, 3, 2, 1)

[:, :, 3, 1] =
 (1, 1, 3, 1)  (1, 2, 3, 1)  (1, 3, 3, 1)
 (2, 1, 3, 1)  (2, 2, 3, 1)  (2, 3, 3, 1)
 (3, 1, 3, 1)  (3, 2, 3, 1)  (3, 3, 3, 1)

[:, :, 1, 2] =
 (1, 1, 1, 2)  (1, 2, 1, 2)  (1, 3, 1, 2)
 (2, 1, 1, 2)  (2, 2, 1, 2)  (2, 3, 1, 2)
 (3, 1, 1, 2)  (3, 2, 1, 2)  (3, 3, 1, 2)
...

Question

How do I modify this code so that instead of using a range 1:3 for the elements, I select elements out of an array, say [1,5], or a set Set([1,5]), with only 2 possibilities?

1

There are 1 best solutions below

1
Ashlin Harris On BEST ANSWER

I think this is what you're looking for:

julia> original = collect(Iterators.product(ntuple(_ -> [1,5], 4)...))
2×2×2×2 Array{NTuple{4, Int64}, 4}:
[:, :, 1, 1] =
 (1, 1, 1, 1)  (1, 5, 1, 1)
 (5, 1, 1, 1)  (5, 5, 1, 1)

[:, :, 2, 1] =
 (1, 1, 5, 1)  (1, 5, 5, 1)
 (5, 1, 5, 1)  (5, 5, 5, 1)

[:, :, 1, 2] =
 (1, 1, 1, 5)  (1, 5, 1, 5)
 (5, 1, 1, 5)  (5, 5, 1, 5)

[:, :, 2, 2] =
 (1, 1, 5, 5)  (1, 5, 5, 5)
 (5, 1, 5, 5)  (5, 5, 5, 5)

julia> flattened = [original...]
16-element Vector{NTuple{4, Int64}}:
 (1, 1, 1, 1)
 (5, 1, 1, 1)
 (1, 5, 1, 1)
 (5, 5, 1, 1)
 (1, 1, 5, 1)
 (5, 1, 5, 1)
 (1, 5, 5, 1)
 (5, 5, 5, 1)
 (1, 1, 1, 5)
 (5, 1, 1, 5)
 (1, 5, 1, 5)
 (5, 5, 1, 5)
 (1, 1, 5, 5)
 (5, 1, 5, 5)
 (1, 5, 5, 5)
 (5, 5, 5, 5)

So, it's possible to simply substitute an array or set for the iterator. Afterwards, you can flatten the resulting matrix with the splat operator.

Additionally, here is how elements can be accessed in the form A[i,j] using list comprehension:

julia> original  =  collect(Iterators.product(ntuple(_ -> 1:3, 4)...));
julia> newMatrix = [original[:,:,a,b] for a in 1:3, b in 1:3];

julia> newMatrix[2,3]
3×3 Matrix{NTuple{4, Int64}}:
 (1, 1, 2, 3)  (1, 2, 2, 3)  (1, 3, 2, 3)
 (2, 1, 2, 3)  (2, 2, 2, 3)  (2, 3, 2, 3)
 (3, 1, 2, 3)  (3, 2, 2, 3)  (3, 3, 2, 3)

julia> typeof(newMatrix)
Matrix{Matrix{NTuple{4, Int64}}} (alias for Array{Array{NTuple{4, Int64}, 2}, 2})