Swizzles are Julia operators that allow the user to fuse reduction and transposition operations into broadcast expressions. Swizzles are lazily evaluated, creating a language of Julia objects to represent tensor contractions and related operations. Swizzles were created as a good-faith attempt to implement tensor algebra using the abstractions and programming patterns of base Julia (broadcasting in particular). We hope that the results of our exploration may help inform future implementation decisions and redesigns of the Julia standard library. This project is no longer actively developed; Willow is working on Finch.jl now. Swizzles.jl has been tested on Julia 1.5.
Swizzle(op, mask...)(init, arg)
creates an operator which initializes dst
using init
, then reduces arg
into dst
such that dimension d
of dst
corresponds to dimension mask[d]
of arg
. This operator is represented lazily using the array type SwizzledArray
. Thus,
julia> using Swizzles
julia> A = [1 2 3; 4 5 6; 7 8 9]
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
julia> Swizzle(+, 2).(A)
3-element Array{Int64,1}:
12
15
18
julia> Swizzle(+).(A)
45
We can use an instance of the singleton type Nil
to insert a size 1 dimension into dst
.
julia> Swizzle(+, nil, 2).(A)
1×3 Array{Int64,2}:
12 15 18
It is convenient to represent transpositions (Swizzle
s which do not initialize or reduce) using the operator Beam(imask...)
. Beam(imask...)(arg)
produces an output array dst
such that dimension imask[d]
of dst
corresponds to dimension d
of arg
.
julia> B = [12; 15; 18]
3-element Array{Int64,1}:
12
15
18
julia> Beam(2).(B)
1×3 Array{Int64,2}:
12 15 18
Notice the similarity between index notation
A[i,j] = ∑ B[i,k,l] * D[l,j] * C[k,j]
and the Swizzles.jl representation
A .= Swizzle(+, 2, 1).(Beam(+, 2, 3, 4).(B) .* Beam(4, 1).(D) .* Beam(3, 1).(C))
Swizzles.jl was created to provide a trait-based dispatch mechanism for tensor
kernel selection and array implementation. Swizzles uses BroadcastStyles
and
eachindex
to help select implementations, and provides an alternative abstract
array supertype, StylishArray
, for new array types to target. The language
of Swizzle
and Broadcast
provides a high-level intermediate representation
for tensor operations.
julia> using Swizzles, LinearAlgebra
julia> x = rand(7); y = rand(7);
julia> Swizzle(+).(x .* y) ≈ dot(x, y)
true
julia> Swizzle(+).(abs.(x)) ≈ norm(x, 1)
true
julia> A = rand(5, 7); B = rand(7, 8);
julia> Swizzle(+, nil, 2).(A) ≈ sum(A, dims=1)
true
julia> Swizzle(+, 2).(A) ≈ sum(A, dims=1)[1,:]
true
julia> Beam(2, 1).(A) ≈ transpose(A)
true
julia> Beam(1, 4).(A) ≈ reshape(A, 5, 1, 1, 7)
true
julia> Swizzle(+, 1, 3).(A.*Beam(2, 3).(B)) ≈ A * B
true