You can do the following with StaticArrays
to get "tuples that can do linear algebra":
julia> using StaticArrays
julia> ⊗(u, v) = (i ⊗ j for i in u for j in v)
⊗ (generic function with 1 method)
julia> ⊗(x::Number, y::Number) = SVector(x, y)
⊗ (generic function with 2 methods)
julia> ⊗(x::SVector{N}, y::Number) where {N} = SVector(x..., y)
⊗ (generic function with 3 methods)
julia> collect((1:3) ⊗ (10:12) ⊗ (100:101))
18-element Array{SArray{Tuple{3},Int64,1,3},1}:
[1, 10, 100]
[1, 10, 101]
[1, 11, 100]
[1, 11, 101]
[1, 12, 100]
[1, 12, 101]
[2, 10, 100]
[2, 10, 101]
[2, 11, 100]
[2, 11, 101]
[2, 12, 100]
[2, 12, 101]
[3, 10, 100]
[3, 10, 101]
[3, 11, 100]
[3, 11, 101]
[3, 12, 100]
[3, 12, 101]
julia> using LinearAlgebra: norm
julia> for M in (1:3) ⊗ (10:12) ⊗ (100:101)
println(norm(M))
end
100.50373127401788
101.49876846543509
100.60815076324582
101.6021653312566
100.72239075796404
101.7152889196113
100.5186549850325
101.51354589413178
100.62305898749054
101.61692772368194
100.73728207570423
101.73003489628813
100.54352291420865
101.5381701627521
100.64790112068906
101.64152694642087
100.7620960480676
101.75460677532
But I'm not sure it's worth it. Ideally, the \otimes
for SVector
s and Number
s would construct a lazy data structure that only creates the appropriately sized SVector
s when iterated (instead of splatting as here). I'm just too lazy to write that now.
A better variant (but slightly less mathy syntax) is to overload ⨂(spaces...)
to do everything at once:
julia> ⨂(spaces::NTuple{N}) where {N} = (SVector{N}(t) for t in Iterators.product(spaces...))
⨂ (generic function with 1 method)
julia> ⨂(spaces...) = ⨂(spaces)
⨂ (generic function with 2 methods)
julia> collect(⨂(1:3, 10:11))
3×2 Array{SArray{Tuple{2},Int64,1,2},2}:
[1, 10] [1, 11]
[2, 10] [2, 11]
[3, 10] [3, 11]
julia> collect(⨂(1:3, 10:11, 100:101))
3×2×2 Array{SArray{Tuple{3},Int64,1,3},3}:
[:, :, 1] =
[1, 10, 100] [1, 11, 100]
[2, 10, 100] [2, 11, 100]
[3, 10, 100] [3, 11, 100]
[:, :, 2] =
[1, 10, 101] [1, 11, 101]
[2, 10, 101] [2, 11, 101]
[3, 10, 101] [3, 11, 101]
This collects to a different shape, although I'd consider that even more appropriate.