From 2e5b0e6c4be5fbb3dba39746a294343f17631fcf Mon Sep 17 00:00:00 2001 From: leburgel Date: Mon, 17 Nov 2025 17:35:28 +0100 Subject: [PATCH 01/26] Add symmetric tensor tutorial to docs as appendix --- docs/Project.toml | 4 + docs/make.jl | 15 +- .../symmetric_tutorial/Fib_fusiontrees.svg | 91 ++ .../symmetric_tutorial/SU2_fusiontrees.svg | 258 ++++ .../symmetric_tutorial/SUN_fusiontrees.svg | 226 +++ .../img/symmetric_tutorial/U1_fusiontrees.svg | 390 ++++++ .../src/appendix/img/symmetric_tutorial/X.svg | 23 + .../img/symmetric_tutorial/Z2_fusiontrees.svg | 175 +++ .../appendix/img/symmetric_tutorial/ZZ.svg | 30 + .../img/symmetric_tutorial/ZZX_symm.svg | 121 ++ .../symmetric_tutorial/anotherfusiontree.svg | 176 +++ .../img/symmetric_tutorial/bosonham.svg | 243 ++++ .../img/symmetric_tutorial/bosonops.svg | 372 +++++ .../symmetric_tutorial/fZ2_fusiontrees.svg | 389 ++++++ .../img/symmetric_tutorial/fermioncomm.svg | 121 ++ .../img/symmetric_tutorial/fermionham.svg | 381 +++++ .../img/symmetric_tutorial/fermionham_bis.svg | 243 ++++ .../img/symmetric_tutorial/fermionops.svg | 256 ++++ .../img/symmetric_tutorial/fusiontree.svg | 67 + .../img/symmetric_tutorial/none2symm.svg | 242 ++++ .../symmetric_tutorial/symmetric_tensor.svg | 105 ++ .../img/symmetric_tutorial/symmtens.svg | 128 ++ .../img/symmetric_tutorial/wignereckart.svg | 386 ++++++ docs/src/appendix/symmetric_tutorial.md | 1222 +++++++++++++++++ docs/src/lib/tensors.md | 6 + docs/src/man/tutorial.md | 2 +- 26 files changed, 5669 insertions(+), 3 deletions(-) create mode 100644 docs/src/appendix/img/symmetric_tutorial/Fib_fusiontrees.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/SU2_fusiontrees.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/SUN_fusiontrees.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/U1_fusiontrees.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/X.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/Z2_fusiontrees.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/ZZ.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/ZZX_symm.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/anotherfusiontree.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/bosonham.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/bosonops.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/fZ2_fusiontrees.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/fermioncomm.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/fermionham.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/fermionham_bis.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/fermionops.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/fusiontree.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/none2symm.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/symmetric_tensor.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/symmtens.svg create mode 100644 docs/src/appendix/img/symmetric_tutorial/wignereckart.svg create mode 100644 docs/src/appendix/symmetric_tutorial.md diff --git a/docs/Project.toml b/docs/Project.toml index fc67550fd..fb18c307c 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,8 +1,12 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" DocumenterInterLinks = "d12716ef-a0f6-4df4-a9f1-a5a34e75c656" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +SUNRepresentations = "1a50b95c-7aac-476d-a9ce-2bfc675fc617" TensorKit = "07d1fe3e-3e46-537d-9eac-e9e13d0d4cec" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +WignerSymbols = "9f57e263-0b3d-5e2e-b1be-24f2bb48858b" [compat] Documenter = "1" diff --git a/docs/make.jl b/docs/make.jl index 057981577..6432dec46 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -21,16 +21,27 @@ pages = [ "lib/spaces.md", "lib/tensors.md", ], "Index" => ["index/index.md"], - "Appendix" => ["appendix/categories.md"], + "Appendix" => ["appendix/categories.md", "appendix/symmetric_tutorial.md"], ] +mathengine = MathJax3( + Dict( + :loader => Dict("load" => ["[tex]/physics"]), + :tex => Dict( + "inlineMath" => [["\$", "\$"], ["\\(", "\\)"]], + "tags" => "ams", + "packages" => ["base", "ams", "autoload", "physics"] + ) + ) +) + makedocs(; modules = [TensorKit, TensorKitSectors], sitename = "TensorKit.jl", authors = "Jutho Haegeman", warnonly = [:missing_docs, :cross_references], format = Documenter.HTML(; - prettyurls = true, mathengine = MathJax(), assets = ["assets/custom.css"] + prettyurls = true, mathengine, assets = ["assets/custom.css"] ), pages = pages, pagesonly = true, diff --git a/docs/src/appendix/img/symmetric_tutorial/Fib_fusiontrees.svg b/docs/src/appendix/img/symmetric_tutorial/Fib_fusiontrees.svg new file mode 100644 index 000000000..222240a5b --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/Fib_fusiontrees.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/SU2_fusiontrees.svg b/docs/src/appendix/img/symmetric_tutorial/SU2_fusiontrees.svg new file mode 100644 index 000000000..098c5745c --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/SU2_fusiontrees.svg @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/SUN_fusiontrees.svg b/docs/src/appendix/img/symmetric_tutorial/SUN_fusiontrees.svg new file mode 100644 index 000000000..99d8df84f --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/SUN_fusiontrees.svg @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/U1_fusiontrees.svg b/docs/src/appendix/img/symmetric_tutorial/U1_fusiontrees.svg new file mode 100644 index 000000000..565d1f142 --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/U1_fusiontrees.svg @@ -0,0 +1,390 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/X.svg b/docs/src/appendix/img/symmetric_tutorial/X.svg new file mode 100644 index 000000000..5ff685a77 --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/X.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/Z2_fusiontrees.svg b/docs/src/appendix/img/symmetric_tutorial/Z2_fusiontrees.svg new file mode 100644 index 000000000..3ed78f661 --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/Z2_fusiontrees.svg @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/ZZ.svg b/docs/src/appendix/img/symmetric_tutorial/ZZ.svg new file mode 100644 index 000000000..535ef54e2 --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/ZZ.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/ZZX_symm.svg b/docs/src/appendix/img/symmetric_tutorial/ZZX_symm.svg new file mode 100644 index 000000000..5b8a2e543 --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/ZZX_symm.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/anotherfusiontree.svg b/docs/src/appendix/img/symmetric_tutorial/anotherfusiontree.svg new file mode 100644 index 000000000..b09fc18e1 --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/anotherfusiontree.svg @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/bosonham.svg b/docs/src/appendix/img/symmetric_tutorial/bosonham.svg new file mode 100644 index 000000000..140bc7e25 --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/bosonham.svg @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/bosonops.svg b/docs/src/appendix/img/symmetric_tutorial/bosonops.svg new file mode 100644 index 000000000..fd32324cc --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/bosonops.svg @@ -0,0 +1,372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/fZ2_fusiontrees.svg b/docs/src/appendix/img/symmetric_tutorial/fZ2_fusiontrees.svg new file mode 100644 index 000000000..6f52ad010 --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/fZ2_fusiontrees.svg @@ -0,0 +1,389 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/fermioncomm.svg b/docs/src/appendix/img/symmetric_tutorial/fermioncomm.svg new file mode 100644 index 000000000..94d7fabe4 --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/fermioncomm.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/fermionham.svg b/docs/src/appendix/img/symmetric_tutorial/fermionham.svg new file mode 100644 index 000000000..97095372c --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/fermionham.svg @@ -0,0 +1,381 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/fermionham_bis.svg b/docs/src/appendix/img/symmetric_tutorial/fermionham_bis.svg new file mode 100644 index 000000000..61d755d08 --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/fermionham_bis.svg @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/fermionops.svg b/docs/src/appendix/img/symmetric_tutorial/fermionops.svg new file mode 100644 index 000000000..ec70cfce1 --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/fermionops.svg @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/fusiontree.svg b/docs/src/appendix/img/symmetric_tutorial/fusiontree.svg new file mode 100644 index 000000000..06ec13f3c --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/fusiontree.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/none2symm.svg b/docs/src/appendix/img/symmetric_tutorial/none2symm.svg new file mode 100644 index 000000000..5fcd78e79 --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/none2symm.svg @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/symmetric_tensor.svg b/docs/src/appendix/img/symmetric_tutorial/symmetric_tensor.svg new file mode 100644 index 000000000..a9490062c --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/symmetric_tensor.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/symmtens.svg b/docs/src/appendix/img/symmetric_tutorial/symmtens.svg new file mode 100644 index 000000000..eea9e734b --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/symmtens.svg @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/img/symmetric_tutorial/wignereckart.svg b/docs/src/appendix/img/symmetric_tutorial/wignereckart.svg new file mode 100644 index 000000000..ded5ba28e --- /dev/null +++ b/docs/src/appendix/img/symmetric_tutorial/wignereckart.svg @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md new file mode 100644 index 000000000..50d429bac --- /dev/null +++ b/docs/src/appendix/symmetric_tutorial.md @@ -0,0 +1,1222 @@ +# [A symmetric tensor deep dive: constructing your first tensor map](@id s_symmetric_tutorial) + +In this tutorial, we will demonstrate how to construct specific [`TensorMap`](@ref)s which +are relevant to some common physical systems, with an increasing degree of complexity. We +will assume the reader is somewhat familiar with [the notion of a 'tensor map'](@ref +ss_whatistensor) and has a rough idea of [what it means for a tensor map to be +'symmetric'](@ref ss_symmetries). In going through these examples we aim to provide a +relatively gently introduction to the meaning of [symmetry sectors](@ref ss_sectors) and +[vector spaces](@ref ss_rep) within the context of TensorKit.jl, [how to initialize a +`TensorMap` over a given vector space](@ref ss_tensor_construction) and finally how to +manually set the data of a [symmetric `TensorMap`](@ref ss_tutorial_symmetries). We will +keep our discussion as intuitive and simple as possible, only adding as many technical +details as strictly necessary to understand each example. When considering a different +physical system of interest, you should then be able to adatpt these recipes and the +intuition behind them to your specific problem at hand. + +!!! note + Many of these examples are readily implemented in the + [TensorKitTensors.jl package](https://github.com/QuantumKitHub/TensorKitTensors.jl), in + which case we basically provide a narrated walk-through of the corresponding code. + + +```@example symmetric_tutorial +using LinearAlgebra +using TensorKit +using WignerSymbols +using SUNRepresentations +using Test # for showcase testing +``` + + +## Level 0: The 1-dimensional Ising model + +As the most basic example, we will consider the +[1-dimensional transverse-field Ising model](https://en.wikipedia.org/wiki/Transverse-field_Ising_model), +whose Hamiltonian is given by + +```math +\begin{equation} +\label{eq:isingham} +H = -J \left (\sum_{\langle i, j \rangle} Z_i Z_j + g \sum_{i} X_i\right). +\end{equation} +``` + +Here, $X_i$ and $Z_i$ are the +[Pauli operators](https://en.wikipedia.org/wiki/Pauli_matrices) acting on site $i$, and the +first sum runs over pairs of nearest neighbors $\langle i, j \rangle$. This model has a +global $\mathbb{Z}_2$ symmetry, as it is invariant under the transformation $U H U^\dagger = +H$ where the symmetry transformation $U$ is given by a global spin flip, + +```math +\begin{equation} +\label{eq:z2gen} +U = \prod_i X_i. +\end{equation} +``` + +We will circle back to the implications of this symmetry later. + +As a warmup we will implement the Hamiltonian \eqref{eq:isingham} in the standard way by +encoding the matrix elements of the single-site operators $X$ and $Z$ into an array of +complex numbers, and then combine them in a suitable way to get the Hamiltonian terms. +Instead of using plain Julia arrays, we will use a representation in terms of `TensorMap`s +over complex vector spaces. These will essentially just be wrappers around base arrays at +this point, but their construction requires some consideration of the notion of *spaces*, +which generalize the notion of `size` for arrays. Each of the operators $X$ and $Z$ acts on +a local 2-dimensional complex vector space. In the context of TensorKit.jl such a space can +be represented as `ComplexSpace(2)`, or using the convenient shorthand `ℂ^2`. A single-site +Pauli operator maps from a domain physical space to a codomain physical space, and can +therefore be represented as instances of a `TensorMap(..., ℂ^2 ← ℂ^2)`. The corresponding +data can then be filled in by hand according to the familiar Pauli matrices in the following +way: + +```@example symmetric_tutorial +# initialize numerical data for Pauli matrices +x_mat = ComplexF64[0 1; 1 0] +z_mat = ComplexF64[1 0; 0 -1] + +# construct physical Hilbert space +V = ℂ^2 + +# construct the physical operators as TensorMaps +X = TensorMap(x_mat, V ← V) +Z = TensorMap(z_mat, V ← V) + +# combine single-site operators into two-site operator +ZZ = Z ⊗ Z; +``` + +We can easily verify that our operators have the desired form by checking their data in the +computational basis. We can print this data by calling the [`blocks`](@ref) method (we'll +explain exactly what these 'blocks' are further down): + +```@example symmetric_tutorial +blocks(ZZ) +``` + +```@example symmetric_tutorial +blocks(X) +``` + +## Level 1: The $\mathbb{Z}_2$-symmetric Ising model + +### The irrep basis and block sparsity + +Let us now return to the global $\mathbb{Z}_2$ invariance of the Hamiltonian +\eqref{eq:isingham}, and consider what this implies for its local terms $ZZ$ and $X$. +Representing these operators as `TensorMap`s, the invariance of $H$ under a global +$\mathbb{Z}_2$ transformation implies the following identities for the local tensors: + +```@raw html +
ZZX_symm
+``` + +These identitities precisely mean that these local tensors transform trivially under a +tensor product representation of $\mathbb{Z}_2$. This implies that, recalling [the +introduction on symmetries](@ref ss_symmetries), in an appropriate basis +for the local physical vector space, our local tensors would become block-diagonal where +each so-called *matrix block* is labeled by a $\mathbb{Z}_2$ irrep.The appropriate local basis transformation is precisely the one that brings the local representation $X$ into block-diagonal form. Clearly, this transformation is nothing more than the Hadamard transformation which maps the computational basis of $Z$ eigenstates $\{\ket{\uparrow}, \ket{\downarrow}\}$ to that of the $X$ +eigenstates $\{\ket{+}, \ket{-}\}$ defined as $\ket{+} = \frac{\ket{\uparrow} + +\ket{\downarrow}}{\sqrt{2}}$ and $\ket{-} = \frac{\ket{\uparrow} - +\ket{\downarrow}}{\sqrt{2}}$. In the current context, this basis is referred to as the +*irrep basis* of $\mathbb{Z}_2$, since each basis state corresponds to a one-dimensional +irreducible representation of $\mathbb{Z}_2$. Indeed, the local symmetry transformation $X$ +acts trivially on the state $\ket{+}$, corresponding to the *trivial irrep*, and yields a +minus sign when acting on $\ket{-}$, corresponding to the *sign irrep*. + +Next, let's make the statement that 'the matrix blocks of the local tensors are labeled by +$\mathbb{Z}_2$ irreps' more concrete. To this end, consider the action of $ZZ$ in the irrep +basis, which is given by the four nonzero matrix elements + +```math +\begin{align} +\label{eq:zz_matel} +ZZ : \mathbb C^2 \otimes \mathbb C^2 &\to \mathbb C^2 \otimes \mathbb C^2 : \\ +\ket{+} \otimes \ket{+} &\mapsto \ket{-} \otimes \ket{-}, \nonumber \\ +\ket{+} \otimes \ket{-} &\mapsto \ket{-} \otimes \ket{+}, \nonumber \\ +\ket{-} \otimes \ket{+} &\mapsto \ket{+} \otimes \ket{-}, \nonumber \\ +\ket{-} \otimes \ket{-} &\mapsto \ket{+} \otimes \ket{+}. \nonumber \\ +\end{align} +``` + +We will denote the trivial $\mathbb{Z}_2$ irrep by $'0'$, corresponding to a local $\ket{+}$ +state, and the sign irrep by $'1'$, corresponding to a local $\ket{-}$ state. Given this +identification, we can naturally associate the tensor product of basis vectors in the irrep +basis to the tensor product of the corresponding $\mathbb{Z}_2$ irreps. One of the key +questions of the [representation theory of groups](representation_theory) is how the tensor +product of two irreps can be decomposed into a direct sum of irreps. This decomposition is +encoded in what are often called the +[*fusion rules*](https://en.wikipedia.org/wiki/Fusion_rules), +```math +a \otimes b \cong \bigoplus_c N_c^{ab} c, +``` +where $N_{ab}^c$ encodes the number of times the irrep $c$ occurs in the tensor product of +irreps $a$ and $b$. These fusion rules are called *Abelian* if the tensor product of any two +irreps corresponds to exactly one irrep. We will return to the implications of *non-Abelian* +fusion rules [later](@ref ss_non_abelian). For the case of the $\mathbb{Z}_2$ irreps, the fusion +rules are Abelian, and are given by addition modulo 2, +```math +0 \otimes 0 \cong 0, \quad 0 \otimes 1 \cong 1, \quad 1 \otimes 0 \cong 1, \quad 1 \otimes 1 \cong 0. +``` +To see how these fusion rules arise, we can consider the action of the symmetry +transformation $XX$ on the possible two-site basis states, each of which corresponds to a +tensor product of representations. We can see that $XX$ acts trivially on both $\ket{+} +\otimes \ket{+}$ and $\ket{-} \otimes \ket{-}$ meaning these transform under the trivial +representation, which gives the first and last entries of the fusion rules. Similarly, $XX$ +acts with a minus sign on both $\ket{+} \otimes \ket{-}$ and $\ket{-} \otimes \ket{+}$, +meaning these transform under the sign representation, which gives the second and third +entries of the fusion rules. Having introduced this notion of 'fusing' irreps, we can now +associate associate a well-defined *coupled irrep* to each of the four two-site basis +states, which is given by the tensor product of the two *uncoupled irreps* associated to +each individual site. From the matrix elements of $ZZ$ given above, we clearly see that this +operator only maps between states in the domain and codomain that have the same coupled +irrep. This means that we can associate each of these matrix elements to a so-called *fusion +tree* of $\mathbb{Z}_2$ irreps with a corresponding coefficient of 1, +```@raw html +
Z2_fusiontrees
+``` +This diagram should be read from top to bottom, where it represents the fusion of the two +uncoupled irreps in the domain to the coupled irrep on the middle line, and the splitting of +this coupled irrep to the uncoupled irreps in the codomain. From this our previous statement +becomes very clear: the $ZZ$ operator indeed consists of two distinct two-dimensional +matrix blocks, each of which are labeled by the value of the *coupled irrep* on the middle +line of each fusion tree. The first block corresponds to the even coupled irrep '0', and +acts within the two-dimensional subspace spanned by $\{\ket{+,+}, \ket{-,-}\}$, while the +second block corresponds to the odd coupled irrep '1', and acts within the two-dimensional +subspace spanned by $\{\ket{+,-}, \ket{-,+}\}$. In TensorKit.jl, this block-diagonal +structure of a symmetric tensor is explicitly encoded into its representation as a +`TensorMap`, where only the matrix blocks corresponding to each coupled irrep are stored. +These matrix blocks associated to each coupled irrep are precisely what is accessed by the +[`blocks`](@ref) method we have already used above. + +For our current purposes however, *we never really need to explicitly consider these matrix +blocks*. Indeed, when constructing a `TensorMap` it is sufficient to set its data by +manually assigning a matrix element to each [fusion tree of the form above](Z2_fusiontrees) +labeled by a given tensor product of irreps. This matrix element is then automatically +inserted into the appropriate matrix block. So, for the purpose of this tutorial **we will +interpret a symmetric `TensorMap` simply as a list of fusion trees, to each of which +corresponds a certain reduced matrix element**. In TensorKit.jl, these reduced tensor +elements corresponding to the fusion trees of a `TensorMap` can be accessed through the +[`subblocks`](@ref) method. + +!!! note + In general, such a reduced matrix element is not necessarily a scalar, but rather an array + whose size is determined by the degeneracy of the irreps in the codomain and domain of the + fusion tree. For this reason, a reduced matrix element associated to a given fusion tree is + also referred to as an *array block*. In the following we will use terms 'reduced matrix + element', 'array block' or just 'block' interchangeably. However, it should be remembered + that these are distinct from the matrix blocks in the block-diagonal decomposition of the + tensor. + + +### [Fusion trees and how to use them](@id sss_fusion_trees) + +This view of the underlying symmetry structure in terms of fusion trees and corresponding +array blocks is a very convenient way of working with the `TensorMap` type. Consider a +generic fusion tree of the form + +```@raw html +
fusiontree
+``` + +which can be used to label a block of a `TensorMap` corresponding to a two-site operator. +This object should actually be seen as a *pair of fusion trees*. The first member of the +pair, related to the codomain of the `TensorMap`, is referred to as the *splitting tree* and +encodes how the *coupled charge* $c$ splits into the *uncoupled charges* $s_1$ and $s_2$. +The second member of the pair, related to the domain of the `TensorMap`, is referred to as +the *fusion tree* and encodes how the uncoupled charges $f_1$ and $f_2$ fuse to the coupled +charge $c$. Both the splitting and fusion tree can be represented as a [`FusionTree`](@ref) +instance. You will find such a `FusionTree` has the following properties encoded into its +fields: + +- `uncoupled::NTuple{N,I}`: a list of `N` uncoupled charges of type `I<:Sector` +- `coupled::I`: a single coupled charge of type `I<:Sector` +- `isdual::NTuple{N,Bool}`: a list of booleans indicating whether the corresponding uncoupled charge is dual +- `innerlines::NTuple{M,I}`: a list of inner lines of type `I<:Sector` of length `M = N - 2` +- `vertices::NTuple{L,T}`: list of fusion vertex labels of type `T` and length `L = N - 1` + +For our current application only `uncoupled` and `coupled` are relevant, since +$\mathbb{Z}_2$ irreps are self-dual and have Abelian fusion rules. We will come back to +these other properties when discussion more involved applications. Given some `TensorMap`, +the method `TensorKit.fusiontrees(t::TensorMap)` returns an iterator over all pairs of +splitting and fusion trees that label the blocks of `t`. + +We can now put this into practice by directly constructing the $ZZ$ operator in the irrep +basis as a $\mathbb{Z}_2$-symmetric `TensorMap`. We will do this in three steps: + +- First we construct the physical space at each site as a $\mathbb{Z}_2$-graded vector space. +- Then we initialize an empty `TensorMap` with the correct domain and codomain vector spaces built from the previously constructed physical space. +- And finally we iterate over all splitting and fusion tree pairs and manually fill in the corresponding nonzero blocks of the operator. + +After the basis transform to the irrep basis, we can view the two-dimensional complex +physical vector space we started with as being spanned by the trivial and sign irrep of +$\mathbb{Z}_2$. In the language of TensorKit.jl, this can be implemented as a `Z2Space`, an +alias for a +$\mathbb{Z}_2$-[graded vector space](@ref GradedSpace) +`Vect[Z2Irrep]`, which contains the trivial irrep `Z2Irrep(0)` with degeneracy 1 and the +sign irrep `Z2Irrep(1)` with degeneracy 1. We can define this space in the following way and +check its dimension: + +```@example symmetric_tutorial +V = Z2Space(0 => 1, 1 => 1) +dim(V) +``` + +Given this physical space, we can initialize the $ZZ$ operator as an empty `TensorMap` with +the appropriate structure. +```@example symmetric_tutorial +ZZ = zeros(ComplexF64, V ⊗ V ← V ⊗ V) +``` +To assess the underlying structure of a symmetric tensor, it is often useful to inspect its +[`subblocks`](@ref subblocks), +```@example symmetric_tutorial +subblocks(ZZ) +``` +While all entries are zero, we see that all eight valid fusion trees with two incoming +irreps and two outgoing irreps [of the type above](fusiontree) are listed with their +corresponding block data. Each of these blocks is an array of shape $(1, 1, 1, 1)$ since +each irrep occuring in the space $V$ has degeneracy 1. Using the [`fusiontrees`](@ref) method and +the fact that we can index a `TensorMap` using a splitting/fusion tree pair, we can now fill +in the nonzero blocks of the operator by observing that the $ZZ$ operator flips the irreps +of the uncoupled charges in the domain with respect to the codomain, as shown in the +diagrams above. Flipping a given `Z2Irrep` in the codomain can be implemented by fusing them +with the sign irrep `Z2Irrep(1)`, giving: + +```@example symmetric_tutorial +flip_charge(charge::Z2Irrep) = only(charge ⊗ Z2Irrep(1)) +for (s, f) in fusiontrees(ZZ) + if s.uncoupled == map(flip_charge, f.uncoupled) + ZZ[s, f] .= 1 + end +end +subblocks(ZZ) +``` + +Indeed, the resulting `TensorMap` exactly encodes the matrix elements of the $ZZ$ operator +shown in [the diagrams above](Z2_fusiontrees). The $X$ operator can be constructed in +a similar way. Since it is by definition diagonal in the irrep basis with blocks directly +corresponding to the trivial and sign irrep, its construction is particularly simple: + +```@example symmetric_tutorial +X = zeros(ComplexF64, V ← V) +for (s, f) in fusiontrees(X) + if only(f.uncoupled) == Z2Irrep(0) + X[s, f] .= 1 + else + X[s, f] .= -1 + end +end +subblocks(X) +``` + +Given these local operators, we can use them to construct the full manifestly +$\mathbb{Z}_2$-symmetric Hamiltonian. + +!!! note + An important observation is that when explicitly imposing the $\mathbb{Z}_2$ symmetry we + directly constructed the full $ZZ$ operator as a single symmetric tensor. This in contrast + to the case without symmetries, where we constructed a single-site $Z$ operator and then + combined them into a two-site operator. Clearly this can no longer be done when imposing + $\mathbb{Z}_2$, since a single $Z$ is not invariant under conjugation with the symmetry + operator $X$. One might wonder whether it is still possible to construct a two-site + Hamiltonian term by combining local objects. This is possible if one introduces an auxiliary + index on the local tensors that carries a non-trivial charge. The intuition behind this will + become more clear in the next example. + + +## Level 2: The $\mathrm{U}(1)$ Bose-Hubbard model + +For our next example we will consider the +[Bose-Hubbard model](https://en.wikipedia.org/wiki/Bose%E2%80%93Hubbard_model), which +describes interacting bosons on a lattice. The Hamiltonian of this model is given by +```math +\begin{equation} +\label{eq:bhh} +H = -t \sum_{\langle i,j \rangle} \left( a_{i}^+ a_{j}^- + a_{i}^- a_{j}^+ \right) - \mu \sum_i N_i + \frac{U}{2} \sum_i N_i(N_i - 1). +\end{equation} +``` +This Hamiltonian is defined on the [Fock space](https://en.wikipedia.org/wiki/Fock_space) associated to a chain of bosons, +where the action bosonic creation, annihilation and number operators $a^+$, $a^-$ and $N = +a^+ a^-$ in the local occupation number basis is given by +```math +\begin{align} +\label{eq:bosonopmatel} +a^+ \ket{n} &= \sqrt{n + 1} \ket{n + 1} \\ +a^- \ket{n} &= \sqrt{n} \ket{n - 1} \nonumber \\ +N \ket{n} &= n \ket{n} \nonumber +\end{align} +``` +Their bosonic nature can be summarized by the familiar the commutation relations +```math +\begin{align*} +\left[a_i^-, a_j^-\right] &= \left[a_i^+, a_j^+\right] = 0 \\ +\left[a_i^-, a_j^+\right] &= \delta_{ij} \\ +\left[N, a^+\right] &= a^+ \\ +\left[N, a^-\right] &= -a^- \\ +\end{align*} +``` + +This Hamiltonian is invariant under conjugation by the global particle number operator, $U H +U^\dagger = H$, where +```math +U = \sum_i N_i +``` +This invariance corresponds to a $\mathrm{U}(1)$ particle number symmetry, which can again +be manifestly imposed when constructing the Hamiltonian terms as `TensorMap`s. From the +representation theory of $\mathrm{U}(1)$ we know that it's irreps are all one-dimensional +and can be labeled by integers $n$ where the tensor product of two irreps is corresponds to +addition of these labels, giving the Abelian fusion rules +```math +n_1 \otimes n_2 \cong (n_1 + n_2). +``` + + +### Directly constructing the Hamiltonian terms + +We recall from our discussion on the $\mathbb{Z}_2$ symmetric Ising model that, in order to +construct the Hamiltonian terms as symmetric tensors, we should work in the irrep basis +where the symmetry transformation is block diagonal. In the current case, the symmetry +operation is the particle number operator, which is already diagonal in the occupation +number basis. Therefore, we don't need an additional local basis transformation this time, +and can just observe that each local basis state can be identified with the $\mathrm{U}(1)$ +irrep associated to the corresponding occupation number. + +Following the same approach as before, we first write down the action of the Hamiltonian +terms in the irrep basis: + +```math +\begin{align*} +a_i^+ a_j^- \ket{n_i, n_j} &= \sqrt{(n_i + 1)n_j} \ket{n_i + 1, n_j - 1} \\ +a_i^- a_j^+ \ket{n_i, n_j} &= \sqrt{n_i(n_j + 1)} \ket{n_i - 1, n_j + 1} \\ +N \ket{n} &= n \ket{n} +\end{align*} +``` + +It is then a simple observation that these matrix elements are exactly captured by the +following $\mathrm{U}(1)$ fusion trees with corresponding block values: + +```@raw html +
U1_fusiontrees
+``` + +This gives us all the information necessary to construct the corresponding `TensorMap`s. We +follow the same steps as outlined in the previous example, starting with the construction of +the physical space. This will now be a $\mathrm{U}(1)$ graded vector space `U1Space`, where +each basis state $\ket{n}$ in the occupation number basis is represented by the +corresponding $\mathrm{U}(1)$ irrep `U1Irrep(n)` with degeneracy 1. While this physical +space is in principle infinite dimensional, we will impose a cutoff in occupation number at +a maximum of 5 bosons per site, giving a 6-dimensional vector space: + +```@example symmetric_tutorial +cutoff = 5 +V = U1Space(n => 1 for n in 0:cutoff) +``` + +We can now initialize the $a^+ a^-$, $a^- a^+$ and $N$ operators as empty `TensorMap`s with +the correct domain and codomain vector spaces, and fill in the nonzero blocks associated to +[the fusion trees shown above](U1_fusiontrees). To do this we need access to the integer +label of the $\mathrm{U}(1)$ irreps in the fusion and splitting trees, which can be accessed +through the `charge` field of the `U1Irrep` type. + +```@example symmetric_tutorial +a⁺a⁻ = zeros(ComplexF64, V ⊗ V ← V ⊗ V) +for (s, f) in fusiontrees(a⁺a⁻) + if s.uncoupled[1] == only(f.uncoupled[1] ⊗ U1Irrep(1)) && s.uncoupled[2] == only(f.uncoupled[2] ⊗ U1Irrep(-1)) + a⁺a⁻[s, f] .= sqrt(s.uncoupled[1].charge * f.uncoupled[2].charge) + end +end +a⁺a⁻ +``` + +```@example symmetric_tutorial +a⁻a⁺ = zeros(ComplexF64, V ⊗ V ← V ⊗ V) +for (s, f) in fusiontrees(a⁻a⁺) + if s.uncoupled[1] == only(f.uncoupled[1] ⊗ U1Irrep(-1)) && s.uncoupled[2] == only(f.uncoupled[2] ⊗ U1Irrep(1)) + a⁻a⁺[s, f] .= sqrt(f.uncoupled[1].charge * s.uncoupled[2].charge) + end +end +a⁻a⁺ +``` + +```@example symmetric_tutorial +N = zeros(ComplexF64, V ← V) +for (s, f) in fusiontrees(N) + N[s, f] .= f.uncoupled[1].charge +end +N +``` + +By inspecting the `subblocks` of each of these tensors you can directly verify that they +each have the correct reduced tensor elements. + + +### Creation and annihilation operators as symmetric tensors + +Just as in the $\mathbb{Z}_2$ case, it is obvious that we cannot directly construct the +creation and annihilation operators as instances of a `TensorMap(..., V ← V)` since they are +not invariant under conjugation by the symmetry operator. However, it is possible to +construct them as `TensorMap`s using an *auxiliary vector space*, based on the following +intuition. The creation operator $a^+$ violates particle number conservation by mapping the +occupation number $n$ to $n + 1$. From the point of view of representation theory, this +process can be thought of as the *fusion* of an `U1Irrep(n)` with an `U1Irrep(1)`, naturally +giving the fusion product `U1Irrep(n + 1)`. This means we can represent $a^+$ as a +`TensorMap(..., V ← V ⊗ A)`, where the auxiliary vector space `A` contains the $+1$ irrep +with degeneracy 1, `A = U1Space(1 => 1)`. Similarly, the decrease in occupation number when +acting with $a^-$ can be thought of as the *splitting* of an `U1Irrep(n)` into an +`U1Irrep(n - 1)` and an `U1Irrep(1)`, leading to a representation in terms of a +`TensorMap(..., A ⊗ V ← V)`. Based on these observations, we can represent the matrix +elements {eq}`eq:bosonopmatel` as blocks labeled by the $\mathrm{U}(1)$ fusion trees + +```@raw html +
bosonops
+``` + +We can then combine these operators to get the appropriate Hamiltonian terms, + +```@raw html +
bosonham
+``` + +!!! note + Although we have made a suggestive distinction between the 'left' and 'right' versions of + the operators $a_L^\pm$ and $a_R^\pm$, one can actually be obtained from the other by + permuting the physical and auxiliary indices of the corresponding `TensorMap`s. This + permutation has no effect on the actual array blocks of the tensors due to the bosonic + [`BraidingStyle`](@ref) of $\mathrm{U}(1)$ irreps, so the left and right operators can + in essence be seen as the 'same' tensors. This is no longer the case when considering + fermionic systems, where permuting indices can in fact change the array blocks as we will + see next. As a consequence, it is much less clear how to construct two-site symmetric + operators in terms of local symmetric objects. + +The explicit construction then looks something like + +```@example symmetric_tutorial +A = U1Space(1 => 1) +``` + +```@example symmetric_tutorial +a⁺ = zeros(ComplexF64, V ← V ⊗ A) +for (s, f) in fusiontrees(a⁺) + a⁺[s, f] .= sqrt(f.uncoupled[1].charge+1) +end +a⁺ +``` + +```@example symmetric_tutorial +a⁻ = zeros(ComplexF64, A ⊗ V ← V) +for (s, f) in fusiontrees(a⁻) + a⁻[s, f] .= sqrt(f.uncoupled[1].charge) +end +a⁻ +``` + +It is then simple to check that this is indeed what we expect. +```@example symmetric_tutorial +@tensor a⁺a⁻_bis[-1 -2; -3 -4] := a⁺[-1; -3 1] * a⁻[1 -2; -4] +@tensor a⁻a⁺_bis[-1 -2; -3 -4] := a⁻[1 -1; -3] * a⁺[-2; -4 1] +@tensor N_bis[-1 ; -2] := a⁺[-1; 1 2] * a⁻[2 1; -2] + +@test a⁺a⁻_bis ≈ a⁺a⁻ atol=1e-14 +@test a⁻a⁺_bis ≈ a⁻a⁺ atol=1e-14 +@test N_bis ≈ N atol=1e-14 +``` + +!!! note + From the construction of the Hamiltonian operators + [in terms of creation and annihilation operators](bosonham) we clearly see that they are + invariant under a transformation $a^\pm \to e^{\pm i\theta} a^\pm$. More generally, any + invertible transformation on the auxiliary space leaves the resulting contraction unchanged. + This ambiguity in the definition clearly shows that one should really always think in terms + of the fully symmetric procucts of $a^+$ and $a^-$ rather than in terms of these operators + themselves. In particular, one can always decompose such a symmetric product into the + [form above](bosonham) by means of an SVD. + + +## Level 3: Fermions and the Kitaev model + +While we have already covered quite a lot of ground towards understanding symmetric tensors +in terms of fusion trees and corresponding blocks, the symmetries considered so far have +been quite 'simple' in the sense that sectors corresponding to irreps of $\mathbb{Z}_2$ and +$\mathrm{U}(1)$ have [*Abelian fusion rules*](@ref FusionStyle) and +[*bosonic exchange statistics*](@ref BraidingStyle). +This means that the fusion of two irreps always gives a single irrep as the fusion product, +and that exchanging two irreps in a tensor product is trivial. In practice, this implies +that for tensors with these symmetries the fusion trees are completely fixed by the +uncoupled charges, which uniquely define both the inner lines and the coupled charge, and +that tensor indices can be permuted freely without any 'strange' side effects. + +In the following we will consider examples with fermionic and even anyonic exchange +statistics, and non-Abelian fusion rules. In going through these examples it will become +clear that the fusion trees labeling the blocks of a symmetric tensor imply more information +than just a labeling. + + +### Fermion parity symmetry + +As a simple example we will consider the Kitaev chain, which describes a chain of +interacting spinless fermions with nearest-neighbor hopping and pairing terms. The +Hamiltonian of this model is given by +```math +\begin{equation} +\label{eq:kitaev} +H = \sum_{\langle i,j \rangle} \left(-\frac{t}{2}(c_i^+ c_j^- - c_i^- c_j^+) + \frac{\Delta}{2}(c_i^+ c_j^+ - c_i^- c_j^-) \right) - \mu \sum_{i} N_i +\end{equation} +``` +where $N_i = c_i^+ c_i^-$ is the local particle number operator. As opposed to the previous +case, the fermionic creation and annihilation operators now satisfy the anticommutation +relations +```math +\begin{align*} +\left\{c_i^-, c_j^-\right\} &= \left\{c_i^+, c_j^+\right\} = 0 \\ +\left\{c_i^-, c_j^+\right\} &= \delta_{ij} .\\ +\end{align*} +``` +These relations justify the choice of the relative minus sign in the hopping and pairing +terms. Indeed, since fermionic operators on different sites always anticommute, these +relative minus signs are needed to ensure that the Hamiltonian is Hermitian, since $\left( +c_i^+ c_j^- \right)^\dagger = c_j^+ c_i^- = - c_i^- c_j^+$ and $\left( c_i^+ c_j^+ +\right)^\dagger = c_j^- c_i^- = - c_i^- c_j^-$. The anticommutation relations also naturally +restrict the local occupation number to be 0 or 1, leading to a well-defined notion of +*fermion-parity*. The local fermion-parity operator is related to the fermion number +operator as $Q_i = (-1)^{N_i}$, and is diagonal in the occupation number basis. The +Hamiltonian {eq}`eq:kitaev` is invariant under conjugation by the global fermion-parity +operator, $Q H Q^\dagger = H$, where +```math +Q = \exp \left( i \pi \sum_i N_i \right) = (-1)^{\sum_i N_i}. +``` +This fermion parity symmetry, which we will denote as $f\mathbb{Z}_2$, is a +$\mathbb{Z}_2$-like symmetry in the sense that it has a trivial representation, which we +call *even* and again denote by '0', and a sign representation which we call *odd* and +denote by '1'. The fusion rules of these irreps are the same as for $\mathbb{Z}_2$. Similar +to the previous case, the local symmetry operator $Q_i$ is already diagonal, so the +occupation number basis coincides with the irrep basis and we don't need an additional basis +transform. The important difference with a regular $\mathbb{Z}_2$ symmetry is that the +irreps of $f\mathbb{Z}_2$ have fermionic braiding statistics, in the sense that exhanging +two odd irreps gives rise to a minus sign. + +In TensorKit.jl, an $f\mathbb{Z}_2$-graded vector spaces is represented as a +`Vect[FermionParity]` space, where a given $f\mathbb{Z}_2$ irrep can be represented as a +[`FermionParity`](@ref FermionParity) +sector instance. Using the simplest instance of a vector space containing a single even and +odd irrep, we can already demonstrate the corresponding fermionic braiding behavior by +[performing a permutation](@ref TensorKit.permute) +on a simple `TensorMap`. + +```@example symmetric_tutorial +V = Vect[FermionParity](0 => 1, 1 => 1) +t = ones(ComplexF64, V ← V ⊗ V) +subblocks(t) +``` + +```@example symmetric_tutorial +tp = permute(t, ((1,), (3, 2))) +subblocks(tp) +``` +In other words, when exchanging the two domain vector spaces, the block of the `TensorMap` +for which both corresponding irreps are odd picks up a minus sign, exactly as we would +expect for fermionic charges. + + +### Constructing the Hamiltonian + +We can directly construct the Hamiltonian terms as symmetric `TensorMap`s using the same +procedure as before starting from their matrix elements in the occupation number basis. +However, in this case we should be a bit more careful about the precise definition of the +basis states in composite systems. Indeed, the tensor product structure of fermionic systems +is inherently tricky to deal with, and should ideally be treated in the context of +[*super vector spaces*](https://en.wikipedia.org/wiki/Super_vector_space). For two sites, we +can define the following basis states on top of the fermionic vacuuum $\ket{00}$: +```math +\begin{align*} +\ket{01} &= c_2^+ \ket{00}, \\ +\ket{10} &= c_1^+ \ket{00}, \\ +\ket{11} &= c_1^+ c_2^+ \ket{00}. \\ +\end{align*} +``` +This definition in combination with the anticommutation relations above give rise to the +nonzero matrix elements +```math +\begin{align*} +c_1^+ c_2^- \ket{0, 1} &= \ket{1, 0}, \\ +c_1^- c_2^+ \ket{1, 0} &= - \ket{0, 1}, \\ +c_1^+ c_2^+ \ket{0, 0} &= \ket{1, 1}, \\ +c_1^- c_2^- \ket{1, 1} &= - \ket{0, 0}, \\ +N \ket{n} &= n \ket{n}. +\end{align*} +``` +While the signs in these expressions may seem a little unintuitive at first sight, they are +essential to the fermionic nature of the system. Indeed, if we for example work out the +matrix element of $c_1^- c_2^+$ we find +```math +\begin{align*} +c_1^- c_2^+ \ket{1, 0} = c_1^- c_2^+ c_1^+ \ket{0, 0} = - c_2^+ c_1^- c_1^+ \ket{0, 0} = - c_2^+ (\mathbb{1} - c_1^+ c_1^-) \ket{0, 0} = - c_2^+ \ket{0, 0} = - \ket{0, 1}. \\ +\end{align*} +``` + +Once we have these matrix elements the hard part is done, and we can straightforwardly +associate these to the following $f\mathbb{Z}_2$ fusion trees with corresponding block +values, + +```@raw html +
fZ2_fusiontrees
+``` + +Given this information, we can go through the same procedure again to construct $c^+ c^-$, +$c^- c^+$ and $N$ operators as `TensorMap`s over $f\mathbb{Z}_2$-graded vector spaces. + +```@example symmetric_tutorial +V = Vect[FermionParity](0 => 1, 1 => 1) +``` + +```@example symmetric_tutorial +c⁺c⁻ = zeros(ComplexF64, V ⊗ V ← V ⊗ V) +odd = FermionParity(1) +for (s, f) in fusiontrees(c⁺c⁻) + if s.uncoupled[1] == odd && f.uncoupled[2] == odd && f.coupled == odd + c⁺c⁻[s, f] .= 1 + end +end +c⁺c⁻ +``` + +```@example symmetric_tutorial +c⁻c⁺ = zeros(ComplexF64, V ⊗ V ← V ⊗ V) +for (s, f) in fusiontrees(c⁻c⁺) + if f.uncoupled[1] == odd && s.uncoupled[2] == odd && f.coupled == odd + c⁻c⁺[s, f] .= -1 + end +end +c⁻c⁺ +``` + +```@example symmetric_tutorial +c⁺c⁺ = zeros(ComplexF64, V ⊗ V ← V ⊗ V) +odd = FermionParity(1) +for (s, f) in fusiontrees(c⁺c⁺) + if s.uncoupled[1] == odd && f.uncoupled[1] != odd && f.coupled != odd + c⁺c⁺[s, f] .= 1 + end +end +c⁺c⁺ +``` + +```@example symmetric_tutorial +c⁻c⁻ = zeros(ComplexF64, V ⊗ V ← V ⊗ V) +for (s, f) in fusiontrees(c⁻c⁻) + if s.uncoupled[1] != odd && f.uncoupled[2] == odd && f.coupled != odd + c⁻c⁻[s, f] .= -1 + end +end +c⁻c⁻ +``` + +```@example symmetric_tutorial +N = zeros(ComplexF64, V ← V) +for (s, f) in fusiontrees(N) + N[s, f] .= f.coupled == odd ? 1 : 0 +end +N +``` + +Again, you can easily verify that all the reduced tensor elements are correct by inspecting +the `subblocks` of each tensor. + +!!! note + Working with fermionic systems is inherently tricky, as can already be seen from something + as simple as computing matrix elements of fermionic operators. Similarly, while constructing + symmetric tensors that correspond to the symmetric Hamiltonian terms was still quite + straightforward, it is far less clear in this case how to construct these terms as + contractions of local symmetric tensors representing individual creation and annihilation + operators in this case. While such a decomposition can always be in principle obtained using + a (now explicitly fermionic) SVD, manually constructing such tensors as we did in the + bosonic case is far from trivial. Trying this would be a good exercise in working with + fermionic symmetries, but it is not something we will do here. + + +## [Level 4: Non-Abelian symmetries and the quantum Heisenberg model](@id ss_non_abelian) + +We will now move on to systems which have more complicated *non-Abelian* symmetries. For a +non-Abelian symmetry group $G$, the fact that its elements do not all commute has a profound +impact on its representation theory. In particular, the irreps of such a group can be higher +dimensional, and the fusion of two irreps can give rise to multiple different irreps. On the +one hand this means that fusion trees of these irreps are no longer completely determined by +the uncoupled charges. Indeed, in this case some of the +[internal structure of the `FusionTree` type](@ref sss_fusion_trees) we have ignored before will +become relevant (of which we will give an [example below](@ref sss_sun_heisenberg)). On the other +hand, it follows that fusion trees of irreps now not only label blocks, but also encode a +certain *nontrivial symmetry structure*. We will make this statement more precise in the +following, but the fact that this is necessary is quite intuitive. If we recall our original +statement that symmetric tensors consist of blocks associated to fusion trees which carry +irrep labels, then for higher-dimensional irreps the corresponding fusion trees must encode +some additional information that implicitly takes into account the internal structure of the +representation spaces. In particular, this means that the conversion of an operator, given +its matrix elements in the irrep basis, to the blocks of the corresponding symmetric +`TensorMap` is less straightforward since it requires an understanding of exactly what this +implied internal structure is. Therefore, we require some more discussion before we can +actually move on to an example. + +We'll start by discussing the general structure of a `TensorMap` which is symmetric under a +non-Abelian group symmetry. We then given an example based on $\mathrm{SU}(2)$, where we +construct the Heisenberg Hamiltonian using two different approaches. Finally, we show how +the more intuitive approach can be used to obtain an elegant generalization to the +$\mathrm{SU}(N)$-symmetric case. + + +### Block sparsity revisited: the Wigner-Eckart theorem + +Let us recall some basics of representation theory first. Consider a group $G$ and a +corresponding representation space $V$, such that every element $g \in G$ can be realized as +a unitary operator $U_g : V \to V$. Let $h$ be a `TensorMap` whose domain and codomain are +given by the tensor product of two of these representation spaces. Recall that, by +definition, the statement that '$h$ is symmetric under $G$' means that +```@raw html +
symmetric_tensor
+``` +for every $g \in G$. If we label the irreducible representations of $G$ by $l$, then any +representation space can be decomposed into a direct sum of irreducible representations, $V += \bigoplus_l V^{(l)}$, in such a way that $U_g$ is block-diagonal where each block is +labeled by a particular irrep $l$. For each irrep space $V^{(l)}$ we can define an +orthonormal basis labeled as $\ket{l, m}$, where the auxiliary label $m$ can take +$\text{dim}\left( V^{(l)} \right)$ different values. Since we know that tensors are +multilinear maps over tensor product spaces, it is natural to consider the tensor product of +representation spaces in more detail. + +[From the representation theory of groups](https://en.wikipedia.org/wiki/Tensor_product_of_representations#Clebsch%E2%80%93Gordan_theory), +it is known that the product of two irreps can in turn be decomposed into a direct sum of +irreps, $V^{(l_1)} \otimes V^{(l_2)} \cong \bigoplus_{k} V^{(k)}$. The precise nature of +this decomposition, also refered to as the *Clebsch-Gordan problem*, is given by the +so-called *Clebsch-Gordan coefficients*, which we will denote as $C^{k}_{l_1,l_2}$. This set +of coefficients, which can be interpreted as a $\text{dim}\left( V^{(l_1)} \right) \times +\text{dim}\left( V^{(l_2)} \right) \times \text{dim}\left( V^{(k)} \right)$ array, that +encodes how a basis state $\ket{k,n} \in V^{(k)}$ corresponding to some term in the direct +sum can be decomposed into a linear combination of basis vectors $\ket{l_1,m_1} \otimes +\ket{l_2,m_2}$ of the tensor product space: +```math +\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}. +``` +These recoupling coefficients turn out to be essential to the structure of symmetric +tensors, which can be best understood in the context of the +[Wigner-Eckart theorem](https://en.wikipedia.org/wiki/Wigner%E2%80%93Eckart_theorem). This +theorem implies that for any +[`TensorMap` $h$ that is symmetric under $G$](@ref ss_symmetries), its matrix elements in the +tensor product irrep basis are given by the product of Clebsch-Gordan coefficients which +characterize the coupling of the basis states in the domain and codomain, and a so-called +*reduced matrix element* which only depends on the irrep labels. Concretely, the matrix +element $\bra{l_1,m_1} \otimes \bra{l_2,m_2} h \ket{l_3,m_3} \otimes \ket{l_4,m_4}$ is given +by +```@raw html +
wignereckart
+``` +Here, the sum runs over all possible irreps $k$ in the fusion product $l_3 \otimes l_4$ and +over all basis states $\ket{k,n}$ of $V^{(k)}$. The reduced matrix elements $h_{\text{red}}$ +are independent of the basis state labels and only depend on the irrep labels themselves. +Each reduced matrix element should be interpreted as being labeled by an irrep fusion tree, +```@raw html +
anotherfusiontree
+``` +The fusion tree itself in turn implies the Clebsch-Gordan coefficients $C^{k}_{l_1,l_2}$ and +conjugate coefficients ${C^{\dagger}}_{k}^{l_1,l_2}$ encode the splitting (decomposition) of +the coupled basis state $\ket{k,n}$ to the codomain basis states $\ket{l_1,m_1} \otimes +\ket{l_2,m_2}$ and the coupling of the domain basis states $\ket{l_3,m_3} \otimes +\ket{l_4,m_4}$ to the coupled basis state $\ket{k,n}$ respectively. + +The Wigner-Eckart theorem dictates that this structure in terms of Clebsch-Gordan +coefficients is necessary to ensure that the corresponding tensor is symmetric. It is +precisely this structure that is inherently encoded into the fusion tree part of a symmetric +`TensorMap`. In particular, **the array block value associated to each fusion tree in a +symmetric tensor is precisely the reduced matrix element in the Clebsch-Gordan +decomposition**. + +As a small demonstration of this fact, we can make a simple $\mathrm{SU}(2)$-symmetric +tensor with trivial block values and verify that its implied symmetry structure exactly +corresponds to the expected Clebsch-Gordan coefficient. First, we [recall](su2_irreps) that +the irreps of $\mathrm{SU}(2)$ can be labeled by a halfinteger *spin* that takes values $l = +0, \frac{1}{2}, 1, \frac{3}{2}, ...$, and where the dimension of the spin-$l$ representation +is equal to $2l + 1$. The fusion rules of $\mathrm{SU}(2)$ are given by +```math +l_1 \otimes l_2 \cong \bigoplus_{k=|l_1-l_2|}^{l_1+l_2}s. +``` +These are clearly non-Abelian since multiple terms appear on the right hand side, for +example $\frac{1}{2} \otimes \frac{1}{2} \cong 0 \oplus 1$. In TensorKit.jl, a +$\mathrm{SU}(2)$-graded vector space is represented as an +[`SU2Space`](@ref), +where a given $\mathrm{SU}(2)$ irrep can be represented as an +[`SU2Irrep`](@ref) +instance of integer or halfinteger spin as encoded in its `j` field. If we construct a +`TensorMap` whose symmetry structure corresponds to the coupling of two spin-$\frac{1}{2}$ +irreps to a spin-$1$ irrep, we can then convert it to a plain array and compare it to the +$\mathrm{SU}(2)$ Clebsch-Gordan coefficients exported by the +[WignerSymbols.jl package](https://github.com/Jutho/WignerSymbols.jl). + +```@example symmetric_tutorial +V1 = SU2Space(1 => 1) +V2 = SU2Space(1//2 => 1) +t = ones(ComplexF64, V1 ← V2 ⊗ V2) +``` + +```@example symmetric_tutorial +ta = convert(Array, t) +``` +The conversion gives us a $3 \times 2 \times 2$ array, which exactly corresponds to the size +of the $C_{1}^{\frac{1}{2},\frac{1}{2}}$ Clebsch-Gordan array. In order to explicitly +compare whether the entries match we need to know the ordering of basis states assumed by +TensorKit.jl when converting the tensor to its matrix elements in the irrep basis. For +$\mathrm{SU}(2)$ the irrep basis is ordered in ascending magnetic quantum number $m$, which +gives us a map $m = i - (l+1)$ for mapping an array index to a corresponding magnetic +quantum number for the spin-$l$ irrep. +```@example symmetric_tutorial +for i1 in 1:dim(V1), i2 in 1:dim(V2), i3 in 1:dim(V2) + # map basis state index to magnetic quantum number + m1 = i1 - (1 + 1) + m2 = i2 - (1//2 + 1) + m3 = i3 - (1//2 + 1) + @test ta[i1, i2, i3] ≈ clebschgordan(1//2, m2, 1//2, m3, 1, m1) +end +``` + +Based on this discussion, we can quantify the aforementioned 'difficulties' in the inverse +operation of what we just demonstrated, namely converting a given operator to a symmetric +`TensorMap` given only its matrix elements in the irrep basis. Indeed, it is now clear that +this precisely requires isolating the reduced matrix elements introduced above. Given the +matrix elements of the operator in the irrep basis, this can in general be done by solving +the system of equations implied by the [Clebsch-Gordan decomposition](wignereckart). A +simpler way to achieve the same thing is to make use of the fact that the +[Clebsch-Gordan tensors form a complete orthonormal basis](https://en.wikipedia.org/wiki/Clebsch%E2%80%93Gordan_coefficients#Orthogonality_relations) +on the coupled space. Indeed, by projecting out the appropriate Clebsch-Gordan coefficients +and using their orthogonality relations, we can construct a diagonal operator on each +coupled irrep space $V^{(k)}$. Each of these diagonal operators is proportional to the +identity, where the proportionality factor is precisely the reduced matrix element +associated to the corresponding irrep fusion tree. +```@raw html +
none2symm
+``` + +This procedure works for any group symmetry, and all we need are matrix elements of the +operator in the irrep basis and the Clebsch-Gordan coefficients. In the following we +demonstrate this explicit procedure for the particular example of $G = \mathrm{SU}(2)$. +However, it should be noted that for general groups the Clebsch-Gordan coefficients may not +be as easy to compute (in general, no closed formulas exist). In addition, the procedure for +manually projecting out the reduced matrix elements requires being particularly careful +about the correspondence between the basis states used to define the original matrix +elements and those implied by the Clebsch-Gordan coefficients. Therefore, it is often easier +to directly construct the symmetric tensor based on some representation theory, as we will +see below. + + +### The 'generic' approach to the spin-1 Heisenberg model: Wigner-Eckart in action + +Consider the spin-1 Heisenberg model with Hamiltonian +```math +H = J \sum_{\langle i,j \rangle} \vec{S}_i \cdot \vec{S}_j +``` +where $\vec{S} = (S^x, S^y, S^z)$ are the spin operators. The physical Hilbert space at each +site is the three-dimensional spin-1 irrep of $\mathrm{SU}(2)$. Each two-site exchange +operator $\vec{S}_i \cdot \vec{S}_j$ in the sum commutes with a global transformation $g \in +\mathrm{SU}(2)$, so that it satisfies the [above symmetry condition](symmetric_tensor). +Therefore, we can represent it as an $\mathrm{SU}(2)$-symmetric `TensorMap`, as long as we +can isolate its reduced matrix elements. + +In order to apply the above procedure, we first require the matrix elements in the irrep +basis. These can be constructed as a $3 \times 3 \times 3 \times 3$ array `SS` using the +[familiar representation of the $\mathrm{SU}(2)$ generators in the spin-1 representation](https://en.wikipedia.org/wiki/Spin_(physics)#Higher_spins), +with respect to the $\{\ket{1,-1}, \ket{1,0}, \ket{1,1}\}$ basis. +```@example symmetric_tutorial +Sx = 1 / sqrt(2) * ComplexF64[0 1 0; 1 0 1; 0 1 0] +Sy = 1 / sqrt(2) * ComplexF64[0 1im 0; -1im 0 1im; 0 -1im 0] +Sz = ComplexF64[-1 0 0; 0 0 0; 0 0 1] + +@tensor SS_arr[-1 -2; -3 -4] := Sx[-1; -3] * Sx[-2; -4] + Sy[-1; -3] * Sy[-2; -4] + Sz[-1; -3] * Sz[-2; -4] +nothing #hide +``` + +The next step is to project out the reduced matrix elements by taking the overlap with the +appropriate Clebsch-Gordan coefficients, according to +[the Clebsch-Gordan decomposition given above](none2symm). In our current case of a spin-1 +physical space we have $l_1 = l_2 = l_3 = l_4 = 1$, and the coupled irrep $k$ can therefore +take the values $0, 1, 2$. The reduced matrix element for a given $k$ can then be +implemented in the following way: +```@example symmetric_tutorial +function get_reduced_element(k) + # construct Clebsch-Gordan coefficients for coupling 1 ⊗ 1 to k + CG = zeros(ComplexF64, 3, 3, 2*k + 1) + for m1 in -k:k, m2 in -1:1, m3 in -1:1 + CG[m2 + 2, m3 + 2, m1 + k + 1] = clebschgordan(1, m2, 1, m3, k, m1) + end + + # project out diagonal matrix on coupled irrep space + @tensor reduced_matrix[-1; -2] := CG[1 2; -1] * SS_arr[1 2; 3 4] * conj(CG[3 4; -2]) + + # check that it is proportional to the identity + @assert isapprox(reduced_matrix, reduced_matrix[1, 1] * I; atol=1e-12) + + # return the proportionality factor + return reduced_matrix[1, 1] +end +``` +If we use this to compute the reduced matrix elements for $k = 0, 1, 2$, +```@example symmetric_tutorial +get_reduced_element(0) +``` +```@example symmetric_tutorial +get_reduced_element(1) +``` +```@example symmetric_tutorial +get_reduced_element(2) +``` +we can read off the entries +```math +\renewcommand\thickspace{\kern .01ex} +\left[ (\vec{S}_i \cdot \vec{S}_j)_\text{red} \right] \,\,\!\! +\begin{smallmatrix} + 1,1\\ + 0\\ + 1,1 +\end{smallmatrix} = -2, \quad +\left[ (\vec{S}_i \cdot \vec{S}_j)_\text{red} \right] \,\,\!\! +\begin{smallmatrix} + 1,1\\ + 1\\ + 1,1 +\end{smallmatrix} = -1, \quad +\left[ (\vec{S}_i \cdot \vec{S}_j)_\text{red} \right] \,\,\!\! +\begin{smallmatrix} + 1,1\\ + 2\\ + 1,1 +\end{smallmatrix} = 1, \quad +``` +These can then be used to construct the symmetric `TensorMap` representing the exchange +interaction: +```@example symmetric_tutorial +V = SU2Space(1 => 1) +SS = zeros(ComplexF64, V ⊗ V ← V ⊗ V) +for (s, f) in fusiontrees(SS) + k = Int(f.coupled.j) + SS[s, f] .= get_reduced_element(k) +end +subblocks(SS) +``` + + +### An 'elegant' approach to the Heisenberg model + +As noted above, the explicit procedure of projecting out the reduced matrix elements from +the action of an operator in the irrep basis can be a bit cumbersome for more complicated +groups. However, using some basic representation theory we can bypass this step altogether +for the Heisenberg model. First, we rewrite the exchange interaction in the following way: +```math +\begin{equation} +\label{eq:casimir_decomp} +\vec{S}_i \cdot \vec{S}_j = \frac{1}{2} \left( \left( \vec{S}_i + \vec{S}_j \right)^2 - \vec{S}_i^2 - \vec{S}_j^2 \right) +\end{equation} +``` +Here, $\vec{S}_i$ and $\vec{S}_j$ are spin operators on the physcial irrep, while total spin +operator $\vec{S}_i + \vec{S}_j$ can be decomposed onto the different coupled irreps $k$. It +is a well known fact that the quadratic sum of the generators of $\mathrm{SU}(2)$, often +refered to as the +[*quadratic Casimir*](https://en.wikipedia.org/wiki/Representation_theory_of_SU(2)#The_Casimir_element), +commutes with all generators. By +[Schur's lemma](https://en.wikipedia.org/wiki/Schur%27s_lemma), it must then act +proportionally to the identity on every irrep, where the corresponding eigenvalue is +determined by the spin irrep label. In particular, we have for each irrep $l$ +```math +\vec{S}^2 \ket{l,m} = l(l+1) \ket{l,m}. +``` +It then follows from Eq. {eq}`eq:casimir_decomp` that the reduced matrix elements of the +exchange interaction are completely determined by the eigenvalue of the quadratic Casimir on +the uncoupled and coupled irreps. Indeed, to each fusion tree we can associate a +well-defined value +```@raw html +
SU2_fusiontrees
+``` +This gives us all we need to directly construct the exchange interaction as a symmetric +`TensorMap`, +```@example symmetric_tutorial +V = SU2Space(1 => 1) +SS = zeros(ComplexF64, V ⊗ V ← V ⊗ V) +for (s, f) in fusiontrees(SS) + l3 = f.uncoupled[1].j + l4 = f.uncoupled[2].j + k = f.coupled.j + SS[s, f] .= (k * (k + 1) - l3 * (l3 + 1) - l4 * (l4 + 1)) / 2 +end +subblocks(SS) +``` +which gives exactly the same result as the previous approach. + +!!! note + This last construction for the exchange interaction immediatly generalizes to any value of + the physical spin. All we need is to fill in the appropriate values for the uncoupled irreps + $l_1$, $l_2$, $l_3$ and $l_4$. + + +### [$\mathrm{SU}(N)$ generalization](@id sss_sun_heisenberg) + +We end this subsection with some comments on the generalization of the above discussion to +$\mathrm{SU}(N)$. As foreshadowed above, the irreps of $\mathrm{SU}(N)$ in general have an +even more complicated structure. In particular, they can admit so-called *fusion +multiplicities*, where the fusion of two irreps can have not only multiple distinct +outcomes, but they can even fuse to a given irrep in multiple inequivalent ways. We can +demonstrate this behavior for the adjoint representation of $\mathrm{SU}(3)$. For this we +can use the the +[SUNRepresentations.jl](https://github.com/QuantumKitHub/SUNRepresentations.jl) +package which provides an interface for working with irreps of $\mathrm{SU}(N)$ and their +Clebsch-Gordan coefficients. A particular representation is represented by an `SUNIrrep{N}` +which can be used with TensorKit.jl. The eight-dimensional adjoint representation of +$\mathrm{SU}(3)$ is given by +```@setup symmetric_tutorial +SUNRepresentations.display_mode("dimension") +``` +```@example symmetric_tutorial +l = SU3Irrep("8") +``` +If we look at the possible outcomes of fusing two adjoint irreps, we find the by now +familiar non-Abelian fusion behavior, +```@example symmetric_tutorial +collect(l ⊗ l) +``` +However, this particular fusion has multiplicities, since the adjoint irrep can actually +fuse to itself in two distinct ways. The full decomposition of this fusion product is given +by +```math +\mathbf{8} \otimes \mathbf{8} = \mathbf{1} \oplus \mathbf{3} \oplus 2 \cdot \mathbf{8} \oplus \mathbf{10} \oplus \mathbf{\overline{10}} \oplus \mathbf{27} +``` +This fusion multiplicity can be detected by using +[`Nsymbol`](@ref) +method from TensorKit.jl to inspect the number of times `l` appears in the fusion product +`l ⊗ l`, +```@example symmetric_tutorial +Nsymbol(l, l, l) +``` +When working with irreps with fusion multiplicities, each `FusionTree` carries additional +`vertices` labels which label which of the distinct fusion vertices is being referred to. We +will return to this at the end of this section. + +Given the generators $T^k$ of $\mathrm{SU}(N)$, we can define a generalized Heisenberg model +using a similar exchange interaction, giving the Hamiltonian +```math +H = J \sum_{\langle i,j \rangle} \vec{T}_i \cdot \vec{T}_j +``` +For a particular choice of physical irrep, the exchange interaction can again be constructed +as a symmetric `TensorMap` by first rewriting it as +```math +\vec{T}_i \cdot \vec{T}_j = \frac{1}{2} \left( \left( \vec{T}_i + \vec{T}_j \right)^2 - \vec{T}_i^2 - \vec{T}_j^2 \right). +``` +For any $N$, the [quadratic Casimir](https://en.wikipedia.org/wiki/Casimir_element#Quadratic_Casimir_element) +```math +\Omega = \sum_k T^k T^k +``` +commutes with all $\mathrm{SU}(N)$ generators, meaning it has a well defined eigenvalue in +each irrep. This observation then immediately given the reduced matrix elements of the +exchange interaction as +```@raw html +
SUN_fusiontrees
+``` +Using these to directly construct the corresponding symmetric `TensorMap` is much simpler +than going through the explicit projection procedure using Clebsch-Gordan coefficients. + +For the particular example of $\mathrm{SU}(3)$, the generators are given by $T^k = +\frac{1}{2} \lambda^k$ , where $\lambda^k$ are the +[Gell-Mann matrices](https://en.wikipedia.org/wiki/Clebsch%E2%80%93Gordan_coefficients_for_SU(3)#Generators_of_the_Lie_algebra). +Each irrep can be labeled as $l = D(p,q)$ where $p$ and $q$ are refered to as the *Dynkin +labels*. The eigenvalue of the quadratic Casimir for a given irrep is given by +[Freudenthal's formula](https://en.wikipedia.org/wiki/Weyl_character_formula#Freudenthal's_formula), +```math +\Omega(D(p,q)) = \frac{1}{3} (p^2 + q^2 + 3p + 3q + pq). +``` +Using SUNRepresentations.jl, we can compute the Casimir as +```@example symmetric_tutorial +function casimir(l::SU3Irrep) + p, q = dynkin_label(l) + return (p^2 + q^2 + 3 * p + 3 * q + p * q) / 3 +end +``` +If we use the adjoint representation of $\mathrm{SU}(3)$ as physical space, the Heisenberg +exchange interaction can then be constructed as +```@example symmetric_tutorial +V = Vect[SUNIrrep{3}](SU3Irrep("8") => 1) +TT = zeros(ComplexF64, V ⊗ V ← V ⊗ V) +for (s, f) in fusiontrees(TT) + l3 = f.uncoupled[1] + l4 = f.uncoupled[2] + k = f.coupled + TT[s, f] .= (casimir(k) - casimir(l3) - casimir(l4)) / 2 +end +subblocks(TT) +``` +Circling back to our earlier remark, we clearly see that the fusion trees of this tensor +indeed have non-trivial vertex labels. +```@example symmetric_tutorial +f = collect(fusiontrees(TT))[3][2] +``` +```@example symmetric_tutorial +f.vertices +``` + +!!! note + While we have given an explicit example using $\mathrm{SU}(3)$ with the adoint irrep on the + physical level, the same construction holds for the general $\mathrm{SU}(N)$ with arbitrary + physical irreps. All we require is the expression for the eigenvalues of the quadratic + Casimir in each irrep. + + +## Level 5: Anyonic Symmetries and the Golden Chain + +While we have focussed exclusively on group-like symmetries in our discussion so far, the +framework of symmetric tensors actually extends beyond groups to so-called +[*categorical symmetries*](@ref ss_representationtheory). +These are quite exotic symmetries characterized in terms of +[the topological data of a unitary fusion category](@ref ss_topologicalfusion). +While the precise details of all the terms in these statements fall beyond the scope of this +tutorial, we can give a simple example of a Hamiltonian model with a categorical symmetry +called [the golden chain](https://arxiv.org/abs/cond-mat/0612341). + +This is a one-dimensional system defined as a spin chain, where each physical 'spin' +corresponds to a so-called [Fibonacci anyon](https://arxiv.org/abs/0902.3275). There are two +such Fibonacci anyons, which we will denote as $1$ and $\tau$. They obey the fusion rules +```math +1 \otimes 1 = 1, \quad 1 \otimes \tau = \tau, \quad \tau \otimes \tau = 1 \oplus \tau. +``` +The Hilbert space of a chain of Fibonacci anyons is not a regular tensor product space, but +rather a *constrained Hilbert space* where the only allowed basis states are labeled by +valid Fibonacci fusion configurations. In the golden chain model, we define a +nearest-neighbor Hamiltonian on this Hilbert space by imposing an energy penalty when two +neighboring anyons fuse to a $\tau$ anyon. + +Even just writing down an explicit expression for this interaction on such a constrained +Hilbert space is not entirely straightforward. However, using the framework of symmetric +tensors it can actually be explicitly constructed in a very straightforward way. Indeed, +TensorKit.jl supports a dedicated [`FibonacciAnyon`](@ref) sector type which can be used to +construct precisely such a constrained Fibonacci-graded vector space. A Hamiltonian +```math +H = \sum_{\langle i,j \rangle} h_{ij} +``` +which favors neighboring anyons fusing to the vacuum can be constructed as a `TensorMap` on +the product space of two Fibonacci-graded physical spaces +```@example symmetric_tutorial +V = Vect[FibonacciAnyon](:τ => 1) +``` +and assigning the following nonzero block value to the two-site fusion trees +```@raw html +
Fib_fusiontrees
+``` +This allows us to define this, at first sight, exotic and complicated Hamiltonian in a few +simple lines of code, +```@example symmetric_tutorial +h = ones(V ⊗ V ← V ⊗ V) +for (s, f) in fusiontrees(h) + h[s, f] .= f.coupled == FibonacciAnyon(:I) ? -1 : 0 +end +subblocks(h) +``` + +!!! note + In the previous section we have stressed the role of Clebsch-Gordan coefficients in + the structure of symmetric tensors, and how they can be used to map between the + representation of an operator in the irrep basis and its symmetric tensor representation. + However, for categorical symmetries such as the Fibonacci anyons, there are no + Clebsch-Gordan coefficients. Therefore, the 'matrix elements of the operator in the irrep + basis' are not well-defined, meaning that a Fibonacci-symmetric tensor cannot actually be + converted to a plain array in a meaningful way. + diff --git a/docs/src/lib/tensors.md b/docs/src/lib/tensors.md index 54a67258c..538f5d391 100644 --- a/docs/src/lib/tensors.md +++ b/docs/src/lib/tensors.md @@ -116,6 +116,12 @@ block blocks ``` +To access the reduced tensor elements associated to fusion tree pairs, you can use: +```@docs +subblock +subblocks +``` + To access the data associated with a specific fusion tree pair, you can use: ```@docs Base.getindex(::AbstractTensorMap, ::FusionTree, ::FusionTree) diff --git a/docs/src/man/tutorial.md b/docs/src/man/tutorial.md index d94bcff17..c89d5be47 100644 --- a/docs/src/man/tutorial.md +++ b/docs/src/man/tutorial.md @@ -294,7 +294,7 @@ to arbitrary tensor contractions require that the two indices to be contracted h which are each others dual. Knowing this, all the other functionality of tensors with `CartesianSpace` indices remains the same for tensors with `ComplexSpace` indices. -## Symmetries +## [Symmetries](@id ss_tutorial_symmetries) So far, the functionality that we have illustrated seems to be just a convenient (or inconvenient?) wrapper around dense multidimensional arrays, e.g. Julia's Base `Array`. From a174751f8639f1569d663e90c45f96fa7fddd0bb Mon Sep 17 00:00:00 2001 From: leburgel Date: Mon, 17 Nov 2025 18:35:48 +0100 Subject: [PATCH 02/26] Add to landing page --- docs/src/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/index.md b/docs/src/index.md index be59bb44e..1b86c4f16 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -49,6 +49,6 @@ Depth = 2 ## Appendix ```@contents -Pages = ["appendix/categories.md"] +Pages = ["appendix/categories.md", "appendix/symmetric_tutorial.md"] Depth = 3 ``` From ee847b43bdb6db7978697d4e1c1ed3d2363a2066 Mon Sep 17 00:00:00 2001 From: Lander Burgelman <39218680+leburgel@users.noreply.github.com> Date: Mon, 17 Nov 2025 19:58:44 +0100 Subject: [PATCH 03/26] Update docs/src/appendix/symmetric_tutorial.md Co-authored-by: Lukas Devos --- docs/src/appendix/symmetric_tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index 50d429bac..4f39c32c5 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -167,7 +167,7 @@ representation, which gives the first and last entries of the fusion rules. Simi acts with a minus sign on both $\ket{+} \otimes \ket{-}$ and $\ket{-} \otimes \ket{+}$, meaning these transform under the sign representation, which gives the second and third entries of the fusion rules. Having introduced this notion of 'fusing' irreps, we can now -associate associate a well-defined *coupled irrep* to each of the four two-site basis +associate a well-defined *coupled irrep* to each of the four two-site basis states, which is given by the tensor product of the two *uncoupled irreps* associated to each individual site. From the matrix elements of $ZZ$ given above, we clearly see that this operator only maps between states in the domain and codomain that have the same coupled From 579ef40748ec5777c93f1fbe0762d8429f878b9b Mon Sep 17 00:00:00 2001 From: leburgel Date: Mon, 17 Nov 2025 20:02:00 +0100 Subject: [PATCH 04/26] Fix equation references --- docs/src/appendix/symmetric_tutorial.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index 4f39c32c5..1904d8127 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -466,7 +466,7 @@ with degeneracy 1, `A = U1Space(1 => 1)`. Similarly, the decrease in occupation acting with $a^-$ can be thought of as the *splitting* of an `U1Irrep(n)` into an `U1Irrep(n - 1)` and an `U1Irrep(1)`, leading to a representation in terms of a `TensorMap(..., A ⊗ V ← V)`. Based on these observations, we can represent the matrix -elements {eq}`eq:bosonopmatel` as blocks labeled by the $\mathrm{U}(1)$ fusion trees +elements \eqref{eq:bosonopmatel} as blocks labeled by the $\mathrm{U}(1)$ fusion trees ```@raw html
bosonops
@@ -580,7 +580,7 @@ c_i^+ c_j^- \right)^\dagger = c_j^+ c_i^- = - c_i^- c_j^+$ and $\left( c_i^+ c_j restrict the local occupation number to be 0 or 1, leading to a well-defined notion of *fermion-parity*. The local fermion-parity operator is related to the fermion number operator as $Q_i = (-1)^{N_i}$, and is diagonal in the occupation number basis. The -Hamiltonian {eq}`eq:kitaev` is invariant under conjugation by the global fermion-parity +Hamiltonian \eqref{eq:kitaev} is invariant under conjugation by the global fermion-parity operator, $Q H Q^\dagger = H$, where ```math Q = \exp \left( i \pi \sum_i N_i \right) = (-1)^{\sum_i N_i}. @@ -1023,7 +1023,7 @@ determined by the spin irrep label. In particular, we have for each irrep $l$ ```math \vec{S}^2 \ket{l,m} = l(l+1) \ket{l,m}. ``` -It then follows from Eq. {eq}`eq:casimir_decomp` that the reduced matrix elements of the +It then follows from Eq. \eqref{eq:casimir_decomp} that the reduced matrix elements of the exchange interaction are completely determined by the eigenvalue of the quadratic Casimir on the uncoupled and coupled irreps. Indeed, to each fusion tree we can associate a well-defined value From d91a40e3740d77fb5716530f97ca88c72b6230e1 Mon Sep 17 00:00:00 2001 From: leburgel Date: Mon, 17 Nov 2025 20:21:29 +0100 Subject: [PATCH 05/26] Pick a different fusion tree --- docs/src/appendix/symmetric_tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index 1904d8127..6610da965 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -1148,7 +1148,7 @@ subblocks(TT) Circling back to our earlier remark, we clearly see that the fusion trees of this tensor indeed have non-trivial vertex labels. ```@example symmetric_tutorial -f = collect(fusiontrees(TT))[3][2] +f = collect(fusiontrees(TT))[4][2] ``` ```@example symmetric_tutorial f.vertices From 9ee361b5bbcb3fa98ea412b2879feb08fed73184 Mon Sep 17 00:00:00 2001 From: leburgel Date: Wed, 19 Nov 2025 13:40:23 +0100 Subject: [PATCH 06/26] Updates on constructing symmetric tensor map from dense data --- docs/src/appendix/symmetric_tutorial.md | 157 +++++++++++++++++------- 1 file changed, 112 insertions(+), 45 deletions(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index 6610da965..6b0325415 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -741,15 +741,15 @@ non-Abelian symmetry group $G$, the fact that its elements do not all commute ha impact on its representation theory. In particular, the irreps of such a group can be higher dimensional, and the fusion of two irreps can give rise to multiple different irreps. On the one hand this means that fusion trees of these irreps are no longer completely determined by -the uncoupled charges. Indeed, in this case some of the -[internal structure of the `FusionTree` type](@ref sss_fusion_trees) we have ignored before will -become relevant (of which we will give an [example below](@ref sss_sun_heisenberg)). On the other -hand, it follows that fusion trees of irreps now not only label blocks, but also encode a -certain *nontrivial symmetry structure*. We will make this statement more precise in the -following, but the fact that this is necessary is quite intuitive. If we recall our original -statement that symmetric tensors consist of blocks associated to fusion trees which carry -irrep labels, then for higher-dimensional irreps the corresponding fusion trees must encode -some additional information that implicitly takes into account the internal structure of the +the uncoupled charges. Indeed, in this case some of the [internal structure of the +`FusionTree` type](@ref sss_fusion_trees) we have ignored before will become relevant (of +which we will give an [example below](@ref sss_sun_heisenberg)). On the other hand, it +follows that fusion trees of irreps now not only label blocks, but also encode a certain +*nontrivial symmetry structure*. We will make this statement more precise in the following, +but the fact that this is necessary is quite intuitive. If we recall our original statement +that symmetric tensors consist of blocks associated to fusion trees which carry irrep +labels, then for higher-dimensional irreps the corresponding fusion trees must encode some +additional information that implicitly takes into account the internal structure of the representation spaces. In particular, this means that the conversion of an operator, given its matrix elements in the irrep basis, to the blocks of the corresponding symmetric `TensorMap` is less straightforward since it requires an understanding of exactly what this @@ -768,8 +768,8 @@ $\mathrm{SU}(N)$-symmetric case. Let us recall some basics of representation theory first. Consider a group $G$ and a corresponding representation space $V$, such that every element $g \in G$ can be realized as a unitary operator $U_g : V \to V$. Let $h$ be a `TensorMap` whose domain and codomain are -given by the tensor product of two of these representation spaces. Recall that, by -definition, the statement that '$h$ is symmetric under $G$' means that +given by the tensor product of two of these representation spaces. By definition, the +statement that '$h$ is symmetric under $G$' means that ```@raw html
symmetric_tensor
``` @@ -793,7 +793,10 @@ encodes how a basis state $\ket{k,n} \in V^{(k)}$ corresponding to some term in sum can be decomposed into a linear combination of basis vectors $\ket{l_1,m_1} \otimes \ket{l_2,m_2}$ of the tensor product space: ```math +\begin{equation} +\label{eq:cg_decomposition} \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}. +\end{equation} ``` These recoupling coefficients turn out to be essential to the structure of symmetric tensors, 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 0, \frac{1}{2}, 1, \frac{3}{2}, ...$, and where the dimension of the spin-$l$ representation is equal to $2l + 1$. The fusion rules of $\mathrm{SU}(2)$ are given by ```math +\begin{equation} +\label{eq:su2_fusion_rules} l_1 \otimes l_2 \cong \bigoplus_{k=|l_1-l_2|}^{l_1+l_2}s. +\end{equation} ``` These are clearly non-Abelian since multiple terms appear on the right hand side, for example $\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 [`SU2Irrep`](@ref) instance of integer or halfinteger spin as encoded in its `j` field. If we construct a `TensorMap` whose symmetry structure corresponds to the coupling of two spin-$\frac{1}{2}$ -irreps to a spin-$1$ irrep, we can then convert it to a plain array and compare it to the -$\mathrm{SU}(2)$ Clebsch-Gordan coefficients exported by the -[WignerSymbols.jl package](https://github.com/Jutho/WignerSymbols.jl). - +irreps to a spin-$1$ irrep in the sense of \eqref{eq:cg_decomposition}, we can then convert +it to a plain array and compare it to the $\mathrm{SU}(2)$ Clebsch-Gordan coefficients +implemented in the [WignerSymbols.jl package](https://github.com/Jutho/WignerSymbols.jl). ```@example symmetric_tutorial -V1 = SU2Space(1 => 1) -V2 = SU2Space(1//2 => 1) -t = ones(ComplexF64, V1 ← V2 ⊗ V2) +V1 = SU2Space(1//2 => 1) +V2 = SU2Space(1 => 1) +t = ones(ComplexF64, V1 ⊗ V1 ← V2) ``` ```@example symmetric_tutorial ta = convert(Array, t) ``` -The conversion gives us a $3 \times 2 \times 2$ array, which exactly corresponds to the size -of the $C_{1}^{\frac{1}{2},\frac{1}{2}}$ Clebsch-Gordan array. In order to explicitly +The conversion gives us a $2 \times 2 \times 3$ array, which exactly corresponds to the size +of the $C^{1}_{\frac{1}{2},\frac{1}{2}}$ Clebsch-Gordan array. In order to explicitly compare whether the entries match we need to know the ordering of basis states assumed by TensorKit.jl when converting the tensor to its matrix elements in the irrep basis. For $\mathrm{SU}(2)$ the irrep basis is ordered in ascending magnetic quantum number $m$, which gives us a map $m = i - (l+1)$ for mapping an array index to a corresponding magnetic quantum number for the spin-$l$ irrep. ```@example symmetric_tutorial -for i1 in 1:dim(V1), i2 in 1:dim(V2), i3 in 1:dim(V2) +checks = map(Iterators.product(1:dim(V1), 1:dim(V1), 1:dim(V2))) do (i1, i2, i3) # map basis state index to magnetic quantum number - m1 = i1 - (1 + 1) + m1 = i1 - (1//2 + 1) m2 = i2 - (1//2 + 1) - m3 = i3 - (1//2 + 1) - @test ta[i1, i2, i3] ≈ clebschgordan(1//2, m2, 1//2, m3, 1, m1) + m3 = i3 - (1 + 1) + # check the corresponding array entry + return ta[i1, i2, i3] ≈ clebschgordan(1//2, m1, 1//2, m2, 1, m3) end +@test all(checks) ``` Based 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 be as easy to compute (in general, no closed formulas exist). In addition, the procedure for manually projecting out the reduced matrix elements requires being particularly careful about the correspondence between the basis states used to define the original matrix -elements and those implied by the Clebsch-Gordan coefficients. Therefore, it is often easier -to directly construct the symmetric tensor based on some representation theory, as we will -see below. +elements and those implied by the Clebsch-Gordan coefficients. Finally, for some symmetries +supported in TensorKit.jl, there are simply no Clebsch-Gordan coefficients. Therefore, it is +often easier and sometimes simply necessary to directly construct the symmetric tensor and +then fill in its reduced tensor elements based on some representation theory. Wel will cover +some examples of this below. + +Having introduced and demonstrated the Clebsch-Gordan decomposition, the corresponding +coefficients and their role in symmetric tensors for the example of $\mathrm{SU}(2)$ using +the WignerSymbols.jl package, we'll continue our discussion using only TensorKit.jl +internals. Within TensorKit.jl, the +$\text{dim}\left( V^{(l_1)} \right) \times \text{dim}\left( V^{(l_2)} \right) \times \text{dim}\left( V^{(k)} \right)$ +array of coefficients that encodes the splitting of the irrep space $V^{(k)}$ to the tensor +product of irrep spaces $V^{(l_1)} \otimes V^{(l_2)}$ according to the Clebsch-Gordan +decomposition \eqref{eq:cg_decomposition} above can be explicitly constructed by calling the +[`TensorKitSectors.fusiontensor`](@ref) method on the corresponding `Sector` instances, +`fusiontensor(l₁, l₂, k)`. This `fusiontensor` is defined for any sector type corresponding +to a symmetry which admits Clebsch-Gordan coefficients. For our example above, +we can build the corresponding fusion tensor as + +```@example symmetric_tutorial +using TensorKit: fusiontensor +f = fusiontensor(SU2Irrep(1//2), SU2Irrep(1//2), SU2Irrep(1)) +``` + +We see that this fusion tensor has a size `2×2×3×1`, which contains an additional trailing +`1` to what we might expect. In the general case, `fusiontensor` returns a 4-dimensional +array, where the size of the first three dimensions corresponds to the dimensions of the +irrep spaces under consideration, and the last dimension corresponds to the number of +distinct ways the irreps $l_1$ and $l_1$ can fuse to irrep $k$. We say that `Sector`s for +which the size of this last dimension can be larger than 1 have *fusion multiplicities*. +We'll encounter an example of this below when we consider an $\mathrm{SU}(3)$ symmetry. +Since $\mathrm{SU}(2)$ doesn't have any fusion multiplicities, we can just discard this last +index. + +We can now explicitly that this `fusiontensor` indeed does what we expect it to do: +```@example symmetric_tutorial +@test ta ≈ f[:, :, :, 1] +``` +Of course, in this case `fusiontensor` just calls `Wignersymbols.clebschgordan` under the +hood. However, `TensorKitSectors.fusiontensor` works for general symmetries, and makes it +so that we never have to manually assemble the coefficients into an array. ### The 'generic' approach to the spin-1 Heisenberg model: Wigner-Eckart in action @@ -931,38 +976,31 @@ nothing #hide ``` The next step is to project out the reduced matrix elements by taking the overlap with the -appropriate Clebsch-Gordan coefficients, according to -[the Clebsch-Gordan decomposition given above](none2symm). In our current case of a spin-1 -physical space we have $l_1 = l_2 = l_3 = l_4 = 1$, and the coupled irrep $k$ can therefore -take the values $0, 1, 2$. The reduced matrix element for a given $k$ can then be -implemented in the following way: +appropriate Clebsch-Gordan coefficients. In our current case of a spin-1 physical space we +have $l_1 = l_2 = l_3 = l_4 = 1$, and the coupled irrep $k$ can therefore take the values +$0, 1, 2$. The reduced matrix element for a given $k$ can be implemented in the +following way: ```@example symmetric_tutorial -function get_reduced_element(k) +function get_reduced_element(k::SU2Irrep) # construct Clebsch-Gordan coefficients for coupling 1 ⊗ 1 to k - CG = zeros(ComplexF64, 3, 3, 2*k + 1) - for m1 in -k:k, m2 in -1:1, m3 in -1:1 - CG[m2 + 2, m3 + 2, m1 + k + 1] = clebschgordan(1, m2, 1, m3, k, m1) - end - + f = fusiontensor(SU2Irrep(1), SU2Irrep(1), k)[:, :, :, 1] # project out diagonal matrix on coupled irrep space - @tensor reduced_matrix[-1; -2] := CG[1 2; -1] * SS_arr[1 2; 3 4] * conj(CG[3 4; -2]) - + @tensor reduced_matrix[-1; -2] := conj(f[1 2; -1]) * SS_arr[1 2; 3 4] * f[3 4; -2] # check that it is proportional to the identity @assert isapprox(reduced_matrix, reduced_matrix[1, 1] * I; atol=1e-12) - # return the proportionality factor return reduced_matrix[1, 1] end ``` If we use this to compute the reduced matrix elements for $k = 0, 1, 2$, ```@example symmetric_tutorial -get_reduced_element(0) +get_reduced_element(SU2Irrep(0)) ``` ```@example symmetric_tutorial -get_reduced_element(1) +get_reduced_element(SU2Irrep(1)) ``` ```@example symmetric_tutorial -get_reduced_element(2) +get_reduced_element(SU2Irrep(2)) ``` we can read off the entries ```math @@ -992,12 +1030,41 @@ interaction: V = SU2Space(1 => 1) SS = zeros(ComplexF64, V ⊗ V ← V ⊗ V) for (s, f) in fusiontrees(SS) - k = Int(f.coupled.j) + k = f.coupled SS[s, f] .= get_reduced_element(k) end subblocks(SS) ``` +We demonstrated this entire procedure of extracting the array blocks of a symmetric tensor +map for each fusion tree by projecting out the corresponding fusion tensors as an explicit +illustration of how symmetric tensor maps work under the hood. In practice however, there's +no need to perform this procedure explicitly. Given a dense array representing the matrix +elements of a tensor map in the irrep basis, we can convert this to the corresponding +symmetric tensor map by passing the data array to the `TensorMap` constructor along with the +corresponding spaces, +```@example symmetric_tutorial +SS_auto = TensorMap(SS_arr, V ⊗ V ← V ⊗ V) +@test SS_auto ≈ SS +``` + +!!! warning + While the example demonstrated here seems fairly straightforward, there's some inherent + challenges to directly initializing a symmetric tensor map from a full dense array. A first + important point to reiterate here is that in order for this procedure to work, we had to + initialize `SS_arr` by assuming an internal basis convention for the $\mathrm{SU}(2)$ + representation space $V^{(1)}$ that is consistent with the convention used by + `fusiontensor`. While that choice here, corresponding to an ascending magnetic quantum + number $m = -1, 0, 1$, seems quite natural, for many symmetries there is no transparent + natural choice. In those cases, the only way to use this approach is to explicitly check the + basis convention used by [`TensorKitSectors.fusiontensor`](@ref) for that specific symmetry. + On top of thes, there's some additional complications when considering graded spaces which + contain multiple sectors with non-trivial degeneracies. In that case, to even initialize the + dense data array in the first place, you would need to know the order in which the sectors + appear in each space internally. This information can be obtained by calling `axes(V, c)`, + where `V` and `c` are either an [`ElementarySpace`](@ref) and a [`Sector`](@ref), or a + [`ProductSpace`](@ref) and a `Tuple` of `Sector`s respectively. + ### An 'elegant' approach to the Heisenberg model From 91f62d6d2d4b5f2a2224b45854e11ed507d7396a Mon Sep 17 00:00:00 2001 From: leburgel Date: Wed, 19 Nov 2025 13:42:14 +0100 Subject: [PATCH 07/26] Reduce toc depths in index --- docs/src/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index 1b86c4f16..96b750fdf 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -36,7 +36,7 @@ whereas support for distributed arrays is planned for the future. ```@contents Pages = ["man/intro.md", "man/spaces.md", "man/sectors.md", "man/tensors.md"] -Depth = 3 +Depth = 2 ``` ## Library outline @@ -50,5 +50,5 @@ Depth = 2 ```@contents Pages = ["appendix/categories.md", "appendix/symmetric_tutorial.md"] -Depth = 3 +Depth = 2 ``` From d877b3da424dc1825d68995b58eff84d9cf3646e Mon Sep 17 00:00:00 2001 From: leburgel Date: Thu, 20 Nov 2025 15:23:09 +0100 Subject: [PATCH 08/26] Address review comments --- docs/src/appendix/symmetric_tutorial.md | 178 ++++++++++++------------ 1 file changed, 90 insertions(+), 88 deletions(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index 6b0325415..81259b3d2 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -114,16 +114,19 @@ $\mathbb{Z}_2$ transformation implies the following identities for the local ten These identitities precisely mean that these local tensors transform trivially under a tensor product representation of $\mathbb{Z}_2$. This implies that, recalling [the -introduction on symmetries](@ref ss_symmetries), in an appropriate basis -for the local physical vector space, our local tensors would become block-diagonal where -each so-called *matrix block* is labeled by a $\mathbb{Z}_2$ irrep.The appropriate local basis transformation is precisely the one that brings the local representation $X$ into block-diagonal form. Clearly, this transformation is nothing more than the Hadamard transformation which maps the computational basis of $Z$ eigenstates $\{\ket{\uparrow}, \ket{\downarrow}\}$ to that of the $X$ -eigenstates $\{\ket{+}, \ket{-}\}$ defined as $\ket{+} = \frac{\ket{\uparrow} + -\ket{\downarrow}}{\sqrt{2}}$ and $\ket{-} = \frac{\ket{\uparrow} - -\ket{\downarrow}}{\sqrt{2}}$. In the current context, this basis is referred to as the -*irrep basis* of $\mathbb{Z}_2$, since each basis state corresponds to a one-dimensional -irreducible representation of $\mathbb{Z}_2$. Indeed, the local symmetry transformation $X$ -acts trivially on the state $\ket{+}$, corresponding to the *trivial irrep*, and yields a -minus sign when acting on $\ket{-}$, corresponding to the *sign irrep*. +introduction on symmetries](@ref ss_symmetries), in an appropriate basis for the local +physical vector space, our local tensors would become block-diagonal where each so-called +*matrix block* is labeled by a $\mathbb{Z}_2$ irrep. The appropriate local basis +transformation is precisely the one that brings the local representation $X$ into +block-diagonal form. Clearly, this transformation is nothing more than the Hadamard +transformation which maps the computational basis of $Z$ eigenstates $\{\ket{\uparrow}, \ket{\downarrow}\}$ to that of the $X$ eigenstates $\{\ket{+}, \ket{-}\}$ defined as +$\ket{+} = \frac{\ket{\uparrow} + \ket{\downarrow}}{\sqrt{2}}$ and +$\ket{-} = \frac{\ket{\uparrow} - \ket{\downarrow}}{\sqrt{2}}$. In the current context, +this basis is referred to as the *irrep basis* of $\mathbb{Z}_2$, since each basis state +corresponds to a one-dimensional irreducible representation of $\mathbb{Z}_2$. Indeed, the +local symmetry transformation $X$ acts trivially on the state $\ket{+}$, corresponding to +the *trivial irrep*, and yields a minus sign when acting on $\ket{-}$, corresponding to the +*sign irrep*. Next, let's make the statement that 'the matrix blocks of the local tensors are labeled by $\mathbb{Z}_2$ irreps' more concrete. To this end, consider the action of $ZZ$ in the irrep @@ -153,9 +156,8 @@ a \otimes b \cong \bigoplus_c N_c^{ab} c, ``` where $N_{ab}^c$ encodes the number of times the irrep $c$ occurs in the tensor product of irreps $a$ and $b$. These fusion rules are called *Abelian* if the tensor product of any two -irreps corresponds to exactly one irrep. We will return to the implications of *non-Abelian* -fusion rules [later](@ref ss_non_abelian). For the case of the $\mathbb{Z}_2$ irreps, the fusion -rules are Abelian, and are given by addition modulo 2, +irreps corresponds to exactly one irrep. We will return to the implications of irreps with *non-Abelian* fusion rules [later](@ref ss_non_abelian). For the case of the $\mathbb{Z}_2$ +irreps, the fusion rules are Abelian, and are given by addition modulo 2, ```math 0 \otimes 0 \cong 0, \quad 0 \otimes 1 \cong 1, \quad 1 \otimes 0 \cong 1, \quad 1 \otimes 1 \cong 0. ``` @@ -196,31 +198,30 @@ manually assigning a matrix element to each [fusion tree of the form above](Z2_f labeled by a given tensor product of irreps. This matrix element is then automatically inserted into the appropriate matrix block. So, for the purpose of this tutorial **we will interpret a symmetric `TensorMap` simply as a list of fusion trees, to each of which -corresponds a certain reduced matrix element**. In TensorKit.jl, these reduced tensor +corresponds a certain reduced tensor element**. In TensorKit.jl, these reduced tensor elements corresponding to the fusion trees of a `TensorMap` can be accessed through the [`subblocks`](@ref) method. !!! note - In general, such a reduced matrix element is not necessarily a scalar, but rather an array + In general, such a reduced tensor element is not necessarily a scalar, but rather an array whose size is determined by the degeneracy of the irreps in the codomain and domain of the - fusion tree. For this reason, a reduced matrix element associated to a given fusion tree is - also referred to as an *array block*. In the following we will use terms 'reduced matrix - element', 'array block' or just 'block' interchangeably. However, it should be remembered - that these are distinct from the matrix blocks in the block-diagonal decomposition of the - tensor. + fusion tree. For this reason, a reduced tensor element associated to a given fusion tree is + also referred to as a *subblock*. In the following we will always use terms 'reduced tensor + element' or 'subblock' for the reduced tensor elements, to make it clear that these are + distinct from the matrix blocks in the block-diagonal decomposition of the tensor. ### [Fusion trees and how to use them](@id sss_fusion_trees) This view of the underlying symmetry structure in terms of fusion trees and corresponding -array blocks is a very convenient way of working with the `TensorMap` type. Consider a -generic fusion tree of the form +reduced tensor elements is a very convenient way of working with the `TensorMap` type. +Consider a generic fusion tree of the form ```@raw html
fusiontree
``` -which can be used to label a block of a `TensorMap` corresponding to a two-site operator. +which can be used to label a subblock of a `TensorMap` corresponding to a two-site operator. This object should actually be seen as a *pair of fusion trees*. The first member of the pair, related to the codomain of the `TensorMap`, is referred to as the *splitting tree* and encodes how the *coupled charge* $c$ splits into the *uncoupled charges* $s_1$ and $s_2$. @@ -240,23 +241,23 @@ For our current application only `uncoupled` and `coupled` are relevant, since $\mathbb{Z}_2$ irreps are self-dual and have Abelian fusion rules. We will come back to these other properties when discussion more involved applications. Given some `TensorMap`, the method `TensorKit.fusiontrees(t::TensorMap)` returns an iterator over all pairs of -splitting and fusion trees that label the blocks of `t`. +splitting and fusion trees that label the subblocks of `t`. We can now put this into practice by directly constructing the $ZZ$ operator in the irrep basis as a $\mathbb{Z}_2$-symmetric `TensorMap`. We will do this in three steps: - First we construct the physical space at each site as a $\mathbb{Z}_2$-graded vector space. -- Then we initialize an empty `TensorMap` with the correct domain and codomain vector spaces built from the previously constructed physical space. -- And finally we iterate over all splitting and fusion tree pairs and manually fill in the corresponding nonzero blocks of the operator. +- Then we initialize an empty `TensorMap` with the correct domain and codomain vector spaces + built from the previously constructed physical space. +- And finally we iterate over all splitting and fusion tree pairs and manually fill in the + corresponding nonzero subblocks of the operator. After the basis transform to the irrep basis, we can view the two-dimensional complex physical vector space we started with as being spanned by the trivial and sign irrep of $\mathbb{Z}_2$. In the language of TensorKit.jl, this can be implemented as a `Z2Space`, an -alias for a -$\mathbb{Z}_2$-[graded vector space](@ref GradedSpace) -`Vect[Z2Irrep]`, which contains the trivial irrep `Z2Irrep(0)` with degeneracy 1 and the -sign irrep `Z2Irrep(1)` with degeneracy 1. We can define this space in the following way and -check its dimension: +alias for a [graded vector space](@ref GradedSpace) `Vect[Z2Irrep]`, which contains the +trivial irrep `Z2Irrep(0)` with degeneracy 1 and the sign irrep `Z2Irrep(1)` with +degeneracy 1. We can define this space in the following way and check its dimension: ```@example symmetric_tutorial V = Z2Space(0 => 1, 1 => 1) @@ -275,13 +276,13 @@ subblocks(ZZ) ``` While all entries are zero, we see that all eight valid fusion trees with two incoming irreps and two outgoing irreps [of the type above](fusiontree) are listed with their -corresponding block data. Each of these blocks is an array of shape $(1, 1, 1, 1)$ since -each irrep occuring in the space $V$ has degeneracy 1. Using the [`fusiontrees`](@ref) method and -the fact that we can index a `TensorMap` using a splitting/fusion tree pair, we can now fill -in the nonzero blocks of the operator by observing that the $ZZ$ operator flips the irreps -of the uncoupled charges in the domain with respect to the codomain, as shown in the -diagrams above. Flipping a given `Z2Irrep` in the codomain can be implemented by fusing them -with the sign irrep `Z2Irrep(1)`, giving: +corresponding subblock data. Each of these subblocks is an array of shape $(1, 1, 1, 1)$ +since each irrep occuring in the space $V$ has degeneracy 1. Using the [`fusiontrees`](@ref) +method and the fact that we can index a `TensorMap` using a splitting/fusion tree pair, we +can now fill in the nonzero subblocks of the operator by observing that the $ZZ$ operator +flips the irreps of the uncoupled charges in the domain with respect to the codomain, as +shown in the diagrams above. Flipping a given `Z2Irrep` in the codomain can be implemented +by fusing them with the sign irrep `Z2Irrep(1)`, giving: ```@example symmetric_tutorial flip_charge(charge::Z2Irrep) = only(charge ⊗ Z2Irrep(1)) @@ -294,9 +295,10 @@ subblocks(ZZ) ``` Indeed, the resulting `TensorMap` exactly encodes the matrix elements of the $ZZ$ operator -shown in [the diagrams above](Z2_fusiontrees). The $X$ operator can be constructed in -a similar way. Since it is by definition diagonal in the irrep basis with blocks directly -corresponding to the trivial and sign irrep, its construction is particularly simple: +shown in [the diagrams above](Z2_fusiontrees). The $X$ operator can be constructed in a +similar way. Since it is by definition diagonal in the irrep basis with matrix blocks +directly corresponding to the trivial and sign irrep, its construction is particularly +simple: ```@example symmetric_tutorial X = zeros(ComplexF64, V ← V) @@ -394,7 +396,7 @@ N \ket{n} &= n \ket{n} ``` It is then a simple observation that these matrix elements are exactly captured by the -following $\mathrm{U}(1)$ fusion trees with corresponding block values: +following $\mathrm{U}(1)$ fusion trees with corresponding subblock values: ```@raw html
U1_fusiontrees
@@ -414,8 +416,8 @@ V = U1Space(n => 1 for n in 0:cutoff) ``` We can now initialize the $a^+ a^-$, $a^- a^+$ and $N$ operators as empty `TensorMap`s with -the correct domain and codomain vector spaces, and fill in the nonzero blocks associated to -[the fusion trees shown above](U1_fusiontrees). To do this we need access to the integer +the correct domain and codomain vector spaces, and fill in the nonzero subblocks associated +to [the fusion trees shown above](U1_fusiontrees). To do this we need access to the integer label of the $\mathrm{U}(1)$ irreps in the fusion and splitting trees, which can be accessed through the `charge` field of the `U1Irrep` type. @@ -466,7 +468,7 @@ with degeneracy 1, `A = U1Space(1 => 1)`. Similarly, the decrease in occupation acting with $a^-$ can be thought of as the *splitting* of an `U1Irrep(n)` into an `U1Irrep(n - 1)` and an `U1Irrep(1)`, leading to a representation in terms of a `TensorMap(..., A ⊗ V ← V)`. Based on these observations, we can represent the matrix -elements \eqref{eq:bosonopmatel} as blocks labeled by the $\mathrm{U}(1)$ fusion trees +elements \eqref{eq:bosonopmatel} as subblocks labeled by the $\mathrm{U}(1)$ fusion trees ```@raw html
bosonops
@@ -482,10 +484,10 @@ We can then combine these operators to get the appropriate Hamiltonian terms, Although we have made a suggestive distinction between the 'left' and 'right' versions of the operators $a_L^\pm$ and $a_R^\pm$, one can actually be obtained from the other by permuting the physical and auxiliary indices of the corresponding `TensorMap`s. This - permutation has no effect on the actual array blocks of the tensors due to the bosonic + permutation has no effect on the actual subblocks of the tensors due to the bosonic [`BraidingStyle`](@ref) of $\mathrm{U}(1)$ irreps, so the left and right operators can in essence be seen as the 'same' tensors. This is no longer the case when considering - fermionic systems, where permuting indices can in fact change the array blocks as we will + fermionic systems, where permuting indices can in fact change the subblocks as we will see next. As a consequence, it is much less clear how to construct two-site symmetric operators in terms of local symmetric objects. @@ -536,7 +538,7 @@ It is then simple to check that this is indeed what we expect. ## Level 3: Fermions and the Kitaev model While we have already covered quite a lot of ground towards understanding symmetric tensors -in terms of fusion trees and corresponding blocks, the symmetries considered so far have +in terms of fusion trees and corresponding subblocks, the symmetries considered so far have been quite 'simple' in the sense that sectors corresponding to irreps of $\mathbb{Z}_2$ and $\mathrm{U}(1)$ have [*Abelian fusion rules*](@ref FusionStyle) and [*bosonic exchange statistics*](@ref BraidingStyle). @@ -548,7 +550,7 @@ that tensor indices can be permuted freely without any 'strange' side effects. In the following we will consider examples with fermionic and even anyonic exchange statistics, and non-Abelian fusion rules. In going through these examples it will become -clear that the fusion trees labeling the blocks of a symmetric tensor imply more information +clear that the fusion trees labeling the subblocks of a symmetric tensor imply more information than just a labeling. @@ -613,9 +615,9 @@ subblocks(t) tp = permute(t, ((1,), (3, 2))) subblocks(tp) ``` -In other words, when exchanging the two domain vector spaces, the block of the `TensorMap` -for which both corresponding irreps are odd picks up a minus sign, exactly as we would -expect for fermionic charges. +In other words, when exchanging the two domain vector spaces, the reduced tensor elements of +the `TensorMap` for which both uncoupled irreps in the domain of the corresponding fusion +tree are odd picks up a minus sign, exactly as we would expect for fermionic charges. ### Constructing the Hamiltonian @@ -655,8 +657,8 @@ c_1^- c_2^+ \ket{1, 0} = c_1^- c_2^+ c_1^+ \ket{0, 0} = - c_2^+ c_1^- c_1^+ \ket ``` Once we have these matrix elements the hard part is done, and we can straightforwardly -associate these to the following $f\mathbb{Z}_2$ fusion trees with corresponding block -values, +associate these to the following $f\mathbb{Z}_2$ fusion trees with corresponding reduced +tensor elements, ```@raw html
fZ2_fusiontrees
@@ -744,14 +746,14 @@ one hand this means that fusion trees of these irreps are no longer completely d the uncoupled charges. Indeed, in this case some of the [internal structure of the `FusionTree` type](@ref sss_fusion_trees) we have ignored before will become relevant (of which we will give an [example below](@ref sss_sun_heisenberg)). On the other hand, it -follows that fusion trees of irreps now not only label blocks, but also encode a certain -*nontrivial symmetry structure*. We will make this statement more precise in the following, -but the fact that this is necessary is quite intuitive. If we recall our original statement -that symmetric tensors consist of blocks associated to fusion trees which carry irrep -labels, then for higher-dimensional irreps the corresponding fusion trees must encode some -additional information that implicitly takes into account the internal structure of the -representation spaces. In particular, this means that the conversion of an operator, given -its matrix elements in the irrep basis, to the blocks of the corresponding symmetric +follows that fusion trees of irreps now not only label reduced tensor elements, but also +encode a certain *nontrivial symmetry structure*. We will make this statement more precise +in the following, but the fact that this is necessary is quite intuitive. If we recall our +original statement that symmetric tensors consist of subblocks associated to fusion trees which +carry irrep labels, then for higher-dimensional irreps the corresponding fusion trees must +encode some additional information that implicitly takes into account the internal structure +of the representation spaces. In particular, this means that the conversion of an operator, +given its matrix elements in the irrep basis, to the subblocks of the corresponding symmetric `TensorMap` is less straightforward since it requires an understanding of exactly what this implied internal structure is. Therefore, we require some more discussion before we can actually move on to an example. @@ -775,8 +777,8 @@ statement that '$h$ is symmetric under $G$' means that ``` for every $g \in G$. If we label the irreducible representations of $G$ by $l$, then any representation space can be decomposed into a direct sum of irreducible representations, $V -= \bigoplus_l V^{(l)}$, in such a way that $U_g$ is block-diagonal where each block is -labeled by a particular irrep $l$. For each irrep space $V^{(l)}$ we can define an += \bigoplus_l V^{(l)}$, in such a way that $U_g$ is block-diagonal where each matrix block +is labeled by a particular irrep $l$. For each irrep space $V^{(l)}$ we can define an orthonormal basis labeled as $\ket{l, m}$, where the auxiliary label $m$ can take $\text{dim}\left( V^{(l)} \right)$ different values. Since we know that tensors are multilinear maps over tensor product spaces, it is natural to consider the tensor product of @@ -805,16 +807,16 @@ theorem implies that for any [`TensorMap` $h$ that is symmetric under $G$](@ref ss_symmetries), its matrix elements in the tensor product irrep basis are given by the product of Clebsch-Gordan coefficients which characterize the coupling of the basis states in the domain and codomain, and a so-called -*reduced matrix element* which only depends on the irrep labels. Concretely, the matrix +*reduced tensor element* which only depends on the irrep labels. Concretely, the matrix element $\bra{l_1,m_1} \otimes \bra{l_2,m_2} h \ket{l_3,m_3} \otimes \ket{l_4,m_4}$ is given by ```@raw html
wignereckart
``` Here, the sum runs over all possible irreps $k$ in the fusion product $l_3 \otimes l_4$ and -over all basis states $\ket{k,n}$ of $V^{(k)}$. The reduced matrix elements $h_{\text{red}}$ +over all basis states $\ket{k,n}$ of $V^{(k)}$. The reduced tensor elements $h_{\text{red}}$ are independent of the basis state labels and only depend on the irrep labels themselves. -Each reduced matrix element should be interpreted as being labeled by an irrep fusion tree, +Each reduced tensor element should be interpreted as being labeled by an irrep fusion tree, ```@raw html
anotherfusiontree
``` @@ -827,12 +829,12 @@ the coupled basis state $\ket{k,n}$ to the codomain basis states $\ket{l_1,m_1} The Wigner-Eckart theorem dictates that this structure in terms of Clebsch-Gordan coefficients is necessary to ensure that the corresponding tensor is symmetric. It is precisely this structure that is inherently encoded into the fusion tree part of a symmetric -`TensorMap`. In particular, **the array block value associated to each fusion tree in a -symmetric tensor is precisely the reduced matrix element in the Clebsch-Gordan +`TensorMap`. In particular, **the subblock value associated to each fusion tree in a +symmetric tensor is precisely the reduced tensor element in the Clebsch-Gordan decomposition**. As a small demonstration of this fact, we can make a simple $\mathrm{SU}(2)$-symmetric -tensor with trivial block values and verify that its implied symmetry structure exactly +tensor with trivial subblock values and verify that its implied symmetry structure exactly corresponds to the expected Clebsch-Gordan coefficient. First, we [recall](su2_irreps) that the irreps of $\mathrm{SU}(2)$ can be labeled by a halfinteger *spin* that takes values $l = 0, \frac{1}{2}, 1, \frac{3}{2}, ...$, and where the dimension of the spin-$l$ representation @@ -885,7 +887,7 @@ end Based on this discussion, we can quantify the aforementioned 'difficulties' in the inverse operation of what we just demonstrated, namely converting a given operator to a symmetric `TensorMap` given only its matrix elements in the irrep basis. Indeed, it is now clear that -this precisely requires isolating the reduced matrix elements introduced above. Given the +this precisely requires isolating the reduced tensor elements introduced above. Given the matrix elements of the operator in the irrep basis, this can in general be done by solving the system of equations implied by the [Clebsch-Gordan decomposition](wignereckart). A simpler way to achieve the same thing is to make use of the fact that the @@ -893,7 +895,7 @@ simpler way to achieve the same thing is to make use of the fact that the on the coupled space. Indeed, by projecting out the appropriate Clebsch-Gordan coefficients and using their orthogonality relations, we can construct a diagonal operator on each coupled irrep space $V^{(k)}$. Each of these diagonal operators is proportional to the -identity, where the proportionality factor is precisely the reduced matrix element +identity, where the proportionality factor is precisely the reduced tensor element associated to the corresponding irrep fusion tree. ```@raw html
none2symm
@@ -904,7 +906,7 @@ operator in the irrep basis and the Clebsch-Gordan coefficients. In the followin demonstrate this explicit procedure for the particular example of $G = \mathrm{SU}(2)$. However, it should be noted that for general groups the Clebsch-Gordan coefficients may not be as easy to compute (in general, no closed formulas exist). In addition, the procedure for -manually projecting out the reduced matrix elements requires being particularly careful +manually projecting out the reduced tensor elements requires being particularly careful about the correspondence between the basis states used to define the original matrix elements and those implied by the Clebsch-Gordan coefficients. Finally, for some symmetries supported in TensorKit.jl, there are simply no Clebsch-Gordan coefficients. Therefore, it is @@ -960,7 +962,7 @@ site is the three-dimensional spin-1 irrep of $\mathrm{SU}(2)$. Each two-site ex operator $\vec{S}_i \cdot \vec{S}_j$ in the sum commutes with a global transformation $g \in \mathrm{SU}(2)$, so that it satisfies the [above symmetry condition](symmetric_tensor). Therefore, we can represent it as an $\mathrm{SU}(2)$-symmetric `TensorMap`, as long as we -can isolate its reduced matrix elements. +can isolate its reduced tensor elements. In order to apply the above procedure, we first require the matrix elements in the irrep basis. These can be constructed as a $3 \times 3 \times 3 \times 3$ array `SS` using the @@ -975,10 +977,10 @@ Sz = ComplexF64[-1 0 0; 0 0 0; 0 0 1] nothing #hide ``` -The next step is to project out the reduced matrix elements by taking the overlap with the +The next step is to project out the reduced tensor elements by taking the overlap with the appropriate Clebsch-Gordan coefficients. In our current case of a spin-1 physical space we have $l_1 = l_2 = l_3 = l_4 = 1$, and the coupled irrep $k$ can therefore take the values -$0, 1, 2$. The reduced matrix element for a given $k$ can be implemented in the +$0, 1, 2$. The reduced tensor element for a given $k$ can be implemented in the following way: ```@example symmetric_tutorial function get_reduced_element(k::SU2Irrep) @@ -992,7 +994,7 @@ function get_reduced_element(k::SU2Irrep) return reduced_matrix[1, 1] end ``` -If we use this to compute the reduced matrix elements for $k = 0, 1, 2$, +If we use this to compute the reduced tensor elements for $k = 0, 1, 2$, ```@example symmetric_tutorial get_reduced_element(SU2Irrep(0)) ``` @@ -1036,13 +1038,13 @@ end subblocks(SS) ``` -We demonstrated this entire procedure of extracting the array blocks of a symmetric tensor -map for each fusion tree by projecting out the corresponding fusion tensors as an explicit -illustration of how symmetric tensor maps work under the hood. In practice however, there's -no need to perform this procedure explicitly. Given a dense array representing the matrix -elements of a tensor map in the irrep basis, we can convert this to the corresponding -symmetric tensor map by passing the data array to the `TensorMap` constructor along with the -corresponding spaces, +We demonstrated this entire procedure of extracting the reduced tensor elements of a +symmetric tensor map for each fusion tree by projecting out the corresponding fusion tensors +as an explicit illustration of how symmetric tensor maps work under the hood. In practice +however, there's no need to perform this procedure explicitly. Given a dense array +representing the matrix elements of a tensor map in the irrep basis, we can convert this to +the corresponding symmetric tensor map by passing the data array to the `TensorMap` +constructor along with the corresponding spaces, ```@example symmetric_tutorial SS_auto = TensorMap(SS_arr, V ⊗ V ← V ⊗ V) @test SS_auto ≈ SS @@ -1068,7 +1070,7 @@ SS_auto = TensorMap(SS_arr, V ⊗ V ← V ⊗ V) ### An 'elegant' approach to the Heisenberg model -As noted above, the explicit procedure of projecting out the reduced matrix elements from +As noted above, the explicit procedure of projecting out the reduced tensor elements from the action of an operator in the irrep basis can be a bit cumbersome for more complicated groups. However, using some basic representation theory we can bypass this step altogether for the Heisenberg model. First, we rewrite the exchange interaction in the following way: @@ -1090,7 +1092,7 @@ determined by the spin irrep label. In particular, we have for each irrep $l$ ```math \vec{S}^2 \ket{l,m} = l(l+1) \ket{l,m}. ``` -It then follows from Eq. \eqref{eq:casimir_decomp} that the reduced matrix elements of the +It then follows from Eq. \eqref{eq:casimir_decomp} that the reduced tensor elements of the exchange interaction are completely determined by the eigenvalue of the quadratic Casimir on the uncoupled and coupled irreps. Indeed, to each fusion tree we can associate a well-defined value @@ -1175,7 +1177,7 @@ For any $N$, the [quadratic Casimir](https://en.wikipedia.org/wiki/Casimir_eleme \Omega = \sum_k T^k T^k ``` commutes with all $\mathrm{SU}(N)$ generators, meaning it has a well defined eigenvalue in -each irrep. This observation then immediately given the reduced matrix elements of the +each irrep. This observation then immediately given the reduced tensor elements of the exchange interaction as ```@raw html
SUN_fusiontrees
@@ -1264,7 +1266,7 @@ the product space of two Fibonacci-graded physical spaces ```@example symmetric_tutorial V = Vect[FibonacciAnyon](:τ => 1) ``` -and assigning the following nonzero block value to the two-site fusion trees +and assigning the following nonzero subblock value to the two-site fusion trees ```@raw html
Fib_fusiontrees
``` From 67f2d013de725d9f88c7bf6f007ef0f00e084c02 Mon Sep 17 00:00:00 2001 From: leburgel Date: Sun, 23 Nov 2025 12:49:31 +0100 Subject: [PATCH 09/26] Switch appendix order --- docs/make.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/make.jl b/docs/make.jl index 6432dec46..e6be96992 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -21,7 +21,7 @@ pages = [ "lib/spaces.md", "lib/tensors.md", ], "Index" => ["index/index.md"], - "Appendix" => ["appendix/categories.md", "appendix/symmetric_tutorial.md"], + "Appendix" => ["appendix/symmetric_tutorial.md", "appendix/categories.md"], ] mathengine = MathJax3( From 076ed21b1de6ebb25de19b2cbe1d7a376ebe629f Mon Sep 17 00:00:00 2001 From: Lander Burgelman <39218680+leburgel@users.noreply.github.com> Date: Wed, 26 Nov 2025 21:35:57 +0100 Subject: [PATCH 10/26] Apply suggestions from code review Co-authored-by: Jutho --- docs/src/appendix/symmetric_tutorial.md | 50 ++++++++++++------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index 81259b3d2..bb23fed78 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -31,7 +31,7 @@ using Test # for showcase testing ## Level 0: The 1-dimensional Ising model -As the most basic example, we will consider the +As the most basic example, we consider the [1-dimensional transverse-field Ising model](https://en.wikipedia.org/wiki/Transverse-field_Ising_model), whose Hamiltonian is given by @@ -57,14 +57,14 @@ U = \prod_i X_i. We will circle back to the implications of this symmetry later. -As a warmup we will implement the Hamiltonian \eqref{eq:isingham} in the standard way by +As a warmup, we implement the Hamiltonian \eqref{eq:isingham} in the standard way by encoding the matrix elements of the single-site operators $X$ and $Z$ into an array of complex numbers, and then combine them in a suitable way to get the Hamiltonian terms. -Instead of using plain Julia arrays, we will use a representation in terms of `TensorMap`s -over complex vector spaces. These will essentially just be wrappers around base arrays at +Instead of using plain Julia arrays, we use a representation in terms of `TensorMap`s +over complex vector spaces. These are essentially just wrappers around base arrays at this point, but their construction requires some consideration of the notion of *spaces*, which generalize the notion of `size` for arrays. Each of the operators $X$ and $Z$ acts on -a local 2-dimensional complex vector space. In the context of TensorKit.jl such a space can +a local 2-dimensional complex vector space. In the context of TensorKit.jl, such a space can be represented as `ComplexSpace(2)`, or using the convenient shorthand `ℂ^2`. A single-site Pauli operator maps from a domain physical space to a codomain physical space, and can therefore be represented as instances of a `TensorMap(..., ℂ^2 ← ℂ^2)`. The corresponding @@ -128,8 +128,8 @@ local symmetry transformation $X$ acts trivially on the state $\ket{+}$, corresp the *trivial irrep*, and yields a minus sign when acting on $\ket{-}$, corresponding to the *sign irrep*. -Next, let's make the statement that 'the matrix blocks of the local tensors are labeled by -$\mathbb{Z}_2$ irreps' more concrete. To this end, consider the action of $ZZ$ in the irrep +Next, let's make the statement that "the matrix blocks of the local tensors are labeled by +$\mathbb{Z}_2$ irreps" more concrete. To this end, consider the action of $ZZ$ in the irrep basis, which is given by the four nonzero matrix elements ```math @@ -164,7 +164,7 @@ irreps, the fusion rules are Abelian, and are given by addition modulo 2, To see how these fusion rules arise, we can consider the action of the symmetry transformation $XX$ on the possible two-site basis states, each of which corresponds to a tensor product of representations. We can see that $XX$ acts trivially on both $\ket{+} -\otimes \ket{+}$ and $\ket{-} \otimes \ket{-}$ meaning these transform under the trivial +\otimes \ket{+}$ and $\ket{-} \otimes \ket{-}$, meaning these transform under the trivial representation, which gives the first and last entries of the fusion rules. Similarly, $XX$ acts with a minus sign on both $\ket{+} \otimes \ket{-}$ and $\ket{-} \otimes \ket{+}$, meaning these transform under the sign representation, which gives the second and third @@ -238,7 +238,7 @@ fields: - `vertices::NTuple{L,T}`: list of fusion vertex labels of type `T` and length `L = N - 1` For our current application only `uncoupled` and `coupled` are relevant, since -$\mathbb{Z}_2$ irreps are self-dual and have Abelian fusion rules. We will come back to +$\mathbb{Z}_2$ irreps are self-dual and have Abelian fusion rules, so that irreps on the inner lines of a fusion tree are completely determined by the uncoupled irreps. We will come back to these other properties when discussion more involved applications. Given some `TensorMap`, the method `TensorKit.fusiontrees(t::TensorMap)` returns an iterator over all pairs of splitting and fusion trees that label the subblocks of `t`. @@ -316,7 +316,7 @@ Given these local operators, we can use them to construct the full manifestly $\mathbb{Z}_2$-symmetric Hamiltonian. !!! note - An important observation is that when explicitly imposing the $\mathbb{Z}_2$ symmetry we + An important observation is that, when explicitly imposing the $\mathbb{Z}_2$ symmetry, we directly constructed the full $ZZ$ operator as a single symmetric tensor. This in contrast to the case without symmetries, where we constructed a single-site $Z$ operator and then combined them into a two-site operator. Clearly this can no longer be done when imposing @@ -329,7 +329,7 @@ $\mathbb{Z}_2$-symmetric Hamiltonian. ## Level 2: The $\mathrm{U}(1)$ Bose-Hubbard model -For our next example we will consider the +For our next example, we consider the [Bose-Hubbard model](https://en.wikipedia.org/wiki/Bose%E2%80%93Hubbard_model), which describes interacting bosons on a lattice. The Hamiltonian of this model is given by ```math @@ -366,7 +366,7 @@ U = \sum_i N_i ``` This invariance corresponds to a $\mathrm{U}(1)$ particle number symmetry, which can again be manifestly imposed when constructing the Hamiltonian terms as `TensorMap`s. From the -representation theory of $\mathrm{U}(1)$ we know that it's irreps are all one-dimensional +representation theory of $\mathrm{U}(1)$, we know that its irreps are all one-dimensional and can be labeled by integers $n$ where the tensor product of two irreps is corresponds to addition of these labels, giving the Abelian fusion rules ```math @@ -542,7 +542,7 @@ in terms of fusion trees and corresponding subblocks, the symmetries considered been quite 'simple' in the sense that sectors corresponding to irreps of $\mathbb{Z}_2$ and $\mathrm{U}(1)$ have [*Abelian fusion rules*](@ref FusionStyle) and [*bosonic exchange statistics*](@ref BraidingStyle). -This means that the fusion of two irreps always gives a single irrep as the fusion product, +This means that the fusion of two irreps always gives a unique irrep as the fusion product, and that exchanging two irreps in a tensor product is trivial. In practice, this implies that for tensors with these symmetries the fusion trees are completely fixed by the uncoupled charges, which uniquely define both the inner lines and the coupled charge, and @@ -730,7 +730,7 @@ the `subblocks` of each tensor. symmetric tensors that correspond to the symmetric Hamiltonian terms was still quite straightforward, it is far less clear in this case how to construct these terms as contractions of local symmetric tensors representing individual creation and annihilation - operators in this case. While such a decomposition can always be in principle obtained using + operators. While such a decomposition can always be in principle obtained using a (now explicitly fermionic) SVD, manually constructing such tensors as we did in the bosonic case is far from trivial. Trying this would be a good exercise in working with fermionic symmetries, but it is not something we will do here. @@ -790,7 +790,7 @@ irreps, $V^{(l_1)} \otimes V^{(l_2)} \cong \bigoplus_{k} V^{(k)}$. The precise n this decomposition, also refered to as the *Clebsch-Gordan problem*, is given by the so-called *Clebsch-Gordan coefficients*, which we will denote as $C^{k}_{l_1,l_2}$. This set of coefficients, which can be interpreted as a $\text{dim}\left( V^{(l_1)} \right) \times -\text{dim}\left( V^{(l_2)} \right) \times \text{dim}\left( V^{(k)} \right)$ array, that +\text{dim}\left( V^{(l_2)} \right) \times \text{dim}\left( V^{(k)} \right)$ array, encodes how a basis state $\ket{k,n} \in V^{(k)}$ corresponding to some term in the direct sum can be decomposed into a linear combination of basis vectors $\ket{l_1,m_1} \otimes \ket{l_2,m_2}$ of the tensor product space: @@ -842,7 +842,7 @@ is equal to $2l + 1$. The fusion rules of $\mathrm{SU}(2)$ are given by ```math \begin{equation} \label{eq:su2_fusion_rules} -l_1 \otimes l_2 \cong \bigoplus_{k=|l_1-l_2|}^{l_1+l_2}s. +l_1 \otimes l_2 \cong \bigoplus_{k=|l_1-l_2|}^{l_1+l_2}k. \end{equation} ``` These are clearly non-Abelian since multiple terms appear on the right hand side, for @@ -902,10 +902,10 @@ associated to the corresponding irrep fusion tree. ``` This procedure works for any group symmetry, and all we need are matrix elements of the -operator in the irrep basis and the Clebsch-Gordan coefficients. In the following we +operator in the irrep basis and the Clebsch-Gordan coefficients. In the following, we demonstrate this explicit procedure for the particular example of $G = \mathrm{SU}(2)$. -However, it should be noted that for general groups the Clebsch-Gordan coefficients may not -be as easy to compute (in general, no closed formulas exist). In addition, the procedure for +However, it should be noted that, for other non-Abelian groups, the Clebsch-Gordan coefficients may not +be as easy to compute (generically, no closed formulas exist). In addition, the procedure for manually projecting out the reduced tensor elements requires being particularly careful about the correspondence between the basis states used to define the original matrix elements and those implied by the Clebsch-Gordan coefficients. Finally, for some symmetries @@ -916,7 +916,7 @@ some examples of this below. Having introduced and demonstrated the Clebsch-Gordan decomposition, the corresponding coefficients and their role in symmetric tensors for the example of $\mathrm{SU}(2)$ using -the WignerSymbols.jl package, we'll continue our discussion using only TensorKit.jl +the WignerSymbols.jl package, we now continue our discussion using only TensorKit.jl internals. Within TensorKit.jl, the $\text{dim}\left( V^{(l_1)} \right) \times \text{dim}\left( V^{(l_2)} \right) \times \text{dim}\left( V^{(k)} \right)$ array of coefficients that encodes the splitting of the irrep space $V^{(k)}$ to the tensor @@ -978,7 +978,7 @@ nothing #hide ``` The next step is to project out the reduced tensor elements by taking the overlap with the -appropriate Clebsch-Gordan coefficients. In our current case of a spin-1 physical space we +appropriate Clebsch-Gordan coefficients. In our current case of a spin-1 physical space, we have $l_1 = l_2 = l_3 = l_4 = 1$, and the coupled irrep $k$ can therefore take the values $0, 1, 2$. The reduced tensor element for a given $k$ can be implemented in the following way: @@ -1041,7 +1041,7 @@ subblocks(SS) We demonstrated this entire procedure of extracting the reduced tensor elements of a symmetric tensor map for each fusion tree by projecting out the corresponding fusion tensors as an explicit illustration of how symmetric tensor maps work under the hood. In practice -however, there's no need to perform this procedure explicitly. Given a dense array +however, there is no need to perform this procedure explicitly. Given a dense array representing the matrix elements of a tensor map in the irrep basis, we can convert this to the corresponding symmetric tensor map by passing the data array to the `TensorMap` constructor along with the corresponding spaces, @@ -1060,7 +1060,7 @@ SS_auto = TensorMap(SS_arr, V ⊗ V ← V ⊗ V) number $m = -1, 0, 1$, seems quite natural, for many symmetries there is no transparent natural choice. In those cases, the only way to use this approach is to explicitly check the basis convention used by [`TensorKitSectors.fusiontensor`](@ref) for that specific symmetry. - On top of thes, there's some additional complications when considering graded spaces which + On top of this, there are some additional complications when considering graded spaces which contain multiple sectors with non-trivial degeneracies. In that case, to even initialize the dense data array in the first place, you would need to know the order in which the sectors appear in each space internally. This information can be obtained by calling `axes(V, c)`, @@ -1080,7 +1080,7 @@ for the Heisenberg model. First, we rewrite the exchange interaction in the foll \vec{S}_i \cdot \vec{S}_j = \frac{1}{2} \left( \left( \vec{S}_i + \vec{S}_j \right)^2 - \vec{S}_i^2 - \vec{S}_j^2 \right) \end{equation} ``` -Here, $\vec{S}_i$ and $\vec{S}_j$ are spin operators on the physcial irrep, while total spin +Here, $\vec{S}_i$ and $\vec{S}_j$ are spin operators on the physical irrep, while total spin operator $\vec{S}_i + \vec{S}_j$ can be decomposed onto the different coupled irreps $k$. It is a well known fact that the quadratic sum of the generators of $\mathrm{SU}(2)$, often refered to as the @@ -1287,5 +1287,5 @@ subblocks(h) However, for categorical symmetries such as the Fibonacci anyons, there are no Clebsch-Gordan coefficients. Therefore, the 'matrix elements of the operator in the irrep basis' are not well-defined, meaning that a Fibonacci-symmetric tensor cannot actually be - converted to a plain array in a meaningful way. + converted to a plain array in a straightforward way. From 11e86e26b513aa1345c12849a36e94897f1cf81d Mon Sep 17 00:00:00 2001 From: Lander Burgelman <39218680+leburgel@users.noreply.github.com> Date: Fri, 28 Nov 2025 16:34:45 +0100 Subject: [PATCH 11/26] Apply suggestions from code review Co-authored-by: Boris De Vos <143942306+borisdevos@users.noreply.github.com> --- docs/src/appendix/symmetric_tutorial.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index bb23fed78..135c28c74 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -5,13 +5,13 @@ are relevant to some common physical systems, with an increasing degree of compl will assume the reader is somewhat familiar with [the notion of a 'tensor map'](@ref ss_whatistensor) and has a rough idea of [what it means for a tensor map to be 'symmetric'](@ref ss_symmetries). In going through these examples we aim to provide a -relatively gently introduction to the meaning of [symmetry sectors](@ref ss_sectors) and +relatively gentle introduction to the meaning of [symmetry sectors](@ref ss_sectors) and [vector spaces](@ref ss_rep) within the context of TensorKit.jl, [how to initialize a `TensorMap` over a given vector space](@ref ss_tensor_construction) and finally how to manually set the data of a [symmetric `TensorMap`](@ref ss_tutorial_symmetries). We will keep our discussion as intuitive and simple as possible, only adding as many technical details as strictly necessary to understand each example. When considering a different -physical system of interest, you should then be able to adatpt these recipes and the +physical system of interest, you should then be able to adapt these recipes and the intuition behind them to your specific problem at hand. !!! note @@ -594,7 +594,7 @@ denote by '1'. The fusion rules of these irreps are the same as for $\mathbb{Z}_ to the previous case, the local symmetry operator $Q_i$ is already diagonal, so the occupation number basis coincides with the irrep basis and we don't need an additional basis transform. The important difference with a regular $\mathbb{Z}_2$ symmetry is that the -irreps of $f\mathbb{Z}_2$ have fermionic braiding statistics, in the sense that exhanging +irreps of $f\mathbb{Z}_2$ have fermionic braiding statistics, in the sense that exchanging two odd irreps gives rise to a minus sign. In TensorKit.jl, an $f\mathbb{Z}_2$-graded vector spaces is represented as a @@ -742,7 +742,7 @@ We will now move on to systems which have more complicated *non-Abelian* symmetr non-Abelian symmetry group $G$, the fact that its elements do not all commute has a profound impact on its representation theory. In particular, the irreps of such a group can be higher dimensional, and the fusion of two irreps can give rise to multiple different irreps. On the -one hand this means that fusion trees of these irreps are no longer completely determined by +one hand, this means that fusion trees of these irreps are no longer completely determined by the uncoupled charges. Indeed, in this case some of the [internal structure of the `FusionTree` type](@ref sss_fusion_trees) we have ignored before will become relevant (of which we will give an [example below](@ref sss_sun_heisenberg)). On the other hand, it @@ -911,7 +911,7 @@ about the correspondence between the basis states used to define the original ma elements and those implied by the Clebsch-Gordan coefficients. Finally, for some symmetries supported in TensorKit.jl, there are simply no Clebsch-Gordan coefficients. Therefore, it is often easier and sometimes simply necessary to directly construct the symmetric tensor and -then fill in its reduced tensor elements based on some representation theory. Wel will cover +then fill in its reduced tensor elements based on some representation theory. We will cover some examples of this below. Having introduced and demonstrated the Clebsch-Gordan decomposition, the corresponding From bb8c26c64f52c6f05ad22e77e2135227a1754453 Mon Sep 17 00:00:00 2001 From: leburgel Date: Wed, 26 Nov 2025 21:55:45 +0100 Subject: [PATCH 12/26] Add comment on the terms 'charge' and 'sector' --- docs/src/appendix/symmetric_tutorial.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index 135c28c74..157b42281 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -213,8 +213,14 @@ elements corresponding to the fusion trees of a `TensorMap` can be accessed thro ### [Fusion trees and how to use them](@id sss_fusion_trees) -This view of the underlying symmetry structure in terms of fusion trees and corresponding -reduced tensor elements is a very convenient way of working with the `TensorMap` type. +This view of the underlying symmetry structure in terms of fusion trees of irreps and +corresponding reduced tensor elements is a very convenient way of working with the +`TensorMap` type. In fact, this symmetry structure is inherently ingrained in a `TensorMap`, +and goes beyond the group-loke symmetries we have considered until now. In this more general +setting, we will refer to the labels that appear on this fusion trees as *charges* or +*sectors*. These can be thought of as generalization of group irreps, and appear in the +context of TensorKit.jl as instances of the [`Sector`](@ref) type. + Consider a generic fusion tree of the form ```@raw html From c9931dd610a6ed6c94af2738e904ac2cf8ba51e7 Mon Sep 17 00:00:00 2001 From: leburgel Date: Wed, 26 Nov 2025 22:12:54 +0100 Subject: [PATCH 13/26] Add note on `FusionStyle`s --- docs/src/appendix/symmetric_tutorial.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index 157b42281..393686292 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -156,8 +156,19 @@ a \otimes b \cong \bigoplus_c N_c^{ab} c, ``` where $N_{ab}^c$ encodes the number of times the irrep $c$ occurs in the tensor product of irreps $a$ and $b$. These fusion rules are called *Abelian* if the tensor product of any two -irreps corresponds to exactly one irrep. We will return to the implications of irreps with *non-Abelian* fusion rules [later](@ref ss_non_abelian). For the case of the $\mathbb{Z}_2$ -irreps, the fusion rules are Abelian, and are given by addition modulo 2, +irreps corresponds to exactly one irrep. We will return to the implications of irreps with +*non-Abelian* fusion rules [later](@ref ss_non_abelian). + +!!! note + Within TensorKit.jl, the nature of the fusion rules for charges of a given symmetry are + represented by the [`FusionStyle`](@ref) of the corresponding `Sector` subtype. What we + refer to as "Abelian" fusion rules in this tutorial corresponds to + `UniqueFusion <: FusionStyle`. We will also consider [examples](@ref ss_non_abelian) of + two different kinds of non-Abelian" fusion rules, corresponding to + `MultipleFusion <: FusionStyle` styles. + +For the case of the $\mathbb{Z}_2$ irreps, the fusion rules are Abelian, and are given by +addition modulo 2, ```math 0 \otimes 0 \cong 0, \quad 0 \otimes 1 \cong 1, \quad 1 \otimes 0 \cong 1, \quad 1 \otimes 1 \cong 0. ``` From 30c803bd04baaaafc0ab5f982a860e5a9fbf7e30 Mon Sep 17 00:00:00 2001 From: leburgel Date: Wed, 26 Nov 2025 22:24:23 +0100 Subject: [PATCH 14/26] Show `subblocks` of fermionic operators --- docs/src/appendix/symmetric_tutorial.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index 393686292..d6fb50d54 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -696,7 +696,7 @@ for (s, f) in fusiontrees(c⁺c⁻) c⁺c⁻[s, f] .= 1 end end -c⁺c⁻ +subblocks(c⁺c⁻) ``` ```@example symmetric_tutorial @@ -706,7 +706,7 @@ for (s, f) in fusiontrees(c⁻c⁺) c⁻c⁺[s, f] .= -1 end end -c⁻c⁺ +subblocks(c⁻c⁺) ``` ```@example symmetric_tutorial @@ -717,7 +717,7 @@ for (s, f) in fusiontrees(c⁺c⁺) c⁺c⁺[s, f] .= 1 end end -c⁺c⁺ +subblocks(c⁺c⁺) ``` ```@example symmetric_tutorial @@ -727,7 +727,7 @@ for (s, f) in fusiontrees(c⁻c⁻) c⁻c⁻[s, f] .= -1 end end -c⁻c⁻ +subblocks(c⁻c⁻) ``` ```@example symmetric_tutorial @@ -735,11 +735,10 @@ N = zeros(ComplexF64, V ← V) for (s, f) in fusiontrees(N) N[s, f] .= f.coupled == odd ? 1 : 0 end -N +subblocks(N) ``` -Again, you can easily verify that all the reduced tensor elements are correct by inspecting -the `subblocks` of each tensor. +We can easily all the reduced tensor elements are indeed correct. !!! note Working with fermionic systems is inherently tricky, as can already be seen from something From c9386885c45b6ee2c0c1d1dfe197c5ca0247d625 Mon Sep 17 00:00:00 2001 From: leburgel Date: Fri, 28 Nov 2025 16:37:03 +0100 Subject: [PATCH 15/26] Some formatting --- docs/src/appendix/symmetric_tutorial.md | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index d6fb50d54..ff8cf7bd6 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -255,10 +255,11 @@ fields: - `vertices::NTuple{L,T}`: list of fusion vertex labels of type `T` and length `L = N - 1` For our current application only `uncoupled` and `coupled` are relevant, since -$\mathbb{Z}_2$ irreps are self-dual and have Abelian fusion rules, so that irreps on the inner lines of a fusion tree are completely determined by the uncoupled irreps. We will come back to -these other properties when discussion more involved applications. Given some `TensorMap`, -the method `TensorKit.fusiontrees(t::TensorMap)` returns an iterator over all pairs of -splitting and fusion trees that label the subblocks of `t`. +$\mathbb{Z}_2$ irreps are self-dual and have Abelian fusion rules, so that irreps on the +inner lines of a fusion tree are completely determined by the uncoupled irreps. We will come +back to these other properties when discussion more involved applications. Given some +`TensorMap`, the method `TensorKit.fusiontrees(t::TensorMap)` returns an iterator over all +pairs of splitting and fusion trees that label the subblocks of `t`. We can now put this into practice by directly constructing the $ZZ$ operator in the irrep basis as a $\mathbb{Z}_2$-symmetric `TensorMap`. We will do this in three steps: @@ -544,12 +545,14 @@ It is then simple to check that this is indeed what we expect. !!! note From the construction of the Hamiltonian operators [in terms of creation and annihilation operators](bosonham) we clearly see that they are - invariant under a transformation $a^\pm \to e^{\pm i\theta} a^\pm$. More generally, any - invertible transformation on the auxiliary space leaves the resulting contraction unchanged. - This ambiguity in the definition clearly shows that one should really always think in terms - of the fully symmetric procucts of $a^+$ and $a^-$ rather than in terms of these operators - themselves. In particular, one can always decompose such a symmetric product into the - [form above](bosonham) by means of an SVD. + invariant under a transformation $a^\pm \to e^{\pm i\theta} a^\pm$. More generally, for + a two-site operator that is defined as the contraction of two one-site operators across + an auxiliary space, modifying the one-site operators by applying transformations $Q$ and + $Q^{-1}$ on their respective auxiliary spaces for any invertible $Q$ leaves the + resulting contraction unchanged. This ambiguity in the definition clearly shows that one + should really always think in terms of the fully symmetric procucts of $a^+$ and $a^-$ + rather than in terms of these operators themselves. In particular, one can always + decompose such a symmetric product into the [form above](bosonham) by means of an SVD. ## Level 3: Fermions and the Kitaev model From 2c54329ced147fa995a4851510059cfa5a12f60d Mon Sep 17 00:00:00 2001 From: leburgel Date: Fri, 28 Nov 2025 16:45:05 +0100 Subject: [PATCH 16/26] Un-specify `fusiontrees` --- docs/src/appendix/symmetric_tutorial.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index ff8cf7bd6..50fabf060 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -258,8 +258,8 @@ For our current application only `uncoupled` and `coupled` are relevant, since $\mathbb{Z}_2$ irreps are self-dual and have Abelian fusion rules, so that irreps on the inner lines of a fusion tree are completely determined by the uncoupled irreps. We will come back to these other properties when discussion more involved applications. Given some -`TensorMap`, the method `TensorKit.fusiontrees(t::TensorMap)` returns an iterator over all -pairs of splitting and fusion trees that label the subblocks of `t`. +`TensorMap`, the method [`fusiontrees`](@ref) returns an iterator over all pairs of +splitting and fusion trees that label the subblocks of `t`. We can now put this into practice by directly constructing the $ZZ$ operator in the irrep basis as a $\mathbb{Z}_2$-symmetric `TensorMap`. We will do this in three steps: From 4adf11b07bda047a17648610598fcdffe9fbe87f Mon Sep 17 00:00:00 2001 From: Lander Burgelman <39218680+leburgel@users.noreply.github.com> Date: Mon, 1 Dec 2025 10:08:51 +0100 Subject: [PATCH 17/26] Apply suggestions from code review Co-authored-by: Lukas Devos --- docs/src/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/index.md b/docs/src/index.md index 96b750fdf..bdd93f541 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -49,6 +49,6 @@ Depth = 2 ## Appendix ```@contents -Pages = ["appendix/categories.md", "appendix/symmetric_tutorial.md"] +Pages = ["appendix/symmetric_tutorial.md", "appendix/categories.md"] Depth = 2 ``` From b4bb3a61ebc8baa58a9c3026a7d8abdcae7f6cb0 Mon Sep 17 00:00:00 2001 From: leburgel Date: Mon, 1 Dec 2025 09:40:43 +0100 Subject: [PATCH 18/26] Add note on fusion multiplicities and their implication for the Clebsch-Gordan decomposition --- docs/src/appendix/symmetric_tutorial.md | 28 ++++++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index 50fabf060..2183008b4 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -852,6 +852,19 @@ precisely this structure that is inherently encoded into the fusion tree part of symmetric tensor is precisely the reduced tensor element in the Clebsch-Gordan decomposition**. +!!! note + In the Clebsch-Gordan decomposition given above, our notation has actually silently + assumed that each irrep $k$ only occurs once in the fusion product of the uncoupled + irreps $l_1$ and $l_2$. However, there exist symmetries which have **fusion multiplicities**, + where two irreps can fuse to a given coupled irrep in multiple *distinct* ways. In + TensorKit.jl, these correspond to `Sector` types with a `GenericFusion <: FusionStyle` + fusion style. In the presence of fusion multiplicities, the Clebsch-Gordan coefficients + actually have an additional index which labels the particular fusion channel according + to which $l_1$ and $l_2$ fuse to $k$. Since the fusion of $\mathrm{SU}(2)$ irreps is + multiplicity-free, we could safely ignore this nuance here. We will encounter the + implication of fusion multiplicities shortly, and will consider an example of a symmetry + which has these multiplicities below. + As a small demonstration of this fact, we can make a simple $\mathrm{SU}(2)$-symmetric tensor with trivial subblock values and verify that its implied symmetry structure exactly corresponds to the expected Clebsch-Gordan coefficient. First, we [recall](su2_irreps) that @@ -954,14 +967,13 @@ f = fusiontensor(SU2Irrep(1//2), SU2Irrep(1//2), SU2Irrep(1)) We see that this fusion tensor has a size `2×2×3×1`, which contains an additional trailing `1` to what we might expect. In the general case, `fusiontensor` returns a 4-dimensional array, where the size of the first three dimensions corresponds to the dimensions of the -irrep spaces under consideration, and the last dimension corresponds to the number of -distinct ways the irreps $l_1$ and $l_1$ can fuse to irrep $k$. We say that `Sector`s for -which the size of this last dimension can be larger than 1 have *fusion multiplicities*. -We'll encounter an example of this below when we consider an $\mathrm{SU}(3)$ symmetry. -Since $\mathrm{SU}(2)$ doesn't have any fusion multiplicities, we can just discard this last -index. - -We can now explicitly that this `fusiontensor` indeed does what we expect it to do: +irrep spaces under consideration, and the last index lables the different fusion channels, +where its dimension corresponds to the number of distinct ways the irreps $l_1$ and $l_2$ +can fuse to irrep $k$. This is precicely the extra label of the Clebsch-Gordan coefficients +that is required in the the presence of fusion multiplicities. Since $\mathrm{SU}(2)$ is +multiplicity-free, we can just discard this last index here. + +We can now explicitly verify that this `fusiontensor` indeed does what we expect it to do: ```@example symmetric_tutorial @test ta ≈ f[:, :, :, 1] ``` From 54adef2ad00d124b2c397288ac13ddb003555bc8 Mon Sep 17 00:00:00 2001 From: leburgel Date: Mon, 1 Dec 2025 09:49:23 +0100 Subject: [PATCH 19/26] Change Ising model title --- docs/src/appendix/symmetric_tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index 2183008b4..a063fe7f2 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -29,7 +29,7 @@ using Test # for showcase testing ``` -## Level 0: The 1-dimensional Ising model +## Level 0: The transverse-field Ising model As the most basic example, we consider the [1-dimensional transverse-field Ising model](https://en.wikipedia.org/wiki/Transverse-field_Ising_model), From 07066daa20dc39ab13ee75e4d60bdafc2fa0b521 Mon Sep 17 00:00:00 2001 From: leburgel Date: Mon, 1 Dec 2025 09:50:34 +0100 Subject: [PATCH 20/26] Remove unnecessary semicolon --- docs/src/appendix/symmetric_tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index a063fe7f2..fd2b49591 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -84,7 +84,7 @@ X = TensorMap(x_mat, V ← V) Z = TensorMap(z_mat, V ← V) # combine single-site operators into two-site operator -ZZ = Z ⊗ Z; +ZZ = Z ⊗ Z ``` We can easily verify that our operators have the desired form by checking their data in the From 8a2c34f1b9555dfcac5bd6788ef9739c15026184 Mon Sep 17 00:00:00 2001 From: leburgel Date: Mon, 1 Dec 2025 10:08:20 +0100 Subject: [PATCH 21/26] Introduce `Z2Irrep` more gently and demonstrate its fusion rules programatically --- docs/src/appendix/symmetric_tutorial.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index fd2b49591..3c9f27fca 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -270,12 +270,23 @@ basis as a $\mathbb{Z}_2$-symmetric `TensorMap`. We will do this in three steps: - And finally we iterate over all splitting and fusion tree pairs and manually fill in the corresponding nonzero subblocks of the operator. +In TensorKit.jl, the representations of $\mathbb{Z}_2$ are represented as instances of the +[`Z2Irrep <: Sector`](@ref ZNIrrep) type. There are two such instances, corresponding to the +trivial irrep `Z2Irrep(0)` and the sign irrep `Z2Irrep(1)`. We can fuse irreps with the `⊗` +(`\otimes`) operator, which can for example be used to check their fusion rules, +```@example symmetric_tutorial +for a in values(Z2Irrep), b in values(Z2Irrep) + println("$a ⊗ $b: $(a ⊗ b)") +end +``` After the basis transform to the irrep basis, we can view the two-dimensional complex physical vector space we started with as being spanned by the trivial and sign irrep of $\mathbb{Z}_2$. In the language of TensorKit.jl, this can be implemented as a `Z2Space`, an -alias for a [graded vector space](@ref GradedSpace) `Vect[Z2Irrep]`, which contains the -trivial irrep `Z2Irrep(0)` with degeneracy 1 and the sign irrep `Z2Irrep(1)` with -degeneracy 1. We can define this space in the following way and check its dimension: +alias for a [graded vector space](@ref GradedSpace) `Vect[Z2Irrep]`. To construct such a +graded space we have to specify which irreps it contains, and indicate the degenaracy of +each irrep. Here, our physical vector space contains the trivial irrep `Z2Irrep(0)` with +degeneracy 1 and the sign irrep `Z2Irrep(1)` with degeneracy 1. This means can define this +space in the following way, and check its dimension: ```@example symmetric_tutorial V = Z2Space(0 => 1, 1 => 1) From 74e08d4d5a385973d9faae21e57f8d3a01741256 Mon Sep 17 00:00:00 2001 From: leburgel Date: Mon, 1 Dec 2025 10:33:33 +0100 Subject: [PATCH 22/26] Fix box to be technically correct. --- docs/src/appendix/symmetric_tutorial.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index 3c9f27fca..17a432a50 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -513,12 +513,13 @@ We can then combine these operators to get the appropriate Hamiltonian terms, Although we have made a suggestive distinction between the 'left' and 'right' versions of the operators $a_L^\pm$ and $a_R^\pm$, one can actually be obtained from the other by permuting the physical and auxiliary indices of the corresponding `TensorMap`s. This - permutation has no effect on the actual subblocks of the tensors due to the bosonic - [`BraidingStyle`](@ref) of $\mathrm{U}(1)$ irreps, so the left and right operators can - in essence be seen as the 'same' tensors. This is no longer the case when considering - fermionic systems, where permuting indices can in fact change the subblocks as we will - see next. As a consequence, it is much less clear how to construct two-site symmetric - operators in terms of local symmetric objects. + permutation has no effect on the actual subblocks of the tensors due to the Abelian + [`FusionStyle`](@ref) and bosonic [`BraidingStyle`](@ref) of $\mathrm{U}(1)$ irreps, so + the left and right operators can in essence be seen as the 'same' tensors. This is no + longer the case when considering non-Abelian or symmetries. For these cases, permuting + indices can in fact change the subblocks, as we will see next. As a consequence, it is + much less clear how to construct two-site symmetric operators in terms of local + symmetric objects. The explicit construction then looks something like From e9defd3c0cfcb1d843ff91e349ea1026ed7dc466 Mon Sep 17 00:00:00 2001 From: Lander Burgelman <39218680+leburgel@users.noreply.github.com> Date: Mon, 1 Dec 2025 14:06:26 +0100 Subject: [PATCH 23/26] Update docs/src/appendix/symmetric_tutorial.md Co-authored-by: Jutho --- docs/src/appendix/symmetric_tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index 17a432a50..5e5bdc672 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -516,7 +516,7 @@ We can then combine these operators to get the appropriate Hamiltonian terms, permutation has no effect on the actual subblocks of the tensors due to the Abelian [`FusionStyle`](@ref) and bosonic [`BraidingStyle`](@ref) of $\mathrm{U}(1)$ irreps, so the left and right operators can in essence be seen as the 'same' tensors. This is no - longer the case when considering non-Abelian or symmetries. For these cases, permuting + longer the case when considering non-Abelian symmetries, or symmetries associated with fermions or anyons. For these cases, permuting indices can in fact change the subblocks, as we will see next. As a consequence, it is much less clear how to construct two-site symmetric operators in terms of local symmetric objects. From d6096a18bd5b2d5473c81f15568e8ee42ea441c1 Mon Sep 17 00:00:00 2001 From: leburgel Date: Mon, 1 Dec 2025 16:09:02 +0100 Subject: [PATCH 24/26] Address more comments, add toc --- docs/src/appendix/symmetric_tutorial.md | 37 ++++++++++++++++++++----- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index 5e5bdc672..4d5778749 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -28,6 +28,10 @@ using SUNRepresentations using Test # for showcase testing ``` +```@contents +Pages = ["symmetric_tutorial.md"] +Depth = 2:3 +``` ## Level 0: The transverse-field Ising model @@ -261,6 +265,8 @@ back to these other properties when discussion more involved applications. Given `TensorMap`, the method [`fusiontrees`](@ref) returns an iterator over all pairs of splitting and fusion trees that label the subblocks of `t`. +### Constructing a $\mathbb{Z}_2$-symmetric `TensorMap` + We can now put this into practice by directly constructing the $ZZ$ operator in the irrep basis as a $\mathbb{Z}_2$-symmetric `TensorMap`. We will do this in three steps: @@ -276,22 +282,39 @@ trivial irrep `Z2Irrep(0)` and the sign irrep `Z2Irrep(1)`. We can fuse irreps w (`\otimes`) operator, which can for example be used to check their fusion rules, ```@example symmetric_tutorial for a in values(Z2Irrep), b in values(Z2Irrep) - println("$a ⊗ $b: $(a ⊗ b)") + println("$a ⊗ $b = $(a ⊗ b)") end ``` After the basis transform to the irrep basis, we can view the two-dimensional complex physical vector space we started with as being spanned by the trivial and sign irrep of $\mathbb{Z}_2$. In the language of TensorKit.jl, this can be implemented as a `Z2Space`, an -alias for a [graded vector space](@ref GradedSpace) `Vect[Z2Irrep]`. To construct such a -graded space we have to specify which irreps it contains, and indicate the degenaracy of -each irrep. Here, our physical vector space contains the trivial irrep `Z2Irrep(0)` with -degeneracy 1 and the sign irrep `Z2Irrep(1)` with degeneracy 1. This means can define this -space in the following way, and check its dimension: - +alias for a [graded vector space](@ref GradedSpace) `Vect[Z2Irrep]`. Such a graded vector +space $V$ is a direct sum of irreducible representation spaces $V^{(a)}$ labeled by the +irreps $a$ of the group, +```math +V = \bigotimes_a N_a \cdot V^{(a)}. +``` +The number of times $N_a$ each irrep $a$ appears in the direct sum is called the +*degeneracy* of the irrep. To construct such a graded space, we therefore have to specify +which irreps it contains, and indicate the degeneracy of each irrep. Here, our physical +vector space contains the trivial irrep `Z2Irrep(0)` with degeneracy 1 and the sign irrep +`Z2Irrep(1)` with degeneracy 1. This means this particular graded space has the form +```math +V = 1 \cdot V^{(0)} \oplus 1 \cdot V^{(1)}, +``` +which can be constructed in the following way, ```@example symmetric_tutorial V = Z2Space(0 => 1, 1 => 1) dim(V) ``` +As a consistency check, we can inspect its dimension as well as the degeneracies of the +individual irreps: +```@example symmetric_tutorial +dim(V, Z2Irrep(0)) +``` +```@example symmetric_tutorial +dim(V, Z2Irrep(1)) +``` Given this physical space, we can initialize the $ZZ$ operator as an empty `TensorMap` with the appropriate structure. From e5c0461957d5e02b47cd462dabdc19c78890a2cf Mon Sep 17 00:00:00 2001 From: leburgel Date: Mon, 1 Dec 2025 16:11:35 +0100 Subject: [PATCH 25/26] Forgot to move the dims check --- docs/src/appendix/symmetric_tutorial.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index 4d5778749..1fef87bee 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -305,11 +305,13 @@ V = 1 \cdot V^{(0)} \oplus 1 \cdot V^{(1)}, which can be constructed in the following way, ```@example symmetric_tutorial V = Z2Space(0 => 1, 1 => 1) -dim(V) ``` As a consistency check, we can inspect its dimension as well as the degeneracies of the individual irreps: ```@example symmetric_tutorial +dim(V) +``` +```@example symmetric_tutorial dim(V, Z2Irrep(0)) ``` ```@example symmetric_tutorial From 9a1203a2ea8147444e47d2a108e597faf2691ae0 Mon Sep 17 00:00:00 2001 From: leburgel Date: Mon, 1 Dec 2025 19:48:26 +0100 Subject: [PATCH 26/26] Add headers for toc and setup, and switch order --- docs/src/appendix/symmetric_tutorial.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/src/appendix/symmetric_tutorial.md b/docs/src/appendix/symmetric_tutorial.md index 1fef87bee..88c9483ff 100644 --- a/docs/src/appendix/symmetric_tutorial.md +++ b/docs/src/appendix/symmetric_tutorial.md @@ -19,6 +19,14 @@ intuition behind them to your specific problem at hand. [TensorKitTensors.jl package](https://github.com/QuantumKitHub/TensorKitTensors.jl), in which case we basically provide a narrated walk-through of the corresponding code. +#### Contents of the tutorial + +```@contents +Pages = ["symmetric_tutorial.md"] +Depth = 2:3 +``` + +#### Setup ```@example symmetric_tutorial using LinearAlgebra @@ -28,11 +36,6 @@ using SUNRepresentations using Test # for showcase testing ``` -```@contents -Pages = ["symmetric_tutorial.md"] -Depth = 2:3 -``` - ## Level 0: The transverse-field Ising model As the most basic example, we consider the