Tensor factorizations

As tensors are linear maps, they suport various kinds of factorizations. These functions all interpret the provided AbstractTensorMap instances as a map from domain to codomain, which can be thought of as reshaping the tensor into a matrix according to the current bipartition of the indices.

TensorKit's factorizations are provided by MatrixAlgebraKit.jl, which is used to supply both the interface, as well as the implementation of the various operations on the blocks of data. For specific details on the provided functionality, we refer to its documentation page.

Finally, note that each of the factorizations takes the current partition of domain and codomain as the axis along which to matricize and perform the factorization. In order to obtain factorizations according to a different bipartition of the indices, we can use any of the previously mentioned index manipulations before the factorization.

Some examples to conclude this section

julia> V1 = SU₂Space(0 => 2, 1/2 => 1)Rep[SU₂](…) of dim 4:
   0 => 2
 1/2 => 1
julia> V2 = SU₂Space(0 => 1, 1/2 => 1, 1 => 1)Rep[SU₂](…) of dim 6: 0 => 1 1/2 => 1 1 => 1
julia> t = randn(V1 ⊗ V1, V2);
julia> U, S, Vh = svd_compact(t);
julia> t ≈ U * S * Vhtrue
julia> D, V = eigh_full(t' * t);
julia> D ≈ S * Strue
julia> U' * U ≈ id(domain(U))true
julia> S6←6 DiagonalTensorMap{Float64, Rep[SU₂], Vector{Float64}}: codomain: ⊗(Rep[SU₂](0 => 1, 1/2 => 1, 1 => 1)) domain: ⊗(Rep[SU₂](0 => 1, 1/2 => 1, 1 => 1)) blocks: * Irrep[SU₂](0) => 1×1 LinearAlgebra.Diagonal{Float64, SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true}}: 2.838920096650787 * Irrep[SU₂](1/2) => 1×1 LinearAlgebra.Diagonal{Float64, SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true}}: 1.36693035558252 * Irrep[SU₂](1) => 1×1 LinearAlgebra.Diagonal{Float64, SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true}}: 0.7666656546058845
julia> Q, R = left_orth(t; alg = :svd);
julia> Q' * Q ≈ id(domain(Q))true
julia> t ≈ Q * Rtrue
julia> U2, S2, Vh2, ε = svd_trunc(t; trunc = truncspace(V1));
julia> Vh2 * Vh2' ≈ id(codomain(Vh2))true
julia> S23←3 DiagonalTensorMap{Float64, Rep[SU₂], Vector{Float64}}: codomain: ⊗(Rep[SU₂](0 => 1, 1/2 => 1)) domain: ⊗(Rep[SU₂](0 => 1, 1/2 => 1)) blocks: * Irrep[SU₂](0) => 1×1 LinearAlgebra.Diagonal{Float64, SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true}}: 2.838920096650787 * Irrep[SU₂](1/2) => 1×1 LinearAlgebra.Diagonal{Float64, SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true}}: 1.36693035558252
julia> ε ≈ norm(block(S, Irrep[SU₂](1))) * sqrt(dim(Irrep[SU₂](1)))true
julia> L, Q = right_orth(permute(t, ((1,), (2, 3))));
julia> codomain(L), domain(L), domain(Q)(⊗(Rep[SU₂](0 => 2, 1/2 => 1)), ⊗(Rep[SU₂](0 => 2, 1/2 => 1)), (Rep[SU₂](0 => 2, 1/2 => 1)' ⊗ Rep[SU₂](0 => 1, 1/2 => 1, 1 => 1)))
julia> Q * Q'4←4 TensorMap{Float64, Rep[SU₂], 1, 1, Vector{Float64}}: codomain: ⊗(Rep[SU₂](0 => 2, 1/2 => 1)) domain: ⊗(Rep[SU₂](0 => 2, 1/2 => 1)) blocks: * Irrep[SU₂](0) => 2×2 reshape(view(::Vector{Float64}, 1:4), 2, 2) with eltype Float64: 1.0 -8.47896e-17 -8.47896e-17 1.0 * Irrep[SU₂](1/2) => 1×1 reshape(view(::Vector{Float64}, 5:5), 1, 1) with eltype Float64: 1.0000000000000002
julia> P = Q' * Q;
julia> P ≈ P * Ptrue
julia> t′ = permute(t, ((1,), (2, 3)));
julia> t′ ≈ t′ * Ptrue