TensorCore.jl
This package is intended as a lightweight foundation for tensor operations across the Julia ecosystem. Currently it exports three operations, hadamard, tensor and boxdot, and corresponding unicode operators ⊙, ⊗ and ⊡.
API
TensorCore.boxdotTensorCore.boxdot!TensorCore.hadamardTensorCore.hadamard!TensorCore.tensorTensorCore.tensor!
TensorCore.hadamard — Functionhadamard(a, b)
a ⊙ bFor arrays a and b, perform elementwise multiplication. a and b must have identical axes.
⊙ can be passed as an operator to higher-order functions.
Examples
julia> a = [2, 3]; b = [5, 7];
julia> a ⊙ b
2-element Vector{Int64}:
10
21
julia> a ⊙ [5]
ERROR: DimensionMismatch: Axes of `A` and `B` must match, got (Base.OneTo(2),) and (Base.OneTo(1),)
[...]See also hadamard!(y, a, b).
TensorCore.hadamard! — Functionhadamard!(dest, A, B)Similar to hadamard(A, B) (which can also be written A ⊙ B), but stores its results in the pre-allocated array dest.
TensorCore.tensor — Functiontensor(A, B)
A ⊗ BCompute the tensor product of A and B. If C = A ⊗ B, then C[i1, ..., im, j1, ..., jn] = A[i1, ... im] * B[j1, ..., jn].
For vectors v and w, the Kronecker product is related to the tensor product by kron(v,w) == vec(w ⊗ v) or w ⊗ v == reshape(kron(v,w), (length(w), length(v))).
Examples
julia> a = [2, 3]; b = [5, 7, 11];
julia> a ⊗ b
2×3 Matrix{Int64}:
10 14 22
15 21 33See also tensor!(Y,A,B).
TensorCore.tensor! — Functiontensor!(dest, A, B)Similar to tensor(A, B) (which can also be written A ⊗ B), but stores its results in the pre-allocated array dest.
TensorCore.boxdot — Functionboxdot(A,B) = A ⊡ B # \boxdotGeneralised matrix multiplication: Contracts the last dimension of A with the first dimension of B, for any ndims(A) & ndims(B). If both are vectors, then it returns a scalar == sum(A .* B).
Examples
julia> A = rand(3,4,5); B = rand(5,6,7);
julia> size(A ⊡ B)
(3, 4, 6, 7)
julia> typeof(rand(5) ⊡ rand(5))
Float64
julia> try B ⊡ A catch err println(err) end
DimensionMismatch("neighbouring axes of `A` and `B` must match, got Base.OneTo(7) and Base.OneTo(3)")This is the same behaviour as Mathematica's function Dot[A, B]. It is not identicaly to Python's numpy.dot(A, B), which contracts with the second-last dimension of B instead of the first, but both keep all the other dimensions. Unlike Julia's LinearAlgebra.dot, it does not conjugate A, so these two agree only for real-valued vectors.
When interacting with Adjoint vectors, this always obeys (x ⊡ y)' == y' ⊡ x', and hence may sometimes return another Adjoint vector. (And similarly for Transpose.)
julia> M = rand(5,5); v = rand(5);
julia> typeof(v ⊡ M')
Vector{Float64} (alias for Array{Float64, 1})
julia> typeof(M ⊡ v') # adjoint of the previous line
LinearAlgebra.Adjoint{Float64, Vector{Float64}}
julia> typeof(v' ⊡ M') # same as *, and equal to adjoint(M ⊡ v)
LinearAlgebra.Adjoint{Float64, Vector{Float64}}
julia> typeof(v' ⊡ v)
Float64See also boxdot!(Y,A,B), which is to ⊡ as mul! is to *.
TensorCore.boxdot! — Functionboxdot!(Y, A, B, α=1, β=0)In-place version of boxdot, i.e. Y .= (A ⊡ B) .* β .+ Y .* α. Like 5-argument mul!, the use of α, β here requires Julia 1.3 or later.