passagemath-singular 10.6.31rc3__cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-singular might be problematic. Click here for more details.
- PySingular.cpython-314-aarch64-linux-gnu.so +0 -0
- passagemath_singular-10.6.31rc3.dist-info/METADATA +183 -0
- passagemath_singular-10.6.31rc3.dist-info/RECORD +490 -0
- passagemath_singular-10.6.31rc3.dist-info/WHEEL +6 -0
- passagemath_singular-10.6.31rc3.dist-info/top_level.txt +3 -0
- passagemath_singular.libs/libSingular-4-6a2a8666.4.1.so +0 -0
- passagemath_singular.libs/libcddgmp-ac579979.so.0.1.3 +0 -0
- passagemath_singular.libs/libfactory-4-66e33516.4.1.so +0 -0
- passagemath_singular.libs/libflint-81de1160.so.21.0.0 +0 -0
- passagemath_singular.libs/libgf2x-fbd36f80.so.3.0.0 +0 -0
- passagemath_singular.libs/libgfortran-e1b7dfc8.so.5.0.0 +0 -0
- passagemath_singular.libs/libgmp-93ebf16a.so.10.5.0 +0 -0
- passagemath_singular.libs/libgsl-e3525837.so.28.0.0 +0 -0
- passagemath_singular.libs/libmpfr-e0f11cf3.so.6.2.1 +0 -0
- passagemath_singular.libs/libntl-0043a3a2.so.44.0.1 +0 -0
- passagemath_singular.libs/libomalloc-0-06512335.9.6.so +0 -0
- passagemath_singular.libs/libopenblasp-r0-4c5b64b1.3.29.so +0 -0
- passagemath_singular.libs/libpolys-4-cb7246b5.4.1.so +0 -0
- passagemath_singular.libs/libreadline-28330744.so.8.2 +0 -0
- passagemath_singular.libs/libsingular_resources-4-8c425241.4.1.so +0 -0
- passagemath_singular.libs/libtinfo-f81c2d16.so.6.3 +0 -0
- sage/algebras/all__sagemath_singular.py +3 -0
- sage/algebras/fusion_rings/all.py +19 -0
- sage/algebras/fusion_rings/f_matrix.py +2448 -0
- sage/algebras/fusion_rings/fast_parallel_fmats_methods.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/fusion_rings/fast_parallel_fmats_methods.pxd +5 -0
- sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx +538 -0
- sage/algebras/fusion_rings/fast_parallel_fusion_ring_braid_repn.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/fusion_rings/fast_parallel_fusion_ring_braid_repn.pxd +3 -0
- sage/algebras/fusion_rings/fast_parallel_fusion_ring_braid_repn.pyx +331 -0
- sage/algebras/fusion_rings/fusion_double.py +899 -0
- sage/algebras/fusion_rings/fusion_ring.py +1580 -0
- sage/algebras/fusion_rings/poly_tup_engine.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/fusion_rings/poly_tup_engine.pxd +24 -0
- sage/algebras/fusion_rings/poly_tup_engine.pyx +579 -0
- sage/algebras/fusion_rings/shm_managers.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/fusion_rings/shm_managers.pxd +24 -0
- sage/algebras/fusion_rings/shm_managers.pyx +780 -0
- sage/algebras/letterplace/all.py +1 -0
- sage/algebras/letterplace/free_algebra_element_letterplace.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/letterplace/free_algebra_element_letterplace.pxd +18 -0
- sage/algebras/letterplace/free_algebra_element_letterplace.pyx +755 -0
- sage/algebras/letterplace/free_algebra_letterplace.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/letterplace/free_algebra_letterplace.pxd +35 -0
- sage/algebras/letterplace/free_algebra_letterplace.pyx +914 -0
- sage/algebras/letterplace/letterplace_ideal.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/letterplace/letterplace_ideal.pyx +408 -0
- sage/algebras/quatalg/all.py +2 -0
- sage/algebras/quatalg/quaternion_algebra.py +4778 -0
- sage/algebras/quatalg/quaternion_algebra_cython.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/quatalg/quaternion_algebra_cython.pyx +261 -0
- sage/algebras/quatalg/quaternion_algebra_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/quatalg/quaternion_algebra_element.pxd +29 -0
- sage/algebras/quatalg/quaternion_algebra_element.pyx +2176 -0
- sage/all__sagemath_singular.py +11 -0
- sage/ext_data/all__sagemath_singular.py +1 -0
- sage/ext_data/singular/function_field/core.lib +98 -0
- sage/interfaces/all__sagemath_singular.py +1 -0
- sage/interfaces/singular.py +2835 -0
- sage/libs/all__sagemath_singular.py +1 -0
- sage/libs/singular/__init__.py +1 -0
- sage/libs/singular/decl.pxd +1168 -0
- sage/libs/singular/function.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/singular/function.pxd +87 -0
- sage/libs/singular/function.pyx +1901 -0
- sage/libs/singular/function_factory.py +61 -0
- sage/libs/singular/groebner_strategy.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/singular/groebner_strategy.pxd +22 -0
- sage/libs/singular/groebner_strategy.pyx +582 -0
- sage/libs/singular/option.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/singular/option.pyx +671 -0
- sage/libs/singular/polynomial.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/singular/polynomial.pxd +39 -0
- sage/libs/singular/polynomial.pyx +661 -0
- sage/libs/singular/ring.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/singular/ring.pxd +58 -0
- sage/libs/singular/ring.pyx +893 -0
- sage/libs/singular/singular.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/singular/singular.pxd +72 -0
- sage/libs/singular/singular.pyx +1944 -0
- sage/libs/singular/standard_options.py +145 -0
- sage/matrix/all__sagemath_singular.py +1 -0
- sage/matrix/matrix_mpolynomial_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_mpolynomial_dense.pxd +7 -0
- sage/matrix/matrix_mpolynomial_dense.pyx +615 -0
- sage/rings/all__sagemath_singular.py +1 -0
- sage/rings/function_field/all__sagemath_singular.py +1 -0
- sage/rings/function_field/derivations_polymod.py +911 -0
- sage/rings/function_field/element_polymod.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/function_field/element_polymod.pyx +406 -0
- sage/rings/function_field/function_field_polymod.py +2611 -0
- sage/rings/function_field/ideal_polymod.py +1775 -0
- sage/rings/function_field/order_polymod.py +1475 -0
- sage/rings/function_field/place_polymod.py +681 -0
- sage/rings/polynomial/all__sagemath_singular.py +1 -0
- sage/rings/polynomial/multi_polynomial_ideal_libsingular.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/multi_polynomial_ideal_libsingular.pxd +5 -0
- sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx +339 -0
- sage/rings/polynomial/multi_polynomial_libsingular.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/multi_polynomial_libsingular.pxd +30 -0
- sage/rings/polynomial/multi_polynomial_libsingular.pyx +6277 -0
- sage/rings/polynomial/plural.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/plural.pxd +48 -0
- sage/rings/polynomial/plural.pyx +3171 -0
- sage/symbolic/all__sagemath_singular.py +1 -0
- sage/symbolic/comparison_impl.pxi +428 -0
- sage/symbolic/constants_c_impl.pxi +178 -0
- sage/symbolic/expression.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/symbolic/expression.pxd +7 -0
- sage/symbolic/expression.pyx +14200 -0
- sage/symbolic/getitem_impl.pxi +202 -0
- sage/symbolic/pynac.pxi +572 -0
- sage/symbolic/pynac_constant_impl.pxi +133 -0
- sage/symbolic/pynac_function_impl.pxi +206 -0
- sage/symbolic/pynac_impl.pxi +2576 -0
- sage/symbolic/pynac_wrap.h +124 -0
- sage/symbolic/series_impl.pxi +272 -0
- sage/symbolic/substitution_map_impl.pxi +94 -0
- sage_wheels/bin/ESingular +0 -0
- sage_wheels/bin/Singular +0 -0
- sage_wheels/bin/TSingular +0 -0
- sage_wheels/lib/singular/MOD/cohomo.la +41 -0
- sage_wheels/lib/singular/MOD/cohomo.so +0 -0
- sage_wheels/lib/singular/MOD/customstd.la +41 -0
- sage_wheels/lib/singular/MOD/customstd.so +0 -0
- sage_wheels/lib/singular/MOD/freealgebra.la +41 -0
- sage_wheels/lib/singular/MOD/freealgebra.so +0 -0
- sage_wheels/lib/singular/MOD/gfanlib.la +41 -0
- sage_wheels/lib/singular/MOD/gfanlib.so +0 -0
- sage_wheels/lib/singular/MOD/gitfan.la +41 -0
- sage_wheels/lib/singular/MOD/gitfan.so +0 -0
- sage_wheels/lib/singular/MOD/interval.la +41 -0
- sage_wheels/lib/singular/MOD/interval.so +0 -0
- sage_wheels/lib/singular/MOD/loctriv.la +41 -0
- sage_wheels/lib/singular/MOD/loctriv.so +0 -0
- sage_wheels/lib/singular/MOD/machinelearning.la +41 -0
- sage_wheels/lib/singular/MOD/machinelearning.so +0 -0
- sage_wheels/lib/singular/MOD/p_Procs_FieldGeneral.la +41 -0
- sage_wheels/lib/singular/MOD/p_Procs_FieldGeneral.so +0 -0
- sage_wheels/lib/singular/MOD/p_Procs_FieldIndep.la +41 -0
- sage_wheels/lib/singular/MOD/p_Procs_FieldIndep.so +0 -0
- sage_wheels/lib/singular/MOD/p_Procs_FieldQ.la +41 -0
- sage_wheels/lib/singular/MOD/p_Procs_FieldQ.so +0 -0
- sage_wheels/lib/singular/MOD/p_Procs_FieldZp.la +41 -0
- sage_wheels/lib/singular/MOD/p_Procs_FieldZp.so +0 -0
- sage_wheels/lib/singular/MOD/partialgb.la +41 -0
- sage_wheels/lib/singular/MOD/partialgb.so +0 -0
- sage_wheels/lib/singular/MOD/pyobject.la +41 -0
- sage_wheels/lib/singular/MOD/pyobject.so +0 -0
- sage_wheels/lib/singular/MOD/singmathic.la +41 -0
- sage_wheels/lib/singular/MOD/singmathic.so +0 -0
- sage_wheels/lib/singular/MOD/sispasm.la +41 -0
- sage_wheels/lib/singular/MOD/sispasm.so +0 -0
- sage_wheels/lib/singular/MOD/subsets.la +41 -0
- sage_wheels/lib/singular/MOD/subsets.so +0 -0
- sage_wheels/lib/singular/MOD/systhreads.la +41 -0
- sage_wheels/lib/singular/MOD/systhreads.so +0 -0
- sage_wheels/lib/singular/MOD/syzextra.la +41 -0
- sage_wheels/lib/singular/MOD/syzextra.so +0 -0
- sage_wheels/libexec/singular/MOD/change_cost +0 -0
- sage_wheels/libexec/singular/MOD/singularsurf +11 -0
- sage_wheels/libexec/singular/MOD/singularsurf_jupyter +9 -0
- sage_wheels/libexec/singular/MOD/singularsurf_win +10 -0
- sage_wheels/libexec/singular/MOD/solve_IP +0 -0
- sage_wheels/libexec/singular/MOD/surfex +16 -0
- sage_wheels/libexec/singular/MOD/toric_ideal +0 -0
- sage_wheels/share/factory/gftables/10201 +342 -0
- sage_wheels/share/factory/gftables/1024 +37 -0
- sage_wheels/share/factory/gftables/10609 +356 -0
- sage_wheels/share/factory/gftables/11449 +384 -0
- sage_wheels/share/factory/gftables/11881 +398 -0
- sage_wheels/share/factory/gftables/121 +6 -0
- sage_wheels/share/factory/gftables/12167 +408 -0
- sage_wheels/share/factory/gftables/125 +7 -0
- sage_wheels/share/factory/gftables/12769 +428 -0
- sage_wheels/share/factory/gftables/128 +7 -0
- sage_wheels/share/factory/gftables/1331 +47 -0
- sage_wheels/share/factory/gftables/1369 +48 -0
- sage_wheels/share/factory/gftables/14641 +490 -0
- sage_wheels/share/factory/gftables/15625 +523 -0
- sage_wheels/share/factory/gftables/16 +3 -0
- sage_wheels/share/factory/gftables/16129 +540 -0
- sage_wheels/share/factory/gftables/16384 +549 -0
- sage_wheels/share/factory/gftables/16807 +563 -0
- sage_wheels/share/factory/gftables/1681 +58 -0
- sage_wheels/share/factory/gftables/169 +8 -0
- sage_wheels/share/factory/gftables/17161 +574 -0
- sage_wheels/share/factory/gftables/1849 +64 -0
- sage_wheels/share/factory/gftables/18769 +628 -0
- sage_wheels/share/factory/gftables/19321 +646 -0
- sage_wheels/share/factory/gftables/19683 +659 -0
- sage_wheels/share/factory/gftables/2048 +71 -0
- sage_wheels/share/factory/gftables/2187 +75 -0
- sage_wheels/share/factory/gftables/2197 +76 -0
- sage_wheels/share/factory/gftables/2209 +76 -0
- sage_wheels/share/factory/gftables/22201 +742 -0
- sage_wheels/share/factory/gftables/22801 +762 -0
- sage_wheels/share/factory/gftables/2401 +82 -0
- sage_wheels/share/factory/gftables/243 +11 -0
- sage_wheels/share/factory/gftables/24389 +815 -0
- sage_wheels/share/factory/gftables/24649 +824 -0
- sage_wheels/share/factory/gftables/25 +3 -0
- sage_wheels/share/factory/gftables/256 +11 -0
- sage_wheels/share/factory/gftables/26569 +888 -0
- sage_wheels/share/factory/gftables/27 +3 -0
- sage_wheels/share/factory/gftables/27889 +932 -0
- sage_wheels/share/factory/gftables/2809 +96 -0
- sage_wheels/share/factory/gftables/28561 +954 -0
- sage_wheels/share/factory/gftables/289 +12 -0
- sage_wheels/share/factory/gftables/29791 +995 -0
- sage_wheels/share/factory/gftables/29929 +1000 -0
- sage_wheels/share/factory/gftables/3125 +107 -0
- sage_wheels/share/factory/gftables/32 +4 -0
- sage_wheels/share/factory/gftables/32041 +1070 -0
- sage_wheels/share/factory/gftables/32761 +1094 -0
- sage_wheels/share/factory/gftables/32768 +1095 -0
- sage_wheels/share/factory/gftables/343 +14 -0
- sage_wheels/share/factory/gftables/3481 +118 -0
- sage_wheels/share/factory/gftables/361 +14 -0
- sage_wheels/share/factory/gftables/36481 +1218 -0
- sage_wheels/share/factory/gftables/3721 +126 -0
- sage_wheels/share/factory/gftables/37249 +1244 -0
- sage_wheels/share/factory/gftables/38809 +1296 -0
- sage_wheels/share/factory/gftables/39601 +1322 -0
- sage_wheels/share/factory/gftables/4 +3 -0
- sage_wheels/share/factory/gftables/4096 +139 -0
- sage_wheels/share/factory/gftables/44521 +1486 -0
- sage_wheels/share/factory/gftables/4489 +152 -0
- sage_wheels/share/factory/gftables/49 +4 -0
- sage_wheels/share/factory/gftables/4913 +166 -0
- sage_wheels/share/factory/gftables/49729 +1660 -0
- sage_wheels/share/factory/gftables/5041 +170 -0
- sage_wheels/share/factory/gftables/50653 +1691 -0
- sage_wheels/share/factory/gftables/512 +20 -0
- sage_wheels/share/factory/gftables/51529 +1720 -0
- sage_wheels/share/factory/gftables/52441 +1750 -0
- sage_wheels/share/factory/gftables/529 +20 -0
- sage_wheels/share/factory/gftables/5329 +180 -0
- sage_wheels/share/factory/gftables/54289 +1812 -0
- sage_wheels/share/factory/gftables/57121 +1906 -0
- sage_wheels/share/factory/gftables/58081 +1938 -0
- sage_wheels/share/factory/gftables/59049 +1971 -0
- sage_wheels/share/factory/gftables/6241 +210 -0
- sage_wheels/share/factory/gftables/625 +23 -0
- sage_wheels/share/factory/gftables/63001 +2102 -0
- sage_wheels/share/factory/gftables/64 +5 -0
- sage_wheels/share/factory/gftables/6561 +221 -0
- sage_wheels/share/factory/gftables/6859 +231 -0
- sage_wheels/share/factory/gftables/6889 +232 -0
- sage_wheels/share/factory/gftables/729 +27 -0
- sage_wheels/share/factory/gftables/7921 +266 -0
- sage_wheels/share/factory/gftables/8 +3 -0
- sage_wheels/share/factory/gftables/81 +5 -0
- sage_wheels/share/factory/gftables/8192 +276 -0
- sage_wheels/share/factory/gftables/841 +30 -0
- sage_wheels/share/factory/gftables/9 +3 -0
- sage_wheels/share/factory/gftables/9409 +316 -0
- sage_wheels/share/factory/gftables/961 +34 -0
- sage_wheels/share/info/singular.info +191898 -0
- sage_wheels/share/singular/LIB/GND.lib +1359 -0
- sage_wheels/share/singular/LIB/JMBTest.lib +976 -0
- sage_wheels/share/singular/LIB/JMSConst.lib +1363 -0
- sage_wheels/share/singular/LIB/KVequiv.lib +699 -0
- sage_wheels/share/singular/LIB/SingularityDBM.lib +491 -0
- sage_wheels/share/singular/LIB/VecField.lib +1542 -0
- sage_wheels/share/singular/LIB/absfact.lib +959 -0
- sage_wheels/share/singular/LIB/ainvar.lib +730 -0
- sage_wheels/share/singular/LIB/aksaka.lib +419 -0
- sage_wheels/share/singular/LIB/alexpoly.lib +2542 -0
- sage_wheels/share/singular/LIB/algebra.lib +1193 -0
- sage_wheels/share/singular/LIB/all.lib +136 -0
- sage_wheels/share/singular/LIB/arcpoint.lib +514 -0
- sage_wheels/share/singular/LIB/arnold.lib +4553 -0
- sage_wheels/share/singular/LIB/arnoldclassify.lib +2058 -0
- sage_wheels/share/singular/LIB/arr.lib +3486 -0
- sage_wheels/share/singular/LIB/assprimeszerodim.lib +755 -0
- sage_wheels/share/singular/LIB/autgradalg.lib +3361 -0
- sage_wheels/share/singular/LIB/bfun.lib +1964 -0
- sage_wheels/share/singular/LIB/bimodules.lib +774 -0
- sage_wheels/share/singular/LIB/brillnoether.lib +226 -0
- sage_wheels/share/singular/LIB/brnoeth.lib +5017 -0
- sage_wheels/share/singular/LIB/central.lib +2169 -0
- sage_wheels/share/singular/LIB/chern.lib +4162 -0
- sage_wheels/share/singular/LIB/cimonom.lib +571 -0
- sage_wheels/share/singular/LIB/cisimplicial.lib +1835 -0
- sage_wheels/share/singular/LIB/classify.lib +3239 -0
- sage_wheels/share/singular/LIB/classify2.lib +1462 -0
- sage_wheels/share/singular/LIB/classifyMapGerms.lib +1515 -0
- sage_wheels/share/singular/LIB/classify_aeq.lib +3253 -0
- sage_wheels/share/singular/LIB/classifyceq.lib +2092 -0
- sage_wheels/share/singular/LIB/classifyci.lib +1133 -0
- sage_wheels/share/singular/LIB/combinat.lib +91 -0
- sage_wheels/share/singular/LIB/compregb.lib +276 -0
- sage_wheels/share/singular/LIB/control.lib +1636 -0
- sage_wheels/share/singular/LIB/crypto.lib +3795 -0
- sage_wheels/share/singular/LIB/curveInv.lib +667 -0
- sage_wheels/share/singular/LIB/curvepar.lib +1817 -0
- sage_wheels/share/singular/LIB/customstd.lib +100 -0
- sage_wheels/share/singular/LIB/deRham.lib +5979 -0
- sage_wheels/share/singular/LIB/decodegb.lib +2134 -0
- sage_wheels/share/singular/LIB/decomp.lib +1655 -0
- sage_wheels/share/singular/LIB/deflation.lib +872 -0
- sage_wheels/share/singular/LIB/deform.lib +925 -0
- sage_wheels/share/singular/LIB/difform.lib +3055 -0
- sage_wheels/share/singular/LIB/divisors.lib +750 -0
- sage_wheels/share/singular/LIB/dmod.lib +5817 -0
- sage_wheels/share/singular/LIB/dmodapp.lib +3269 -0
- sage_wheels/share/singular/LIB/dmodideal.lib +1211 -0
- sage_wheels/share/singular/LIB/dmodloc.lib +2645 -0
- sage_wheels/share/singular/LIB/dmodvar.lib +818 -0
- sage_wheels/share/singular/LIB/dummy.lib +17 -0
- sage_wheels/share/singular/LIB/elim.lib +1009 -0
- sage_wheels/share/singular/LIB/ellipticcovers.lib +548 -0
- sage_wheels/share/singular/LIB/enumpoints.lib +146 -0
- sage_wheels/share/singular/LIB/equising.lib +2127 -0
- sage_wheels/share/singular/LIB/ffmodstd.lib +2384 -0
- sage_wheels/share/singular/LIB/ffsolve.lib +1289 -0
- sage_wheels/share/singular/LIB/findifs.lib +778 -0
- sage_wheels/share/singular/LIB/finitediff.lib +1768 -0
- sage_wheels/share/singular/LIB/finvar.lib +7989 -0
- sage_wheels/share/singular/LIB/fpadim.lib +2429 -0
- sage_wheels/share/singular/LIB/fpalgebras.lib +1666 -0
- sage_wheels/share/singular/LIB/fpaprops.lib +1462 -0
- sage_wheels/share/singular/LIB/freegb.lib +3853 -0
- sage_wheels/share/singular/LIB/general.lib +1350 -0
- sage_wheels/share/singular/LIB/gfan.lib +1768 -0
- sage_wheels/share/singular/LIB/gitfan.lib +3130 -0
- sage_wheels/share/singular/LIB/gkdim.lib +99 -0
- sage_wheels/share/singular/LIB/gmspoly.lib +589 -0
- sage_wheels/share/singular/LIB/gmssing.lib +1739 -0
- sage_wheels/share/singular/LIB/goettsche.lib +909 -0
- sage_wheels/share/singular/LIB/graal.lib +1366 -0
- sage_wheels/share/singular/LIB/gradedModules.lib +2541 -0
- sage_wheels/share/singular/LIB/graphics.lib +360 -0
- sage_wheels/share/singular/LIB/grobcov.lib +7706 -0
- sage_wheels/share/singular/LIB/groups.lib +1123 -0
- sage_wheels/share/singular/LIB/grwalk.lib +507 -0
- sage_wheels/share/singular/LIB/hdepth.lib +194 -0
- sage_wheels/share/singular/LIB/help.cnf +57 -0
- sage_wheels/share/singular/LIB/hess.lib +1946 -0
- sage_wheels/share/singular/LIB/hnoether.lib +4292 -0
- sage_wheels/share/singular/LIB/hodge.lib +400 -0
- sage_wheels/share/singular/LIB/homolog.lib +1965 -0
- sage_wheels/share/singular/LIB/hyperel.lib +975 -0
- sage_wheels/share/singular/LIB/inout.lib +679 -0
- sage_wheels/share/singular/LIB/integralbasis.lib +6224 -0
- sage_wheels/share/singular/LIB/interval.lib +1418 -0
- sage_wheels/share/singular/LIB/intprog.lib +778 -0
- sage_wheels/share/singular/LIB/invar.lib +443 -0
- sage_wheels/share/singular/LIB/involut.lib +980 -0
- sage_wheels/share/singular/LIB/jacobson.lib +1215 -0
- sage_wheels/share/singular/LIB/kskernel.lib +534 -0
- sage_wheels/share/singular/LIB/latex.lib +3146 -0
- sage_wheels/share/singular/LIB/lejeune.lib +651 -0
- sage_wheels/share/singular/LIB/linalg.lib +2040 -0
- sage_wheels/share/singular/LIB/locnormal.lib +212 -0
- sage_wheels/share/singular/LIB/lrcalc.lib +526 -0
- sage_wheels/share/singular/LIB/makedbm.lib +294 -0
- sage_wheels/share/singular/LIB/mathml.lib +813 -0
- sage_wheels/share/singular/LIB/matrix.lib +1372 -0
- sage_wheels/share/singular/LIB/maxlike.lib +1132 -0
- sage_wheels/share/singular/LIB/methods.lib +212 -0
- sage_wheels/share/singular/LIB/moddiq.lib +322 -0
- sage_wheels/share/singular/LIB/modfinduni.lib +181 -0
- sage_wheels/share/singular/LIB/modnormal.lib +218 -0
- sage_wheels/share/singular/LIB/modprimdec.lib +1278 -0
- sage_wheels/share/singular/LIB/modquotient.lib +269 -0
- sage_wheels/share/singular/LIB/modstd.lib +1024 -0
- sage_wheels/share/singular/LIB/modular.lib +545 -0
- sage_wheels/share/singular/LIB/modules.lib +2561 -0
- sage_wheels/share/singular/LIB/modwalk.lib +609 -0
- sage_wheels/share/singular/LIB/mondromy.lib +1016 -0
- sage_wheels/share/singular/LIB/monomialideal.lib +3851 -0
- sage_wheels/share/singular/LIB/mprimdec.lib +2353 -0
- sage_wheels/share/singular/LIB/mregular.lib +1863 -0
- sage_wheels/share/singular/LIB/multigrading.lib +5629 -0
- sage_wheels/share/singular/LIB/ncHilb.lib +777 -0
- sage_wheels/share/singular/LIB/ncModslimgb.lib +791 -0
- sage_wheels/share/singular/LIB/ncalg.lib +16311 -0
- sage_wheels/share/singular/LIB/ncall.lib +31 -0
- sage_wheels/share/singular/LIB/ncdecomp.lib +468 -0
- sage_wheels/share/singular/LIB/ncfactor.lib +13371 -0
- sage_wheels/share/singular/LIB/ncfrac.lib +1023 -0
- sage_wheels/share/singular/LIB/nchilbert.lib +448 -0
- sage_wheels/share/singular/LIB/nchomolog.lib +759 -0
- sage_wheels/share/singular/LIB/ncloc.lib +361 -0
- sage_wheels/share/singular/LIB/ncpreim.lib +795 -0
- sage_wheels/share/singular/LIB/ncrat.lib +2849 -0
- sage_wheels/share/singular/LIB/nctools.lib +1887 -0
- sage_wheels/share/singular/LIB/nets.lib +1456 -0
- sage_wheels/share/singular/LIB/nfmodstd.lib +1000 -0
- sage_wheels/share/singular/LIB/nfmodsyz.lib +732 -0
- sage_wheels/share/singular/LIB/noether.lib +1106 -0
- sage_wheels/share/singular/LIB/normal.lib +8700 -0
- sage_wheels/share/singular/LIB/normaliz.lib +2226 -0
- sage_wheels/share/singular/LIB/ntsolve.lib +362 -0
- sage_wheels/share/singular/LIB/numerAlg.lib +560 -0
- sage_wheels/share/singular/LIB/numerDecom.lib +2261 -0
- sage_wheels/share/singular/LIB/olga.lib +1933 -0
- sage_wheels/share/singular/LIB/orbitparam.lib +351 -0
- sage_wheels/share/singular/LIB/parallel.lib +319 -0
- sage_wheels/share/singular/LIB/paraplanecurves.lib +3110 -0
- sage_wheels/share/singular/LIB/perron.lib +202 -0
- sage_wheels/share/singular/LIB/pfd.lib +2223 -0
- sage_wheels/share/singular/LIB/phindex.lib +642 -0
- sage_wheels/share/singular/LIB/pointid.lib +673 -0
- sage_wheels/share/singular/LIB/polybori.lib +1430 -0
- sage_wheels/share/singular/LIB/polyclass.lib +525 -0
- sage_wheels/share/singular/LIB/polylib.lib +1174 -0
- sage_wheels/share/singular/LIB/polymake.lib +1902 -0
- sage_wheels/share/singular/LIB/presolve.lib +1533 -0
- sage_wheels/share/singular/LIB/primdec.lib +9576 -0
- sage_wheels/share/singular/LIB/primdecint.lib +1782 -0
- sage_wheels/share/singular/LIB/primitiv.lib +401 -0
- sage_wheels/share/singular/LIB/puiseuxexpansions.lib +1631 -0
- sage_wheels/share/singular/LIB/purityfiltration.lib +960 -0
- sage_wheels/share/singular/LIB/qhmoduli.lib +1561 -0
- sage_wheels/share/singular/LIB/qmatrix.lib +293 -0
- sage_wheels/share/singular/LIB/random.lib +455 -0
- sage_wheels/share/singular/LIB/ratgb.lib +489 -0
- sage_wheels/share/singular/LIB/realclassify.lib +5759 -0
- sage_wheels/share/singular/LIB/realizationMatroids.lib +772 -0
- sage_wheels/share/singular/LIB/realrad.lib +1197 -0
- sage_wheels/share/singular/LIB/recover.lib +2628 -0
- sage_wheels/share/singular/LIB/redcgs.lib +3984 -0
- sage_wheels/share/singular/LIB/reesclos.lib +465 -0
- sage_wheels/share/singular/LIB/resbinomial.lib +2802 -0
- sage_wheels/share/singular/LIB/resgraph.lib +789 -0
- sage_wheels/share/singular/LIB/resjung.lib +820 -0
- sage_wheels/share/singular/LIB/resolve.lib +5110 -0
- sage_wheels/share/singular/LIB/resources.lib +170 -0
- sage_wheels/share/singular/LIB/reszeta.lib +5473 -0
- sage_wheels/share/singular/LIB/ring.lib +1328 -0
- sage_wheels/share/singular/LIB/ringgb.lib +343 -0
- sage_wheels/share/singular/LIB/rinvar.lib +1153 -0
- sage_wheels/share/singular/LIB/rootisolation.lib +1481 -0
- sage_wheels/share/singular/LIB/rootsmr.lib +709 -0
- sage_wheels/share/singular/LIB/rootsur.lib +886 -0
- sage_wheels/share/singular/LIB/rstandard.lib +607 -0
- sage_wheels/share/singular/LIB/rwalk.lib +336 -0
- sage_wheels/share/singular/LIB/sagbi.lib +1353 -0
- sage_wheels/share/singular/LIB/sagbiNormaliz.lib +1622 -0
- sage_wheels/share/singular/LIB/sagbiNormaliz0.lib +1498 -0
- sage_wheels/share/singular/LIB/sagbigrob.lib +449 -0
- sage_wheels/share/singular/LIB/schreyer.lib +321 -0
- sage_wheels/share/singular/LIB/schubert.lib +2551 -0
- sage_wheels/share/singular/LIB/sets.lib +524 -0
- sage_wheels/share/singular/LIB/sheafcoh.lib +1663 -0
- sage_wheels/share/singular/LIB/signcond.lib +437 -0
- sage_wheels/share/singular/LIB/sing.lib +1094 -0
- sage_wheels/share/singular/LIB/sing4ti2.lib +419 -0
- sage_wheels/share/singular/LIB/solve.lib +2243 -0
- sage_wheels/share/singular/LIB/spcurve.lib +1077 -0
- sage_wheels/share/singular/LIB/spectrum.lib +62 -0
- sage_wheels/share/singular/LIB/sresext.lib +757 -0
- sage_wheels/share/singular/LIB/ssi.lib +143 -0
- sage_wheels/share/singular/LIB/standard.lib +2769 -0
- sage_wheels/share/singular/LIB/stanleyreisner.lib +473 -0
- sage_wheels/share/singular/LIB/stdmodule.lib +547 -0
- sage_wheels/share/singular/LIB/stratify.lib +1070 -0
- sage_wheels/share/singular/LIB/surf.lib +506 -0
- sage_wheels/share/singular/LIB/surf_jupyter.lib +223 -0
- sage_wheels/share/singular/LIB/surfacesignature.lib +522 -0
- sage_wheels/share/singular/LIB/surfex.lib +1462 -0
- sage_wheels/share/singular/LIB/swalk.lib +877 -0
- sage_wheels/share/singular/LIB/symodstd.lib +1570 -0
- sage_wheels/share/singular/LIB/systhreads.lib +74 -0
- sage_wheels/share/singular/LIB/tasks.lib +1324 -0
- sage_wheels/share/singular/LIB/tateProdCplxNegGrad.lib +2412 -0
- sage_wheels/share/singular/LIB/teachstd.lib +858 -0
- sage_wheels/share/singular/LIB/template.lib +116 -0
- sage_wheels/share/singular/LIB/toric.lib +1119 -0
- sage_wheels/share/singular/LIB/transformation.lib +116 -0
- sage_wheels/share/singular/LIB/triang.lib +1197 -0
- sage_wheels/share/singular/LIB/tropical.lib +8741 -0
- sage_wheels/share/singular/LIB/tropicalEllipticCovers.lib +2922 -0
- sage_wheels/share/singular/LIB/tropicalNewton.lib +1128 -0
- sage_wheels/share/singular/LIB/tst.lib +1108 -0
- sage_wheels/share/singular/LIB/weierstr.lib +241 -0
- sage_wheels/share/singular/LIB/zeroset.lib +1478 -0
- sage_wheels/share/singular/emacs/.emacs-general +184 -0
- sage_wheels/share/singular/emacs/.emacs-singular +234 -0
- sage_wheels/share/singular/emacs/COPYING +44 -0
- sage_wheels/share/singular/emacs/cmd-cmpl.el +241 -0
- sage_wheels/share/singular/emacs/ex-cmpl.el +1681 -0
- sage_wheels/share/singular/emacs/hlp-cmpl.el +4318 -0
- sage_wheels/share/singular/emacs/lib-cmpl.el +179 -0
- sage_wheels/share/singular/emacs/singular.el +4273 -0
- sage_wheels/share/singular/emacs/singular.xpm +39 -0
- sage_wheels/share/singular/singular.idx +5002 -0
|
@@ -0,0 +1,1580 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-singular
|
|
2
|
+
"""
|
|
3
|
+
Fusion rings
|
|
4
|
+
"""
|
|
5
|
+
# ****************************************************************************
|
|
6
|
+
# Copyright (C) 2019 Daniel Bump <bump at match.stanford.edu>
|
|
7
|
+
# Guillermo Aboumrad <gh_willieab>
|
|
8
|
+
# Travis Scrimshaw <tcscrims at gmail.com>
|
|
9
|
+
# Nicolas Thiery <nthiery at users.sf.net>
|
|
10
|
+
# 2022 Guillermo Aboumrad <gh_willieab>
|
|
11
|
+
#
|
|
12
|
+
# This program is free software: you can redistribute it and/or modify
|
|
13
|
+
# it under the terms of the GNU General Public License as published by
|
|
14
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
15
|
+
# (at your option) any later version.
|
|
16
|
+
# https://www.gnu.org/licenses/
|
|
17
|
+
# ****************************************************************************
|
|
18
|
+
|
|
19
|
+
from itertools import product, zip_longest
|
|
20
|
+
from multiprocessing import Pool, set_start_method
|
|
21
|
+
from sage.combinat.q_analogues import q_int
|
|
22
|
+
from sage.algebras.fusion_rings.fast_parallel_fusion_ring_braid_repn import (
|
|
23
|
+
executor,
|
|
24
|
+
_unflatten_entries
|
|
25
|
+
)
|
|
26
|
+
from sage.combinat.root_system.weyl_characters import WeylCharacterRing
|
|
27
|
+
from sage.matrix.constructor import matrix
|
|
28
|
+
from sage.matrix.special import diagonal_matrix
|
|
29
|
+
from sage.misc.cachefunc import cached_method
|
|
30
|
+
from sage.misc.misc import inject_variable
|
|
31
|
+
from sage.rings.integer_ring import ZZ
|
|
32
|
+
from sage.rings.number_field.number_field import CyclotomicField
|
|
33
|
+
from sage.rings.qqbar import QQbar
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class FusionRing(WeylCharacterRing):
|
|
37
|
+
r"""
|
|
38
|
+
Return the Fusion Ring (Verlinde Algebra) of level ``k``.
|
|
39
|
+
|
|
40
|
+
INPUT:
|
|
41
|
+
|
|
42
|
+
- ``ct`` -- the Cartan type of a simple (finite-dimensional) Lie algebra
|
|
43
|
+
- ``k`` -- nonnegative integer
|
|
44
|
+
- ``conjugate`` -- (default: ``False``) set ``True`` to obtain
|
|
45
|
+
the complex conjugate ring
|
|
46
|
+
- ``cyclotomic_order`` -- (default: computed depending on ``ct`` and ``k``)
|
|
47
|
+
- ``fusion_labels`` -- (default: ``None``) either a tuple of strings to use as labels of the
|
|
48
|
+
basis of simple objects, or a string from which the labels will be
|
|
49
|
+
constructed
|
|
50
|
+
- ``inject_variables`` -- (default: ``False``) use with ``fusion_labels``.
|
|
51
|
+
If ``inject_variables`` is ``True``, the fusion labels will be variables
|
|
52
|
+
that can be accessed from the command line
|
|
53
|
+
|
|
54
|
+
The cyclotomic order is an integer `N` such that all computations
|
|
55
|
+
will return elements of the cyclotomic field of `N`-th roots of unity.
|
|
56
|
+
Normally you will never need to change this but consider changing it
|
|
57
|
+
if :meth:`root_of_unity` raises a :exc:`ValueError`.
|
|
58
|
+
|
|
59
|
+
This algebra has a basis (sometimes called *primary fields* but here
|
|
60
|
+
called *simple objects*) indexed by the weights of level `\leq k`.
|
|
61
|
+
These arise as the fusion algebras of Wess-Zumino-Witten (WZW) conformal
|
|
62
|
+
field theories, or as Grothendieck groups of tilting modules for quantum
|
|
63
|
+
groups at roots of unity. The :class:`FusionRing` class is implemented as
|
|
64
|
+
a variant of the :class:`WeylCharacterRing`.
|
|
65
|
+
|
|
66
|
+
REFERENCES:
|
|
67
|
+
|
|
68
|
+
- [BaKi2001]_ Chapter 3
|
|
69
|
+
- [DFMS1996]_ Chapter 16
|
|
70
|
+
- [EGNO2015]_ Chapter 8
|
|
71
|
+
- [Feingold2004]_
|
|
72
|
+
- [Fuchs1994]_
|
|
73
|
+
- [Row2006]_
|
|
74
|
+
- [Walton1990]_
|
|
75
|
+
- [Wan2010]_
|
|
76
|
+
|
|
77
|
+
EXAMPLES::
|
|
78
|
+
|
|
79
|
+
sage: A22 = FusionRing("A2", 2)
|
|
80
|
+
sage: [f1, f2] = A22.fundamental_weights()
|
|
81
|
+
sage: M = [A22(x) for x in [0*f1, 2*f1, 2*f2, f1+f2, f2, f1]]
|
|
82
|
+
sage: [M[3] * x for x in M]
|
|
83
|
+
[A22(1,1),
|
|
84
|
+
A22(0,1),
|
|
85
|
+
A22(1,0),
|
|
86
|
+
A22(0,0) + A22(1,1),
|
|
87
|
+
A22(0,1) + A22(2,0),
|
|
88
|
+
A22(1,0) + A22(0,2)]
|
|
89
|
+
|
|
90
|
+
You may assign your own labels to the basis elements. In the next
|
|
91
|
+
example, we create the `SO(5)` fusion ring of level `2`, check the
|
|
92
|
+
weights of the basis elements, then assign new labels to them while
|
|
93
|
+
injecting them into the global namespace::
|
|
94
|
+
|
|
95
|
+
sage: B22 = FusionRing("B2", 2)
|
|
96
|
+
sage: b = [B22(x) for x in B22.get_order()]; b
|
|
97
|
+
[B22(0,0), B22(1,0), B22(0,1), B22(2,0), B22(1,1), B22(0,2)]
|
|
98
|
+
sage: [x.weight() for x in b]
|
|
99
|
+
[(0, 0), (1, 0), (1/2, 1/2), (2, 0), (3/2, 1/2), (1, 1)]
|
|
100
|
+
sage: B22.fusion_labels(['I0', 'Y1', 'X', 'Z', 'Xp', 'Y2'], inject_variables=True)
|
|
101
|
+
sage: b = [B22(x) for x in B22.get_order()]; b
|
|
102
|
+
[I0, Y1, X, Z, Xp, Y2]
|
|
103
|
+
sage: [(x, x.weight()) for x in b]
|
|
104
|
+
[(I0, (0, 0)),
|
|
105
|
+
(Y1, (1, 0)),
|
|
106
|
+
(X, (1/2, 1/2)),
|
|
107
|
+
(Z, (2, 0)),
|
|
108
|
+
(Xp, (3/2, 1/2)),
|
|
109
|
+
(Y2, (1, 1))]
|
|
110
|
+
sage: X * Y1
|
|
111
|
+
X + Xp
|
|
112
|
+
sage: Z * Z
|
|
113
|
+
I0
|
|
114
|
+
|
|
115
|
+
A fixed order of the basis keys is available with :meth:`get_order`.
|
|
116
|
+
This is the order used by methods such as :meth:`s_matrix`. You may
|
|
117
|
+
use :meth:`CombinatorialFreeModule.set_order` to reorder the basis::
|
|
118
|
+
|
|
119
|
+
sage: B22.set_order([x.weight() for x in [I0, Y1, Y2, X, Xp, Z]])
|
|
120
|
+
sage: [B22(x) for x in B22.get_order()]
|
|
121
|
+
[I0, Y1, Y2, X, Xp, Z]
|
|
122
|
+
|
|
123
|
+
To reset the labels, you may run :meth:`fusion_labels` with no parameter::
|
|
124
|
+
|
|
125
|
+
sage: B22.fusion_labels()
|
|
126
|
+
sage: [B22(x) for x in B22.get_order()]
|
|
127
|
+
[B22(0,0), B22(1,0), B22(0,2), B22(0,1), B22(1,1), B22(2,0)]
|
|
128
|
+
|
|
129
|
+
To reset the order to the default, simply set it to the list of basis
|
|
130
|
+
element keys::
|
|
131
|
+
|
|
132
|
+
sage: B22.set_order(B22.basis().keys().list())
|
|
133
|
+
sage: [B22(x) for x in B22.get_order()]
|
|
134
|
+
[B22(0,0), B22(1,0), B22(0,1), B22(2,0), B22(1,1), B22(0,2)]
|
|
135
|
+
|
|
136
|
+
The fusion ring has a number of methods that reflect its role
|
|
137
|
+
as the Grothendieck ring of a *modular tensor category* (MTC). These
|
|
138
|
+
include twist methods :meth:`Element.twist` and :meth:`Element.ribbon`
|
|
139
|
+
for its elements related to the ribbon structure, and the
|
|
140
|
+
`S`-matrix :meth:`s_ij`.
|
|
141
|
+
|
|
142
|
+
There are two natural normalizations of the `S`-matrix. Both
|
|
143
|
+
are explained in Chapter 3 of [BaKi2001]_. The one that is computed
|
|
144
|
+
by the method :meth:`s_matrix`, or whose individual entries
|
|
145
|
+
are computed by :meth:`s_ij` is denoted `\tilde{s}` in
|
|
146
|
+
[BaKi2001]_. It is not unitary.
|
|
147
|
+
|
|
148
|
+
The unitary `S`-matrix is `s=D^{-1/2}\tilde{s}` where
|
|
149
|
+
|
|
150
|
+
.. MATH::
|
|
151
|
+
|
|
152
|
+
D = \sum_V d_i(V)^2.
|
|
153
|
+
|
|
154
|
+
The sum is over all simple objects `V` with
|
|
155
|
+
`d_i(V)` the *quantum dimension*. We will call quantity `D`
|
|
156
|
+
the *global quantum dimension* and `\sqrt{D}` the
|
|
157
|
+
*total quantum order*. They are computed by :meth:`global_q_dimension`
|
|
158
|
+
and :meth:`total_q_order`. The unitary `S`-matrix `s` may be obtained
|
|
159
|
+
using :meth:`s_matrix` with the option ``unitary=True``.
|
|
160
|
+
|
|
161
|
+
Let us check the Verlinde formula, which is [DFMS1996]_ (16.3). This
|
|
162
|
+
famous identity states that
|
|
163
|
+
|
|
164
|
+
.. MATH::
|
|
165
|
+
|
|
166
|
+
N^k_{ij} = \sum_l \frac{s(i, \ell)\, s(j, \ell)\, \overline{s(k, \ell)}}{s(I, \ell)},
|
|
167
|
+
|
|
168
|
+
where `N^k_{ij}` are the fusion coefficients, i.e. the structure
|
|
169
|
+
constants of the fusion ring, and ``I`` is the unit object.
|
|
170
|
+
The `S`-matrix has the property that if `i*` denotes the dual
|
|
171
|
+
object of `i`, implemented in Sage as ``i.dual()``, then
|
|
172
|
+
|
|
173
|
+
.. MATH::
|
|
174
|
+
|
|
175
|
+
s(i*, j) = s(i, j*) = \overline{s(i, j)}.
|
|
176
|
+
|
|
177
|
+
This is equation (16.5) in [DFMS1996]_. Thus with `N_{ijk}=N^{k*}_{ij}`
|
|
178
|
+
the Verlinde formula is equivalent to
|
|
179
|
+
|
|
180
|
+
.. MATH::
|
|
181
|
+
|
|
182
|
+
N_{ijk} = \sum_l \frac{s(i, \ell)\, s(j, \ell)\, s(k, \ell)}{s(I, \ell)},
|
|
183
|
+
|
|
184
|
+
In this formula `s` is the normalized unitary `S`-matrix
|
|
185
|
+
denoted `s` in [BaKi2001]_. We may define a function that
|
|
186
|
+
corresponds to the right-hand side, except using
|
|
187
|
+
`\tilde{s}` instead of `s`::
|
|
188
|
+
|
|
189
|
+
sage: def V(i, j, k):
|
|
190
|
+
....: R = i.parent()
|
|
191
|
+
....: return sum(R.s_ij(i, l) * R.s_ij(j, l) * R.s_ij(k, l) / R.s_ij(R.one(), l)
|
|
192
|
+
....: for l in R.basis())
|
|
193
|
+
|
|
194
|
+
This does not produce ``self.N_ijk(i, j, k)`` exactly, because of the
|
|
195
|
+
missing normalization factor. The following code to check the
|
|
196
|
+
Verlinde formula takes this into account::
|
|
197
|
+
|
|
198
|
+
sage: def test_verlinde(R):
|
|
199
|
+
....: b0 = R.one()
|
|
200
|
+
....: c = R.global_q_dimension()
|
|
201
|
+
....: return all(V(i, j, k) == c * R.N_ijk(i, j, k) for i in R.basis()
|
|
202
|
+
....: for j in R.basis() for k in R.basis())
|
|
203
|
+
|
|
204
|
+
Every fusion ring should pass this test::
|
|
205
|
+
|
|
206
|
+
sage: test_verlinde(FusionRing("A2", 1))
|
|
207
|
+
True
|
|
208
|
+
sage: test_verlinde(FusionRing("B4", 2)) # long time (.56s)
|
|
209
|
+
True
|
|
210
|
+
|
|
211
|
+
As an exercise, the reader may verify the examples in
|
|
212
|
+
Section 5.3 of [RoStWa2009]_. Here we check the example
|
|
213
|
+
of the Ising modular tensor category, which is related
|
|
214
|
+
to the Belavin, Polyakov, Zamolodchikov minimal model `M(4, 3)`
|
|
215
|
+
or to an `E_8` coset model. See [DFMS1996]_ Sections 7.4.2 and 18.4.1.
|
|
216
|
+
[RoStWa2009]_ Example 5.3.4 tells us how to
|
|
217
|
+
construct it as the conjugate of the `E_8` level 2
|
|
218
|
+
:class:`FusionRing`::
|
|
219
|
+
|
|
220
|
+
sage: I = FusionRing("E8", 2, conjugate=True)
|
|
221
|
+
sage: I.fusion_labels(["i0", "p", "s"], inject_variables=True)
|
|
222
|
+
sage: b = I.basis().list(); b
|
|
223
|
+
[i0, p, s]
|
|
224
|
+
sage: Matrix([[x*y for x in b] for y in b]) # long time (.93s)
|
|
225
|
+
[ i0 p s]
|
|
226
|
+
[ p i0 s]
|
|
227
|
+
[ s s i0 + p]
|
|
228
|
+
sage: [x.twist() for x in b]
|
|
229
|
+
[0, 1, 1/8]
|
|
230
|
+
sage: [x.ribbon() for x in b]
|
|
231
|
+
[1, -1, zeta128^8]
|
|
232
|
+
sage: [I.r_matrix(i, j, k) for (i, j, k) in [(s, s, i0), (p, p, i0), (p, s, s), (s, p, s), (s, s, p)]]
|
|
233
|
+
[-zeta128^56, -1, -zeta128^32, -zeta128^32, zeta128^24]
|
|
234
|
+
sage: I.r_matrix(s, s, i0) == I.root_of_unity(-1/8)
|
|
235
|
+
True
|
|
236
|
+
sage: I.global_q_dimension()
|
|
237
|
+
4
|
|
238
|
+
sage: I.total_q_order()
|
|
239
|
+
2
|
|
240
|
+
sage: [x.q_dimension()^2 for x in b]
|
|
241
|
+
[1, 1, 2]
|
|
242
|
+
sage: I.s_matrix()
|
|
243
|
+
[ 1 1 -zeta128^48 + zeta128^16]
|
|
244
|
+
[ 1 1 zeta128^48 - zeta128^16]
|
|
245
|
+
[-zeta128^48 + zeta128^16 zeta128^48 - zeta128^16 0]
|
|
246
|
+
sage: I.s_matrix().apply_map(lambda x:x^2)
|
|
247
|
+
[1 1 2]
|
|
248
|
+
[1 1 2]
|
|
249
|
+
[2 2 0]
|
|
250
|
+
|
|
251
|
+
The term *modular tensor category* refers to the fact that associated
|
|
252
|
+
with the category there is a projective representation of the modular
|
|
253
|
+
group `SL(2, \ZZ)`. We recall that this group is generated by
|
|
254
|
+
|
|
255
|
+
.. MATH::
|
|
256
|
+
|
|
257
|
+
S = \begin{pmatrix} & -1\\1\end{pmatrix}, \qquad
|
|
258
|
+
T = \begin{pmatrix} 1 & 1\\ &1 \end{pmatrix}
|
|
259
|
+
|
|
260
|
+
subject to the relations `(ST)^3 = S^2`, `S^2T = TS^2`, and `S^4 = I`.
|
|
261
|
+
Let `s` be the normalized `S`-matrix, and
|
|
262
|
+
`t` the diagonal matrix whose entries are the twists of the simple
|
|
263
|
+
objects. Let `s` the unitary `S`-matrix and `t` the matrix of twists,
|
|
264
|
+
and `C` the conjugation matrix :meth:`conj_matrix`. Let
|
|
265
|
+
|
|
266
|
+
.. MATH::
|
|
267
|
+
|
|
268
|
+
D_+ = \sum_i d_i^2 \theta_i, \qquad D_- = d_i^2 \theta_i^{-1},
|
|
269
|
+
|
|
270
|
+
where `d_i` and `\theta_i` are the quantum dimensions and twists of the
|
|
271
|
+
simple objects. Let `c` be the Virasoro central charge, a rational number
|
|
272
|
+
that is computed in :meth:`virasoro_central_charge`. It is known that
|
|
273
|
+
|
|
274
|
+
.. MATH::
|
|
275
|
+
|
|
276
|
+
\sqrt{\frac{D_+}{D_-}} = e^{i\pi c/4}.
|
|
277
|
+
|
|
278
|
+
It is proved in [BaKi2001]_ Equation (3.1.17) that
|
|
279
|
+
|
|
280
|
+
.. MATH::
|
|
281
|
+
|
|
282
|
+
(st)^3 = e^{i\pi c/4} s^2, \qquad
|
|
283
|
+
s^2 = C, \qquad C^2 = 1, \qquad Ct = tC.
|
|
284
|
+
|
|
285
|
+
Therefore `S \mapsto s, T \mapsto t` is a projective representation
|
|
286
|
+
of `SL(2, \ZZ)`. Let us confirm these identities for the Fibonacci MTC
|
|
287
|
+
``FusionRing("G2", 1)``::
|
|
288
|
+
|
|
289
|
+
sage: R = FusionRing("G2", 1)
|
|
290
|
+
sage: S = R.s_matrix(unitary=True)
|
|
291
|
+
sage: T = R.twists_matrix()
|
|
292
|
+
sage: C = R.conj_matrix()
|
|
293
|
+
sage: c = R.virasoro_central_charge(); c
|
|
294
|
+
14/5
|
|
295
|
+
sage: (S*T)^3 == R.root_of_unity(c/4) * S^2
|
|
296
|
+
True
|
|
297
|
+
sage: S^2 == C
|
|
298
|
+
True
|
|
299
|
+
sage: C*T == T*C
|
|
300
|
+
True
|
|
301
|
+
"""
|
|
302
|
+
@staticmethod
|
|
303
|
+
def __classcall__(cls, ct, k, base_ring=ZZ, prefix=None, style='coroots', conjugate=False, cyclotomic_order=None, fusion_labels=None, inject_variables=False):
|
|
304
|
+
"""
|
|
305
|
+
Normalize input to ensure a unique representation.
|
|
306
|
+
|
|
307
|
+
TESTS::
|
|
308
|
+
|
|
309
|
+
sage: F1 = FusionRing('B3', 2)
|
|
310
|
+
sage: F2 = FusionRing(CartanType('B3'), QQ(2), ZZ)
|
|
311
|
+
sage: F3 = FusionRing(CartanType('B3'), int(2), style='coroots')
|
|
312
|
+
sage: F1 is F2 and F2 is F3
|
|
313
|
+
True
|
|
314
|
+
|
|
315
|
+
sage: A23 = FusionRing('A2', 3)
|
|
316
|
+
sage: TestSuite(A23).run()
|
|
317
|
+
|
|
318
|
+
sage: B22 = FusionRing('B2', 2)
|
|
319
|
+
sage: TestSuite(B22).run()
|
|
320
|
+
|
|
321
|
+
sage: C31 = FusionRing('C3', 1)
|
|
322
|
+
sage: TestSuite(C31).run()
|
|
323
|
+
|
|
324
|
+
sage: D41 = FusionRing('D4', 1)
|
|
325
|
+
sage: TestSuite(D41).run()
|
|
326
|
+
|
|
327
|
+
sage: G22 = FusionRing('G2', 2)
|
|
328
|
+
sage: TestSuite(G22).run()
|
|
329
|
+
|
|
330
|
+
sage: F41 = FusionRing('F4', 1)
|
|
331
|
+
sage: TestSuite(F41).run()
|
|
332
|
+
|
|
333
|
+
sage: E61 = FusionRing('E6', 1)
|
|
334
|
+
sage: TestSuite(E61).run()
|
|
335
|
+
|
|
336
|
+
sage: E71 = FusionRing('E7', 1)
|
|
337
|
+
sage: TestSuite(E71).run()
|
|
338
|
+
|
|
339
|
+
sage: E81 = FusionRing('E8', 1)
|
|
340
|
+
sage: TestSuite(E81).run()
|
|
341
|
+
"""
|
|
342
|
+
return super().__classcall__(cls, ct, base_ring=base_ring,
|
|
343
|
+
prefix=prefix, style=style, k=k,
|
|
344
|
+
conjugate=conjugate,
|
|
345
|
+
cyclotomic_order=cyclotomic_order,
|
|
346
|
+
fusion_labels=fusion_labels,
|
|
347
|
+
inject_variables=inject_variables)
|
|
348
|
+
|
|
349
|
+
def _test_verlinde(self, **options):
|
|
350
|
+
"""
|
|
351
|
+
Check the Verlinde formula for this :class:`FusionRing` instance.
|
|
352
|
+
|
|
353
|
+
EXAMPLES::
|
|
354
|
+
|
|
355
|
+
sage: G22 = FusionRing("G2", 2)
|
|
356
|
+
sage: G22._test_verlinde()
|
|
357
|
+
"""
|
|
358
|
+
tester = self._tester(**options)
|
|
359
|
+
c = self.global_q_dimension()
|
|
360
|
+
i0 = self.one()
|
|
361
|
+
from sage.misc.misc import some_tuples
|
|
362
|
+
B = self.basis()
|
|
363
|
+
for x, y, z in some_tuples(B, 3, tester._max_runs):
|
|
364
|
+
v = sum(self.s_ij(x, w) * self.s_ij(y, w) * self.s_ij(z, w) / self.s_ij(i0, w) for w in B)
|
|
365
|
+
tester.assertEqual(v, c * self.N_ijk(x, y, z))
|
|
366
|
+
|
|
367
|
+
def _test_total_q_order(self, **options):
|
|
368
|
+
r"""
|
|
369
|
+
Check that the total quantum order is real and positive.
|
|
370
|
+
|
|
371
|
+
The total quantum order is the positive square root
|
|
372
|
+
of the global quantum dimension. This indirectly test the
|
|
373
|
+
Virasoro central charge.
|
|
374
|
+
|
|
375
|
+
EXAMPLES::
|
|
376
|
+
|
|
377
|
+
sage: G22 = FusionRing("G2", 2)
|
|
378
|
+
sage: G22._test_total_q_order()
|
|
379
|
+
"""
|
|
380
|
+
tester = self._tester(**options)
|
|
381
|
+
tqo = self.total_q_order(base_coercion=False)
|
|
382
|
+
tester.assertTrue(tqo.is_real_positive())
|
|
383
|
+
tester.assertEqual(tqo**2, self.global_q_dimension(base_coercion=False))
|
|
384
|
+
|
|
385
|
+
def test_braid_representation(self, max_strands=6, anyon=None):
|
|
386
|
+
"""
|
|
387
|
+
Check that we can compute valid braid group representations.
|
|
388
|
+
|
|
389
|
+
INPUT:
|
|
390
|
+
|
|
391
|
+
- ``max_strands`` -- (default: 6) maximum number of braid group strands
|
|
392
|
+
- ``anyon`` -- (optional) run this test on this particular simple object
|
|
393
|
+
|
|
394
|
+
Create a braid group representation using :meth:`get_braid_generators`
|
|
395
|
+
and confirms the braid relations. This test indirectly partially
|
|
396
|
+
verifies the correctness of the orthogonal F-matrix solver. If the
|
|
397
|
+
code were incorrect the method would not be deterministic because the
|
|
398
|
+
fusing anyon is chosen randomly. (A different choice is made for each
|
|
399
|
+
number of strands tested.) However the doctest is deterministic since
|
|
400
|
+
it will always return ``True``. If the anyon parameter is omitted,
|
|
401
|
+
a random anyon is tested for each number of strands up to ``max_strands``.
|
|
402
|
+
|
|
403
|
+
EXAMPLES::
|
|
404
|
+
|
|
405
|
+
sage: A21 = FusionRing("A2", 1)
|
|
406
|
+
sage: A21.test_braid_representation(max_strands=4)
|
|
407
|
+
True
|
|
408
|
+
sage: F41 = FusionRing("F4", 1) # long time
|
|
409
|
+
sage: F41.test_braid_representation() # long time
|
|
410
|
+
True
|
|
411
|
+
"""
|
|
412
|
+
if not self.is_multiplicity_free(): # Braid group representation is not available if self is not multiplicity free
|
|
413
|
+
raise NotImplementedError("only implemented for multiplicity free fusion rings")
|
|
414
|
+
b = self.basis()
|
|
415
|
+
results = []
|
|
416
|
+
# Test with different numbers of strands
|
|
417
|
+
for n_strands in range(3, max_strands+1):
|
|
418
|
+
# Randomly select a fusing anyon. Skip the identity element, since
|
|
419
|
+
# its braiding matrices are trivial
|
|
420
|
+
if anyon is not None:
|
|
421
|
+
a = anyon
|
|
422
|
+
else:
|
|
423
|
+
while True:
|
|
424
|
+
a = b.random_element()
|
|
425
|
+
if a != self.one():
|
|
426
|
+
break
|
|
427
|
+
pow = a ** n_strands
|
|
428
|
+
d = pow.monomials()[0]
|
|
429
|
+
# Try to find 'interesting' braid group reps i.e. skip 1-d reps
|
|
430
|
+
for k, v in pow.monomial_coefficients().items():
|
|
431
|
+
if v > 1:
|
|
432
|
+
d = self(k)
|
|
433
|
+
break
|
|
434
|
+
comp_basis, sig = self.get_braid_generators(a, d, n_strands, verbose=False)
|
|
435
|
+
results.append(len(comp_basis) > 0)
|
|
436
|
+
results.append(self.gens_satisfy_braid_gp_rels(sig))
|
|
437
|
+
return all(results)
|
|
438
|
+
|
|
439
|
+
def fusion_labels(self, labels=None, inject_variables=False):
|
|
440
|
+
r"""
|
|
441
|
+
Set the labels of the basis.
|
|
442
|
+
|
|
443
|
+
INPUT:
|
|
444
|
+
|
|
445
|
+
- ``labels`` -- (default: ``None``) a list of strings or string
|
|
446
|
+
- ``inject_variables`` -- boolean (default: ``False``); if ``True``,
|
|
447
|
+
then inject the variable names into the global namespace; note that
|
|
448
|
+
this could override objects already defined
|
|
449
|
+
|
|
450
|
+
If ``labels`` is a list, the length of the list must equal the
|
|
451
|
+
number of basis elements. These become the names of
|
|
452
|
+
the basis elements.
|
|
453
|
+
|
|
454
|
+
If ``labels`` is a string, this is treated as a prefix and a
|
|
455
|
+
list of names is generated.
|
|
456
|
+
|
|
457
|
+
If ``labels`` is ``None``, then this resets the labels to the default.
|
|
458
|
+
|
|
459
|
+
EXAMPLES::
|
|
460
|
+
|
|
461
|
+
sage: A13 = FusionRing("A1", 3)
|
|
462
|
+
sage: A13.fusion_labels("x")
|
|
463
|
+
sage: fb = list(A13.basis()); fb
|
|
464
|
+
[x0, x1, x2, x3]
|
|
465
|
+
sage: Matrix([[x*y for y in A13.basis()] for x in A13.basis()])
|
|
466
|
+
[ x0 x1 x2 x3]
|
|
467
|
+
[ x1 x0 + x2 x1 + x3 x2]
|
|
468
|
+
[ x2 x1 + x3 x0 + x2 x1]
|
|
469
|
+
[ x3 x2 x1 x0]
|
|
470
|
+
|
|
471
|
+
We give an example where the variables are injected into the
|
|
472
|
+
global namespace::
|
|
473
|
+
|
|
474
|
+
sage: A13.fusion_labels("y", inject_variables=True)
|
|
475
|
+
sage: y0
|
|
476
|
+
y0
|
|
477
|
+
sage: y0.parent() is A13
|
|
478
|
+
True
|
|
479
|
+
|
|
480
|
+
We reset the labels to the default::
|
|
481
|
+
|
|
482
|
+
sage: A13.fusion_labels()
|
|
483
|
+
sage: fb
|
|
484
|
+
[A13(0), A13(1), A13(2), A13(3)]
|
|
485
|
+
sage: y0
|
|
486
|
+
A13(0)
|
|
487
|
+
"""
|
|
488
|
+
if labels is None:
|
|
489
|
+
# Remove the fusion labels
|
|
490
|
+
self._fusion_labels = None
|
|
491
|
+
return
|
|
492
|
+
|
|
493
|
+
B = self.basis()
|
|
494
|
+
if isinstance(labels, str):
|
|
495
|
+
labels = [labels + str(k) for k in range(len(B))]
|
|
496
|
+
elif len(labels) != len(B):
|
|
497
|
+
raise ValueError('invalid data')
|
|
498
|
+
|
|
499
|
+
d = {}
|
|
500
|
+
ac = self.simple_coroots()
|
|
501
|
+
for j, b in enumerate(self.get_order()):
|
|
502
|
+
t = tuple([b.inner_product(x) for x in ac])
|
|
503
|
+
d[t] = labels[j]
|
|
504
|
+
if inject_variables:
|
|
505
|
+
inject_variable(labels[j], B[b])
|
|
506
|
+
self._fusion_labels = d
|
|
507
|
+
|
|
508
|
+
@cached_method
|
|
509
|
+
def field(self):
|
|
510
|
+
r"""
|
|
511
|
+
Return a cyclotomic field large enough to
|
|
512
|
+
contain the `2 \ell`-th roots of unity, as well as
|
|
513
|
+
all the `S`-matrix entries.
|
|
514
|
+
|
|
515
|
+
EXAMPLES::
|
|
516
|
+
|
|
517
|
+
sage: FusionRing("A2", 2).field()
|
|
518
|
+
Cyclotomic Field of order 60 and degree 16
|
|
519
|
+
sage: FusionRing("B2", 2).field()
|
|
520
|
+
Cyclotomic Field of order 40 and degree 16
|
|
521
|
+
"""
|
|
522
|
+
# if self._field is None:
|
|
523
|
+
# self._field = CyclotomicField(4 * self._cyclotomic_order)
|
|
524
|
+
# return self._field
|
|
525
|
+
return CyclotomicField(4 * self._cyclotomic_order)
|
|
526
|
+
|
|
527
|
+
def fvars_field(self):
|
|
528
|
+
r"""
|
|
529
|
+
Return a field containing the ``CyclotomicField`` computed by
|
|
530
|
+
:meth:`field` as well as all the F-symbols of the associated
|
|
531
|
+
``FMatrix`` factory object.
|
|
532
|
+
|
|
533
|
+
This method is only available if ``self`` is multiplicity-free.
|
|
534
|
+
|
|
535
|
+
OUTPUT:
|
|
536
|
+
|
|
537
|
+
Depending on the ``CartanType`` associated to ``self`` and whether
|
|
538
|
+
a call to an F-matrix solver has been made, this method
|
|
539
|
+
will return the same field as :meth:`field`, a :func:`NumberField`,
|
|
540
|
+
or the :class:`QQbar<AlgebraicField>`.
|
|
541
|
+
See :meth:`FMatrix.attempt_number_field_computation` for more details.
|
|
542
|
+
|
|
543
|
+
Before running an F-matrix solver, the output of this method matches
|
|
544
|
+
that of :meth:`field`. However, the output may change upon successfully
|
|
545
|
+
computing F-symbols. Requesting braid generators triggers a call to
|
|
546
|
+
:meth:`FMatrix.find_orthogonal_solution`, so the output of this method
|
|
547
|
+
may change after such a computation.
|
|
548
|
+
|
|
549
|
+
By default, the output of methods like :meth:`r_matrix`,
|
|
550
|
+
:meth:`s_matrix`, :meth:`twists_matrix`, etc. will lie in the
|
|
551
|
+
``fvars_field``, unless the ``base_coercion`` option is set to
|
|
552
|
+
``False``.
|
|
553
|
+
|
|
554
|
+
This method does not trigger a solver run.
|
|
555
|
+
|
|
556
|
+
EXAMPLES::
|
|
557
|
+
|
|
558
|
+
sage: A13 = FusionRing("A1", 3, fusion_labels='a', inject_variables=True)
|
|
559
|
+
sage: A13.fvars_field()
|
|
560
|
+
Cyclotomic Field of order 40 and degree 16
|
|
561
|
+
sage: A13.field()
|
|
562
|
+
Cyclotomic Field of order 40 and degree 16
|
|
563
|
+
sage: a2**4
|
|
564
|
+
2*a0 + 3*a2
|
|
565
|
+
sage: comp_basis, sig = A13.get_braid_generators(a2, a2, 3, verbose=False) # long time (<3s)
|
|
566
|
+
sage: A13.fvars_field() # long time
|
|
567
|
+
Number Field in a with defining polynomial y^32 - ... - 500*y^2 + 25
|
|
568
|
+
sage: a2.q_dimension().parent() # long time
|
|
569
|
+
Number Field in a with defining polynomial y^32 - ... - 500*y^2 + 25
|
|
570
|
+
sage: A13.field()
|
|
571
|
+
Cyclotomic Field of order 40 and degree 16
|
|
572
|
+
|
|
573
|
+
In some cases, the :meth:`NumberField.optimized_representation()
|
|
574
|
+
<sage.rings.number_field.number_field.NumberField_absolute.optimized_representation>`
|
|
575
|
+
may be used to obtain a better defining polynomial for the
|
|
576
|
+
computed :func:`NumberField`.
|
|
577
|
+
"""
|
|
578
|
+
if self.is_multiplicity_free():
|
|
579
|
+
return self.get_fmatrix().field()
|
|
580
|
+
raise NotImplementedError("method is only available for multiplicity free fusion rings")
|
|
581
|
+
|
|
582
|
+
def root_of_unity(self, r, base_coercion=True):
|
|
583
|
+
r"""
|
|
584
|
+
Return `e^{i\pi r}` as an element of ``self.field()`` if possible.
|
|
585
|
+
|
|
586
|
+
INPUT:
|
|
587
|
+
|
|
588
|
+
- ``r`` -- a rational number
|
|
589
|
+
|
|
590
|
+
EXAMPLES::
|
|
591
|
+
|
|
592
|
+
sage: A11 = FusionRing("A1", 1)
|
|
593
|
+
sage: A11.field()
|
|
594
|
+
Cyclotomic Field of order 24 and degree 8
|
|
595
|
+
sage: for n in [1..7]:
|
|
596
|
+
....: try:
|
|
597
|
+
....: print(n, A11.root_of_unity(2/n))
|
|
598
|
+
....: except ValueError as err:
|
|
599
|
+
....: print(n, err)
|
|
600
|
+
1 1
|
|
601
|
+
2 -1
|
|
602
|
+
3 zeta24^4 - 1
|
|
603
|
+
4 zeta24^6
|
|
604
|
+
5 not a root of unity in the field
|
|
605
|
+
6 zeta24^4
|
|
606
|
+
7 not a root of unity in the field
|
|
607
|
+
"""
|
|
608
|
+
n = 2 * r * self._cyclotomic_order
|
|
609
|
+
if n not in ZZ:
|
|
610
|
+
raise ValueError("not a root of unity in the field")
|
|
611
|
+
ret = self.field().gen() ** n
|
|
612
|
+
if (not base_coercion) or (self._basecoer is None):
|
|
613
|
+
return ret
|
|
614
|
+
return self._basecoer(ret)
|
|
615
|
+
|
|
616
|
+
def get_order(self):
|
|
617
|
+
r"""
|
|
618
|
+
Return the weights of the basis vectors in a fixed order.
|
|
619
|
+
|
|
620
|
+
You may change the order of the basis using :meth:`CombinatorialFreeModule.set_order`
|
|
621
|
+
|
|
622
|
+
EXAMPLES::
|
|
623
|
+
|
|
624
|
+
sage: A15 = FusionRing("A1", 5)
|
|
625
|
+
sage: w = A15.get_order(); w
|
|
626
|
+
[(0, 0), (1/2, -1/2), (1, -1), (3/2, -3/2), (2, -2), (5/2, -5/2)]
|
|
627
|
+
sage: A15.set_order([w[k] for k in [0, 4, 1, 3, 5, 2]])
|
|
628
|
+
sage: [A15(x) for x in A15.get_order()]
|
|
629
|
+
[A15(0), A15(4), A15(1), A15(3), A15(5), A15(2)]
|
|
630
|
+
|
|
631
|
+
.. WARNING::
|
|
632
|
+
|
|
633
|
+
This duplicates :meth:`get_order` from
|
|
634
|
+
:class:`CombinatorialFreeModule` except the result
|
|
635
|
+
is *not* cached. Caching of
|
|
636
|
+
:meth:`CombinatorialFreeModule.get_order` causes inconsistent
|
|
637
|
+
results after calling :meth:`CombinatorialFreeModule.set_order`.
|
|
638
|
+
"""
|
|
639
|
+
if self._order is None:
|
|
640
|
+
self.set_order(self.basis().keys().list())
|
|
641
|
+
return self._order
|
|
642
|
+
|
|
643
|
+
def some_elements(self):
|
|
644
|
+
"""
|
|
645
|
+
Return some elements of ``self``.
|
|
646
|
+
|
|
647
|
+
EXAMPLES::
|
|
648
|
+
|
|
649
|
+
sage: D41 = FusionRing('D4', 1)
|
|
650
|
+
sage: D41.some_elements()
|
|
651
|
+
[D41(1,0,0,0), D41(0,0,1,0), D41(0,0,0,1)]
|
|
652
|
+
"""
|
|
653
|
+
return [self.monomial(x) for x in self.fundamental_weights()
|
|
654
|
+
if self.level(x) <= self._k]
|
|
655
|
+
|
|
656
|
+
def fusion_level(self):
|
|
657
|
+
r"""
|
|
658
|
+
Return the level `k` of ``self``.
|
|
659
|
+
|
|
660
|
+
EXAMPLES::
|
|
661
|
+
|
|
662
|
+
sage: B22 = FusionRing('B2', 2)
|
|
663
|
+
sage: B22.fusion_level()
|
|
664
|
+
2
|
|
665
|
+
"""
|
|
666
|
+
return self._k
|
|
667
|
+
|
|
668
|
+
def fusion_l(self):
|
|
669
|
+
r"""
|
|
670
|
+
Return the product `\ell = m_g(k + h^\vee)`, where `m_g` denotes the
|
|
671
|
+
square of the ratio of the lengths of long to short roots of
|
|
672
|
+
the underlying Lie algebra, `k` denotes the level of the FusionRing,
|
|
673
|
+
and `h^\vee` denotes the dual Coxeter number of the underlying Lie
|
|
674
|
+
algebra.
|
|
675
|
+
|
|
676
|
+
This value is used to define the associated root `2\ell`-th
|
|
677
|
+
of unity `q = e^{i\pi/\ell}`.
|
|
678
|
+
|
|
679
|
+
EXAMPLES::
|
|
680
|
+
|
|
681
|
+
sage: B22 = FusionRing('B2', 2)
|
|
682
|
+
sage: B22.fusion_l()
|
|
683
|
+
10
|
|
684
|
+
sage: D52 = FusionRing('D5', 2)
|
|
685
|
+
sage: D52.fusion_l()
|
|
686
|
+
10
|
|
687
|
+
"""
|
|
688
|
+
return self._l
|
|
689
|
+
|
|
690
|
+
def virasoro_central_charge(self):
|
|
691
|
+
r"""
|
|
692
|
+
Return the Virasoro central charge of the WZW conformal
|
|
693
|
+
field theory associated with the Fusion Ring.
|
|
694
|
+
|
|
695
|
+
If `\mathfrak{g}` is the corresponding semisimple Lie algebra, this is
|
|
696
|
+
|
|
697
|
+
.. MATH::
|
|
698
|
+
|
|
699
|
+
\frac{k\dim\mathfrak{g}}{k+h^\vee},
|
|
700
|
+
|
|
701
|
+
where `k` is the level and `h^\vee` is the dual Coxeter number.
|
|
702
|
+
See [DFMS1996]_ Equation (15.61).
|
|
703
|
+
|
|
704
|
+
Let `d_i` and `\theta_i` be the quantum dimensions and
|
|
705
|
+
twists of the simple objects. By Proposition 2.3 in [RoStWa2009]_,
|
|
706
|
+
there exists a rational number `c` such that
|
|
707
|
+
`D_+ / \sqrt{D} = e^{i\pi c/4}`, where `D_+ = \sum d_i^2 \theta_i`
|
|
708
|
+
is computed in :meth:`D_plus` and `D = \sum d_i^2 > 0` is computed
|
|
709
|
+
by :meth:`global_q_dimension`. Squaring this identity and
|
|
710
|
+
remembering that `D_+ D_- = D` gives
|
|
711
|
+
|
|
712
|
+
.. MATH::
|
|
713
|
+
|
|
714
|
+
D_+ / D_- = e^{i\pi c/2}.
|
|
715
|
+
|
|
716
|
+
EXAMPLES::
|
|
717
|
+
|
|
718
|
+
sage: R = FusionRing("A1", 2)
|
|
719
|
+
sage: c = R.virasoro_central_charge(); c
|
|
720
|
+
3/2
|
|
721
|
+
sage: Dp = R.D_plus(); Dp
|
|
722
|
+
2*zeta32^6
|
|
723
|
+
sage: Dm = R.D_minus(); Dm
|
|
724
|
+
-2*zeta32^10
|
|
725
|
+
sage: Dp / Dm == R.root_of_unity(c/2)
|
|
726
|
+
True
|
|
727
|
+
"""
|
|
728
|
+
dim_g = len(self.space().roots()) + self.cartan_type().rank()
|
|
729
|
+
return self._conj * self._k * dim_g / (self._k + self._h_check)
|
|
730
|
+
|
|
731
|
+
def conj_matrix(self):
|
|
732
|
+
r"""
|
|
733
|
+
Return the conjugation matrix, which is the permutation matrix
|
|
734
|
+
for the conjugation (dual) operation on basis elements.
|
|
735
|
+
|
|
736
|
+
EXAMPLES::
|
|
737
|
+
|
|
738
|
+
sage: FusionRing("A2", 1).conj_matrix()
|
|
739
|
+
[1 0 0]
|
|
740
|
+
[0 0 1]
|
|
741
|
+
[0 1 0]
|
|
742
|
+
"""
|
|
743
|
+
b = self.basis().list()
|
|
744
|
+
return matrix(ZZ, [[i == j.dual() for i in b] for j in b])
|
|
745
|
+
|
|
746
|
+
def twists_matrix(self):
|
|
747
|
+
r"""
|
|
748
|
+
Return a diagonal matrix describing the twist corresponding to
|
|
749
|
+
each simple object in the ``FusionRing``.
|
|
750
|
+
|
|
751
|
+
EXAMPLES::
|
|
752
|
+
|
|
753
|
+
sage: B21=FusionRing("B2", 1)
|
|
754
|
+
sage: [x.twist() for x in B21.basis().list()]
|
|
755
|
+
[0, 1, 5/8]
|
|
756
|
+
sage: [B21.root_of_unity(x.twist()) for x in B21.basis().list()]
|
|
757
|
+
[1, -1, zeta32^10]
|
|
758
|
+
sage: B21.twists_matrix()
|
|
759
|
+
[ 1 0 0]
|
|
760
|
+
[ 0 -1 0]
|
|
761
|
+
[ 0 0 zeta32^10]
|
|
762
|
+
"""
|
|
763
|
+
B = self.basis()
|
|
764
|
+
return diagonal_matrix(B[x].ribbon() for x in self.get_order())
|
|
765
|
+
|
|
766
|
+
@cached_method
|
|
767
|
+
def N_ijk(self, elt_i, elt_j, elt_k):
|
|
768
|
+
r"""
|
|
769
|
+
Return the symmetric fusion coefficient `N_{ijk}`.
|
|
770
|
+
|
|
771
|
+
INPUT:
|
|
772
|
+
|
|
773
|
+
- ``elt_i``, ``elt_j``, ``elt_k`` -- elements of the fusion basis
|
|
774
|
+
|
|
775
|
+
This is the same as `N_{ij}^{k\ast}`, where `N_{ij}^k` are
|
|
776
|
+
the structure coefficients of the ring (see :meth:`Nk_ij`),
|
|
777
|
+
and `k\ast` denotes the dual element. The coefficient `N_{ijk}`
|
|
778
|
+
is unchanged under permutations of the three basis vectors.
|
|
779
|
+
|
|
780
|
+
EXAMPLES::
|
|
781
|
+
|
|
782
|
+
sage: G23 = FusionRing("G2", 3)
|
|
783
|
+
sage: G23.fusion_labels("g")
|
|
784
|
+
sage: b = G23.basis().list(); b
|
|
785
|
+
[g0, g1, g2, g3, g4, g5]
|
|
786
|
+
sage: [(x, y, z) for x in b for y in b for z in b if G23.N_ijk(x, y, z) > 1]
|
|
787
|
+
[(g3, g3, g3), (g3, g3, g4), (g3, g4, g3), (g4, g3, g3)]
|
|
788
|
+
sage: all(G23.N_ijk(x, y, z)==G23.N_ijk(y, z, x) for x in b for y in b for z in b)
|
|
789
|
+
True
|
|
790
|
+
sage: all(G23.N_ijk(x, y, z)==G23.N_ijk(y, x, z) for x in b for y in b for z in b)
|
|
791
|
+
True
|
|
792
|
+
"""
|
|
793
|
+
return (elt_i * elt_j).monomial_coefficients().get(elt_k.dual().weight(), 0)
|
|
794
|
+
|
|
795
|
+
@cached_method
|
|
796
|
+
def Nk_ij(self, elt_i, elt_j, elt_k):
|
|
797
|
+
r"""
|
|
798
|
+
Return the fusion coefficient `N^k_{ij}`.
|
|
799
|
+
|
|
800
|
+
These are the structure coefficients of the fusion ring, so
|
|
801
|
+
|
|
802
|
+
.. MATH::
|
|
803
|
+
|
|
804
|
+
i * j = \sum_{k} N_{ij}^k k.
|
|
805
|
+
|
|
806
|
+
EXAMPLES::
|
|
807
|
+
|
|
808
|
+
sage: A22 = FusionRing("A2", 2)
|
|
809
|
+
sage: b = A22.basis().list()
|
|
810
|
+
sage: all(x*y == sum(A22.Nk_ij(x, y, k)*k for k in b) for x in b for y in b)
|
|
811
|
+
True
|
|
812
|
+
"""
|
|
813
|
+
return (elt_i * elt_j).monomial_coefficients(copy=False).get(elt_k.weight(), 0)
|
|
814
|
+
|
|
815
|
+
@cached_method
|
|
816
|
+
def s_ij(self, elt_i, elt_j, base_coercion=True):
|
|
817
|
+
r"""
|
|
818
|
+
Return the element of the `S`-matrix of this fusion ring corresponding to
|
|
819
|
+
the given elements.
|
|
820
|
+
|
|
821
|
+
This is the unnormalized `S`-matrix, denoted `\tilde{s}_{ij}`
|
|
822
|
+
in [BaKi2001]_ . To obtain the normalized `S`-matrix, divide by
|
|
823
|
+
:meth:`global_q_dimension()` or use :meth:`S_matrix()` with
|
|
824
|
+
the option ``unitary=True``.
|
|
825
|
+
|
|
826
|
+
This is computed using the formula
|
|
827
|
+
|
|
828
|
+
.. MATH::
|
|
829
|
+
|
|
830
|
+
s_{i, j} = \frac{1}{\theta_i\theta_j} \sum_k N_{ik}^j d_k \theta_k,
|
|
831
|
+
|
|
832
|
+
where `\theta_k` is the twist and `d_k` is the quantum
|
|
833
|
+
dimension. See [Row2006]_ Equation (2.2) or [EGNO2015]_
|
|
834
|
+
Proposition 8.13.8.
|
|
835
|
+
|
|
836
|
+
INPUT:
|
|
837
|
+
|
|
838
|
+
- ``elt_i``, ``elt_j`` -- elements of the fusion basis
|
|
839
|
+
|
|
840
|
+
EXAMPLES::
|
|
841
|
+
|
|
842
|
+
sage: G21 = FusionRing("G2", 1)
|
|
843
|
+
sage: b = G21.basis()
|
|
844
|
+
sage: [G21.s_ij(x, y) for x in b for y in b]
|
|
845
|
+
[1, -zeta60^14 + zeta60^6 + zeta60^4, -zeta60^14 + zeta60^6 + zeta60^4, -1]
|
|
846
|
+
"""
|
|
847
|
+
ijtwist = elt_i.twist() + elt_j.twist()
|
|
848
|
+
ret = sum(k.q_dimension(base_coercion=False) * self.Nk_ij(elt_i, k, elt_j)
|
|
849
|
+
* self.root_of_unity(k.twist() - ijtwist, base_coercion=False)
|
|
850
|
+
for k in self.basis())
|
|
851
|
+
if (not base_coercion) or (self._basecoer is None):
|
|
852
|
+
return ret
|
|
853
|
+
return self._basecoer(ret)
|
|
854
|
+
|
|
855
|
+
def s_ijconj(self, elt_i, elt_j, base_coercion=True):
|
|
856
|
+
"""
|
|
857
|
+
Return the conjugate of the element of the `S`-matrix given by
|
|
858
|
+
``self.s_ij(elt_i, elt_j, base_coercion=base_coercion)``.
|
|
859
|
+
|
|
860
|
+
See :meth:`s_ij`.
|
|
861
|
+
|
|
862
|
+
EXAMPLES::
|
|
863
|
+
|
|
864
|
+
sage: G21 = FusionRing("G2", 1)
|
|
865
|
+
sage: b = G21.basis()
|
|
866
|
+
sage: [G21.s_ijconj(x, y) for x in b for y in b]
|
|
867
|
+
[1, -zeta60^14 + zeta60^6 + zeta60^4, -zeta60^14 + zeta60^6 + zeta60^4, -1]
|
|
868
|
+
|
|
869
|
+
This method works with all possible types of fields returned by
|
|
870
|
+
``self.fmats.field()``.
|
|
871
|
+
|
|
872
|
+
TESTS::
|
|
873
|
+
|
|
874
|
+
sage: E62 = FusionRing("E6", 2)
|
|
875
|
+
sage: E62.fusion_labels("e", inject_variables=True)
|
|
876
|
+
sage: E62.s_ij(e8, e1).conjugate() == E62.s_ijconj(e8, e1)
|
|
877
|
+
True
|
|
878
|
+
sage: F41 = FusionRing("F4", 1)
|
|
879
|
+
sage: fmats = F41.get_fmatrix()
|
|
880
|
+
sage: fmats.find_orthogonal_solution(verbose=False)
|
|
881
|
+
sage: b = F41.basis()
|
|
882
|
+
sage: all(F41.s_ijconj(x, y) == F41._basecoer(F41.s_ij(x, y, base_coercion=False).conjugate()) for x in b for y in b)
|
|
883
|
+
True
|
|
884
|
+
sage: G22 = FusionRing("G2", 2)
|
|
885
|
+
sage: fmats = G22.get_fmatrix()
|
|
886
|
+
sage: fmats.find_orthogonal_solution(verbose=False) # long time (~11 s)
|
|
887
|
+
sage: b = G22.basis() # long time
|
|
888
|
+
sage: all(G22.s_ijconj(x, y) == fmats.field()(G22.s_ij(x, y, base_coercion=False).conjugate()) for x in b for y in b) # long time
|
|
889
|
+
True
|
|
890
|
+
"""
|
|
891
|
+
ret = self.s_ij(elt_i, elt_j, base_coercion=False).conjugate()
|
|
892
|
+
if (not base_coercion) or (self._basecoer is None):
|
|
893
|
+
return ret
|
|
894
|
+
return self._basecoer(ret)
|
|
895
|
+
|
|
896
|
+
def s_matrix(self, unitary=False, base_coercion=True):
|
|
897
|
+
r"""
|
|
898
|
+
Return the `S`-matrix of this fusion ring.
|
|
899
|
+
|
|
900
|
+
OPTIONAL:
|
|
901
|
+
|
|
902
|
+
- ``unitary`` -- boolean (default: ``False``); set to ``True`` to
|
|
903
|
+
obtain the unitary `S`-matrix
|
|
904
|
+
|
|
905
|
+
Without the ``unitary`` parameter, this is the matrix denoted
|
|
906
|
+
`\widetilde{s}` in [BaKi2001]_.
|
|
907
|
+
|
|
908
|
+
EXAMPLES::
|
|
909
|
+
|
|
910
|
+
sage: D91 = FusionRing("D9", 1)
|
|
911
|
+
sage: D91.s_matrix()
|
|
912
|
+
[ 1 1 1 1]
|
|
913
|
+
[ 1 1 -1 -1]
|
|
914
|
+
[ 1 -1 -zeta136^34 zeta136^34]
|
|
915
|
+
[ 1 -1 zeta136^34 -zeta136^34]
|
|
916
|
+
sage: S = D91.s_matrix(unitary=True); S
|
|
917
|
+
[ 1/2 1/2 1/2 1/2]
|
|
918
|
+
[ 1/2 1/2 -1/2 -1/2]
|
|
919
|
+
[ 1/2 -1/2 -1/2*zeta136^34 1/2*zeta136^34]
|
|
920
|
+
[ 1/2 -1/2 1/2*zeta136^34 -1/2*zeta136^34]
|
|
921
|
+
sage: S*S.conjugate()
|
|
922
|
+
[1 0 0 0]
|
|
923
|
+
[0 1 0 0]
|
|
924
|
+
[0 0 1 0]
|
|
925
|
+
[0 0 0 1]
|
|
926
|
+
"""
|
|
927
|
+
b = self.basis()
|
|
928
|
+
S = matrix([[self.s_ij(b[x], b[y], base_coercion=base_coercion)
|
|
929
|
+
for x in self.get_order()] for y in self.get_order()])
|
|
930
|
+
if unitary:
|
|
931
|
+
return S / self.total_q_order(base_coercion=base_coercion)
|
|
932
|
+
return S
|
|
933
|
+
|
|
934
|
+
@cached_method
|
|
935
|
+
def r_matrix(self, i, j, k, base_coercion=True):
|
|
936
|
+
r"""
|
|
937
|
+
Return the R-matrix entry corresponding to the subobject ``k``
|
|
938
|
+
in the tensor product of ``i`` with ``j``.
|
|
939
|
+
|
|
940
|
+
.. WARNING::
|
|
941
|
+
|
|
942
|
+
This method only gives complete information when `N_{ij}^k = 1`
|
|
943
|
+
(an important special case). Tables of MTC including R-matrices
|
|
944
|
+
may be found in Section 5.3 of [RoStWa2009]_ and in [Bond2007]_.
|
|
945
|
+
|
|
946
|
+
The R-matrix is a homomorphism `i \otimes j \rightarrow j \otimes i`.
|
|
947
|
+
This may be hard to describe since the object `i \otimes j`
|
|
948
|
+
may be reducible. However if `k` is a simple subobject of
|
|
949
|
+
`i \otimes j` it is also a subobject of `j \otimes i`. If we fix
|
|
950
|
+
embeddings `k \rightarrow i \otimes j`, `k \rightarrow j \otimes i`
|
|
951
|
+
we may ask for the scalar automorphism of `k` induced by the
|
|
952
|
+
R-matrix. This method computes that scalar. It is possible to
|
|
953
|
+
adjust the set of embeddings `k \rightarrow i \otimes j` (called
|
|
954
|
+
a *gauge*) so that this scalar equals
|
|
955
|
+
|
|
956
|
+
.. MATH::
|
|
957
|
+
|
|
958
|
+
\pm \sqrt{\frac{ \theta_k }{ \theta_i \theta_j }}.
|
|
959
|
+
|
|
960
|
+
If `i \neq j`, the gauge may be used to control the sign of
|
|
961
|
+
the square root. But if `i = j` then we must be careful
|
|
962
|
+
about the sign. These cases are computed by a formula
|
|
963
|
+
of [BDGRTW2019]_, Proposition 2.3.
|
|
964
|
+
|
|
965
|
+
EXAMPLES::
|
|
966
|
+
|
|
967
|
+
sage: I = FusionRing("E8", 2, conjugate=True) # Ising MTC
|
|
968
|
+
sage: I.fusion_labels(["i0", "p", "s"], inject_variables=True)
|
|
969
|
+
sage: I.r_matrix(s, s, i0) == I.root_of_unity(-1/8)
|
|
970
|
+
True
|
|
971
|
+
sage: I.r_matrix(p, p, i0)
|
|
972
|
+
-1
|
|
973
|
+
sage: I.r_matrix(p, s, s) == I.root_of_unity(-1/2)
|
|
974
|
+
True
|
|
975
|
+
sage: I.r_matrix(s, p, s) == I.root_of_unity(-1/2)
|
|
976
|
+
True
|
|
977
|
+
sage: I.r_matrix(s, s, p) == I.root_of_unity(3/8)
|
|
978
|
+
True
|
|
979
|
+
"""
|
|
980
|
+
if self.Nk_ij(i, j, k) == 0:
|
|
981
|
+
return self.field().zero() if (not base_coercion) or (self._basecoer is None) else self.fvars_field().zero()
|
|
982
|
+
if i != j:
|
|
983
|
+
ret = self.root_of_unity((k.twist(reduced=False) - i.twist(reduced=False) - j.twist(reduced=False)) / 2, base_coercion=False)
|
|
984
|
+
else:
|
|
985
|
+
i0 = self.one()
|
|
986
|
+
B = self.basis()
|
|
987
|
+
ret = sum(y.ribbon(base_coercion=False)**2 / (i.ribbon(base_coercion=False) * x.ribbon(base_coercion=False)**2)
|
|
988
|
+
* self.s_ij(i0, y, base_coercion=False) * self.s_ij(i, z, base_coercion=False) * self.s_ijconj(x, z, base_coercion=False)
|
|
989
|
+
* self.s_ijconj(k, x, base_coercion=False) * self.s_ijconj(y, z, base_coercion=False) / self.s_ij(i0, z, base_coercion=False)
|
|
990
|
+
for x in B for y in B for z in B) / (self.total_q_order(base_coercion=False)**4)
|
|
991
|
+
if (not base_coercion) or (self._basecoer is None):
|
|
992
|
+
return ret
|
|
993
|
+
return self._basecoer(ret)
|
|
994
|
+
|
|
995
|
+
def global_q_dimension(self, base_coercion=True):
|
|
996
|
+
r"""
|
|
997
|
+
Return `\sum d_i^2`, where the sum is over all simple objects
|
|
998
|
+
and `d_i` is the quantum dimension.
|
|
999
|
+
|
|
1000
|
+
The global `q`-dimension is a positive real number.
|
|
1001
|
+
|
|
1002
|
+
EXAMPLES::
|
|
1003
|
+
|
|
1004
|
+
sage: FusionRing("E6", 1).global_q_dimension()
|
|
1005
|
+
3
|
|
1006
|
+
"""
|
|
1007
|
+
ret = sum(x.q_dimension(base_coercion=False) ** 2 for x in self.basis())
|
|
1008
|
+
if (not base_coercion) or (self._basecoer is None):
|
|
1009
|
+
return ret
|
|
1010
|
+
return self._basecoer(ret)
|
|
1011
|
+
|
|
1012
|
+
def total_q_order(self, base_coercion=True):
|
|
1013
|
+
r"""
|
|
1014
|
+
Return the positive square root of :meth:`self.global_q_dimension()
|
|
1015
|
+
<global_q_dimension>` as an element of :meth:`self.field() <field>`.
|
|
1016
|
+
|
|
1017
|
+
This is implemented as `D_{+}e^{-i\pi c/4}`, where `D_+` is
|
|
1018
|
+
:meth:`D_plus()` and `c` is :meth:`virasoro_central_charge()`.
|
|
1019
|
+
|
|
1020
|
+
EXAMPLES::
|
|
1021
|
+
|
|
1022
|
+
sage: F = FusionRing("G2", 1)
|
|
1023
|
+
sage: tqo=F.total_q_order(); tqo
|
|
1024
|
+
zeta60^15 - zeta60^11 - zeta60^9 + 2*zeta60^3 + zeta60
|
|
1025
|
+
sage: tqo.is_real_positive()
|
|
1026
|
+
True
|
|
1027
|
+
sage: tqo^2 == F.global_q_dimension()
|
|
1028
|
+
True
|
|
1029
|
+
"""
|
|
1030
|
+
c = self.virasoro_central_charge()
|
|
1031
|
+
ret = self.D_plus(base_coercion=False) * self.root_of_unity(-c/4, base_coercion=False)
|
|
1032
|
+
if (not base_coercion) or (self._basecoer is None):
|
|
1033
|
+
return ret
|
|
1034
|
+
return self._basecoer(ret)
|
|
1035
|
+
|
|
1036
|
+
def D_plus(self, base_coercion=True):
|
|
1037
|
+
r"""
|
|
1038
|
+
Return `\sum d_i^2\theta_i` where `i` runs through the simple objects,
|
|
1039
|
+
`d_i` is the quantum dimension and `\theta_i` is the twist.
|
|
1040
|
+
|
|
1041
|
+
This is denoted `p_+` in [BaKi2001]_ Chapter 3.
|
|
1042
|
+
|
|
1043
|
+
EXAMPLES::
|
|
1044
|
+
|
|
1045
|
+
sage: B31 = FusionRing("B3", 1)
|
|
1046
|
+
sage: Dp = B31.D_plus(); Dp
|
|
1047
|
+
2*zeta48^13 - 2*zeta48^5
|
|
1048
|
+
sage: Dm = B31.D_minus(); Dm
|
|
1049
|
+
-2*zeta48^3
|
|
1050
|
+
sage: Dp*Dm == B31.global_q_dimension()
|
|
1051
|
+
True
|
|
1052
|
+
sage: c = B31.virasoro_central_charge(); c
|
|
1053
|
+
7/2
|
|
1054
|
+
sage: Dp/Dm == B31.root_of_unity(c/2)
|
|
1055
|
+
True
|
|
1056
|
+
"""
|
|
1057
|
+
ret = sum((x.q_dimension(base_coercion=False))**2 * x.ribbon(base_coercion=False) for x in self.basis())
|
|
1058
|
+
if (not base_coercion) or (self._basecoer is None):
|
|
1059
|
+
return ret
|
|
1060
|
+
return self._basecoer(ret)
|
|
1061
|
+
|
|
1062
|
+
def D_minus(self, base_coercion=True):
|
|
1063
|
+
r"""
|
|
1064
|
+
Return `\sum d_i^2\theta_i^{-1}` where `i` runs through the simple
|
|
1065
|
+
objects, `d_i` is the quantum dimension and `\theta_i` is the twist.
|
|
1066
|
+
|
|
1067
|
+
This is denoted `p_-` in [BaKi2001]_ Chapter 3.
|
|
1068
|
+
|
|
1069
|
+
EXAMPLES::
|
|
1070
|
+
|
|
1071
|
+
sage: E83 = FusionRing("E8", 3, conjugate=True)
|
|
1072
|
+
sage: [Dp, Dm] = [E83.D_plus(), E83.D_minus()]
|
|
1073
|
+
sage: Dp*Dm == E83.global_q_dimension()
|
|
1074
|
+
True
|
|
1075
|
+
sage: c = E83.virasoro_central_charge(); c
|
|
1076
|
+
-248/11
|
|
1077
|
+
sage: Dp*Dm == E83.global_q_dimension()
|
|
1078
|
+
True
|
|
1079
|
+
"""
|
|
1080
|
+
ret = sum((x.q_dimension(base_coercion=False))**2 / x.ribbon(base_coercion=False) for x in self.basis())
|
|
1081
|
+
if (not base_coercion) or (self._basecoer is None):
|
|
1082
|
+
return ret
|
|
1083
|
+
return self._basecoer(ret)
|
|
1084
|
+
|
|
1085
|
+
def is_multiplicity_free(self):
|
|
1086
|
+
r"""
|
|
1087
|
+
Return ``True`` if the fusion multiplicities
|
|
1088
|
+
:meth:`Nk_ij` are bounded by 1.
|
|
1089
|
+
|
|
1090
|
+
The :class:`FMatrix` is available only for multiplicity free
|
|
1091
|
+
instances of :class:`FusionRing`.
|
|
1092
|
+
|
|
1093
|
+
EXAMPLES::
|
|
1094
|
+
|
|
1095
|
+
sage: [FusionRing(ct, k).is_multiplicity_free() for ct in ("A1", "A2", "B2", "C3") for k in (1, 2, 3)]
|
|
1096
|
+
[True, True, True, True, True, False, True, True, False, True, False, False]
|
|
1097
|
+
"""
|
|
1098
|
+
ct = self.cartan_type()
|
|
1099
|
+
k = self.fusion_level()
|
|
1100
|
+
if ct.letter == 'A':
|
|
1101
|
+
if ct.n == 1:
|
|
1102
|
+
return True
|
|
1103
|
+
return k <= 2
|
|
1104
|
+
# if ct.letter in ['B', 'D', 'G', 'F', 'E']:
|
|
1105
|
+
if ct.letter in ['B', 'D', 'F', 'G']:
|
|
1106
|
+
return k <= 2
|
|
1107
|
+
if ct.letter == 'C':
|
|
1108
|
+
if ct.n == 2:
|
|
1109
|
+
return k <= 2
|
|
1110
|
+
return k == 1
|
|
1111
|
+
if ct.letter == 'E':
|
|
1112
|
+
if ct.n == 8:
|
|
1113
|
+
return k <= 3
|
|
1114
|
+
return k <= 2
|
|
1115
|
+
|
|
1116
|
+
###################################
|
|
1117
|
+
# Braid group representations #
|
|
1118
|
+
###################################
|
|
1119
|
+
|
|
1120
|
+
def get_computational_basis(self, a, b, n_strands):
|
|
1121
|
+
r"""
|
|
1122
|
+
Return the so-called computational basis for `\text{Hom}(b, a^n)`.
|
|
1123
|
+
|
|
1124
|
+
INPUT:
|
|
1125
|
+
|
|
1126
|
+
- ``a`` -- a basis element
|
|
1127
|
+
- ``b`` -- another basis element
|
|
1128
|
+
- ``n_strands`` -- the number of strands for a braid group
|
|
1129
|
+
|
|
1130
|
+
Let `n=` ``n_strands`` and let `k` be the greatest integer `\leq n/2`.
|
|
1131
|
+
The braid group acts on `\text{Hom}(b, a^n)`. This action
|
|
1132
|
+
is computed in :meth:`get_braid_generators`. This method
|
|
1133
|
+
returns the computational basis in the form of a list of
|
|
1134
|
+
fusion trees. Each tree is represented by an `(n-2)`-tuple
|
|
1135
|
+
|
|
1136
|
+
.. MATH::
|
|
1137
|
+
|
|
1138
|
+
(m_1, \ldots, m_k, l_1, \ldots, l_{k-2})
|
|
1139
|
+
|
|
1140
|
+
such that each `m_j` is an irreducible constituent in `a \otimes a`
|
|
1141
|
+
and
|
|
1142
|
+
|
|
1143
|
+
.. MATH::
|
|
1144
|
+
|
|
1145
|
+
\begin{array}{l}
|
|
1146
|
+
b \in l_{k-2} \otimes m_{k}, \\
|
|
1147
|
+
l_{k-2} \in l_{k-3} \otimes m_{k-1}, \\
|
|
1148
|
+
\cdots, \\
|
|
1149
|
+
l_2 \in l_1 \otimes m_3, \\
|
|
1150
|
+
l_1 \in m_1 \otimes m_2,
|
|
1151
|
+
\end{array}
|
|
1152
|
+
|
|
1153
|
+
where `z \in x \otimes y` means `N_{xy}^z \neq 0`.
|
|
1154
|
+
|
|
1155
|
+
As a computational device when ``n_strands`` is odd, we pad the
|
|
1156
|
+
vector `(m_1, \ldots, m_k)` with an additional `m_{k+1}` equal to `a`.
|
|
1157
|
+
However, this `m_{k+1}` does *not* appear in the output of this method.
|
|
1158
|
+
|
|
1159
|
+
The following example appears in Section 3.1 of [CW2015]_.
|
|
1160
|
+
|
|
1161
|
+
EXAMPLES::
|
|
1162
|
+
|
|
1163
|
+
sage: A14 = FusionRing("A1", 4)
|
|
1164
|
+
sage: A14.get_order()
|
|
1165
|
+
[(0, 0), (1/2, -1/2), (1, -1), (3/2, -3/2), (2, -2)]
|
|
1166
|
+
sage: A14.fusion_labels(["zero", "one", "two", "three", "four"], inject_variables=True)
|
|
1167
|
+
sage: [A14(x) for x in A14.get_order()]
|
|
1168
|
+
[zero, one, two, three, four]
|
|
1169
|
+
sage: A14.get_computational_basis(one, two, 4)
|
|
1170
|
+
[(two, two), (two, zero), (zero, two)]
|
|
1171
|
+
"""
|
|
1172
|
+
def _get_trees(fr, top_row, root):
|
|
1173
|
+
if len(top_row) == 2:
|
|
1174
|
+
m1, m2 = top_row
|
|
1175
|
+
return [[]] if fr.Nk_ij(m1, m2, root) else []
|
|
1176
|
+
else:
|
|
1177
|
+
m1, m2 = top_row[:2]
|
|
1178
|
+
return [(l, *b) for l in fr.basis() for b in _get_trees(fr, [l]+top_row[2:], root) if fr.Nk_ij(m1, m2, l)]
|
|
1179
|
+
|
|
1180
|
+
comp_basis = []
|
|
1181
|
+
for top in product((a*a).monomials(), repeat=n_strands//2):
|
|
1182
|
+
# If the n_strands is odd, we must extend the top row by a fusing anyon
|
|
1183
|
+
top_row = list(top)+[a]*(n_strands % 2)
|
|
1184
|
+
comp_basis.extend((*top, *levels) for levels in _get_trees(self, top_row, b))
|
|
1185
|
+
return comp_basis
|
|
1186
|
+
|
|
1187
|
+
def get_fmatrix(self, *args, **kwargs):
|
|
1188
|
+
r"""
|
|
1189
|
+
Construct an :class:`FMatrix` factory to solve the pentagon relations
|
|
1190
|
+
and organize the resulting F-symbols.
|
|
1191
|
+
|
|
1192
|
+
EXAMPLES::
|
|
1193
|
+
|
|
1194
|
+
sage: A15 = FusionRing("A1", 5)
|
|
1195
|
+
sage: A15.get_fmatrix()
|
|
1196
|
+
F-Matrix factory for The Fusion Ring of Type A1 and level 5 with Integer Ring coefficients
|
|
1197
|
+
"""
|
|
1198
|
+
# Initialize fresh FMatrix object. Useful if you need to reset
|
|
1199
|
+
# FMatrix properties and there are various FusionRing objects (unique)
|
|
1200
|
+
# associated to same level and algebra.
|
|
1201
|
+
if not hasattr(self, 'fmats') or kwargs.get('new', False):
|
|
1202
|
+
kwargs.pop('new', None)
|
|
1203
|
+
from sage.algebras.fusion_rings.f_matrix import FMatrix
|
|
1204
|
+
self.fmats = FMatrix(self, *args, **kwargs)
|
|
1205
|
+
return self.fmats
|
|
1206
|
+
|
|
1207
|
+
def _emap(self, mapper, input_args, worker_pool=None):
|
|
1208
|
+
r"""
|
|
1209
|
+
Apply the given mapper to each element of the given input iterable
|
|
1210
|
+
and return the results (with no duplicates) in a list.
|
|
1211
|
+
|
|
1212
|
+
INPUT:
|
|
1213
|
+
|
|
1214
|
+
- ``mapper`` -- string specifying the name of a function defined
|
|
1215
|
+
in the ``fast_parallel_fusion_ring_braid_repn`` module
|
|
1216
|
+
- ``input_args`` -- tuple of arguments to be passed to mapper
|
|
1217
|
+
|
|
1218
|
+
This method applies the mapper in parallel if a ``worker_pool``
|
|
1219
|
+
is provided.
|
|
1220
|
+
|
|
1221
|
+
.. NOTE::
|
|
1222
|
+
|
|
1223
|
+
If ``worker_pool`` is not provided, function maps and reduces on
|
|
1224
|
+
a single process. If ``worker_pool`` is provided, the function
|
|
1225
|
+
attempts to determine whether it should use multiprocessing
|
|
1226
|
+
based on the length of the input iterable. If it cannot determine
|
|
1227
|
+
the length of the input iterable then it uses multiprocessing
|
|
1228
|
+
with the default chunksize of `1` if chunksize is not
|
|
1229
|
+
explicitly provided.
|
|
1230
|
+
|
|
1231
|
+
EXAMPLES::
|
|
1232
|
+
|
|
1233
|
+
sage: FR = FusionRing("A1", 4)
|
|
1234
|
+
sage: FR.fusion_labels(['idd', 'one', 'two', 'three', 'four'], inject_variables=True)
|
|
1235
|
+
sage: fmats = FR.get_fmatrix()
|
|
1236
|
+
sage: fmats.find_orthogonal_solution(verbose=False) # long time
|
|
1237
|
+
sage: len(FR._emap('sig_2k', (1, one, one, 5))) # long time
|
|
1238
|
+
13
|
|
1239
|
+
sage: FR = FusionRing("A1", 2)
|
|
1240
|
+
sage: FR.fusion_labels("a", inject_variables=True)
|
|
1241
|
+
sage: fmats = FR.get_fmatrix()
|
|
1242
|
+
sage: fmats.find_orthogonal_solution(verbose=False)
|
|
1243
|
+
sage: len(FR._emap('odd_one_out', (a1, a1, 7)))
|
|
1244
|
+
16
|
|
1245
|
+
"""
|
|
1246
|
+
n_proc = worker_pool._processes if worker_pool is not None else 1
|
|
1247
|
+
input_iter = [(child_id, n_proc, input_args) for child_id in range(n_proc)]
|
|
1248
|
+
no_mp = worker_pool is None
|
|
1249
|
+
# Map phase
|
|
1250
|
+
input_iter = zip_longest([], input_iter, fillvalue=(mapper, id(self)))
|
|
1251
|
+
results = []
|
|
1252
|
+
if no_mp:
|
|
1253
|
+
mapped = map(executor, input_iter)
|
|
1254
|
+
else:
|
|
1255
|
+
mapped = worker_pool.imap_unordered(executor, input_iter, chunksize=1)
|
|
1256
|
+
# Reduce phase
|
|
1257
|
+
for worker_results in mapped:
|
|
1258
|
+
results.extend(worker_results)
|
|
1259
|
+
return results
|
|
1260
|
+
|
|
1261
|
+
def get_braid_generators(self,
|
|
1262
|
+
fusing_anyon,
|
|
1263
|
+
total_charge_anyon,
|
|
1264
|
+
n_strands,
|
|
1265
|
+
checkpoint=False,
|
|
1266
|
+
save_results='',
|
|
1267
|
+
warm_start='',
|
|
1268
|
+
use_mp=True,
|
|
1269
|
+
verbose=True):
|
|
1270
|
+
r"""
|
|
1271
|
+
Compute generators of the Artin braid group on ``n_strands`` strands.
|
|
1272
|
+
|
|
1273
|
+
If `a = ` ``fusing_anyon`` and `b = ` ``total_charge_anyon``
|
|
1274
|
+
the generators are endomorphisms of `\text{Hom}(b, a^n)`.
|
|
1275
|
+
|
|
1276
|
+
INPUT:
|
|
1277
|
+
|
|
1278
|
+
- ``fusing_anyon`` -- a basis element of ``self``
|
|
1279
|
+
- ``total_charge_anyon`` -- a basis element of ``self``
|
|
1280
|
+
- ``n_strands`` -- positive integer greater than 2
|
|
1281
|
+
- ``checkpoint`` -- boolean (default: ``False``);
|
|
1282
|
+
whether the F-matrix solver should pickle checkpoints
|
|
1283
|
+
- ``save_results`` -- (optional) a string indicating the name of
|
|
1284
|
+
a file in which to pickle computed F-symbols for later use
|
|
1285
|
+
- ``warm_start`` -- (optional) a string indicating the name of a
|
|
1286
|
+
pickled checkpoint file to "warm" start the F-matrix solver.
|
|
1287
|
+
The pickle may be a checkpoint generated by the solver, or
|
|
1288
|
+
a file containing solver results. If all F-symbols are known,
|
|
1289
|
+
we don't run the solver again.
|
|
1290
|
+
- ``use_mp`` -- boolean (default: ``True``); whether
|
|
1291
|
+
to use multiprocessing to speed up the computation; this is
|
|
1292
|
+
highly recommended.
|
|
1293
|
+
- ``verbose`` -- boolean (default: ``True``); whether
|
|
1294
|
+
to be verbose with the computation
|
|
1295
|
+
|
|
1296
|
+
For more information on the optional parameters, see
|
|
1297
|
+
:meth:`FMatrix.find_orthogonal_solution`.
|
|
1298
|
+
|
|
1299
|
+
Given a simple object in the fusion category, here called
|
|
1300
|
+
``fusing_anyon`` allowing the universal R-matrix to act on adjacent
|
|
1301
|
+
pairs in the fusion of ``n_strands`` copies of ``fusing_anyon``
|
|
1302
|
+
produces an action of the braid group. This representation can
|
|
1303
|
+
be decomposed over another anyon, here called ``total_charge_anyon``.
|
|
1304
|
+
See [CHW2015]_.
|
|
1305
|
+
|
|
1306
|
+
OUTPUT:
|
|
1307
|
+
|
|
1308
|
+
The method outputs a pair of data ``(comp_basis, sig)`` where
|
|
1309
|
+
``comp_basis`` is a list of basis elements of the braid group
|
|
1310
|
+
module, parametrized by a list of fusion ring elements describing
|
|
1311
|
+
a fusion tree. For example with 5 strands the fusion tree
|
|
1312
|
+
is as follows. See :meth:`get_computational_basis`
|
|
1313
|
+
for more information.
|
|
1314
|
+
|
|
1315
|
+
.. IMAGE:: ../../../media/fusiontree.png
|
|
1316
|
+
:scale: 45
|
|
1317
|
+
:align: center
|
|
1318
|
+
|
|
1319
|
+
``sig`` is a list of braid group generators as matrices. In
|
|
1320
|
+
some cases these will be represented as sparse matrices.
|
|
1321
|
+
|
|
1322
|
+
In the following example we compute a 5-dimensional braid group
|
|
1323
|
+
representation on 5 strands associated to the spin representation
|
|
1324
|
+
in the modular tensor category `SU(2)_4 \cong SO(3)_2`.
|
|
1325
|
+
|
|
1326
|
+
EXAMPLES::
|
|
1327
|
+
|
|
1328
|
+
sage: A14 = FusionRing("A1", 4)
|
|
1329
|
+
sage: A14.get_order()
|
|
1330
|
+
[(0, 0), (1/2, -1/2), (1, -1), (3/2, -3/2), (2, -2)]
|
|
1331
|
+
sage: A14.fusion_labels(["one", "two", "three", "four", "five"], inject_variables=True)
|
|
1332
|
+
sage: [A14(x) for x in A14.get_order()]
|
|
1333
|
+
[one, two, three, four, five]
|
|
1334
|
+
sage: two ** 5
|
|
1335
|
+
5*two + 4*four
|
|
1336
|
+
sage: comp_basis, sig = A14.get_braid_generators(two, two, 5, verbose=False) # long time
|
|
1337
|
+
sage: A14.gens_satisfy_braid_gp_rels(sig) # long time
|
|
1338
|
+
True
|
|
1339
|
+
sage: len(comp_basis) == 5 # long time
|
|
1340
|
+
True
|
|
1341
|
+
"""
|
|
1342
|
+
if n_strands < 3:
|
|
1343
|
+
raise ValueError("the number of strands must be an integer at least 3")
|
|
1344
|
+
# Construct associated FMatrix object and solve for F-symbols
|
|
1345
|
+
self.get_fmatrix()
|
|
1346
|
+
if self.fmats._chkpt_status < 7:
|
|
1347
|
+
self.fmats.find_orthogonal_solution(checkpoint=checkpoint,
|
|
1348
|
+
save_results=save_results,
|
|
1349
|
+
warm_start=warm_start,
|
|
1350
|
+
use_mp=use_mp,
|
|
1351
|
+
verbose=verbose)
|
|
1352
|
+
|
|
1353
|
+
# Set multiprocessing parameters. Context can only be set once, so we try to set it
|
|
1354
|
+
try:
|
|
1355
|
+
set_start_method('fork')
|
|
1356
|
+
except RuntimeError:
|
|
1357
|
+
pass
|
|
1358
|
+
# Turn off multiprocessing when field is QQbar due to pickling issues introduced by PARI upgrade in github issue #30537
|
|
1359
|
+
pool = Pool() if use_mp and self.fvars_field() != QQbar else None
|
|
1360
|
+
|
|
1361
|
+
# Set up computational basis and compute generators one at a time
|
|
1362
|
+
a, b = fusing_anyon, total_charge_anyon
|
|
1363
|
+
comp_basis = self.get_computational_basis(a, b, n_strands)
|
|
1364
|
+
d = len(comp_basis)
|
|
1365
|
+
if verbose:
|
|
1366
|
+
print("Computing an {}-dimensional representation of the Artin braid group on {} strands...".format(d, n_strands))
|
|
1367
|
+
|
|
1368
|
+
# Compute diagonal odd-indexed generators using the 3j-symbols
|
|
1369
|
+
gens = {2*i+1: diagonal_matrix(self.r_matrix(a, a, c[i]) for c in comp_basis) for i in range(n_strands//2)}
|
|
1370
|
+
|
|
1371
|
+
# Compute even-indexed generators using F-matrices
|
|
1372
|
+
for k in range(1, n_strands//2):
|
|
1373
|
+
entries = self._emap('sig_2k', (k, a, b, n_strands), pool)
|
|
1374
|
+
|
|
1375
|
+
# Build cyclotomic field element objects from tuple of rationals repn
|
|
1376
|
+
_unflatten_entries(self, entries)
|
|
1377
|
+
gens[2*k] = matrix(dict(entries))
|
|
1378
|
+
|
|
1379
|
+
# If n_strands is odd, we compute the final generator
|
|
1380
|
+
if n_strands % 2:
|
|
1381
|
+
entries = self._emap('odd_one_out', (a, b, n_strands), pool)
|
|
1382
|
+
|
|
1383
|
+
# Build cyclotomic field element objects from tuple of rationals repn
|
|
1384
|
+
_unflatten_entries(self, entries)
|
|
1385
|
+
gens[n_strands-1] = matrix(dict(entries))
|
|
1386
|
+
|
|
1387
|
+
return comp_basis, [gens[k] for k in sorted(gens)]
|
|
1388
|
+
|
|
1389
|
+
def gens_satisfy_braid_gp_rels(self, sig):
|
|
1390
|
+
r"""
|
|
1391
|
+
Return ``True`` if the matrices in the list ``sig`` satisfy
|
|
1392
|
+
the braid relations.
|
|
1393
|
+
|
|
1394
|
+
This if `n` is the cardinality of ``sig``, this
|
|
1395
|
+
confirms that these matrices define a representation of
|
|
1396
|
+
the Artin braid group on `n+1` strands. Tests correctness of
|
|
1397
|
+
:meth:`get_braid_generators`.
|
|
1398
|
+
|
|
1399
|
+
EXAMPLES::
|
|
1400
|
+
|
|
1401
|
+
sage: F41 = FusionRing("F4", 1, fusion_labels='f', inject_variables=True)
|
|
1402
|
+
sage: f1*f1
|
|
1403
|
+
f0 + f1
|
|
1404
|
+
sage: comp, sig = F41.get_braid_generators(f1, f0, 4, verbose=False)
|
|
1405
|
+
sage: F41.gens_satisfy_braid_gp_rels(sig)
|
|
1406
|
+
True
|
|
1407
|
+
"""
|
|
1408
|
+
n = len(sig)
|
|
1409
|
+
braid_rels = all(sig[i] * sig[i+1] * sig[i] == sig[i+1] * sig[i] * sig[i+1] for i in range(n-1))
|
|
1410
|
+
far_comm = all(sig[i] * sig[j] == sig[j] * sig[i] for i, j in product(range(n), repeat=2) if abs(i-j) > 1 and i > j)
|
|
1411
|
+
singular = any(s.is_singular() for s in sig)
|
|
1412
|
+
return braid_rels and far_comm and not singular
|
|
1413
|
+
|
|
1414
|
+
class Element(WeylCharacterRing.Element):
|
|
1415
|
+
"""
|
|
1416
|
+
A class for FusionRing elements.
|
|
1417
|
+
"""
|
|
1418
|
+
def is_simple_object(self):
|
|
1419
|
+
r"""
|
|
1420
|
+
Determine whether ``self`` is a simple object of the fusion ring.
|
|
1421
|
+
|
|
1422
|
+
EXAMPLES::
|
|
1423
|
+
|
|
1424
|
+
sage: A22 = FusionRing("A2", 2)
|
|
1425
|
+
sage: x = A22(1, 0); x
|
|
1426
|
+
A22(1,0)
|
|
1427
|
+
sage: x.is_simple_object()
|
|
1428
|
+
True
|
|
1429
|
+
sage: x^2
|
|
1430
|
+
A22(0,1) + A22(2,0)
|
|
1431
|
+
sage: (x^2).is_simple_object()
|
|
1432
|
+
False
|
|
1433
|
+
"""
|
|
1434
|
+
return self.parent()._k is not None and len(self._monomial_coefficients) == 1
|
|
1435
|
+
|
|
1436
|
+
def weight(self):
|
|
1437
|
+
r"""
|
|
1438
|
+
Return the parametrizing dominant weight in the level `k` alcove.
|
|
1439
|
+
|
|
1440
|
+
This method is only available for basis elements.
|
|
1441
|
+
|
|
1442
|
+
EXAMPLES::
|
|
1443
|
+
|
|
1444
|
+
sage: A21 = FusionRing("A2", 1)
|
|
1445
|
+
sage: [x.weight() for x in A21.basis().list()]
|
|
1446
|
+
[(0, 0, 0), (2/3, -1/3, -1/3), (1/3, 1/3, -2/3)]
|
|
1447
|
+
"""
|
|
1448
|
+
if len(self._monomial_coefficients) != 1:
|
|
1449
|
+
raise ValueError("fusion weight is valid for basis elements only")
|
|
1450
|
+
return next(iter(self._monomial_coefficients))
|
|
1451
|
+
|
|
1452
|
+
def twist(self, reduced=True):
|
|
1453
|
+
r"""
|
|
1454
|
+
Return a rational number `h` such that `\theta = e^{i \pi h}`
|
|
1455
|
+
is the twist of ``self``. The quantity `e^{i \pi h}` is
|
|
1456
|
+
also available using :meth:`ribbon`.
|
|
1457
|
+
|
|
1458
|
+
This method is only available for simple objects. If
|
|
1459
|
+
`\lambda` is the weight of the object, then
|
|
1460
|
+
`h = \langle \lambda, \lambda+2\rho \rangle`, where
|
|
1461
|
+
`\rho` is half the sum of the positive roots.
|
|
1462
|
+
As in [Row2006]_, this requires normalizing
|
|
1463
|
+
the invariant bilinear form so that
|
|
1464
|
+
`\langle \alpha, \alpha \rangle = 2` for short roots.
|
|
1465
|
+
|
|
1466
|
+
INPUT:
|
|
1467
|
+
|
|
1468
|
+
- ``reduced`` -- boolean (default: ``True``); if ``True``
|
|
1469
|
+
then return the twist reduced modulo 2
|
|
1470
|
+
|
|
1471
|
+
EXAMPLES::
|
|
1472
|
+
|
|
1473
|
+
sage: G21 = FusionRing("G2", 1)
|
|
1474
|
+
sage: [x.twist() for x in G21.basis()]
|
|
1475
|
+
[0, 4/5]
|
|
1476
|
+
sage: [G21.root_of_unity(x.twist()) for x in G21.basis()]
|
|
1477
|
+
[1, zeta60^14 - zeta60^4]
|
|
1478
|
+
sage: zeta60 = G21.field().gen()
|
|
1479
|
+
sage: zeta60^((4/5)*(60/2))
|
|
1480
|
+
zeta60^14 - zeta60^4
|
|
1481
|
+
|
|
1482
|
+
sage: F42 = FusionRing("F4", 2)
|
|
1483
|
+
sage: [x.twist() for x in F42.basis()]
|
|
1484
|
+
[0, 18/11, 2/11, 12/11, 4/11]
|
|
1485
|
+
|
|
1486
|
+
sage: E62 = FusionRing("E6", 2)
|
|
1487
|
+
sage: [x.twist() for x in E62.basis()]
|
|
1488
|
+
[0, 26/21, 12/7, 8/21, 8/21, 26/21, 2/3, 4/7, 2/3]
|
|
1489
|
+
"""
|
|
1490
|
+
if not self.is_simple_object():
|
|
1491
|
+
raise ValueError("quantum twist is only available for simple objects of a FusionRing")
|
|
1492
|
+
P = self.parent()
|
|
1493
|
+
rho = P.space().rho()
|
|
1494
|
+
# We copy self.weight() to skip the test (which was already done
|
|
1495
|
+
# by self.is_simple_object()).
|
|
1496
|
+
lam = next(iter(self._monomial_coefficients))
|
|
1497
|
+
inner = lam.inner_product(lam + 2*rho)
|
|
1498
|
+
twist = P._conj * P._nf * inner / P.fusion_l()
|
|
1499
|
+
# Reduce modulo 2
|
|
1500
|
+
if reduced:
|
|
1501
|
+
f = twist.floor()
|
|
1502
|
+
twist -= f
|
|
1503
|
+
return twist + (f % 2)
|
|
1504
|
+
return twist
|
|
1505
|
+
|
|
1506
|
+
def ribbon(self, base_coercion=True):
|
|
1507
|
+
r"""
|
|
1508
|
+
Return the twist or ribbon element of ``self``.
|
|
1509
|
+
|
|
1510
|
+
If `h` is the rational number modulo 2 produced by
|
|
1511
|
+
``self.twist()``, this method produces `e^{i\pi h}`.
|
|
1512
|
+
|
|
1513
|
+
.. SEEALSO::
|
|
1514
|
+
|
|
1515
|
+
An additive version of this is available as :meth:`twist`.
|
|
1516
|
+
|
|
1517
|
+
EXAMPLES::
|
|
1518
|
+
|
|
1519
|
+
sage: F = FusionRing("A1", 3)
|
|
1520
|
+
sage: [x.twist() for x in F.basis()]
|
|
1521
|
+
[0, 3/10, 4/5, 3/2]
|
|
1522
|
+
sage: [x.ribbon(base_coercion=False) for x in F.basis()]
|
|
1523
|
+
[1, zeta40^6, zeta40^12 - zeta40^8 + zeta40^4 - 1, -zeta40^10]
|
|
1524
|
+
sage: [F.root_of_unity(x, base_coercion=False) for x in [0, 3/10, 4/5, 3/2]]
|
|
1525
|
+
[1, zeta40^6, zeta40^12 - zeta40^8 + zeta40^4 - 1, -zeta40^10]
|
|
1526
|
+
"""
|
|
1527
|
+
ret = self.parent().root_of_unity(self.twist(), base_coercion=False)
|
|
1528
|
+
if (not base_coercion) or (self.parent()._basecoer is None):
|
|
1529
|
+
return ret
|
|
1530
|
+
return self.parent()._basecoer(ret)
|
|
1531
|
+
|
|
1532
|
+
@cached_method
|
|
1533
|
+
def q_dimension(self, base_coercion=True):
|
|
1534
|
+
r"""
|
|
1535
|
+
Return the quantum dimension as an element of the cyclotomic
|
|
1536
|
+
field of the `2\ell`-th roots of unity, where `l = m (k+h^\vee)`
|
|
1537
|
+
with `m=1, 2, 3` depending on whether type is simply, doubly or
|
|
1538
|
+
triply laced, `k` is the level and `h^\vee` is the dual
|
|
1539
|
+
Coxeter number.
|
|
1540
|
+
|
|
1541
|
+
EXAMPLES::
|
|
1542
|
+
|
|
1543
|
+
sage: B22 = FusionRing("B2", 2)
|
|
1544
|
+
sage: [(b.q_dimension())^2 for b in B22.basis()]
|
|
1545
|
+
[1, 4, 5, 1, 5, 4]
|
|
1546
|
+
"""
|
|
1547
|
+
if not self.is_simple_object():
|
|
1548
|
+
raise ValueError("quantum dimension is only available for simple objects of a FusionRing")
|
|
1549
|
+
P = self.parent()
|
|
1550
|
+
lam = self.weight()
|
|
1551
|
+
space = P.space()
|
|
1552
|
+
rho = space.rho()
|
|
1553
|
+
powers = {}
|
|
1554
|
+
for alpha in space.positive_roots():
|
|
1555
|
+
val = alpha.inner_product(lam + rho)
|
|
1556
|
+
if val in powers:
|
|
1557
|
+
powers[val] += 1
|
|
1558
|
+
else:
|
|
1559
|
+
powers[val] = 1
|
|
1560
|
+
val = alpha.inner_product(rho)
|
|
1561
|
+
if val in powers:
|
|
1562
|
+
powers[val] -= 1
|
|
1563
|
+
else:
|
|
1564
|
+
powers[val] = -1
|
|
1565
|
+
R = ZZ['q']
|
|
1566
|
+
q = R.gen()
|
|
1567
|
+
expr = R.fraction_field().one()
|
|
1568
|
+
for val, exp in powers.items():
|
|
1569
|
+
if exp > 0:
|
|
1570
|
+
expr *= q_int(P._nf * val, q)**exp
|
|
1571
|
+
elif exp < 0:
|
|
1572
|
+
expr /= q_int(P._nf * val, q)**(-exp)
|
|
1573
|
+
expr = R(expr)
|
|
1574
|
+
expr = expr.substitute(q=q**4) / (q**(2 * expr.degree()))
|
|
1575
|
+
zet = P.field().gen() ** (P._cyclotomic_order / P._l)
|
|
1576
|
+
ret = expr.substitute(q=zet)
|
|
1577
|
+
|
|
1578
|
+
if (not base_coercion) or (self.parent()._basecoer is None):
|
|
1579
|
+
return ret
|
|
1580
|
+
return self.parent()._basecoer(ret)
|