@@ -741,15 +741,15 @@ non-Abelian symmetry group $G$, the fact that its elements do not all commute ha
741741impact on its representation theory. In particular, the irreps of such a group can be higher
742742dimensional, and the fusion of two irreps can give rise to multiple different irreps. On the
743743one hand this means that fusion trees of these irreps are no longer completely determined by
744- the uncoupled charges. Indeed, in this case some of the
745- [ internal structure of the ` FusionTree ` type] (@ref sss_fusion_trees) we have ignored before will
746- become relevant (of which we will give an [ example below] (@ref sss_sun_heisenberg)). On the other
747- hand, it follows that fusion trees of irreps now not only label blocks, but also encode a
748- certain * nontrivial symmetry structure* . We will make this statement more precise in the
749- following, but the fact that this is necessary is quite intuitive. If we recall our original
750- statement that symmetric tensors consist of blocks associated to fusion trees which carry
751- irrep labels, then for higher-dimensional irreps the corresponding fusion trees must encode
752- some additional information that implicitly takes into account the internal structure of the
744+ the uncoupled charges. Indeed, in this case some of the [ internal structure of the
745+ ` FusionTree ` type] (@ref sss_fusion_trees) we have ignored before will become relevant (of
746+ which we will give an [ example below] (@ref sss_sun_heisenberg)). On the other hand, it
747+ follows that fusion trees of irreps now not only label blocks, but also encode a certain
748+ * nontrivial symmetry structure* . We will make this statement more precise in the following,
749+ but the fact that this is necessary is quite intuitive. If we recall our original statement
750+ that symmetric tensors consist of blocks associated to fusion trees which carry irrep
751+ labels, then for higher-dimensional irreps the corresponding fusion trees must encode some
752+ additional information that implicitly takes into account the internal structure of the
753753representation spaces. In particular, this means that the conversion of an operator, given
754754its matrix elements in the irrep basis, to the blocks of the corresponding symmetric
755755` TensorMap ` is less straightforward since it requires an understanding of exactly what this
@@ -768,8 +768,8 @@ $\mathrm{SU}(N)$-symmetric case.
768768Let us recall some basics of representation theory first. Consider a group $G$ and a
769769corresponding representation space $V$, such that every element $g \in G$ can be realized as
770770a unitary operator $U_g : V \to V$. Let $h$ be a ` TensorMap ` whose domain and codomain are
771- given by the tensor product of two of these representation spaces. Recall that, by
772- definition, the statement that '$h$ is symmetric under $G$' means that
771+ given by the tensor product of two of these representation spaces. By definition, the
772+ statement that '$h$ is symmetric under $G$' means that
773773``` @raw html
774774<center><img src="../img/symmetric_tutorial/symmetric_tensor.svg" alt="symmetric_tensor" class="color-invertible" style="zoom: 170%"/></center>
775775```
@@ -793,7 +793,10 @@ encodes how a basis state $\ket{k,n} \in V^{(k)}$ corresponding to some term in
793793sum can be decomposed into a linear combination of basis vectors $\ket{l_1,m_1} \otimes
794794\ket{l_2,m_2}$ of the tensor product space:
795795``` math
796+ \begin{equation}
797+ \label{eq:cg_decomposition}
796798\ket{k,n} = \sum_{m_1, m_2} \left( C^{k}_{l_1,l_2} \right)^{n}_{m_1, m_2} \ket{l_1,m_1} \otimes \ket{l_2,m_2}.
799+ \end{equation}
797800```
798801These recoupling coefficients turn out to be essential to the structure of symmetric
799802tensors, which can be best understood in the context of the
@@ -835,7 +838,10 @@ the irreps of $\mathrm{SU}(2)$ can be labeled by a halfinteger *spin* that takes
8358380, \frac{1}{2}, 1, \frac{3}{2}, ...$, and where the dimension of the spin-$l$ representation
836839is equal to $2l + 1$. The fusion rules of $\mathrm{SU}(2)$ are given by
837840``` math
841+ \begin{equation}
842+ \label{eq:su2_fusion_rules}
838843l_1 \otimes l_2 \cong \bigoplus_{k=|l_1-l_2|}^{l_1+l_2}s.
844+ \end{equation}
839845```
840846These are clearly non-Abelian since multiple terms appear on the right hand side, for
841847example $\frac{1}{2} \otimes \frac{1}{2} \cong 0 \oplus 1$. In TensorKit.jl, a
@@ -845,34 +851,35 @@ where a given $\mathrm{SU}(2)$ irrep can be represented as an
845851[ ` SU2Irrep ` ] ( @ref )
846852instance of integer or halfinteger spin as encoded in its ` j ` field. If we construct a
847853` TensorMap ` whose symmetry structure corresponds to the coupling of two spin-$\frac{1}{2}$
848- irreps to a spin-$1$ irrep, we can then convert it to a plain array and compare it to the
849- $\mathrm{SU}(2)$ Clebsch-Gordan coefficients exported by the
850- [ WignerSymbols.jl package] ( https://github.com/Jutho/WignerSymbols.jl ) .
851-
854+ irreps to a spin-$1$ irrep in the sense of \eqref{eq: cg_decomposition }, we can then convert
855+ it to a plain array and compare it to the $\mathrm{SU}(2)$ Clebsch-Gordan coefficients
856+ implemented in the [ WignerSymbols.jl package] ( https://github.com/Jutho/WignerSymbols.jl ) .
852857``` @example symmetric_tutorial
853- V1 = SU2Space(1 => 1)
854- V2 = SU2Space(1//2 => 1)
855- t = ones(ComplexF64, V1 ← V2 ⊗ V2)
858+ V1 = SU2Space(1//2 => 1)
859+ V2 = SU2Space(1 => 1)
860+ t = ones(ComplexF64, V1 ⊗ V1 ← V2)
856861```
857862
858863``` @example symmetric_tutorial
859864ta = convert(Array, t)
860865```
861- The conversion gives us a $3 \times 2 \times 2 $ array, which exactly corresponds to the size
862- of the $C _ {1}^ {\frac{1}{2},\frac{1}{2}}$ Clebsch-Gordan array. In order to explicitly
866+ The conversion gives us a $2 \times 2 \times 3 $ array, which exactly corresponds to the size
867+ of the $C^ {1}_ {\frac{1}{2},\frac{1}{2}}$ Clebsch-Gordan array. In order to explicitly
863868compare whether the entries match we need to know the ordering of basis states assumed by
864869TensorKit.jl when converting the tensor to its matrix elements in the irrep basis. For
865870$\mathrm{SU}(2)$ the irrep basis is ordered in ascending magnetic quantum number $m$, which
866871gives us a map $m = i - (l+1)$ for mapping an array index to a corresponding magnetic
867872quantum number for the spin-$l$ irrep.
868873``` @example symmetric_tutorial
869- for i1 in 1:dim(V1), i2 in 1:dim(V2 ), i3 in 1:dim(V2)
874+ checks = map(Iterators.product( 1:dim(V1), 1:dim(V1 ), 1:dim(V2))) do (i1, i2, i3 )
870875 # map basis state index to magnetic quantum number
871- m1 = i1 - (1 + 1)
876+ m1 = i1 - (1//2 + 1)
872877 m2 = i2 - (1//2 + 1)
873- m3 = i3 - (1//2 + 1)
874- @test ta[i1, i2, i3] ≈ clebschgordan(1//2, m2, 1//2, m3, 1, m1)
878+ m3 = i3 - (1 + 1)
879+ # check the corresponding array entry
880+ return ta[i1, i2, i3] ≈ clebschgordan(1//2, m1, 1//2, m2, 1, m3)
875881end
882+ @test all(checks)
876883```
877884
878885Based on this discussion, we can quantify the aforementioned 'difficulties' in the inverse
@@ -899,9 +906,47 @@ However, it should be noted that for general groups the Clebsch-Gordan coefficie
899906be as easy to compute (in general, no closed formulas exist). In addition, the procedure for
900907manually projecting out the reduced matrix elements requires being particularly careful
901908about the correspondence between the basis states used to define the original matrix
902- elements and those implied by the Clebsch-Gordan coefficients. Therefore, it is often easier
903- to directly construct the symmetric tensor based on some representation theory, as we will
904- see below.
909+ elements and those implied by the Clebsch-Gordan coefficients. Finally, for some symmetries
910+ supported in TensorKit.jl, there are simply no Clebsch-Gordan coefficients. Therefore, it is
911+ often easier and sometimes simply necessary to directly construct the symmetric tensor and
912+ then fill in its reduced tensor elements based on some representation theory. Wel will cover
913+ some examples of this below.
914+
915+ Having introduced and demonstrated the Clebsch-Gordan decomposition, the corresponding
916+ coefficients and their role in symmetric tensors for the example of $\mathrm{SU}(2)$ using
917+ the WignerSymbols.jl package, we'll continue our discussion using only TensorKit.jl
918+ internals. Within TensorKit.jl, the
919+ $\text{dim}\left( V^{(l_1)} \right) \times \text{dim}\left( V^{(l_2)} \right) \times \text{dim}\left( V^{(k)} \right)$
920+ array of coefficients that encodes the splitting of the irrep space $V^{(k)}$ to the tensor
921+ product of irrep spaces $V^{(l_1)} \otimes V^{(l_2)}$ according to the Clebsch-Gordan
922+ decomposition \eqref{eq: cg_decomposition } above can be explicitly constructed by calling the
923+ [ ` TensorKitSectors.fusiontensor ` ] ( @ref ) method on the corresponding ` Sector ` instances,
924+ ` fusiontensor(l₁, l₂, k) ` . This ` fusiontensor ` is defined for any sector type corresponding
925+ to a symmetry which admits Clebsch-Gordan coefficients. For our example above,
926+ we can build the corresponding fusion tensor as
927+
928+ ``` @example symmetric_tutorial
929+ using TensorKit: fusiontensor
930+ f = fusiontensor(SU2Irrep(1//2), SU2Irrep(1//2), SU2Irrep(1))
931+ ```
932+
933+ We see that this fusion tensor has a size ` 2×2×3×1 ` , which contains an additional trailing
934+ ` 1 ` to what we might expect. In the general case, ` fusiontensor ` returns a 4-dimensional
935+ array, where the size of the first three dimensions corresponds to the dimensions of the
936+ irrep spaces under consideration, and the last dimension corresponds to the number of
937+ distinct ways the irreps $l_1$ and $l_1$ can fuse to irrep $k$. We say that ` Sector ` s for
938+ which the size of this last dimension can be larger than 1 have * fusion multiplicities* .
939+ We'll encounter an example of this below when we consider an $\mathrm{SU}(3)$ symmetry.
940+ Since $\mathrm{SU}(2)$ doesn't have any fusion multiplicities, we can just discard this last
941+ index.
942+
943+ We can now explicitly that this ` fusiontensor ` indeed does what we expect it to do:
944+ ``` @example symmetric_tutorial
945+ @test ta ≈ f[:, :, :, 1]
946+ ```
947+ Of course, in this case ` fusiontensor ` just calls ` Wignersymbols.clebschgordan ` under the
948+ hood. However, ` TensorKitSectors.fusiontensor ` works for general symmetries, and makes it
949+ so that we never have to manually assemble the coefficients into an array.
905950
906951
907952### The 'generic' approach to the spin-1 Heisenberg model: Wigner-Eckart in action
@@ -931,38 +976,31 @@ nothing #hide
931976```
932977
933978The next step is to project out the reduced matrix elements by taking the overlap with the
934- appropriate Clebsch-Gordan coefficients, according to
935- [ the Clebsch-Gordan decomposition given above] ( none2symm ) . In our current case of a spin-1
936- physical space we have $l_1 = l_2 = l_3 = l_4 = 1$, and the coupled irrep $k$ can therefore
937- take the values $0, 1, 2$. The reduced matrix element for a given $k$ can then be
938- implemented in the following way:
979+ appropriate Clebsch-Gordan coefficients. In our current case of a spin-1 physical space we
980+ have $l_1 = l_2 = l_3 = l_4 = 1$, and the coupled irrep $k$ can therefore take the values
981+ $0, 1, 2$. The reduced matrix element for a given $k$ can be implemented in the
982+ following way:
939983``` @example symmetric_tutorial
940- function get_reduced_element(k)
984+ function get_reduced_element(k::SU2Irrep )
941985 # construct Clebsch-Gordan coefficients for coupling 1 ⊗ 1 to k
942- CG = zeros(ComplexF64, 3, 3, 2*k + 1)
943- for m1 in -k:k, m2 in -1:1, m3 in -1:1
944- CG[m2 + 2, m3 + 2, m1 + k + 1] = clebschgordan(1, m2, 1, m3, k, m1)
945- end
946-
986+ f = fusiontensor(SU2Irrep(1), SU2Irrep(1), k)[:, :, :, 1]
947987 # project out diagonal matrix on coupled irrep space
948- @tensor reduced_matrix[-1; -2] := CG[1 2; -1] * SS_arr[1 2; 3 4] * conj(CG[3 4; -2])
949-
988+ @tensor reduced_matrix[-1; -2] := conj(f[1 2; -1]) * SS_arr[1 2; 3 4] * f[3 4; -2]
950989 # check that it is proportional to the identity
951990 @assert isapprox(reduced_matrix, reduced_matrix[1, 1] * I; atol=1e-12)
952-
953991 # return the proportionality factor
954992 return reduced_matrix[1, 1]
955993end
956994```
957995If we use this to compute the reduced matrix elements for $k = 0, 1, 2$,
958996``` @example symmetric_tutorial
959- get_reduced_element(0 )
997+ get_reduced_element(SU2Irrep(0) )
960998```
961999``` @example symmetric_tutorial
962- get_reduced_element(1 )
1000+ get_reduced_element(SU2Irrep(1) )
9631001```
9641002``` @example symmetric_tutorial
965- get_reduced_element(2 )
1003+ get_reduced_element(SU2Irrep(2) )
9661004```
9671005we can read off the entries
9681006``` math
@@ -992,12 +1030,41 @@ interaction:
9921030V = SU2Space(1 => 1)
9931031SS = zeros(ComplexF64, V ⊗ V ← V ⊗ V)
9941032for (s, f) in fusiontrees(SS)
995- k = Int( f.coupled.j)
1033+ k = f.coupled
9961034 SS[s, f] .= get_reduced_element(k)
9971035end
9981036subblocks(SS)
9991037```
10001038
1039+ We demonstrated this entire procedure of extracting the array blocks of a symmetric tensor
1040+ map for each fusion tree by projecting out the corresponding fusion tensors as an explicit
1041+ illustration of how symmetric tensor maps work under the hood. In practice however, there's
1042+ no need to perform this procedure explicitly. Given a dense array representing the matrix
1043+ elements of a tensor map in the irrep basis, we can convert this to the corresponding
1044+ symmetric tensor map by passing the data array to the ` TensorMap ` constructor along with the
1045+ corresponding spaces,
1046+ ``` @example symmetric_tutorial
1047+ SS_auto = TensorMap(SS_arr, V ⊗ V ← V ⊗ V)
1048+ @test SS_auto ≈ SS
1049+ ```
1050+
1051+ !!! warning
1052+ While the example demonstrated here seems fairly straightforward, there's some inherent
1053+ challenges to directly initializing a symmetric tensor map from a full dense array. A first
1054+ important point to reiterate here is that in order for this procedure to work, we had to
1055+ initialize ` SS_arr ` by assuming an internal basis convention for the $\mathrm{SU}(2)$
1056+ representation space $V^{(1)}$ that is consistent with the convention used by
1057+ ` fusiontensor ` . While that choice here, corresponding to an ascending magnetic quantum
1058+ number $m = -1, 0, 1$, seems quite natural, for many symmetries there is no transparent
1059+ natural choice. In those cases, the only way to use this approach is to explicitly check the
1060+ basis convention used by [ ` TensorKitSectors.fusiontensor ` ] ( @ref ) for that specific symmetry.
1061+ On top of thes, there's some additional complications when considering graded spaces which
1062+ contain multiple sectors with non-trivial degeneracies. In that case, to even initialize the
1063+ dense data array in the first place, you would need to know the order in which the sectors
1064+ appear in each space internally. This information can be obtained by calling ` axes(V, c) ` ,
1065+ where ` V ` and ` c ` are either an [ ` ElementarySpace ` ] ( @ref ) and a [ ` Sector ` ] ( @ref ) , or a
1066+ [ ` ProductSpace ` ] ( @ref ) and a ` Tuple ` of ` Sector ` s respectively.
1067+
10011068
10021069### An 'elegant' approach to the Heisenberg model
10031070
0 commit comments