passagemath-categories 10.6.32__cp314-cp314t-musllinux_1_2_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.
- passagemath_categories-10.6.32.dist-info/METADATA +156 -0
- passagemath_categories-10.6.32.dist-info/RECORD +719 -0
- passagemath_categories-10.6.32.dist-info/WHEEL +5 -0
- passagemath_categories-10.6.32.dist-info/top_level.txt +2 -0
- passagemath_categories.libs/libgcc_s-2d945d6c.so.1 +0 -0
- passagemath_categories.libs/libgmp-28992bcb.so.10.5.0 +0 -0
- passagemath_categories.libs/libstdc++-85f2cd6d.so.6.0.33 +0 -0
- sage/all__sagemath_categories.py +28 -0
- sage/arith/all.py +38 -0
- sage/arith/constants.pxd +27 -0
- sage/arith/functions.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/functions.pxd +4 -0
- sage/arith/functions.pyx +221 -0
- sage/arith/misc.py +6552 -0
- sage/arith/multi_modular.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/multi_modular.pxd +39 -0
- sage/arith/multi_modular.pyx +994 -0
- sage/arith/rational_reconstruction.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/rational_reconstruction.pxd +4 -0
- sage/arith/rational_reconstruction.pyx +115 -0
- sage/arith/srange.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/srange.pyx +571 -0
- sage/calculus/all__sagemath_categories.py +2 -0
- sage/calculus/functional.py +481 -0
- sage/calculus/functions.py +151 -0
- sage/categories/additive_groups.py +73 -0
- sage/categories/additive_magmas.py +1044 -0
- sage/categories/additive_monoids.py +114 -0
- sage/categories/additive_semigroups.py +184 -0
- sage/categories/affine_weyl_groups.py +238 -0
- sage/categories/algebra_ideals.py +95 -0
- sage/categories/algebra_modules.py +96 -0
- sage/categories/algebras.py +349 -0
- sage/categories/algebras_with_basis.py +377 -0
- sage/categories/all.py +160 -0
- sage/categories/aperiodic_semigroups.py +29 -0
- sage/categories/associative_algebras.py +47 -0
- sage/categories/bialgebras.py +101 -0
- sage/categories/bialgebras_with_basis.py +414 -0
- sage/categories/bimodules.py +206 -0
- sage/categories/chain_complexes.py +268 -0
- sage/categories/classical_crystals.py +480 -0
- sage/categories/coalgebras.py +405 -0
- sage/categories/coalgebras_with_basis.py +232 -0
- sage/categories/coercion_methods.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/categories/coercion_methods.pyx +52 -0
- sage/categories/commutative_additive_groups.py +104 -0
- sage/categories/commutative_additive_monoids.py +45 -0
- sage/categories/commutative_additive_semigroups.py +48 -0
- sage/categories/commutative_algebra_ideals.py +87 -0
- sage/categories/commutative_algebras.py +94 -0
- sage/categories/commutative_ring_ideals.py +58 -0
- sage/categories/commutative_rings.py +736 -0
- sage/categories/complete_discrete_valuation.py +293 -0
- sage/categories/complex_reflection_groups.py +145 -0
- sage/categories/complex_reflection_or_generalized_coxeter_groups.py +1249 -0
- sage/categories/coxeter_group_algebras.py +186 -0
- sage/categories/coxeter_groups.py +3402 -0
- sage/categories/crystals.py +2628 -0
- sage/categories/cw_complexes.py +216 -0
- sage/categories/dedekind_domains.py +137 -0
- sage/categories/discrete_valuation.py +325 -0
- sage/categories/distributive_magmas_and_additive_magmas.py +100 -0
- sage/categories/division_rings.py +114 -0
- sage/categories/domains.py +95 -0
- sage/categories/drinfeld_modules.py +789 -0
- sage/categories/dual.py +42 -0
- sage/categories/enumerated_sets.py +1146 -0
- sage/categories/euclidean_domains.py +271 -0
- sage/categories/examples/algebras_with_basis.py +102 -0
- sage/categories/examples/all.py +1 -0
- sage/categories/examples/commutative_additive_monoids.py +130 -0
- sage/categories/examples/commutative_additive_semigroups.py +199 -0
- sage/categories/examples/coxeter_groups.py +8 -0
- sage/categories/examples/crystals.py +236 -0
- sage/categories/examples/cw_complexes.py +163 -0
- sage/categories/examples/facade_sets.py +187 -0
- sage/categories/examples/filtered_algebras_with_basis.py +204 -0
- sage/categories/examples/filtered_modules_with_basis.py +154 -0
- sage/categories/examples/finite_coxeter_groups.py +252 -0
- sage/categories/examples/finite_dimensional_algebras_with_basis.py +148 -0
- sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +495 -0
- sage/categories/examples/finite_enumerated_sets.py +208 -0
- sage/categories/examples/finite_monoids.py +150 -0
- sage/categories/examples/finite_semigroups.py +190 -0
- sage/categories/examples/finite_weyl_groups.py +191 -0
- sage/categories/examples/graded_connected_hopf_algebras_with_basis.py +152 -0
- sage/categories/examples/graded_modules_with_basis.py +168 -0
- sage/categories/examples/graphs.py +122 -0
- sage/categories/examples/hopf_algebras_with_basis.py +145 -0
- sage/categories/examples/infinite_enumerated_sets.py +190 -0
- sage/categories/examples/lie_algebras.py +352 -0
- sage/categories/examples/lie_algebras_with_basis.py +196 -0
- sage/categories/examples/magmas.py +162 -0
- sage/categories/examples/manifolds.py +94 -0
- sage/categories/examples/monoids.py +144 -0
- sage/categories/examples/posets.py +178 -0
- sage/categories/examples/semigroups.py +580 -0
- sage/categories/examples/semigroups_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/categories/examples/semigroups_cython.pyx +221 -0
- sage/categories/examples/semirings.py +249 -0
- sage/categories/examples/sets_cat.py +706 -0
- sage/categories/examples/sets_with_grading.py +101 -0
- sage/categories/examples/with_realizations.py +542 -0
- sage/categories/fields.py +991 -0
- sage/categories/filtered_algebras.py +63 -0
- sage/categories/filtered_algebras_with_basis.py +548 -0
- sage/categories/filtered_hopf_algebras_with_basis.py +138 -0
- sage/categories/filtered_modules.py +210 -0
- sage/categories/filtered_modules_with_basis.py +1209 -0
- sage/categories/finite_complex_reflection_groups.py +1506 -0
- sage/categories/finite_coxeter_groups.py +1138 -0
- sage/categories/finite_crystals.py +103 -0
- sage/categories/finite_dimensional_algebras_with_basis.py +1860 -0
- sage/categories/finite_dimensional_bialgebras_with_basis.py +33 -0
- sage/categories/finite_dimensional_coalgebras_with_basis.py +33 -0
- sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py +231 -0
- sage/categories/finite_dimensional_hopf_algebras_with_basis.py +38 -0
- sage/categories/finite_dimensional_lie_algebras_with_basis.py +2774 -0
- sage/categories/finite_dimensional_modules_with_basis.py +1407 -0
- sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py +167 -0
- sage/categories/finite_dimensional_semisimple_algebras_with_basis.py +270 -0
- sage/categories/finite_enumerated_sets.py +769 -0
- sage/categories/finite_fields.py +252 -0
- sage/categories/finite_groups.py +256 -0
- sage/categories/finite_lattice_posets.py +242 -0
- sage/categories/finite_monoids.py +316 -0
- sage/categories/finite_permutation_groups.py +339 -0
- sage/categories/finite_posets.py +1994 -0
- sage/categories/finite_semigroups.py +136 -0
- sage/categories/finite_sets.py +93 -0
- sage/categories/finite_weyl_groups.py +39 -0
- sage/categories/finitely_generated_lambda_bracket_algebras.py +112 -0
- sage/categories/finitely_generated_lie_conformal_algebras.py +114 -0
- sage/categories/finitely_generated_magmas.py +57 -0
- sage/categories/finitely_generated_semigroups.py +214 -0
- sage/categories/function_fields.py +76 -0
- sage/categories/g_sets.py +77 -0
- sage/categories/gcd_domains.py +65 -0
- sage/categories/generalized_coxeter_groups.py +94 -0
- sage/categories/graded_algebras.py +85 -0
- sage/categories/graded_algebras_with_basis.py +258 -0
- sage/categories/graded_bialgebras.py +32 -0
- sage/categories/graded_bialgebras_with_basis.py +32 -0
- sage/categories/graded_coalgebras.py +65 -0
- sage/categories/graded_coalgebras_with_basis.py +51 -0
- sage/categories/graded_hopf_algebras.py +41 -0
- sage/categories/graded_hopf_algebras_with_basis.py +169 -0
- sage/categories/graded_lie_algebras.py +91 -0
- sage/categories/graded_lie_algebras_with_basis.py +44 -0
- sage/categories/graded_lie_conformal_algebras.py +74 -0
- sage/categories/graded_modules.py +133 -0
- sage/categories/graded_modules_with_basis.py +329 -0
- sage/categories/graphs.py +138 -0
- sage/categories/group_algebras.py +430 -0
- sage/categories/groupoid.py +94 -0
- sage/categories/groups.py +667 -0
- sage/categories/h_trivial_semigroups.py +64 -0
- sage/categories/hecke_modules.py +185 -0
- sage/categories/highest_weight_crystals.py +980 -0
- sage/categories/hopf_algebras.py +219 -0
- sage/categories/hopf_algebras_with_basis.py +309 -0
- sage/categories/infinite_enumerated_sets.py +115 -0
- sage/categories/integral_domains.py +203 -0
- sage/categories/j_trivial_semigroups.py +29 -0
- sage/categories/kac_moody_algebras.py +82 -0
- sage/categories/kahler_algebras.py +203 -0
- sage/categories/l_trivial_semigroups.py +63 -0
- sage/categories/lambda_bracket_algebras.py +280 -0
- sage/categories/lambda_bracket_algebras_with_basis.py +107 -0
- sage/categories/lattice_posets.py +89 -0
- sage/categories/left_modules.py +49 -0
- sage/categories/lie_algebras.py +1070 -0
- sage/categories/lie_algebras_with_basis.py +261 -0
- sage/categories/lie_conformal_algebras.py +350 -0
- sage/categories/lie_conformal_algebras_with_basis.py +147 -0
- sage/categories/lie_groups.py +73 -0
- sage/categories/loop_crystals.py +1290 -0
- sage/categories/magmas.py +1189 -0
- sage/categories/magmas_and_additive_magmas.py +149 -0
- sage/categories/magmatic_algebras.py +365 -0
- sage/categories/manifolds.py +352 -0
- sage/categories/matrix_algebras.py +40 -0
- sage/categories/metric_spaces.py +387 -0
- sage/categories/modular_abelian_varieties.py +78 -0
- sage/categories/modules.py +989 -0
- sage/categories/modules_with_basis.py +2794 -0
- sage/categories/monoid_algebras.py +38 -0
- sage/categories/monoids.py +739 -0
- sage/categories/noetherian_rings.py +87 -0
- sage/categories/number_fields.py +242 -0
- sage/categories/ore_modules.py +189 -0
- sage/categories/partially_ordered_monoids.py +49 -0
- sage/categories/permutation_groups.py +63 -0
- sage/categories/pointed_sets.py +42 -0
- sage/categories/polyhedra.py +74 -0
- sage/categories/poor_man_map.py +270 -0
- sage/categories/posets.py +722 -0
- sage/categories/principal_ideal_domains.py +270 -0
- sage/categories/quantum_group_representations.py +543 -0
- sage/categories/quotient_fields.py +728 -0
- sage/categories/r_trivial_semigroups.py +45 -0
- sage/categories/regular_crystals.py +898 -0
- sage/categories/regular_supercrystals.py +170 -0
- sage/categories/right_modules.py +49 -0
- sage/categories/ring_ideals.py +74 -0
- sage/categories/rings.py +1904 -0
- sage/categories/rngs.py +175 -0
- sage/categories/schemes.py +393 -0
- sage/categories/semigroups.py +1060 -0
- sage/categories/semirings.py +71 -0
- sage/categories/semisimple_algebras.py +114 -0
- sage/categories/sets_with_grading.py +235 -0
- sage/categories/shephard_groups.py +43 -0
- sage/categories/signed_tensor.py +120 -0
- sage/categories/simplicial_complexes.py +134 -0
- sage/categories/simplicial_sets.py +1206 -0
- sage/categories/super_algebras.py +149 -0
- sage/categories/super_algebras_with_basis.py +144 -0
- sage/categories/super_hopf_algebras_with_basis.py +126 -0
- sage/categories/super_lie_conformal_algebras.py +193 -0
- sage/categories/super_modules.py +229 -0
- sage/categories/super_modules_with_basis.py +193 -0
- sage/categories/supercommutative_algebras.py +99 -0
- sage/categories/supercrystals.py +406 -0
- sage/categories/tensor.py +110 -0
- sage/categories/topological_spaces.py +170 -0
- sage/categories/triangular_kac_moody_algebras.py +439 -0
- sage/categories/tutorial.py +58 -0
- sage/categories/unique_factorization_domains.py +318 -0
- sage/categories/unital_algebras.py +426 -0
- sage/categories/vector_bundles.py +159 -0
- sage/categories/vector_spaces.py +357 -0
- sage/categories/weyl_groups.py +853 -0
- sage/combinat/all__sagemath_categories.py +34 -0
- sage/combinat/backtrack.py +180 -0
- sage/combinat/combinat.py +2269 -0
- sage/combinat/combinat_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/combinat_cython.pxd +6 -0
- sage/combinat/combinat_cython.pyx +390 -0
- sage/combinat/combination.py +796 -0
- sage/combinat/combinatorial_map.py +416 -0
- sage/combinat/composition.py +2192 -0
- sage/combinat/dlx.py +510 -0
- sage/combinat/integer_lists/__init__.py +7 -0
- sage/combinat/integer_lists/base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/integer_lists/base.pxd +16 -0
- sage/combinat/integer_lists/base.pyx +713 -0
- sage/combinat/integer_lists/invlex.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/integer_lists/invlex.pxd +4 -0
- sage/combinat/integer_lists/invlex.pyx +1650 -0
- sage/combinat/integer_lists/lists.py +328 -0
- sage/combinat/integer_lists/nn.py +48 -0
- sage/combinat/integer_vector.py +1818 -0
- sage/combinat/integer_vector_weighted.py +413 -0
- sage/combinat/matrices/all__sagemath_categories.py +5 -0
- sage/combinat/matrices/dancing_links.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/matrices/dancing_links.pyx +1159 -0
- sage/combinat/matrices/dancing_links_c.h +380 -0
- sage/combinat/matrices/dlxcpp.py +136 -0
- sage/combinat/partition.py +10070 -0
- sage/combinat/partitions.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/partitions.pyx +743 -0
- sage/combinat/permutation.py +10168 -0
- sage/combinat/permutation_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/permutation_cython.pxd +11 -0
- sage/combinat/permutation_cython.pyx +407 -0
- sage/combinat/q_analogues.py +1090 -0
- sage/combinat/ranker.py +268 -0
- sage/combinat/subset.py +1561 -0
- sage/combinat/subsets_hereditary.py +202 -0
- sage/combinat/subsets_pairwise.py +184 -0
- sage/combinat/tools.py +63 -0
- sage/combinat/tuple.py +348 -0
- sage/data_structures/all.py +2 -0
- sage/data_structures/all__sagemath_categories.py +2 -0
- sage/data_structures/binary_matrix.pxd +138 -0
- sage/data_structures/binary_search.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/binary_search.pxd +3 -0
- sage/data_structures/binary_search.pyx +66 -0
- sage/data_structures/bitset.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/bitset.pxd +40 -0
- sage/data_structures/bitset.pyx +2385 -0
- sage/data_structures/bitset_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/bitset_base.pxd +926 -0
- sage/data_structures/bitset_base.pyx +117 -0
- sage/data_structures/bitset_intrinsics.h +487 -0
- sage/data_structures/blas_dict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/blas_dict.pxd +12 -0
- sage/data_structures/blas_dict.pyx +469 -0
- sage/data_structures/list_of_pairs.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/list_of_pairs.pxd +16 -0
- sage/data_structures/list_of_pairs.pyx +122 -0
- sage/data_structures/mutable_poset.py +3312 -0
- sage/data_structures/pairing_heap.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/pairing_heap.h +346 -0
- sage/data_structures/pairing_heap.pxd +88 -0
- sage/data_structures/pairing_heap.pyx +1464 -0
- sage/data_structures/sparse_bitset.pxd +62 -0
- sage/data_structures/stream.py +5070 -0
- sage/databases/all__sagemath_categories.py +7 -0
- sage/databases/sql_db.py +2236 -0
- sage/ext/all__sagemath_categories.py +3 -0
- sage/ext/fast_callable.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/fast_callable.pxd +4 -0
- sage/ext/fast_callable.pyx +2746 -0
- sage/ext/fast_eval.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/fast_eval.pxd +1 -0
- sage/ext/fast_eval.pyx +102 -0
- sage/ext/interpreters/__init__.py +1 -0
- sage/ext/interpreters/all__sagemath_categories.py +2 -0
- sage/ext/interpreters/wrapper_el.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_el.pxd +18 -0
- sage/ext/interpreters/wrapper_el.pyx +148 -0
- sage/ext/interpreters/wrapper_py.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_py.pxd +17 -0
- sage/ext/interpreters/wrapper_py.pyx +133 -0
- sage/functions/airy.py +937 -0
- sage/functions/all.py +97 -0
- sage/functions/bessel.py +2102 -0
- sage/functions/error.py +784 -0
- sage/functions/exp_integral.py +1529 -0
- sage/functions/gamma.py +1087 -0
- sage/functions/generalized.py +672 -0
- sage/functions/hyperbolic.py +747 -0
- sage/functions/hypergeometric.py +1156 -0
- sage/functions/jacobi.py +1705 -0
- sage/functions/log.py +1402 -0
- sage/functions/min_max.py +338 -0
- sage/functions/orthogonal_polys.py +3106 -0
- sage/functions/other.py +2303 -0
- sage/functions/piecewise.py +1505 -0
- sage/functions/prime_pi.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/functions/prime_pi.pyx +262 -0
- sage/functions/special.py +1212 -0
- sage/functions/spike_function.py +278 -0
- sage/functions/transcendental.py +690 -0
- sage/functions/trig.py +1062 -0
- sage/functions/wigner.py +726 -0
- sage/geometry/abc.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/geometry/abc.pyx +82 -0
- sage/geometry/all__sagemath_categories.py +1 -0
- sage/groups/all__sagemath_categories.py +11 -0
- sage/groups/generic.py +1733 -0
- sage/groups/groups_catalog.py +113 -0
- sage/groups/perm_gps/all__sagemath_categories.py +1 -0
- sage/groups/perm_gps/partn_ref/all.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_categories.py +1 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pxd +52 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx +906 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd +85 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx +534 -0
- sage/groups/perm_gps/partn_ref/data_structures.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/data_structures.pxd +576 -0
- sage/groups/perm_gps/partn_ref/data_structures.pyx +1792 -0
- sage/groups/perm_gps/partn_ref/double_coset.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/double_coset.pxd +45 -0
- sage/groups/perm_gps/partn_ref/double_coset.pyx +739 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.pxd +18 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.pyx +82 -0
- sage/groups/perm_gps/partn_ref/refinement_python.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_python.pxd +16 -0
- sage/groups/perm_gps/partn_ref/refinement_python.pyx +564 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.pxd +60 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.pyx +858 -0
- sage/interfaces/abc.py +140 -0
- sage/interfaces/all.py +58 -0
- sage/interfaces/all__sagemath_categories.py +1 -0
- sage/interfaces/expect.py +1643 -0
- sage/interfaces/interface.py +1682 -0
- sage/interfaces/process.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/interfaces/process.pxd +5 -0
- sage/interfaces/process.pyx +288 -0
- sage/interfaces/quit.py +167 -0
- sage/interfaces/sage0.py +604 -0
- sage/interfaces/sagespawn.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/interfaces/sagespawn.pyx +308 -0
- sage/interfaces/tab_completion.py +101 -0
- sage/misc/all__sagemath_categories.py +78 -0
- sage/misc/allocator.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/allocator.pxd +6 -0
- sage/misc/allocator.pyx +47 -0
- sage/misc/binary_tree.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/binary_tree.pxd +29 -0
- sage/misc/binary_tree.pyx +537 -0
- sage/misc/callable_dict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/callable_dict.pyx +89 -0
- sage/misc/citation.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/citation.pyx +159 -0
- sage/misc/converting_dict.py +293 -0
- sage/misc/defaults.py +129 -0
- sage/misc/derivative.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/derivative.pyx +223 -0
- sage/misc/functional.py +2005 -0
- sage/misc/html.py +589 -0
- sage/misc/latex.py +2673 -0
- sage/misc/latex_macros.py +236 -0
- sage/misc/latex_standalone.py +1833 -0
- sage/misc/map_threaded.py +38 -0
- sage/misc/mathml.py +76 -0
- sage/misc/method_decorator.py +88 -0
- sage/misc/mrange.py +755 -0
- sage/misc/multireplace.py +41 -0
- sage/misc/object_multiplexer.py +92 -0
- sage/misc/parser.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/parser.pyx +1107 -0
- sage/misc/random_testing.py +264 -0
- sage/misc/rest_index_of_methods.py +377 -0
- sage/misc/search.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/search.pxd +2 -0
- sage/misc/search.pyx +68 -0
- sage/misc/stopgap.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/stopgap.pyx +95 -0
- sage/misc/table.py +853 -0
- sage/monoids/all__sagemath_categories.py +1 -0
- sage/monoids/indexed_free_monoid.py +1071 -0
- sage/monoids/monoid.py +82 -0
- sage/numerical/all__sagemath_categories.py +1 -0
- sage/numerical/backends/all__sagemath_categories.py +1 -0
- sage/numerical/backends/generic_backend.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/numerical/backends/generic_backend.pxd +61 -0
- sage/numerical/backends/generic_backend.pyx +1893 -0
- sage/numerical/backends/generic_sdp_backend.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/numerical/backends/generic_sdp_backend.pxd +38 -0
- sage/numerical/backends/generic_sdp_backend.pyx +755 -0
- sage/parallel/all.py +6 -0
- sage/parallel/decorate.py +575 -0
- sage/parallel/map_reduce.py +1997 -0
- sage/parallel/multiprocessing_sage.py +76 -0
- sage/parallel/ncpus.py +35 -0
- sage/parallel/parallelism.py +364 -0
- sage/parallel/reference.py +47 -0
- sage/parallel/use_fork.py +333 -0
- sage/rings/abc.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/abc.pxd +31 -0
- sage/rings/abc.pyx +526 -0
- sage/rings/algebraic_closure_finite_field.py +1154 -0
- sage/rings/all__sagemath_categories.py +91 -0
- sage/rings/big_oh.py +227 -0
- sage/rings/continued_fraction.py +2754 -0
- sage/rings/continued_fraction_gosper.py +220 -0
- sage/rings/factorint.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/factorint.pyx +295 -0
- sage/rings/fast_arith.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/fast_arith.pxd +21 -0
- sage/rings/fast_arith.pyx +535 -0
- sage/rings/finite_rings/all__sagemath_categories.py +9 -0
- sage/rings/finite_rings/conway_polynomials.py +542 -0
- sage/rings/finite_rings/element_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/element_base.pxd +12 -0
- sage/rings/finite_rings/element_base.pyx +1176 -0
- sage/rings/finite_rings/finite_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/finite_field_base.pxd +7 -0
- sage/rings/finite_rings/finite_field_base.pyx +2171 -0
- sage/rings/finite_rings/finite_field_constructor.py +827 -0
- sage/rings/finite_rings/finite_field_prime_modn.py +372 -0
- sage/rings/finite_rings/galois_group.py +154 -0
- sage/rings/finite_rings/hom_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_finite_field.pxd +23 -0
- sage/rings/finite_rings/hom_finite_field.pyx +856 -0
- sage/rings/finite_rings/hom_prime_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_prime_finite_field.pxd +15 -0
- sage/rings/finite_rings/hom_prime_finite_field.pyx +164 -0
- sage/rings/finite_rings/homset.py +357 -0
- sage/rings/finite_rings/integer_mod.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/integer_mod.pxd +56 -0
- sage/rings/finite_rings/integer_mod.pyx +4586 -0
- sage/rings/finite_rings/integer_mod_limits.h +11 -0
- sage/rings/finite_rings/integer_mod_ring.py +2044 -0
- sage/rings/finite_rings/residue_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/residue_field.pxd +30 -0
- sage/rings/finite_rings/residue_field.pyx +1811 -0
- sage/rings/finite_rings/stdint.pxd +19 -0
- sage/rings/fraction_field.py +1452 -0
- sage/rings/fraction_field_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/fraction_field_element.pyx +1357 -0
- sage/rings/function_field/all.py +7 -0
- sage/rings/function_field/all__sagemath_categories.py +2 -0
- sage/rings/function_field/constructor.py +218 -0
- sage/rings/function_field/element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/element.pxd +11 -0
- sage/rings/function_field/element.pyx +1008 -0
- sage/rings/function_field/element_rational.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/element_rational.pyx +513 -0
- sage/rings/function_field/extensions.py +230 -0
- sage/rings/function_field/function_field.py +1468 -0
- sage/rings/function_field/function_field_rational.py +1005 -0
- sage/rings/function_field/ideal.py +1155 -0
- sage/rings/function_field/ideal_rational.py +629 -0
- sage/rings/function_field/jacobian_base.py +826 -0
- sage/rings/function_field/jacobian_hess.py +1053 -0
- sage/rings/function_field/jacobian_khuri_makdisi.py +1027 -0
- sage/rings/function_field/maps.py +1039 -0
- sage/rings/function_field/order.py +281 -0
- sage/rings/function_field/order_basis.py +586 -0
- sage/rings/function_field/order_rational.py +576 -0
- sage/rings/function_field/place.py +426 -0
- sage/rings/function_field/place_rational.py +181 -0
- sage/rings/generic.py +320 -0
- sage/rings/homset.py +332 -0
- sage/rings/ideal.py +1885 -0
- sage/rings/ideal_monoid.py +215 -0
- sage/rings/infinity.py +1890 -0
- sage/rings/integer.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/integer.pxd +45 -0
- sage/rings/integer.pyx +7874 -0
- sage/rings/integer_ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/integer_ring.pxd +8 -0
- sage/rings/integer_ring.pyx +1693 -0
- sage/rings/laurent_series_ring.py +931 -0
- sage/rings/laurent_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/laurent_series_ring_element.pxd +11 -0
- sage/rings/laurent_series_ring_element.pyx +1927 -0
- sage/rings/lazy_series.py +7815 -0
- sage/rings/lazy_series_ring.py +4356 -0
- sage/rings/localization.py +1043 -0
- sage/rings/morphism.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/morphism.pxd +39 -0
- sage/rings/morphism.pyx +3299 -0
- sage/rings/multi_power_series_ring.py +1145 -0
- sage/rings/multi_power_series_ring_element.py +2184 -0
- sage/rings/noncommutative_ideals.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/noncommutative_ideals.pyx +423 -0
- sage/rings/number_field/all__sagemath_categories.py +1 -0
- sage/rings/number_field/number_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/number_field/number_field_base.pxd +8 -0
- sage/rings/number_field/number_field_base.pyx +507 -0
- sage/rings/number_field/number_field_element_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/number_field/number_field_element_base.pxd +6 -0
- sage/rings/number_field/number_field_element_base.pyx +36 -0
- sage/rings/number_field/number_field_ideal.py +3550 -0
- sage/rings/padics/all__sagemath_categories.py +4 -0
- sage/rings/padics/local_generic.py +1670 -0
- sage/rings/padics/local_generic_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/padics/local_generic_element.pxd +5 -0
- sage/rings/padics/local_generic_element.pyx +1017 -0
- sage/rings/padics/misc.py +256 -0
- sage/rings/padics/padic_generic.py +1911 -0
- sage/rings/padics/pow_computer.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/padics/pow_computer.pxd +38 -0
- sage/rings/padics/pow_computer.pyx +671 -0
- sage/rings/padics/precision_error.py +24 -0
- sage/rings/polynomial/all__sagemath_categories.py +25 -0
- sage/rings/polynomial/commutative_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/commutative_polynomial.pxd +6 -0
- sage/rings/polynomial/commutative_polynomial.pyx +24 -0
- sage/rings/polynomial/cyclotomic.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/cyclotomic.pyx +404 -0
- sage/rings/polynomial/flatten.py +711 -0
- sage/rings/polynomial/ideal.py +102 -0
- sage/rings/polynomial/infinite_polynomial_element.py +1768 -0
- sage/rings/polynomial/infinite_polynomial_ring.py +1653 -0
- sage/rings/polynomial/laurent_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/laurent_polynomial.pxd +18 -0
- sage/rings/polynomial/laurent_polynomial.pyx +2190 -0
- sage/rings/polynomial/laurent_polynomial_ideal.py +590 -0
- sage/rings/polynomial/laurent_polynomial_ring.py +832 -0
- sage/rings/polynomial/laurent_polynomial_ring_base.py +708 -0
- sage/rings/polynomial/multi_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/multi_polynomial.pxd +12 -0
- sage/rings/polynomial/multi_polynomial.pyx +3082 -0
- sage/rings/polynomial/multi_polynomial_element.py +2570 -0
- sage/rings/polynomial/multi_polynomial_ideal.py +5771 -0
- sage/rings/polynomial/multi_polynomial_ring.py +947 -0
- sage/rings/polynomial/multi_polynomial_ring_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/multi_polynomial_ring_base.pxd +15 -0
- sage/rings/polynomial/multi_polynomial_ring_base.pyx +1855 -0
- sage/rings/polynomial/multi_polynomial_sequence.py +2204 -0
- sage/rings/polynomial/polydict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polydict.pxd +45 -0
- sage/rings/polynomial/polydict.pyx +2701 -0
- sage/rings/polynomial/polynomial_compiled.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_compiled.pxd +59 -0
- sage/rings/polynomial/polynomial_compiled.pyx +509 -0
- sage/rings/polynomial/polynomial_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_element.pxd +64 -0
- sage/rings/polynomial/polynomial_element.pyx +13255 -0
- sage/rings/polynomial/polynomial_element_generic.py +1637 -0
- sage/rings/polynomial/polynomial_fateman.py +97 -0
- sage/rings/polynomial/polynomial_quotient_ring.py +2465 -0
- sage/rings/polynomial/polynomial_quotient_ring_element.py +779 -0
- sage/rings/polynomial/polynomial_ring.py +3784 -0
- sage/rings/polynomial/polynomial_ring_constructor.py +1051 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.pxd +5 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.pyx +121 -0
- sage/rings/polynomial/polynomial_singular_interface.py +549 -0
- sage/rings/polynomial/symmetric_ideal.py +989 -0
- sage/rings/polynomial/symmetric_reduction.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/symmetric_reduction.pxd +8 -0
- sage/rings/polynomial/symmetric_reduction.pyx +669 -0
- sage/rings/polynomial/term_order.py +2279 -0
- sage/rings/polynomial/toy_buchberger.py +449 -0
- sage/rings/polynomial/toy_d_basis.py +387 -0
- sage/rings/polynomial/toy_variety.py +362 -0
- sage/rings/power_series_mpoly.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_mpoly.pxd +9 -0
- sage/rings/power_series_mpoly.pyx +161 -0
- sage/rings/power_series_poly.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_poly.pxd +10 -0
- sage/rings/power_series_poly.pyx +1317 -0
- sage/rings/power_series_ring.py +1441 -0
- sage/rings/power_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_ring_element.pxd +12 -0
- sage/rings/power_series_ring_element.pyx +3028 -0
- sage/rings/puiseux_series_ring.py +487 -0
- sage/rings/puiseux_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/puiseux_series_ring_element.pxd +7 -0
- sage/rings/puiseux_series_ring_element.pyx +1055 -0
- sage/rings/qqbar_decorators.py +167 -0
- sage/rings/quotient_ring.py +1598 -0
- sage/rings/quotient_ring_element.py +979 -0
- sage/rings/rational.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/rational.pxd +20 -0
- sage/rings/rational.pyx +4284 -0
- sage/rings/rational_field.py +1730 -0
- sage/rings/real_double.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/real_double.pxd +16 -0
- sage/rings/real_double.pyx +2218 -0
- sage/rings/real_lazy.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/real_lazy.pxd +30 -0
- sage/rings/real_lazy.pyx +1773 -0
- sage/rings/ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/ring.pxd +30 -0
- sage/rings/ring.pyx +850 -0
- sage/rings/semirings/all.py +3 -0
- sage/rings/semirings/non_negative_integer_semiring.py +107 -0
- sage/rings/semirings/tropical_mpolynomial.py +972 -0
- sage/rings/semirings/tropical_polynomial.py +997 -0
- sage/rings/semirings/tropical_semiring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/semirings/tropical_semiring.pyx +676 -0
- sage/rings/semirings/tropical_variety.py +1701 -0
- sage/rings/sum_of_squares.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/sum_of_squares.pxd +3 -0
- sage/rings/sum_of_squares.pyx +336 -0
- sage/rings/tests.py +504 -0
- sage/schemes/affine/affine_homset.py +508 -0
- sage/schemes/affine/affine_morphism.py +1574 -0
- sage/schemes/affine/affine_point.py +460 -0
- sage/schemes/affine/affine_rational_point.py +308 -0
- sage/schemes/affine/affine_space.py +1264 -0
- sage/schemes/affine/affine_subscheme.py +592 -0
- sage/schemes/affine/all.py +25 -0
- sage/schemes/all__sagemath_categories.py +5 -0
- sage/schemes/generic/algebraic_scheme.py +2092 -0
- sage/schemes/generic/all.py +5 -0
- sage/schemes/generic/ambient_space.py +400 -0
- sage/schemes/generic/divisor.py +465 -0
- sage/schemes/generic/divisor_group.py +313 -0
- sage/schemes/generic/glue.py +84 -0
- sage/schemes/generic/homset.py +820 -0
- sage/schemes/generic/hypersurface.py +234 -0
- sage/schemes/generic/morphism.py +2107 -0
- sage/schemes/generic/point.py +237 -0
- sage/schemes/generic/scheme.py +1190 -0
- sage/schemes/generic/spec.py +199 -0
- sage/schemes/product_projective/all.py +6 -0
- sage/schemes/product_projective/homset.py +236 -0
- sage/schemes/product_projective/morphism.py +517 -0
- sage/schemes/product_projective/point.py +568 -0
- sage/schemes/product_projective/rational_point.py +550 -0
- sage/schemes/product_projective/space.py +1301 -0
- sage/schemes/product_projective/subscheme.py +466 -0
- sage/schemes/projective/all.py +24 -0
- sage/schemes/projective/proj_bdd_height.py +453 -0
- sage/schemes/projective/projective_homset.py +718 -0
- sage/schemes/projective/projective_morphism.py +2792 -0
- sage/schemes/projective/projective_point.py +1484 -0
- sage/schemes/projective/projective_rational_point.py +569 -0
- sage/schemes/projective/projective_space.py +2571 -0
- sage/schemes/projective/projective_subscheme.py +1574 -0
- sage/sets/all.py +17 -0
- sage/sets/cartesian_product.py +376 -0
- sage/sets/condition_set.py +525 -0
- sage/sets/disjoint_set.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/disjoint_set.pxd +36 -0
- sage/sets/disjoint_set.pyx +998 -0
- sage/sets/disjoint_union_enumerated_sets.py +625 -0
- sage/sets/family.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/family.pxd +12 -0
- sage/sets/family.pyx +1556 -0
- sage/sets/finite_enumerated_set.py +406 -0
- sage/sets/finite_set_map_cy.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/finite_set_map_cy.pxd +34 -0
- sage/sets/finite_set_map_cy.pyx +708 -0
- sage/sets/finite_set_maps.py +591 -0
- sage/sets/image_set.py +448 -0
- sage/sets/integer_range.py +829 -0
- sage/sets/non_negative_integers.py +241 -0
- sage/sets/positive_integers.py +93 -0
- sage/sets/primes.py +188 -0
- sage/sets/real_set.py +2760 -0
- sage/sets/recursively_enumerated_set.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/recursively_enumerated_set.pxd +31 -0
- sage/sets/recursively_enumerated_set.pyx +2082 -0
- sage/sets/set.py +2083 -0
- sage/sets/set_from_iterator.py +1021 -0
- sage/sets/totally_ordered_finite_set.py +329 -0
- sage/symbolic/all__sagemath_categories.py +1 -0
- sage/symbolic/function.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/symbolic/function.pxd +29 -0
- sage/symbolic/function.pyx +1488 -0
- sage/symbolic/symbols.py +56 -0
- sage/tests/all__sagemath_categories.py +1 -0
- sage/tests/cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/tests/cython.pyx +37 -0
- sage/tests/stl_vector.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/tests/stl_vector.pyx +171 -0
- sage/typeset/all.py +6 -0
- sage/typeset/ascii_art.py +295 -0
- sage/typeset/character_art.py +789 -0
- sage/typeset/character_art_factory.py +572 -0
- sage/typeset/symbols.py +334 -0
- sage/typeset/unicode_art.py +183 -0
- sage/typeset/unicode_characters.py +101 -0
|
@@ -0,0 +1,3402 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-categories
|
|
2
|
+
r"""
|
|
3
|
+
Coxeter Groups
|
|
4
|
+
"""
|
|
5
|
+
# ****************************************************************************
|
|
6
|
+
# Copyright (C) 2009 Nicolas M. Thiery <nthiery at users.sf.net>
|
|
7
|
+
# 2015 Christian Stump <christian.stump at gmail.com>
|
|
8
|
+
#
|
|
9
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
10
|
+
# https://www.gnu.org/licenses/
|
|
11
|
+
# *****************************************************************************
|
|
12
|
+
# With contributions from Dan Bump, Steve Pon, Qiang Wang, Anne Schilling, Christian Stump, Mark Shimozono
|
|
13
|
+
from copy import copy
|
|
14
|
+
from collections import deque
|
|
15
|
+
|
|
16
|
+
from sage.categories.category_singleton import Category_singleton
|
|
17
|
+
from sage.categories.enumerated_sets import EnumeratedSets
|
|
18
|
+
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
|
|
19
|
+
from sage.categories.generalized_coxeter_groups import GeneralizedCoxeterGroups
|
|
20
|
+
from sage.misc.abstract_method import abstract_method
|
|
21
|
+
from sage.misc.cachefunc import cached_method, cached_in_parent_method
|
|
22
|
+
from sage.misc.call import attrcall
|
|
23
|
+
from sage.misc.constant_function import ConstantFunction
|
|
24
|
+
from sage.misc.flatten import flatten
|
|
25
|
+
from sage.misc.lazy_import import LazyImport
|
|
26
|
+
from sage.structure.element import have_same_parent, parent
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class CoxeterGroups(Category_singleton):
|
|
30
|
+
r"""
|
|
31
|
+
The category of Coxeter groups.
|
|
32
|
+
|
|
33
|
+
A *Coxeter group* is a group `W` with a distinguished (finite)
|
|
34
|
+
family of involutions `(s_i)_{i\in I}`, called the *simple
|
|
35
|
+
reflections*, subject to relations of the form `(s_is_j)^{m_{i,j}} = 1`.
|
|
36
|
+
|
|
37
|
+
`I` is the *index set* of `W` and `|I|` is the *rank* of `W`.
|
|
38
|
+
|
|
39
|
+
See :wikipedia:`Coxeter_group` for details.
|
|
40
|
+
|
|
41
|
+
EXAMPLES::
|
|
42
|
+
|
|
43
|
+
sage: C = CoxeterGroups(); C
|
|
44
|
+
Category of Coxeter groups
|
|
45
|
+
sage: C.super_categories()
|
|
46
|
+
[Category of generalized Coxeter groups]
|
|
47
|
+
|
|
48
|
+
sage: W = C.example(); W
|
|
49
|
+
The symmetric group on {0, ..., 3}
|
|
50
|
+
|
|
51
|
+
sage: W.simple_reflections()
|
|
52
|
+
Finite family {0: (1, 0, 2, 3), 1: (0, 2, 1, 3), 2: (0, 1, 3, 2)}
|
|
53
|
+
|
|
54
|
+
Here are some further examples::
|
|
55
|
+
|
|
56
|
+
sage: FiniteCoxeterGroups().example()
|
|
57
|
+
The 5-th dihedral group of order 10
|
|
58
|
+
sage: FiniteWeylGroups().example()
|
|
59
|
+
The symmetric group on {0, ..., 3}
|
|
60
|
+
sage: WeylGroup(["B", 3]) # needs sage.combinat sage.groups
|
|
61
|
+
Weyl Group of type ['B', 3] (as a matrix group acting on the ambient space)
|
|
62
|
+
|
|
63
|
+
sage: S4 = SymmetricGroup(4); S4 # needs sage.groups
|
|
64
|
+
Symmetric group of order 4! as a permutation group
|
|
65
|
+
sage: S4 in CoxeterGroups().Finite() # needs sage.groups
|
|
66
|
+
True
|
|
67
|
+
|
|
68
|
+
Those will eventually be also in this category::
|
|
69
|
+
|
|
70
|
+
sage: DihedralGroup(5) # needs sage.groups
|
|
71
|
+
Dihedral group of order 10 as a permutation group
|
|
72
|
+
|
|
73
|
+
.. TODO:: add a demo of usual computations on Coxeter groups.
|
|
74
|
+
|
|
75
|
+
.. SEEALSO::
|
|
76
|
+
|
|
77
|
+
- :mod:`sage.combinat.root_system`
|
|
78
|
+
- :class:`WeylGroups`
|
|
79
|
+
- :class:`GeneralizedCoxeterGroups`
|
|
80
|
+
|
|
81
|
+
.. WARNING::
|
|
82
|
+
|
|
83
|
+
It is assumed that morphisms in this category preserve the
|
|
84
|
+
distinguished choice of simple reflections. In particular,
|
|
85
|
+
subobjects in this category are parabolic subgroups. In this
|
|
86
|
+
sense, this category might be better named ``Coxeter
|
|
87
|
+
Systems``. In the long run we might want to have two distinct
|
|
88
|
+
categories, one for Coxeter groups (with morphisms being just
|
|
89
|
+
group morphisms) and one for Coxeter systems::
|
|
90
|
+
|
|
91
|
+
sage: CoxeterGroups().is_full_subcategory(Groups())
|
|
92
|
+
False
|
|
93
|
+
sage: from sage.categories.generalized_coxeter_groups import GeneralizedCoxeterGroups
|
|
94
|
+
sage: CoxeterGroups().is_full_subcategory(GeneralizedCoxeterGroups())
|
|
95
|
+
True
|
|
96
|
+
|
|
97
|
+
TESTS::
|
|
98
|
+
|
|
99
|
+
sage: W = CoxeterGroups().example()
|
|
100
|
+
sage: TestSuite(W).run()
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
def super_categories(self):
|
|
104
|
+
"""
|
|
105
|
+
EXAMPLES::
|
|
106
|
+
|
|
107
|
+
sage: CoxeterGroups().super_categories()
|
|
108
|
+
[Category of generalized Coxeter groups]
|
|
109
|
+
"""
|
|
110
|
+
return [GeneralizedCoxeterGroups()]
|
|
111
|
+
|
|
112
|
+
def additional_structure(self):
|
|
113
|
+
r"""
|
|
114
|
+
Return ``None``.
|
|
115
|
+
|
|
116
|
+
Indeed, all the structure Coxeter groups have in addition to
|
|
117
|
+
groups (simple reflections, ...) is already defined in the
|
|
118
|
+
super category.
|
|
119
|
+
|
|
120
|
+
.. SEEALSO:: :meth:`Category.additional_structure`
|
|
121
|
+
|
|
122
|
+
EXAMPLES::
|
|
123
|
+
|
|
124
|
+
sage: CoxeterGroups().additional_structure()
|
|
125
|
+
"""
|
|
126
|
+
return None
|
|
127
|
+
|
|
128
|
+
Finite = LazyImport('sage.categories.finite_coxeter_groups', 'FiniteCoxeterGroups')
|
|
129
|
+
Algebras = LazyImport('sage.categories.coxeter_group_algebras', 'CoxeterGroupAlgebras')
|
|
130
|
+
|
|
131
|
+
class ParentMethods:
|
|
132
|
+
@abstract_method
|
|
133
|
+
def coxeter_matrix(self):
|
|
134
|
+
"""
|
|
135
|
+
Return the Coxeter matrix associated to ``self``.
|
|
136
|
+
|
|
137
|
+
EXAMPLES::
|
|
138
|
+
|
|
139
|
+
sage: G = WeylGroup(['A', 3]) # needs sage.combinat sage.groups
|
|
140
|
+
sage: G.coxeter_matrix() # needs sage.combinat sage.groups
|
|
141
|
+
[1 3 2]
|
|
142
|
+
[3 1 3]
|
|
143
|
+
[2 3 1]
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
@cached_method
|
|
147
|
+
def index_set(self):
|
|
148
|
+
"""
|
|
149
|
+
Return the index set of ``self``.
|
|
150
|
+
|
|
151
|
+
EXAMPLES::
|
|
152
|
+
|
|
153
|
+
sage: # needs sage.combinat sage.groups
|
|
154
|
+
sage: W = CoxeterGroup([[1,3],[3,1]])
|
|
155
|
+
sage: W.index_set()
|
|
156
|
+
(1, 2)
|
|
157
|
+
sage: W = CoxeterGroup([[1,3],[3,1]], index_set=['x', 'y'])
|
|
158
|
+
sage: W.index_set()
|
|
159
|
+
('x', 'y')
|
|
160
|
+
sage: W = CoxeterGroup(['H', 3])
|
|
161
|
+
sage: W.index_set()
|
|
162
|
+
(1, 2, 3)
|
|
163
|
+
"""
|
|
164
|
+
return self.coxeter_matrix().index_set()
|
|
165
|
+
|
|
166
|
+
def coxeter_diagram(self):
|
|
167
|
+
"""
|
|
168
|
+
Return the Coxeter diagram of ``self``.
|
|
169
|
+
|
|
170
|
+
EXAMPLES::
|
|
171
|
+
|
|
172
|
+
sage: # needs sage.combinat sage.graphs sage.groups
|
|
173
|
+
sage: W = CoxeterGroup(['H', 3], implementation='reflection')
|
|
174
|
+
sage: G = W.coxeter_diagram(); G
|
|
175
|
+
Graph on 3 vertices
|
|
176
|
+
sage: G.edges(sort=True)
|
|
177
|
+
[(1, 2, 3), (2, 3, 5)]
|
|
178
|
+
sage: CoxeterGroup(G) is W
|
|
179
|
+
True
|
|
180
|
+
sage: G = Graph([(0, 1, 3), (1, 2, oo)])
|
|
181
|
+
sage: W = CoxeterGroup(G)
|
|
182
|
+
sage: W.coxeter_diagram() == G
|
|
183
|
+
True
|
|
184
|
+
sage: CoxeterGroup(W.coxeter_diagram()) is W
|
|
185
|
+
True
|
|
186
|
+
"""
|
|
187
|
+
return self.coxeter_matrix().coxeter_graph()
|
|
188
|
+
|
|
189
|
+
def coxeter_type(self):
|
|
190
|
+
"""
|
|
191
|
+
Return the Coxeter type of ``self``.
|
|
192
|
+
|
|
193
|
+
EXAMPLES::
|
|
194
|
+
|
|
195
|
+
sage: W = CoxeterGroup(['H', 3]) # needs sage.combinat sage.groups
|
|
196
|
+
sage: W.coxeter_type() # needs sage.combinat sage.groups
|
|
197
|
+
Coxeter type of ['H', 3]
|
|
198
|
+
"""
|
|
199
|
+
return self.coxeter_matrix().coxeter_type()
|
|
200
|
+
|
|
201
|
+
def braid_relations(self):
|
|
202
|
+
r"""
|
|
203
|
+
Return the braid relations of ``self`` as a list of reduced
|
|
204
|
+
words of the braid relations.
|
|
205
|
+
|
|
206
|
+
EXAMPLES::
|
|
207
|
+
|
|
208
|
+
sage: W = WeylGroup(["A", 2]) # needs sage.combinat sage.groups
|
|
209
|
+
sage: W.braid_relations() # needs sage.combinat sage.groups
|
|
210
|
+
[[[1, 2, 1], [2, 1, 2]]]
|
|
211
|
+
|
|
212
|
+
sage: W = WeylGroup(["B", 3]) # needs sage.combinat sage.groups
|
|
213
|
+
sage: W.braid_relations() # needs sage.combinat sage.groups
|
|
214
|
+
[[[1, 2, 1], [2, 1, 2]], [[1, 3], [3, 1]], [[2, 3, 2, 3], [3, 2, 3, 2]]]
|
|
215
|
+
"""
|
|
216
|
+
rels = []
|
|
217
|
+
M = self.coxeter_matrix()
|
|
218
|
+
I = self.index_set()
|
|
219
|
+
for ii, i in enumerate(I):
|
|
220
|
+
for j in I[ii + 1:]:
|
|
221
|
+
m = M[i, j]
|
|
222
|
+
rel = [i, j] * m
|
|
223
|
+
rels.append([rel[:m], rel[m:] if m % 2 else
|
|
224
|
+
list(reversed(rel[m:]))])
|
|
225
|
+
return rels
|
|
226
|
+
|
|
227
|
+
def braid_group_as_finitely_presented_group(self):
|
|
228
|
+
r"""
|
|
229
|
+
Return the associated braid group.
|
|
230
|
+
|
|
231
|
+
EXAMPLES::
|
|
232
|
+
|
|
233
|
+
sage: W = CoxeterGroup(['A', 2]) # needs sage.combinat sage.groups
|
|
234
|
+
sage: W.braid_group_as_finitely_presented_group() # needs sage.combinat sage.groups
|
|
235
|
+
Finitely presented group < S1, S2 | S1*S2*S1*S2^-1*S1^-1*S2^-1 >
|
|
236
|
+
|
|
237
|
+
sage: W = WeylGroup(['B', 2]) # needs sage.combinat sage.groups
|
|
238
|
+
sage: W.braid_group_as_finitely_presented_group() # needs sage.combinat sage.groups
|
|
239
|
+
Finitely presented group < S1, S2 | (S1*S2)^2*(S1^-1*S2^-1)^2 >
|
|
240
|
+
|
|
241
|
+
sage: W = ReflectionGroup(['B',3], index_set=["AA","BB","5"]) # optional - gap3
|
|
242
|
+
sage: W.braid_group_as_finitely_presented_group() # optional - gap3
|
|
243
|
+
Finitely presented group < SAA, SBB, S5 |
|
|
244
|
+
(SAA*SBB)^2*(SAA^-1*SBB^-1)^2, SAA*S5*SAA^-1*S5^-1,
|
|
245
|
+
SBB*S5*SBB*S5^-1*SBB^-1*S5^-1 >
|
|
246
|
+
"""
|
|
247
|
+
from sage.groups.free_group import FreeGroup
|
|
248
|
+
from sage.misc.misc_c import prod
|
|
249
|
+
|
|
250
|
+
I = self.index_set()
|
|
251
|
+
F = FreeGroup(["S%s" % i for i in I])
|
|
252
|
+
S = F.gens()
|
|
253
|
+
rels = self.braid_relations()
|
|
254
|
+
return F / [prod(S[I.index(i)] for i in l) * prod(S[I.index(i)]**-1 for i in reversed(r)) for l, r in rels]
|
|
255
|
+
|
|
256
|
+
def braid_orbit_iter(self, word):
|
|
257
|
+
r"""
|
|
258
|
+
Iterate over the braid orbit of a word ``word`` of indices.
|
|
259
|
+
|
|
260
|
+
The input word does not need to be a reduced expression of
|
|
261
|
+
an element.
|
|
262
|
+
|
|
263
|
+
INPUT:
|
|
264
|
+
|
|
265
|
+
- ``word`` -- list (or iterable) of indices in
|
|
266
|
+
``self.index_set()``
|
|
267
|
+
|
|
268
|
+
OUTPUT:
|
|
269
|
+
|
|
270
|
+
all lists that can be obtained from
|
|
271
|
+
``word`` by replacements of braid relations
|
|
272
|
+
|
|
273
|
+
EXAMPLES::
|
|
274
|
+
|
|
275
|
+
sage: W = CoxeterGroups().example()
|
|
276
|
+
sage: sorted(W.braid_orbit_iter([0, 1, 2, 1])) # needs sage.combinat sage.graphs sage.modules
|
|
277
|
+
[[0, 1, 2, 1], [0, 2, 1, 2], [2, 0, 1, 2]]
|
|
278
|
+
"""
|
|
279
|
+
word = list(word)
|
|
280
|
+
from sage.combinat.root_system.braid_orbit import BraidOrbit
|
|
281
|
+
|
|
282
|
+
braid_rels = self.braid_relations()
|
|
283
|
+
I = self.index_set()
|
|
284
|
+
|
|
285
|
+
from sage.rings.integer_ring import ZZ
|
|
286
|
+
be_careful = any(i not in ZZ for i in I)
|
|
287
|
+
|
|
288
|
+
if be_careful:
|
|
289
|
+
Iinv = {i: j for j, i in enumerate(I)}
|
|
290
|
+
word = [Iinv[i] for i in word]
|
|
291
|
+
braid_rels = [[[Iinv[i] for i in l],
|
|
292
|
+
[Iinv[i] for i in r]] for l, r in braid_rels]
|
|
293
|
+
|
|
294
|
+
orb = BraidOrbit(word, braid_rels)
|
|
295
|
+
|
|
296
|
+
if be_careful:
|
|
297
|
+
for word in orb:
|
|
298
|
+
yield [I[i] for i in word]
|
|
299
|
+
else:
|
|
300
|
+
for I in orb:
|
|
301
|
+
yield list(I)
|
|
302
|
+
|
|
303
|
+
def braid_orbit(self, word):
|
|
304
|
+
r"""
|
|
305
|
+
Return the braid orbit of a word ``word`` of indices.
|
|
306
|
+
|
|
307
|
+
The input word does not need to be a reduced expression of
|
|
308
|
+
an element.
|
|
309
|
+
|
|
310
|
+
INPUT:
|
|
311
|
+
|
|
312
|
+
- ``word`` -- a list (or iterable) of indices in
|
|
313
|
+
``self.index_set()``
|
|
314
|
+
|
|
315
|
+
OUTPUT:
|
|
316
|
+
|
|
317
|
+
a list of all lists that can be obtained from
|
|
318
|
+
``word`` by replacements of braid relations
|
|
319
|
+
|
|
320
|
+
See :meth:`braid_relations` for the definition of braid
|
|
321
|
+
relations.
|
|
322
|
+
|
|
323
|
+
EXAMPLES::
|
|
324
|
+
|
|
325
|
+
sage: W = CoxeterGroups().example()
|
|
326
|
+
sage: s = W.simple_reflections()
|
|
327
|
+
sage: w = s[0] * s[1] * s[2] * s[1]
|
|
328
|
+
sage: word = w.reduced_word(); word
|
|
329
|
+
[0, 1, 2, 1]
|
|
330
|
+
|
|
331
|
+
sage: sorted(W.braid_orbit(word)) # needs sage.combinat sage.graphs sage.modules
|
|
332
|
+
[[0, 1, 2, 1], [0, 2, 1, 2], [2, 0, 1, 2]]
|
|
333
|
+
|
|
334
|
+
sage: sorted(W.braid_orbit([2,1,1,2,1])) # needs sage.combinat sage.graphs sage.modules
|
|
335
|
+
[[1, 2, 1, 1, 2], [2, 1, 1, 2, 1], [2, 1, 2, 1, 2], [2, 2, 1, 2, 2]]
|
|
336
|
+
|
|
337
|
+
sage: # optional - gap3
|
|
338
|
+
sage: W = ReflectionGroup(['A',3], index_set=["AA","BB","5"])
|
|
339
|
+
sage: w = W.long_element()
|
|
340
|
+
sage: W.braid_orbit(w.reduced_word())
|
|
341
|
+
[['BB', '5', 'AA', 'BB', '5', 'AA'],
|
|
342
|
+
['5', 'BB', '5', 'AA', 'BB', '5'],
|
|
343
|
+
['BB', 'AA', 'BB', '5', 'BB', 'AA'],
|
|
344
|
+
['AA', '5', 'BB', 'AA', '5', 'BB'],
|
|
345
|
+
['5', 'AA', 'BB', 'AA', '5', 'BB'],
|
|
346
|
+
['AA', 'BB', '5', 'AA', 'BB', 'AA'],
|
|
347
|
+
['AA', 'BB', 'AA', '5', 'BB', 'AA'],
|
|
348
|
+
['AA', 'BB', '5', 'BB', 'AA', 'BB'],
|
|
349
|
+
['BB', 'AA', '5', 'BB', 'AA', '5'],
|
|
350
|
+
['BB', '5', 'AA', 'BB', 'AA', '5'],
|
|
351
|
+
['AA', '5', 'BB', '5', 'AA', 'BB'],
|
|
352
|
+
['5', 'BB', 'AA', '5', 'BB', '5'],
|
|
353
|
+
['5', 'BB', 'AA', 'BB', '5', 'BB'],
|
|
354
|
+
['5', 'AA', 'BB', '5', 'AA', 'BB'],
|
|
355
|
+
['BB', '5', 'BB', 'AA', 'BB', '5'],
|
|
356
|
+
['BB', 'AA', '5', 'BB', '5', 'AA']]
|
|
357
|
+
|
|
358
|
+
.. TODO::
|
|
359
|
+
|
|
360
|
+
The result should be full featured finite enumerated set
|
|
361
|
+
(e.g., counting can be done much faster than iterating).
|
|
362
|
+
|
|
363
|
+
.. SEEALSO::
|
|
364
|
+
|
|
365
|
+
:meth:`.reduced_words`
|
|
366
|
+
"""
|
|
367
|
+
return list(self.braid_orbit_iter(word))
|
|
368
|
+
|
|
369
|
+
def __iter__(self):
|
|
370
|
+
r"""
|
|
371
|
+
Return an iterator over the elements of this Coxeter group.
|
|
372
|
+
|
|
373
|
+
EXAMPLES::
|
|
374
|
+
|
|
375
|
+
sage: D5 = FiniteCoxeterGroups().example(5)
|
|
376
|
+
sage: sorted(list(D5)) # indirect doctest (but see :meth:`._test_enumerated_set_iter_list`)
|
|
377
|
+
[(),
|
|
378
|
+
(1,),
|
|
379
|
+
(1, 2),
|
|
380
|
+
(1, 2, 1),
|
|
381
|
+
(1, 2, 1, 2),
|
|
382
|
+
(1, 2, 1, 2, 1),
|
|
383
|
+
(2,),
|
|
384
|
+
(2, 1),
|
|
385
|
+
(2, 1, 2),
|
|
386
|
+
(2, 1, 2, 1)]
|
|
387
|
+
|
|
388
|
+
sage: # needs sage.combinat sage.groups
|
|
389
|
+
sage: W = WeylGroup(["A", 2, 1])
|
|
390
|
+
sage: g = iter(W)
|
|
391
|
+
sage: next(g)
|
|
392
|
+
[1 0 0]
|
|
393
|
+
[0 1 0]
|
|
394
|
+
[0 0 1]
|
|
395
|
+
sage: next(g)
|
|
396
|
+
[-1 1 1]
|
|
397
|
+
[ 0 1 0]
|
|
398
|
+
[ 0 0 1]
|
|
399
|
+
sage: next(g)
|
|
400
|
+
[ 1 0 0]
|
|
401
|
+
[ 1 -1 1]
|
|
402
|
+
[ 0 0 1]
|
|
403
|
+
"""
|
|
404
|
+
return iter(self.weak_order_ideal(predicate=ConstantFunction(True)))
|
|
405
|
+
|
|
406
|
+
def _element_constructor_(self, x, **args):
|
|
407
|
+
"""
|
|
408
|
+
Construct an element of ``self`` from ``x``.
|
|
409
|
+
|
|
410
|
+
EXAMPLES::
|
|
411
|
+
|
|
412
|
+
sage: # needs sage.combinat sage.groups
|
|
413
|
+
sage: W1 = WeylGroup("G2", prefix='s')
|
|
414
|
+
sage: W2 = CoxeterGroup("G2")
|
|
415
|
+
sage: W3 = CoxeterGroup("G2", implementation='permutation')
|
|
416
|
+
sage: W1(W2.an_element())
|
|
417
|
+
s1*s2
|
|
418
|
+
sage: W2(W1.an_element())
|
|
419
|
+
[ 2 -a]
|
|
420
|
+
[ a -1]
|
|
421
|
+
sage: W1(W3.an_element())
|
|
422
|
+
s1*s2
|
|
423
|
+
sage: s1, s2 = W1.simple_reflections()
|
|
424
|
+
sage: W = CoxeterGroup("A1")
|
|
425
|
+
sage: W(s1 * s2)
|
|
426
|
+
Traceback (most recent call last):
|
|
427
|
+
...
|
|
428
|
+
ValueError: inconsistent number of rows: should be 1 but got 3
|
|
429
|
+
"""
|
|
430
|
+
P = parent(x)
|
|
431
|
+
if P in CoxeterGroups():
|
|
432
|
+
try:
|
|
433
|
+
return self.from_reduced_word(x.reduced_word())
|
|
434
|
+
except KeyError:
|
|
435
|
+
# Unable to convert using the reduced word
|
|
436
|
+
# because of an incompatible index
|
|
437
|
+
pass
|
|
438
|
+
return self.element_class(self, x, **args)
|
|
439
|
+
|
|
440
|
+
def weak_order_ideal(self, predicate, side='right', category=None):
|
|
441
|
+
"""
|
|
442
|
+
Return a weak order ideal defined by a predicate.
|
|
443
|
+
|
|
444
|
+
INPUT:
|
|
445
|
+
|
|
446
|
+
- ``predicate`` -- a predicate on the elements of ``self`` defining an
|
|
447
|
+
weak order ideal in ``self``
|
|
448
|
+
- ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``)
|
|
449
|
+
|
|
450
|
+
OUTPUT: an enumerated set
|
|
451
|
+
|
|
452
|
+
EXAMPLES::
|
|
453
|
+
|
|
454
|
+
sage: D6 = FiniteCoxeterGroups().example(5)
|
|
455
|
+
sage: I = D6.weak_order_ideal(predicate=lambda w: w.length() <= 3)
|
|
456
|
+
sage: I.cardinality()
|
|
457
|
+
7
|
|
458
|
+
sage: list(I)
|
|
459
|
+
[(), (1,), (2,), (1, 2), (2, 1), (1, 2, 1), (2, 1, 2)]
|
|
460
|
+
|
|
461
|
+
We now consider an infinite Coxeter group::
|
|
462
|
+
|
|
463
|
+
sage: W = WeylGroup(["A",1,1]) # needs sage.groups sage.rings.number_field
|
|
464
|
+
sage: I = W.weak_order_ideal(predicate=lambda w: w.length() <= 2) # needs sage.groups sage.rings.number_field
|
|
465
|
+
sage: list(iter(I)) # needs sage.groups sage.rings.number_field
|
|
466
|
+
[
|
|
467
|
+
[1 0] [-1 2] [ 1 0] [ 3 -2] [-1 2]
|
|
468
|
+
[0 1], [ 0 1], [ 2 -1], [ 2 -1], [-2 3]
|
|
469
|
+
]
|
|
470
|
+
|
|
471
|
+
Even when the result is finite, some features of
|
|
472
|
+
:class:`FiniteEnumeratedSets` are not available::
|
|
473
|
+
|
|
474
|
+
sage: I.cardinality() # todo: not implemented
|
|
475
|
+
5
|
|
476
|
+
sage: list(I) # todo: not implemented
|
|
477
|
+
|
|
478
|
+
unless this finiteness is explicitly specified::
|
|
479
|
+
|
|
480
|
+
sage: I = W.weak_order_ideal(predicate=lambda w: w.length() <= 2, # needs sage.groups sage.rings.number_field
|
|
481
|
+
....: category=FiniteEnumeratedSets())
|
|
482
|
+
sage: I.cardinality() # needs sage.groups sage.rings.number_field
|
|
483
|
+
5
|
|
484
|
+
sage: list(I) # needs sage.groups sage.rings.number_field
|
|
485
|
+
[
|
|
486
|
+
[1 0] [-1 2] [ 1 0] [ 3 -2] [-1 2]
|
|
487
|
+
[0 1], [ 0 1], [ 2 -1], [ 2 -1], [-2 3]
|
|
488
|
+
]
|
|
489
|
+
|
|
490
|
+
.. rubric:: Background
|
|
491
|
+
|
|
492
|
+
The weak order is returned as a :class:`RecursivelyEnumeratedSet_forest`.
|
|
493
|
+
This is achieved by assigning to each element `u1` of the
|
|
494
|
+
ideal a single ancestor `u=u1 s_i`, where `i` is the
|
|
495
|
+
smallest descent of `u`.
|
|
496
|
+
|
|
497
|
+
This allows for iterating through the elements in
|
|
498
|
+
roughly Constant Amortized Time and constant memory
|
|
499
|
+
(taking the operations and size of the generated objects
|
|
500
|
+
as constants).
|
|
501
|
+
|
|
502
|
+
TESTS:
|
|
503
|
+
|
|
504
|
+
We iterate over each level (i.e., breadth-first-search in the
|
|
505
|
+
search forest), see :issue:`19926`::
|
|
506
|
+
|
|
507
|
+
sage: W = CoxeterGroup(['A',2]) # needs sage.groups sage.rings.number_field
|
|
508
|
+
sage: [x.length() for x in W] # needs sage.groups sage.rings.number_field
|
|
509
|
+
[0, 1, 1, 2, 2, 3]
|
|
510
|
+
"""
|
|
511
|
+
from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
512
|
+
|
|
513
|
+
def succ(u):
|
|
514
|
+
for i in u.descents(positive=True, side=side):
|
|
515
|
+
u1 = u.apply_simple_reflection(i, side)
|
|
516
|
+
if i == u1.first_descent(side=side) and predicate(u1):
|
|
517
|
+
yield u1
|
|
518
|
+
|
|
519
|
+
from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups
|
|
520
|
+
default_category = FiniteEnumeratedSets() if self in FiniteCoxeterGroups() else EnumeratedSets()
|
|
521
|
+
cat = default_category.or_subcategory(category)
|
|
522
|
+
return RecursivelyEnumeratedSet_forest((self.one(),), succ,
|
|
523
|
+
algorithm='breadth',
|
|
524
|
+
category=cat)
|
|
525
|
+
|
|
526
|
+
@cached_method
|
|
527
|
+
def coxeter_element(self):
|
|
528
|
+
"""
|
|
529
|
+
Return a Coxeter element.
|
|
530
|
+
|
|
531
|
+
The result is the product of the simple reflections, in some order.
|
|
532
|
+
|
|
533
|
+
.. NOTE::
|
|
534
|
+
|
|
535
|
+
This implementation is shared with well generated
|
|
536
|
+
complex reflection groups. It would be nicer to put it
|
|
537
|
+
in some joint super category; however, in the current
|
|
538
|
+
state of the art, there is none where it is clear that
|
|
539
|
+
this is the right construction for obtaining a Coxeter
|
|
540
|
+
element.
|
|
541
|
+
|
|
542
|
+
In this context, this is an element having a regular
|
|
543
|
+
eigenvector (a vector not contained in any reflection
|
|
544
|
+
hyperplane of ``self``).
|
|
545
|
+
|
|
546
|
+
EXAMPLES::
|
|
547
|
+
|
|
548
|
+
sage: # needs sage.combinat sage.groups
|
|
549
|
+
sage: CoxeterGroup(['A', 4]).coxeter_element().reduced_word()
|
|
550
|
+
[1, 2, 3, 4]
|
|
551
|
+
sage: CoxeterGroup(['B', 4]).coxeter_element().reduced_word()
|
|
552
|
+
[1, 2, 3, 4]
|
|
553
|
+
sage: CoxeterGroup(['D', 4]).coxeter_element().reduced_word()
|
|
554
|
+
[1, 2, 4, 3]
|
|
555
|
+
sage: CoxeterGroup(['F', 4]).coxeter_element().reduced_word()
|
|
556
|
+
[1, 2, 3, 4]
|
|
557
|
+
sage: CoxeterGroup(['E', 8]).coxeter_element().reduced_word()
|
|
558
|
+
[1, 3, 2, 4, 5, 6, 7, 8]
|
|
559
|
+
sage: CoxeterGroup(['H', 3]).coxeter_element().reduced_word()
|
|
560
|
+
[1, 2, 3]
|
|
561
|
+
|
|
562
|
+
This method is also used for well generated finite complex
|
|
563
|
+
reflection groups::
|
|
564
|
+
|
|
565
|
+
sage: W = ReflectionGroup((1,1,4)) # optional - gap3
|
|
566
|
+
sage: W.coxeter_element().reduced_word() # optional - gap3
|
|
567
|
+
[1, 2, 3]
|
|
568
|
+
|
|
569
|
+
sage: W = ReflectionGroup((2,1,4)) # optional - gap3
|
|
570
|
+
sage: W.coxeter_element().reduced_word() # optional - gap3
|
|
571
|
+
[1, 2, 3, 4]
|
|
572
|
+
|
|
573
|
+
sage: W = ReflectionGroup((4,1,4)) # optional - gap3
|
|
574
|
+
sage: W.coxeter_element().reduced_word() # optional - gap3
|
|
575
|
+
[1, 2, 3, 4]
|
|
576
|
+
|
|
577
|
+
sage: W = ReflectionGroup((4,4,4)) # optional - gap3
|
|
578
|
+
sage: W.coxeter_element().reduced_word() # optional - gap3
|
|
579
|
+
[1, 2, 3, 4]
|
|
580
|
+
|
|
581
|
+
TESTS::
|
|
582
|
+
|
|
583
|
+
sage: WeylGroup(['A', 4]).coxeter_element().reduced_word() # needs sage.combinat sage.groups
|
|
584
|
+
[1, 2, 3, 4]
|
|
585
|
+
sage: SymmetricGroup(3).coxeter_element() # needs sage.groups
|
|
586
|
+
(1,3,2)
|
|
587
|
+
"""
|
|
588
|
+
return self.prod(self.simple_reflections())
|
|
589
|
+
|
|
590
|
+
@cached_method
|
|
591
|
+
def standard_coxeter_elements(self):
|
|
592
|
+
r"""
|
|
593
|
+
Return all standard Coxeter elements in ``self``.
|
|
594
|
+
|
|
595
|
+
This is the set of all elements in ``self`` obtained from any
|
|
596
|
+
product of the simple reflections in ``self``.
|
|
597
|
+
|
|
598
|
+
.. NOTE::
|
|
599
|
+
|
|
600
|
+
- ``self`` is assumed to be well-generated.
|
|
601
|
+
- This works even beyond real reflection groups, but the conjugacy
|
|
602
|
+
class is not unique and we only obtain one such class.
|
|
603
|
+
|
|
604
|
+
EXAMPLES::
|
|
605
|
+
|
|
606
|
+
sage: W = ReflectionGroup(4) # optional - gap3
|
|
607
|
+
sage: sorted(W.standard_coxeter_elements()) # optional - gap3
|
|
608
|
+
[(1,7,6,12,23,20)(2,8,17,24,9,5)(3,16,10,19,15,21)(4,14,11,22,18,13),
|
|
609
|
+
(1,10,4,12,21,22)(2,11,19,24,13,3)(5,15,7,17,16,23)(6,18,8,20,14,9)]
|
|
610
|
+
|
|
611
|
+
TESTS::
|
|
612
|
+
|
|
613
|
+
sage: W = SymmetricGroup(3) # needs sage.groups
|
|
614
|
+
sage: sorted(W.standard_coxeter_elements()) # needs sage.combinat sage.groups
|
|
615
|
+
[(1,2,3), (1,3,2)]
|
|
616
|
+
|
|
617
|
+
sage: W = Permutations(3)
|
|
618
|
+
sage: sorted(W.standard_coxeter_elements()) # needs sage.graphs
|
|
619
|
+
[[2, 3, 1], [3, 1, 2]]
|
|
620
|
+
|
|
621
|
+
sage: W = CoxeterGroup(['D', 3]) # needs sage.combinat sage.groups
|
|
622
|
+
sage: sorted(W.standard_coxeter_elements()) # needs sage.combinat sage.groups
|
|
623
|
+
[
|
|
624
|
+
[-1 1 1] [ 0 -1 1] [ 0 1 -1] [ 1 -1 -1]
|
|
625
|
+
[-1 0 1] [ 1 -1 0] [ 0 0 -1] [ 1 -1 0]
|
|
626
|
+
[-1 1 0], [ 0 -1 0], [ 1 0 -1], [ 1 0 -1]
|
|
627
|
+
]
|
|
628
|
+
|
|
629
|
+
sage: W = ColoredPermutations(3,2) # needs sage.combinat
|
|
630
|
+
sage: len(W.standard_coxeter_elements()) # needs sage.combinat sage.graphs
|
|
631
|
+
2
|
|
632
|
+
"""
|
|
633
|
+
if not self.is_irreducible() or not self.is_well_generated():
|
|
634
|
+
raise ValueError("this method is available for irreducible, well-generated complex reflection groups")
|
|
635
|
+
from sage.combinat.permutation import Permutations
|
|
636
|
+
return {self.from_reduced_word(w)
|
|
637
|
+
for w in Permutations(self.index_set())}
|
|
638
|
+
|
|
639
|
+
def grassmannian_elements(self, side='right'):
|
|
640
|
+
"""
|
|
641
|
+
Return the left or right Grassmannian elements of ``self``
|
|
642
|
+
as an enumerated set.
|
|
643
|
+
|
|
644
|
+
INPUT:
|
|
645
|
+
|
|
646
|
+
- ``side`` -- (default: ``'right'``) ``'left'`` or ``'right'``
|
|
647
|
+
|
|
648
|
+
EXAMPLES::
|
|
649
|
+
|
|
650
|
+
sage: S = CoxeterGroups().example()
|
|
651
|
+
sage: G = S.grassmannian_elements()
|
|
652
|
+
sage: G.cardinality()
|
|
653
|
+
12
|
|
654
|
+
sage: G.list()
|
|
655
|
+
[(0, 1, 2, 3), (1, 0, 2, 3), (0, 2, 1, 3), (0, 1, 3, 2),
|
|
656
|
+
(2, 0, 1, 3), (1, 2, 0, 3), (0, 3, 1, 2), (0, 2, 3, 1),
|
|
657
|
+
(3, 0, 1, 2), (1, 3, 0, 2), (1, 2, 3, 0), (2, 3, 0, 1)]
|
|
658
|
+
sage: sorted(tuple(w.descents()) for w in G)
|
|
659
|
+
[(), (0,), (0,), (0,), (1,), (1,), (1,), (1,), (1,), (2,), (2,), (2,)]
|
|
660
|
+
sage: G = S.grassmannian_elements(side = "left")
|
|
661
|
+
sage: G.cardinality()
|
|
662
|
+
12
|
|
663
|
+
sage: sorted(tuple(w.descents(side = "left")) for w in G)
|
|
664
|
+
[(), (0,), (0,), (0,), (1,), (1,), (1,), (1,), (1,), (2,), (2,), (2,)]
|
|
665
|
+
"""
|
|
666
|
+
order_side = "left" if side == "right" else "right"
|
|
667
|
+
return self.weak_order_ideal(attrcall("is_grassmannian", side=side),
|
|
668
|
+
side=order_side)
|
|
669
|
+
|
|
670
|
+
def fully_commutative_elements(self):
|
|
671
|
+
r"""
|
|
672
|
+
Return the set of fully commutative elements in this Coxeter group.
|
|
673
|
+
|
|
674
|
+
.. SEEALSO::
|
|
675
|
+
|
|
676
|
+
:class:`~sage.combinat.fully_commutative_elements.FullyCommutativeElements`
|
|
677
|
+
|
|
678
|
+
EXAMPLES::
|
|
679
|
+
|
|
680
|
+
sage: CoxeterGroup(['A', 3]).fully_commutative_elements() # needs sage.combinat sage.groups
|
|
681
|
+
Fully commutative elements of
|
|
682
|
+
Finite Coxeter group over Integer Ring with Coxeter matrix:
|
|
683
|
+
[1 3 2]
|
|
684
|
+
[3 1 3]
|
|
685
|
+
[2 3 1]
|
|
686
|
+
"""
|
|
687
|
+
from sage.combinat.fully_commutative_elements import FullyCommutativeElements
|
|
688
|
+
return FullyCommutativeElements(self)
|
|
689
|
+
|
|
690
|
+
def _test_reduced_word(self, **options):
|
|
691
|
+
"""
|
|
692
|
+
Run sanity checks on :meth:`CoxeterGroups.ElementMethods.reduced_word` and
|
|
693
|
+
:meth:`~sage.categories.complex_reflection_or_generalized_coxeter_groups.ComplexReflectionOrGeneralizedCoxeterGroups.ParentMethods.from_reduced_word`
|
|
694
|
+
|
|
695
|
+
EXAMPLES::
|
|
696
|
+
|
|
697
|
+
sage: W = CoxeterGroups().example()
|
|
698
|
+
sage: W._test_reduced_word()
|
|
699
|
+
"""
|
|
700
|
+
tester = self._tester(**options)
|
|
701
|
+
s = self.simple_reflections()
|
|
702
|
+
for x in tester.some_elements():
|
|
703
|
+
red = x.reduced_word()
|
|
704
|
+
tester.assertEqual(self.from_reduced_word(red), x)
|
|
705
|
+
tester.assertEqual(self.prod(s[i] for i in red), x)
|
|
706
|
+
|
|
707
|
+
def simple_projection(self, i, side='right', length_increasing=True):
|
|
708
|
+
r"""
|
|
709
|
+
Return the simple projection `\pi_i` (or `\overline\pi_i` if ``length_increasing`` is ``False``).
|
|
710
|
+
|
|
711
|
+
INPUT:
|
|
712
|
+
|
|
713
|
+
- ``i`` -- an element of the index set of ``self``
|
|
714
|
+
|
|
715
|
+
See :meth:`.simple_projections` for the options and for
|
|
716
|
+
the definition of the simple projections.
|
|
717
|
+
|
|
718
|
+
EXAMPLES::
|
|
719
|
+
|
|
720
|
+
sage: W = CoxeterGroups().example()
|
|
721
|
+
sage: W
|
|
722
|
+
The symmetric group on {0, ..., 3}
|
|
723
|
+
sage: s = W.simple_reflections()
|
|
724
|
+
sage: sigma = W.an_element()
|
|
725
|
+
sage: sigma
|
|
726
|
+
(1, 2, 3, 0)
|
|
727
|
+
sage: u0 = W.simple_projection(0)
|
|
728
|
+
sage: d0 = W.simple_projection(0, length_increasing=False)
|
|
729
|
+
sage: sigma.length()
|
|
730
|
+
3
|
|
731
|
+
sage: pi=sigma*s[0]
|
|
732
|
+
sage: pi.length()
|
|
733
|
+
4
|
|
734
|
+
sage: u0(sigma)
|
|
735
|
+
(2, 1, 3, 0)
|
|
736
|
+
sage: pi
|
|
737
|
+
(2, 1, 3, 0)
|
|
738
|
+
sage: u0(pi)
|
|
739
|
+
(2, 1, 3, 0)
|
|
740
|
+
sage: d0(sigma)
|
|
741
|
+
(1, 2, 3, 0)
|
|
742
|
+
sage: d0(pi)
|
|
743
|
+
(1, 2, 3, 0)
|
|
744
|
+
"""
|
|
745
|
+
if not (i in self.index_set() or i == 0):
|
|
746
|
+
raise ValueError("%s is not 0 and not in the Dynkin node set %s" % (i, self.index_set()))
|
|
747
|
+
return lambda x: x.apply_simple_projection(i, side=side,
|
|
748
|
+
length_increasing=length_increasing)
|
|
749
|
+
|
|
750
|
+
def kazhdan_lusztig_cells(self, side='left'):
|
|
751
|
+
r"""
|
|
752
|
+
Compute the left, right, or two-sided Kazhdan-Lusztig cells of
|
|
753
|
+
``self`` if ``self`` is finite.
|
|
754
|
+
|
|
755
|
+
The cells are computed by using :func:`kazhdan_lusztig_cell()
|
|
756
|
+
<CoxeterGroups.ElementMethods.kazhdan_lusztig_cell()>`.
|
|
757
|
+
|
|
758
|
+
As detailed there, installation of the optional package ``coxeter3``
|
|
759
|
+
is recommended (though not required) before using this function
|
|
760
|
+
as it speeds up the computation.
|
|
761
|
+
|
|
762
|
+
INPUT:
|
|
763
|
+
|
|
764
|
+
- ``side`` -- (default: ``'left'``) either ``'left'``,
|
|
765
|
+
``'right'``, or ``'two-sided'``
|
|
766
|
+
|
|
767
|
+
EXAMPLES:
|
|
768
|
+
|
|
769
|
+
We compute the right cells in the Coxeter group of type `A_2`
|
|
770
|
+
below. Note that each Coxeter group may be created with multiple
|
|
771
|
+
implementations, namely, 'reflection' (default), 'permutation',
|
|
772
|
+
'matrix', or 'coxeter3'. The choice of implementation affects the
|
|
773
|
+
representation of elements in the output cells but not the method
|
|
774
|
+
used for the cell computation::
|
|
775
|
+
|
|
776
|
+
sage: # needs sage.combinat sage.groups
|
|
777
|
+
sage: W = CoxeterGroup('A2')
|
|
778
|
+
sage: KL_cells = W.kazhdan_lusztig_cells(side='right')
|
|
779
|
+
sage: set([tuple(sorted(C, key=lambda w: w.reduced_word()))
|
|
780
|
+
....: for C in KL_cells])
|
|
781
|
+
{(
|
|
782
|
+
[-1 1] [ 0 -1]
|
|
783
|
+
[ 0 1], [ 1 -1]
|
|
784
|
+
),
|
|
785
|
+
(
|
|
786
|
+
[ 0 -1]
|
|
787
|
+
[-1 0]
|
|
788
|
+
),
|
|
789
|
+
(
|
|
790
|
+
[1 0]
|
|
791
|
+
[0 1]
|
|
792
|
+
),
|
|
793
|
+
(
|
|
794
|
+
[ 1 0] [-1 1]
|
|
795
|
+
[ 1 -1], [-1 0]
|
|
796
|
+
)}
|
|
797
|
+
sage: len(KL_cells)
|
|
798
|
+
4
|
|
799
|
+
|
|
800
|
+
sage: W = CoxeterGroup('A2', implementation='permutation') # needs sage.combinat sage.groups
|
|
801
|
+
sage: len(W.kazhdan_lusztig_cells(side='right')) # needs sage.combinat sage.groups
|
|
802
|
+
4
|
|
803
|
+
|
|
804
|
+
We compute the left cells in the Coxeter group of type `A_3`
|
|
805
|
+
below. If the optional package ``coxeter3`` is installed, it
|
|
806
|
+
runs in the background even if the group is not created with
|
|
807
|
+
the ``'coxeter3'`` implementation::
|
|
808
|
+
|
|
809
|
+
sage: # optional - coxeter3, needs sage.combinat sage.groups sage.libs.gap sage.modules sage.rings.number_field
|
|
810
|
+
sage: W = CoxeterGroup('A3', implementation='coxeter3')
|
|
811
|
+
sage: KL_cells = W.kazhdan_lusztig_cells()
|
|
812
|
+
sage: set([tuple(sorted(C)) for C in KL_cells])
|
|
813
|
+
{([],),
|
|
814
|
+
([1], [2, 1], [3, 2, 1]),
|
|
815
|
+
([1, 2], [2], [3, 2]),
|
|
816
|
+
([1, 2, 1], [1, 3, 2, 1], [2, 1, 3, 2, 1]),
|
|
817
|
+
([1, 2, 1, 3], [1, 2, 3, 2, 1], [2, 3, 2, 1]),
|
|
818
|
+
([1, 2, 1, 3, 2], [1, 2, 3, 2], [2, 3, 2]),
|
|
819
|
+
([1, 2, 1, 3, 2, 1],),
|
|
820
|
+
([1, 2, 3], [2, 3], [3]),
|
|
821
|
+
([1, 3], [2, 1, 3]),
|
|
822
|
+
([1, 3, 2], [2, 1, 3, 2])}
|
|
823
|
+
sage: len(KL_cells)
|
|
824
|
+
10
|
|
825
|
+
sage: W = CoxeterGroup('A3', implementation='permutation')
|
|
826
|
+
sage: len(W.kazhdan_lusztig_cells())
|
|
827
|
+
10
|
|
828
|
+
|
|
829
|
+
Computing the two-sided cells in `B_3`::
|
|
830
|
+
|
|
831
|
+
sage: # optional - coxeter3, needs sage.combinat sage.groups sage.libs.gap sage.modules sage.rings.number_field
|
|
832
|
+
sage: W = CoxeterGroup('B3', implementation='coxeter3')
|
|
833
|
+
sage: b3_cells = W.kazhdan_lusztig_cells('two-sided')
|
|
834
|
+
sage: len(b3_cells)
|
|
835
|
+
6
|
|
836
|
+
sage: set([tuple(sorted(C))
|
|
837
|
+
....: for C in W.kazhdan_lusztig_cells()])
|
|
838
|
+
{([],),
|
|
839
|
+
([1], [1, 2, 3, 2, 1], [2, 1], [2, 3, 2, 1], [3, 2, 1]),
|
|
840
|
+
([1, 2], [1, 2, 3, 2], [2], [2, 3, 2], [3, 2]),
|
|
841
|
+
([1, 2, 3], [2, 3], [3], [3, 2, 3]),
|
|
842
|
+
([2, 1, 2], [2, 3, 2, 1, 2], [3, 2, 1, 2]),
|
|
843
|
+
([2, 1, 2, 3], [2, 3, 2, 1, 2, 3], [3, 2, 1, 2, 3]),
|
|
844
|
+
([2, 1, 2, 3, 2], [2, 3, 2, 1, 2, 3, 2], [3, 2, 1, 2, 3, 2]),
|
|
845
|
+
([2, 1, 2, 3, 2, 1],
|
|
846
|
+
[2, 3, 2, 1, 2, 3, 2, 1],
|
|
847
|
+
[3, 2, 1, 2, 3, 2, 1],
|
|
848
|
+
[3, 2, 3, 2, 1, 2]),
|
|
849
|
+
([2, 3, 1], [3, 1], [3, 2, 3, 1]),
|
|
850
|
+
([2, 3, 1, 2], [3, 1, 2], [3, 2, 3, 1, 2]),
|
|
851
|
+
([2, 3, 1, 2, 3], [3, 1, 2, 3], [3, 2, 3, 1, 2, 3]),
|
|
852
|
+
([2, 3, 1, 2, 3, 2],
|
|
853
|
+
[3, 1, 2, 3, 2],
|
|
854
|
+
[3, 2, 3, 1, 2, 3, 2],
|
|
855
|
+
[3, 2, 3, 2],
|
|
856
|
+
[3, 2, 3, 2, 1, 2, 3, 2]),
|
|
857
|
+
([2, 3, 1, 2, 3, 2, 1],
|
|
858
|
+
[3, 1, 2, 3, 2, 1],
|
|
859
|
+
[3, 2, 3, 1, 2, 3, 2, 1],
|
|
860
|
+
[3, 2, 3, 2, 1],
|
|
861
|
+
[3, 2, 3, 2, 1, 2, 3]),
|
|
862
|
+
([3, 2, 3, 2, 1, 2, 3, 2, 1],)}
|
|
863
|
+
|
|
864
|
+
TESTS::
|
|
865
|
+
|
|
866
|
+
sage: W = CoxeterGroup(['A', 2, 1]) # needs sage.combinat sage.groups
|
|
867
|
+
sage: W.kazhdan_lusztig_cells() # needs sage.combinat sage.groups
|
|
868
|
+
Traceback (most recent call last):
|
|
869
|
+
...
|
|
870
|
+
ValueError: the Coxeter group must be finite to compute Kazhdan--Lusztig cells
|
|
871
|
+
"""
|
|
872
|
+
if not self.coxeter_type().is_finite():
|
|
873
|
+
raise ValueError('the Coxeter group must be finite to compute Kazhdan--Lusztig cells')
|
|
874
|
+
|
|
875
|
+
# The identity is its own left-, right-, and two-sided- cell.
|
|
876
|
+
identity = frozenset([self.one()])
|
|
877
|
+
cells = {identity}
|
|
878
|
+
|
|
879
|
+
for w in self:
|
|
880
|
+
if not any(w in c for c in cells):
|
|
881
|
+
cell = w.kazhdan_lusztig_cell(side=side)
|
|
882
|
+
cells.add(frozenset(cell))
|
|
883
|
+
|
|
884
|
+
return cells
|
|
885
|
+
|
|
886
|
+
@cached_method
|
|
887
|
+
def simple_projections(self, side='right', length_increasing=True):
|
|
888
|
+
r"""
|
|
889
|
+
Return the family of simple projections, also known as 0-Hecke or Demazure operators.
|
|
890
|
+
|
|
891
|
+
INPUT:
|
|
892
|
+
|
|
893
|
+
- ``self`` -- a Coxeter group `W`
|
|
894
|
+
- ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``)
|
|
895
|
+
- ``length_increasing`` -- boolean (default: ``True``); whether
|
|
896
|
+
the operator increases or decreases length
|
|
897
|
+
|
|
898
|
+
This returns the simple projections of `W`, as a family.
|
|
899
|
+
|
|
900
|
+
To each simple reflection `s_i` of `W`, corresponds a
|
|
901
|
+
*simple projection* `\pi_i` from `W` to `W` defined by:
|
|
902
|
+
|
|
903
|
+
`\pi_i(w) = w s_i` if `i` is not a descent of `w`
|
|
904
|
+
`\pi_i(w) = w` otherwise.
|
|
905
|
+
|
|
906
|
+
The simple projections `(\pi_i)_{i\in I}` move elements
|
|
907
|
+
down the right permutohedron, toward the maximal element.
|
|
908
|
+
They satisfy the same braid relations as the simple reflections,
|
|
909
|
+
but are idempotents `\pi_i^2=\pi` not involutions `s_i^2 = 1`. As such,
|
|
910
|
+
the simple projections generate the `0`-Hecke monoid.
|
|
911
|
+
|
|
912
|
+
By symmetry, one can also define the projections
|
|
913
|
+
`(\overline\pi_i)_{i\in I}` (when the option ``length_increasing`` is False):
|
|
914
|
+
|
|
915
|
+
`\overline\pi_i(w) = w s_i` if `i` is a descent of `w`
|
|
916
|
+
`\overline\pi_i(w) = w` otherwise.
|
|
917
|
+
|
|
918
|
+
as well as the analogues acting on the left (when the option ``side`` is 'left').
|
|
919
|
+
|
|
920
|
+
EXAMPLES::
|
|
921
|
+
|
|
922
|
+
sage: W = CoxeterGroups().example(); W
|
|
923
|
+
The symmetric group on {0, ..., 3}
|
|
924
|
+
sage: s = W.simple_reflections()
|
|
925
|
+
sage: sigma = W.an_element(); sigma
|
|
926
|
+
(1, 2, 3, 0)
|
|
927
|
+
sage: pi = W.simple_projections(); pi
|
|
928
|
+
Finite family {0: <function ...<lambda> at ...>,
|
|
929
|
+
1: <function ...<lambda> at ...>,
|
|
930
|
+
2: <function ...<lambda> ...>}
|
|
931
|
+
sage: pi[1](sigma)
|
|
932
|
+
(1, 3, 2, 0)
|
|
933
|
+
sage: W.simple_projection(1)(sigma)
|
|
934
|
+
(1, 3, 2, 0)
|
|
935
|
+
"""
|
|
936
|
+
from sage.sets.family import Family
|
|
937
|
+
return Family(self.index_set(), lambda i: self.simple_projection(i, side=side, length_increasing=length_increasing))
|
|
938
|
+
|
|
939
|
+
def sign_representation(self, base_ring=None):
|
|
940
|
+
r"""
|
|
941
|
+
Return the sign representation of ``self`` over ``base_ring``.
|
|
942
|
+
|
|
943
|
+
INPUT:
|
|
944
|
+
|
|
945
|
+
- ``base_ring`` -- (optional) the base ring; the default is `\ZZ`
|
|
946
|
+
|
|
947
|
+
EXAMPLES::
|
|
948
|
+
|
|
949
|
+
sage: W = WeylGroup(['D', 4]) # needs sage.combinat sage.groups
|
|
950
|
+
sage: W.sign_representation(QQ) # needs sage.combinat sage.groups
|
|
951
|
+
Sign representation of
|
|
952
|
+
Weyl Group of type ['D', 4] (as a matrix group acting on the ambient space)
|
|
953
|
+
over Rational Field
|
|
954
|
+
|
|
955
|
+
sage: # optional - gap3
|
|
956
|
+
sage: W = CoxeterGroup(['B',3], implementation="coxeter3")
|
|
957
|
+
sage: W.sign_representation()
|
|
958
|
+
Sign representation of Coxeter group of type ['B', 3]
|
|
959
|
+
implemented by Coxeter3 over Integer Ring
|
|
960
|
+
"""
|
|
961
|
+
if base_ring is None:
|
|
962
|
+
from sage.rings.integer_ring import ZZ
|
|
963
|
+
base_ring = ZZ
|
|
964
|
+
from sage.modules.with_basis.representation import SignRepresentationCoxeterGroup
|
|
965
|
+
return SignRepresentationCoxeterGroup(self, base_ring)
|
|
966
|
+
|
|
967
|
+
def reflection_representation(self, base_ring=None, side='left'):
|
|
968
|
+
r"""
|
|
969
|
+
Return the reflection representation of ``self``.
|
|
970
|
+
|
|
971
|
+
This is also the canonical faithful representation of a
|
|
972
|
+
Coxeter group.
|
|
973
|
+
|
|
974
|
+
INPUT:
|
|
975
|
+
|
|
976
|
+
- ``base_ring`` -- (optional) the base ring; the default is
|
|
977
|
+
the base ring of :meth:`canonical_representation`
|
|
978
|
+
- ``side`` -- ignored
|
|
979
|
+
|
|
980
|
+
EXAMPLES::
|
|
981
|
+
|
|
982
|
+
sage: W = CoxeterGroup(['D', 4]) # needs sage.graphs sage.groups
|
|
983
|
+
sage: W.reflection_representation() # needs sage.graphs sage.groups
|
|
984
|
+
Reflection representation of Finite Coxeter group over
|
|
985
|
+
Integer Ring with Coxeter matrix:
|
|
986
|
+
[1 3 2 2]
|
|
987
|
+
[3 1 3 3]
|
|
988
|
+
[2 3 1 2]
|
|
989
|
+
[2 3 2 1]
|
|
990
|
+
|
|
991
|
+
sage: W = CoxeterGroup(['I', 13]) # needs sage.graphs sage.modules sage.rings.number_field
|
|
992
|
+
sage: W.reflection_representation() # needs sage.graphs sage.modules sage.rings.number_field
|
|
993
|
+
Reflection representation of Finite Coxeter group over
|
|
994
|
+
Universal Cyclotomic Field with Coxeter matrix:
|
|
995
|
+
[ 1 13]
|
|
996
|
+
[13 1]
|
|
997
|
+
|
|
998
|
+
sage: W = WeylGroup(["B", 3, 1]) # needs sage.graphs sage.groups
|
|
999
|
+
sage: W.reflection_representation(QQ) # needs sage.graphs sage.groups
|
|
1000
|
+
Reflection representation of Weyl Group of type ['B', 3, 1]
|
|
1001
|
+
(as a matrix group acting on the root space)
|
|
1002
|
+
"""
|
|
1003
|
+
from sage.modules.with_basis.representation import ReflectionRepresentation
|
|
1004
|
+
return ReflectionRepresentation(self, base_ring)
|
|
1005
|
+
|
|
1006
|
+
def demazure_product(self, Q):
|
|
1007
|
+
r"""
|
|
1008
|
+
Return the Demazure product of the list ``Q`` in ``self``.
|
|
1009
|
+
|
|
1010
|
+
INPUT:
|
|
1011
|
+
|
|
1012
|
+
- ``Q`` -- list of elements from the index set of ``self``
|
|
1013
|
+
|
|
1014
|
+
This returns the Coxeter group element that represents the
|
|
1015
|
+
composition of 0-Hecke or Demazure operators.
|
|
1016
|
+
|
|
1017
|
+
See :meth:`CoxeterGroups.ParentMethods.simple_projections`.
|
|
1018
|
+
|
|
1019
|
+
EXAMPLES::
|
|
1020
|
+
|
|
1021
|
+
sage: # needs sage.combinat sage.groups
|
|
1022
|
+
sage: W = WeylGroup(['A', 2])
|
|
1023
|
+
sage: w = W.demazure_product([2,2,1])
|
|
1024
|
+
sage: w.reduced_word()
|
|
1025
|
+
[2, 1]
|
|
1026
|
+
sage: w = W.demazure_product([2,1,2,1,2])
|
|
1027
|
+
sage: w.reduced_word()
|
|
1028
|
+
[1, 2, 1]
|
|
1029
|
+
|
|
1030
|
+
sage: W = WeylGroup(['B', 2]) # needs sage.combinat sage.groups
|
|
1031
|
+
sage: w = W.demazure_product([2,1,2,1,2]) # needs sage.combinat sage.groups
|
|
1032
|
+
sage: w.reduced_word() # needs sage.combinat sage.groups
|
|
1033
|
+
[2, 1, 2, 1]
|
|
1034
|
+
"""
|
|
1035
|
+
return self.one().apply_demazure_product(Q)
|
|
1036
|
+
|
|
1037
|
+
def bruhat_interval(self, x, y):
|
|
1038
|
+
"""
|
|
1039
|
+
Return the list of ``t`` such that ``x <= t <= y``.
|
|
1040
|
+
|
|
1041
|
+
EXAMPLES::
|
|
1042
|
+
|
|
1043
|
+
sage: W = WeylGroup("A3", prefix='s') # needs sage.combinat sage.groups
|
|
1044
|
+
sage: s1, s2, s3 = W.simple_reflections() # needs sage.combinat sage.groups
|
|
1045
|
+
sage: W.bruhat_interval(s2, s1*s3*s2*s1*s3) # needs sage.combinat sage.groups
|
|
1046
|
+
[s1*s2*s3*s2*s1, s2*s3*s2*s1, s3*s1*s2*s1, s1*s2*s3*s1,
|
|
1047
|
+
s1*s2*s3*s2, s3*s2*s1, s2*s3*s1, s2*s3*s2, s1*s2*s1,
|
|
1048
|
+
s3*s1*s2, s1*s2*s3, s2*s1, s3*s2, s2*s3, s1*s2, s2]
|
|
1049
|
+
|
|
1050
|
+
sage: W = WeylGroup(['A', 2, 1], prefix='s') # needs sage.combinat sage.groups
|
|
1051
|
+
sage: s0, s1, s2 = W.simple_reflections() # needs sage.combinat sage.groups
|
|
1052
|
+
sage: W.bruhat_interval(1, s0*s1*s2) # needs sage.combinat sage.groups
|
|
1053
|
+
[s0*s1*s2, s1*s2, s0*s2, s0*s1, s2, s1, s0, 1]
|
|
1054
|
+
"""
|
|
1055
|
+
if x == 1:
|
|
1056
|
+
x = self.one()
|
|
1057
|
+
if y == 1:
|
|
1058
|
+
y = self.one()
|
|
1059
|
+
if x == y:
|
|
1060
|
+
return [x]
|
|
1061
|
+
ret = []
|
|
1062
|
+
if not x.bruhat_le(y):
|
|
1063
|
+
return ret
|
|
1064
|
+
ret.append([y])
|
|
1065
|
+
while ret[-1]:
|
|
1066
|
+
nextlayer = []
|
|
1067
|
+
for z in ret[-1]:
|
|
1068
|
+
for t in z.bruhat_lower_covers():
|
|
1069
|
+
if t not in nextlayer:
|
|
1070
|
+
if x.bruhat_le(t):
|
|
1071
|
+
nextlayer.append(t)
|
|
1072
|
+
ret.append(nextlayer)
|
|
1073
|
+
return flatten(ret)
|
|
1074
|
+
|
|
1075
|
+
def bruhat_interval_poset(self, x, y, facade=False):
|
|
1076
|
+
r"""
|
|
1077
|
+
Return the poset of the Bruhat interval between ``x`` and ``y``
|
|
1078
|
+
in Bruhat order.
|
|
1079
|
+
|
|
1080
|
+
EXAMPLES::
|
|
1081
|
+
|
|
1082
|
+
sage: W = WeylGroup("A3", prefix='s') # needs sage.combinat sage.groups
|
|
1083
|
+
sage: s1, s2, s3 = W.simple_reflections() # needs sage.combinat sage.groups
|
|
1084
|
+
sage: W.bruhat_interval_poset(s2, s1*s3*s2*s1*s3) # needs sage.combinat sage.groups
|
|
1085
|
+
Finite poset containing 16 elements
|
|
1086
|
+
|
|
1087
|
+
sage: W = WeylGroup(['A', 2, 1], prefix='s') # needs sage.combinat sage.groups
|
|
1088
|
+
sage: s0, s1, s2 = W.simple_reflections() # needs sage.combinat sage.groups
|
|
1089
|
+
sage: W.bruhat_interval_poset(1, s0*s1*s2) # needs sage.combinat sage.groups
|
|
1090
|
+
Finite poset containing 8 elements
|
|
1091
|
+
|
|
1092
|
+
TESTS::
|
|
1093
|
+
|
|
1094
|
+
sage: W.bruhat_interval_poset(s0*s1*s2, s0*s1*s2) # needs sage.combinat sage.groups
|
|
1095
|
+
Finite poset containing 1 elements
|
|
1096
|
+
"""
|
|
1097
|
+
if x == 1:
|
|
1098
|
+
x = self.one()
|
|
1099
|
+
if y == 1:
|
|
1100
|
+
y = self.one()
|
|
1101
|
+
from sage.combinat.posets.posets import Poset
|
|
1102
|
+
if x == y:
|
|
1103
|
+
return Poset([[x], []])
|
|
1104
|
+
if not x.bruhat_le(y):
|
|
1105
|
+
return Poset()
|
|
1106
|
+
curlayer = {y}
|
|
1107
|
+
d = {}
|
|
1108
|
+
while curlayer:
|
|
1109
|
+
nextlayer = set()
|
|
1110
|
+
for z in curlayer:
|
|
1111
|
+
for t in z.bruhat_lower_covers():
|
|
1112
|
+
if not x.bruhat_le(t):
|
|
1113
|
+
continue
|
|
1114
|
+
if t in d:
|
|
1115
|
+
d[t].append(z)
|
|
1116
|
+
else:
|
|
1117
|
+
d[t] = [z]
|
|
1118
|
+
if t not in nextlayer:
|
|
1119
|
+
nextlayer.add(t)
|
|
1120
|
+
curlayer = nextlayer
|
|
1121
|
+
|
|
1122
|
+
from sage.graphs.digraph import DiGraph
|
|
1123
|
+
return Poset(DiGraph(d, format='dict_of_lists',
|
|
1124
|
+
data_structure='static_sparse'),
|
|
1125
|
+
cover_relations=True,
|
|
1126
|
+
facade=facade)
|
|
1127
|
+
|
|
1128
|
+
def bruhat_graph(self, x=None, y=None, edge_labels=False):
|
|
1129
|
+
r"""
|
|
1130
|
+
Return the Bruhat graph as a directed graph, with an edge `u \to v`
|
|
1131
|
+
if and only if `u < v` in the Bruhat order, and `u = r \cdot v`.
|
|
1132
|
+
|
|
1133
|
+
The Bruhat graph `\Gamma(x,y)`, defined if `x \leq y` in the
|
|
1134
|
+
Bruhat order, has as its vertices the Bruhat interval
|
|
1135
|
+
`\{ t | x \leq t \leq y \}`, and as its edges are the pairs
|
|
1136
|
+
`(u, v)` such that `u = r \cdot v` where `r` is a reflection,
|
|
1137
|
+
that is, a conjugate of a simple reflection.
|
|
1138
|
+
|
|
1139
|
+
REFERENCES:
|
|
1140
|
+
|
|
1141
|
+
Carrell, The Bruhat graph of a Coxeter group, a conjecture of Deodhar,
|
|
1142
|
+
and rational smoothness of Schubert varieties. Algebraic groups and
|
|
1143
|
+
their generalizations: classical methods (University Park, PA, 1991),
|
|
1144
|
+
53--61, Proc. Sympos. Pure Math., 56, Part 1, Amer. Math. Soc.,
|
|
1145
|
+
Providence, RI, 1994.
|
|
1146
|
+
|
|
1147
|
+
EXAMPLES::
|
|
1148
|
+
|
|
1149
|
+
sage: W = CoxeterGroup(['H', 3]) # needs sage.combinat sage.graphs sage.groups
|
|
1150
|
+
sage: G = W.bruhat_graph(); G # needs sage.combinat sage.graphs sage.groups
|
|
1151
|
+
Digraph on 120 vertices
|
|
1152
|
+
|
|
1153
|
+
sage: # needs sage.combinat sage.graphs sage.groups
|
|
1154
|
+
sage: W = CoxeterGroup(['A', 2, 1])
|
|
1155
|
+
sage: s1, s2, s3 = W.simple_reflections()
|
|
1156
|
+
sage: W.bruhat_graph(s1, s1*s3*s2*s3)
|
|
1157
|
+
Digraph on 6 vertices
|
|
1158
|
+
sage: W.bruhat_graph(s1, s3*s2*s3)
|
|
1159
|
+
Digraph on 0 vertices
|
|
1160
|
+
|
|
1161
|
+
sage: W = WeylGroup("A3", prefix='s') # needs sage.combinat sage.graphs sage.groups
|
|
1162
|
+
sage: s1, s2, s3 = W.simple_reflections() # needs sage.combinat sage.graphs sage.groups
|
|
1163
|
+
sage: G = W.bruhat_graph(s1*s3, s1*s2*s3*s2*s1); G # needs sage.combinat sage.graphs sage.groups
|
|
1164
|
+
Digraph on 10 vertices
|
|
1165
|
+
|
|
1166
|
+
Check that the graph has the correct number of edges
|
|
1167
|
+
(see :issue:`17744`)::
|
|
1168
|
+
|
|
1169
|
+
sage: len(G.edges(sort=False)) # needs sage.combinat sage.graphs sage.groups
|
|
1170
|
+
16
|
|
1171
|
+
"""
|
|
1172
|
+
if x is None or x == 1:
|
|
1173
|
+
x = self.one()
|
|
1174
|
+
if y is None:
|
|
1175
|
+
if self.is_finite():
|
|
1176
|
+
y = self.long_element()
|
|
1177
|
+
else:
|
|
1178
|
+
raise TypeError("infinite groups must specify a maximal element")
|
|
1179
|
+
elif y == 1:
|
|
1180
|
+
y = self.one()
|
|
1181
|
+
|
|
1182
|
+
# Sort bruhat_interval in weakly decreasing order of length.
|
|
1183
|
+
# We do this so we do not need to check the length in the
|
|
1184
|
+
# for loops below.
|
|
1185
|
+
g = sorted(self.bruhat_interval(x, y), key=lambda w: -w.length())
|
|
1186
|
+
d = []
|
|
1187
|
+
|
|
1188
|
+
if self.is_finite():
|
|
1189
|
+
ref = self.reflections()
|
|
1190
|
+
for i, u in enumerate(g):
|
|
1191
|
+
for v in g[:i]:
|
|
1192
|
+
w = u * v.inverse()
|
|
1193
|
+
if w in ref:
|
|
1194
|
+
if edge_labels:
|
|
1195
|
+
d.append((u, v, w))
|
|
1196
|
+
else:
|
|
1197
|
+
d.append((u, v))
|
|
1198
|
+
else:
|
|
1199
|
+
for i, u in enumerate(g):
|
|
1200
|
+
for v in g[:i]:
|
|
1201
|
+
w = u * v.inverse()
|
|
1202
|
+
if w.is_reflection():
|
|
1203
|
+
if edge_labels:
|
|
1204
|
+
d.append((u, v, w))
|
|
1205
|
+
else:
|
|
1206
|
+
d.append((u, v))
|
|
1207
|
+
|
|
1208
|
+
from sage.graphs.digraph import DiGraph
|
|
1209
|
+
return DiGraph(d)
|
|
1210
|
+
|
|
1211
|
+
def canonical_representation(self):
|
|
1212
|
+
r"""
|
|
1213
|
+
Return the canonical faithful representation of ``self``.
|
|
1214
|
+
|
|
1215
|
+
.. SEEALSO::
|
|
1216
|
+
|
|
1217
|
+
To obtain the underlying module with the action, use
|
|
1218
|
+
:meth:`reflection_representation`.
|
|
1219
|
+
|
|
1220
|
+
EXAMPLES::
|
|
1221
|
+
|
|
1222
|
+
sage: W = WeylGroup("A3") # needs sage.combinat sage.groups
|
|
1223
|
+
sage: W.canonical_representation() # needs sage.combinat sage.groups
|
|
1224
|
+
Finite Coxeter group over Integer Ring with Coxeter matrix:
|
|
1225
|
+
[1 3 2]
|
|
1226
|
+
[3 1 3]
|
|
1227
|
+
[2 3 1]
|
|
1228
|
+
"""
|
|
1229
|
+
from sage.groups.matrix_gps.coxeter_group import CoxeterMatrixGroup
|
|
1230
|
+
return CoxeterMatrixGroup(self.coxeter_matrix(),
|
|
1231
|
+
index_set=self.index_set())
|
|
1232
|
+
|
|
1233
|
+
def elements_of_length(self, n):
|
|
1234
|
+
r"""
|
|
1235
|
+
Return all elements of length `n`.
|
|
1236
|
+
|
|
1237
|
+
EXAMPLES::
|
|
1238
|
+
|
|
1239
|
+
sage: A = AffinePermutationGroup(['A', 2, 1]) # needs sage.combinat sage.groups
|
|
1240
|
+
sage: [len(list(A.elements_of_length(i))) for i in [0..5]] # needs sage.combinat sage.groups
|
|
1241
|
+
[1, 3, 6, 9, 12, 15]
|
|
1242
|
+
|
|
1243
|
+
sage: W = CoxeterGroup(['H', 3]) # needs sage.combinat sage.groups
|
|
1244
|
+
sage: [len(list(W.elements_of_length(i))) for i in range(4)] # needs sage.combinat sage.groups
|
|
1245
|
+
[1, 3, 5, 7]
|
|
1246
|
+
|
|
1247
|
+
sage: W = CoxeterGroup(['A', 2]) # needs sage.combinat sage.groups
|
|
1248
|
+
sage: [len(list(W.elements_of_length(i))) for i in range(6)] # needs sage.combinat sage.groups
|
|
1249
|
+
[1, 2, 2, 1, 0, 0]
|
|
1250
|
+
"""
|
|
1251
|
+
I = self.weak_order_ideal(ConstantFunction(True), side='right')
|
|
1252
|
+
return I.elements_of_depth_iterator(n)
|
|
1253
|
+
|
|
1254
|
+
def random_element_of_length(self, n):
|
|
1255
|
+
r"""
|
|
1256
|
+
Return a random element of length ``n`` in ``self``.
|
|
1257
|
+
|
|
1258
|
+
Starts at the identity, then chooses an upper cover at random.
|
|
1259
|
+
|
|
1260
|
+
Not very uniform: actually constructs a uniformly random
|
|
1261
|
+
reduced word of length `n`. Thus we most likely get
|
|
1262
|
+
elements with lots of reduced words!
|
|
1263
|
+
|
|
1264
|
+
EXAMPLES::
|
|
1265
|
+
|
|
1266
|
+
sage: # needs sage.combinat sage.groups
|
|
1267
|
+
sage: A = AffinePermutationGroup(['A', 7, 1])
|
|
1268
|
+
sage: p = A.random_element_of_length(10)
|
|
1269
|
+
sage: p in A
|
|
1270
|
+
True
|
|
1271
|
+
sage: p.length() == 10
|
|
1272
|
+
True
|
|
1273
|
+
|
|
1274
|
+
sage: # needs sage.combinat sage.groups
|
|
1275
|
+
sage: W = CoxeterGroup(['A', 4])
|
|
1276
|
+
sage: p = W.random_element_of_length(5)
|
|
1277
|
+
sage: p in W
|
|
1278
|
+
True
|
|
1279
|
+
sage: p.length() == 5
|
|
1280
|
+
True
|
|
1281
|
+
"""
|
|
1282
|
+
from sage.misc.prandom import randint
|
|
1283
|
+
x = self.one()
|
|
1284
|
+
for _ in range(1, n + 1):
|
|
1285
|
+
antiD = x.descents(positive=True)
|
|
1286
|
+
rnd = randint(0, len(antiD) - 1)
|
|
1287
|
+
x = x.apply_simple_reflection_right(antiD[rnd])
|
|
1288
|
+
return x
|
|
1289
|
+
|
|
1290
|
+
# parabolic_subgroup
|
|
1291
|
+
|
|
1292
|
+
def _test_simple_projections(self, **options):
|
|
1293
|
+
"""
|
|
1294
|
+
Run sanity checks on :meth:`.simple_projections`
|
|
1295
|
+
and :meth:`CoxeterGroups.ElementMethods.apply_simple_projection`
|
|
1296
|
+
|
|
1297
|
+
EXAMPLES::
|
|
1298
|
+
|
|
1299
|
+
sage: W = CoxeterGroups().example()
|
|
1300
|
+
sage: W._test_simple_projections()
|
|
1301
|
+
"""
|
|
1302
|
+
tester = self._tester(**options)
|
|
1303
|
+
for side in ['left', 'right']:
|
|
1304
|
+
pi = self.simple_projections(side=side)
|
|
1305
|
+
opi = self.simple_projections(side=side, length_increasing=False)
|
|
1306
|
+
for i in self.index_set():
|
|
1307
|
+
for w in tester.some_elements():
|
|
1308
|
+
tester.assertEqual(pi[i](w), w.apply_simple_projection(i, side=side))
|
|
1309
|
+
tester.assertEqual(pi[i](w), w.apply_simple_projection(i, side=side, length_increasing=True))
|
|
1310
|
+
tester.assertEqual(opi[i](w), w.apply_simple_projection(i, side=side, length_increasing=False))
|
|
1311
|
+
tester.assertTrue(pi[i](w).has_descent(i, side=side))
|
|
1312
|
+
tester.assertFalse(opi[i](w).has_descent(i, side=side))
|
|
1313
|
+
tester.assertEqual({pi[i](w), opi[i](w)},
|
|
1314
|
+
{w, w.apply_simple_reflection(i, side=side)})
|
|
1315
|
+
|
|
1316
|
+
def _test_has_descent(self, **options):
|
|
1317
|
+
"""
|
|
1318
|
+
Run sanity checks on the method
|
|
1319
|
+
:meth:`CoxeterGroups.ElementMethods.has_descent` of the
|
|
1320
|
+
elements of ``self``.
|
|
1321
|
+
|
|
1322
|
+
EXAMPLES::
|
|
1323
|
+
|
|
1324
|
+
sage: W = CoxeterGroups().example()
|
|
1325
|
+
sage: W._test_has_descent()
|
|
1326
|
+
|
|
1327
|
+
sage: # needs sage.combinat sage.groups
|
|
1328
|
+
sage: W = Permutations(4)
|
|
1329
|
+
sage: W._test_has_descent()
|
|
1330
|
+
sage: sage.combinat.permutation.Permutations.options.mult = "r2l"
|
|
1331
|
+
sage: W._test_has_descent()
|
|
1332
|
+
sage: sage.combinat.permutation.Permutations.options._reset()
|
|
1333
|
+
|
|
1334
|
+
sage: W = SignedPermutations(3) # needs sage.combinat
|
|
1335
|
+
sage: W._test_has_descent()
|
|
1336
|
+
"""
|
|
1337
|
+
tester = self._tester(**options)
|
|
1338
|
+
s = self.simple_reflections()
|
|
1339
|
+
for i in self.index_set():
|
|
1340
|
+
tester.assertTrue(not self.one().has_descent(i))
|
|
1341
|
+
tester.assertTrue(not self.one().has_descent(i, side='left'))
|
|
1342
|
+
tester.assertTrue(not self.one().has_descent(i, side='right'))
|
|
1343
|
+
tester.assertTrue(self.one().has_descent(i, positive=True))
|
|
1344
|
+
tester.assertTrue(self.one().has_descent(i, positive=True, side='left'))
|
|
1345
|
+
tester.assertTrue(self.one().has_descent(i, positive=True, side='right'))
|
|
1346
|
+
for j in self.index_set():
|
|
1347
|
+
tester.assertEqual(s[i].has_descent(j, side='left'), i == j)
|
|
1348
|
+
tester.assertEqual(s[i].has_descent(j, side='right'), i == j)
|
|
1349
|
+
tester.assertEqual(s[i].has_descent(j), i == j)
|
|
1350
|
+
tester.assertEqual(s[i].has_descent(j, positive=True, side='left'), i != j)
|
|
1351
|
+
tester.assertEqual(s[i].has_descent(j, positive=True, side='right'), i != j)
|
|
1352
|
+
tester.assertEqual(s[i].has_descent(j, positive=True), i != j)
|
|
1353
|
+
if i == j:
|
|
1354
|
+
continue
|
|
1355
|
+
u = s[i].apply_simple_reflection_right(j)
|
|
1356
|
+
v = s[j].apply_simple_reflection_right(i)
|
|
1357
|
+
tester.assertTrue(u.has_descent(i, side='left'))
|
|
1358
|
+
tester.assertTrue(u.has_descent(j, side='right'))
|
|
1359
|
+
tester.assertEqual(u.has_descent(j, side='left'), u == v)
|
|
1360
|
+
tester.assertEqual(u.has_descent(i, side='right'), u == v)
|
|
1361
|
+
|
|
1362
|
+
def _test_descents(self, **options):
|
|
1363
|
+
"""
|
|
1364
|
+
Run sanity checks on the method
|
|
1365
|
+
:meth:`CoxeterGroups.ElementMethods.descents` of the
|
|
1366
|
+
elements of ``self``.
|
|
1367
|
+
|
|
1368
|
+
EXAMPLES::
|
|
1369
|
+
|
|
1370
|
+
sage: W = CoxeterGroups().example()
|
|
1371
|
+
sage: W._test_descents()
|
|
1372
|
+
"""
|
|
1373
|
+
tester = self._tester(**options)
|
|
1374
|
+
s = self.simple_reflections()
|
|
1375
|
+
tester.assertEqual(len(self.one().descents(side='right')), 0)
|
|
1376
|
+
tester.assertEqual(len(self.one().descents(side='left')), 0)
|
|
1377
|
+
for i in self.index_set():
|
|
1378
|
+
si = s[i]
|
|
1379
|
+
tester.assertEqual([i], si.descents(side='left'))
|
|
1380
|
+
tester.assertEqual([i], si.descents(side='right'))
|
|
1381
|
+
tester.assertNotIn(i, si.descents(positive=True, side='left'))
|
|
1382
|
+
tester.assertNotIn(i, si.descents(positive=True, side='right'))
|
|
1383
|
+
|
|
1384
|
+
def _test_coxeter_relations(self, **options):
|
|
1385
|
+
r"""
|
|
1386
|
+
Test whether the Coxeter relations hold for ``self``.
|
|
1387
|
+
|
|
1388
|
+
This checks nothing in the case of infinite order.
|
|
1389
|
+
|
|
1390
|
+
TESTS::
|
|
1391
|
+
|
|
1392
|
+
sage: A = AffinePermutationGroup(['A', 7, 1]) # needs sage.combinat sage.modules
|
|
1393
|
+
sage: A._test_coxeter_relations() # needs sage.combinat sage.modules
|
|
1394
|
+
|
|
1395
|
+
sage: cm = CartanMatrix([[2,-5,0], [-2,2,-1], [0,-1,2]]) # needs sage.graphs sage.modules
|
|
1396
|
+
sage: W = WeylGroup(cm) # needs sage.combinat sage.graphs sage.groups sage.modules
|
|
1397
|
+
sage: W._test_coxeter_relations() # needs sage.combinat sage.graphs sage.groups sage.modules
|
|
1398
|
+
|
|
1399
|
+
sage: # needs sage.combinat sage.groups
|
|
1400
|
+
sage: W = Permutations(4)
|
|
1401
|
+
sage: W._test_coxeter_relations()
|
|
1402
|
+
sage: sage.combinat.permutation.Permutations.options.mult = "r2l"
|
|
1403
|
+
sage: W._test_coxeter_relations()
|
|
1404
|
+
sage: sage.combinat.permutation.Permutations.options._reset()
|
|
1405
|
+
|
|
1406
|
+
sage: W = SignedPermutations(3) # needs sage.combinat
|
|
1407
|
+
sage: W._test_coxeter_relations() # needs sage.combinat
|
|
1408
|
+
"""
|
|
1409
|
+
tester = self._tester(**options)
|
|
1410
|
+
s = self.simple_reflections()
|
|
1411
|
+
one = self.one()
|
|
1412
|
+
for si in s:
|
|
1413
|
+
tester.assertEqual(si**2, one)
|
|
1414
|
+
try:
|
|
1415
|
+
cox_mat = self.coxeter_matrix()
|
|
1416
|
+
except ImportError:
|
|
1417
|
+
return
|
|
1418
|
+
I = cox_mat.index_set()
|
|
1419
|
+
for ii, i in enumerate(I):
|
|
1420
|
+
for j in I[ii + 1:]:
|
|
1421
|
+
mij = cox_mat[i, j]
|
|
1422
|
+
if mij == -1: # -1 stands for infinity
|
|
1423
|
+
continue
|
|
1424
|
+
l = s[i] * s[j]
|
|
1425
|
+
tester.assertEqual(l**mij, one, "Coxeter relation fails")
|
|
1426
|
+
for p in range(1, mij):
|
|
1427
|
+
tester.assertNotEqual(l**p, one, "unexpected relation")
|
|
1428
|
+
|
|
1429
|
+
class ElementMethods:
|
|
1430
|
+
def has_descent(self, i, side='right', positive=False) -> bool:
|
|
1431
|
+
"""
|
|
1432
|
+
Return whether `i` is a (left/right) descent of ``self``.
|
|
1433
|
+
|
|
1434
|
+
See :meth:`.descents` for a description of the options.
|
|
1435
|
+
|
|
1436
|
+
EXAMPLES::
|
|
1437
|
+
|
|
1438
|
+
sage: W = CoxeterGroups().example()
|
|
1439
|
+
sage: s = W.simple_reflections()
|
|
1440
|
+
sage: w = s[0] * s[1] * s[2]
|
|
1441
|
+
sage: w.has_descent(2)
|
|
1442
|
+
True
|
|
1443
|
+
sage: [ w.has_descent(i) for i in [0,1,2] ]
|
|
1444
|
+
[False, False, True]
|
|
1445
|
+
sage: [ w.has_descent(i, side='left') for i in [0,1,2] ]
|
|
1446
|
+
[True, False, False]
|
|
1447
|
+
sage: [ w.has_descent(i, positive=True) for i in [0,1,2] ]
|
|
1448
|
+
[True, True, False]
|
|
1449
|
+
|
|
1450
|
+
This default implementation delegates the work to
|
|
1451
|
+
:meth:`.has_left_descent` and :meth:`.has_right_descent`.
|
|
1452
|
+
"""
|
|
1453
|
+
if not isinstance(positive, bool):
|
|
1454
|
+
raise TypeError("%s is not a boolean" % bool)
|
|
1455
|
+
if side == 'right':
|
|
1456
|
+
return self.has_right_descent(i) != positive
|
|
1457
|
+
if side != 'left':
|
|
1458
|
+
raise ValueError("%s is neither 'right' nor 'left'" % side)
|
|
1459
|
+
return self.has_left_descent(i) != positive
|
|
1460
|
+
|
|
1461
|
+
# @abstract_method(optional = True)
|
|
1462
|
+
def has_right_descent(self, i) -> bool:
|
|
1463
|
+
"""
|
|
1464
|
+
Return whether `i` is a right descent of ``self``.
|
|
1465
|
+
|
|
1466
|
+
EXAMPLES::
|
|
1467
|
+
|
|
1468
|
+
sage: W = CoxeterGroups().example(); W
|
|
1469
|
+
The symmetric group on {0, ..., 3}
|
|
1470
|
+
sage: w = W.an_element(); w
|
|
1471
|
+
(1, 2, 3, 0)
|
|
1472
|
+
sage: w.has_right_descent(0)
|
|
1473
|
+
False
|
|
1474
|
+
sage: w.has_right_descent(1)
|
|
1475
|
+
False
|
|
1476
|
+
sage: w.has_right_descent(2)
|
|
1477
|
+
True
|
|
1478
|
+
"""
|
|
1479
|
+
return (~self).has_left_descent(i)
|
|
1480
|
+
|
|
1481
|
+
def has_left_descent(self, i) -> bool:
|
|
1482
|
+
"""
|
|
1483
|
+
Return whether `i` is a left descent of ``self``.
|
|
1484
|
+
|
|
1485
|
+
This default implementation uses that a left descent of
|
|
1486
|
+
`w` is a right descent of `w^{-1}`.
|
|
1487
|
+
|
|
1488
|
+
EXAMPLES::
|
|
1489
|
+
|
|
1490
|
+
sage: W = CoxeterGroups().example(); W
|
|
1491
|
+
The symmetric group on {0, ..., 3}
|
|
1492
|
+
sage: w = W.an_element(); w
|
|
1493
|
+
(1, 2, 3, 0)
|
|
1494
|
+
sage: w.has_left_descent(0)
|
|
1495
|
+
True
|
|
1496
|
+
sage: w.has_left_descent(1)
|
|
1497
|
+
False
|
|
1498
|
+
sage: w.has_left_descent(2)
|
|
1499
|
+
False
|
|
1500
|
+
|
|
1501
|
+
TESTS::
|
|
1502
|
+
|
|
1503
|
+
sage: w.has_left_descent.__module__
|
|
1504
|
+
'sage.categories.coxeter_groups'
|
|
1505
|
+
"""
|
|
1506
|
+
return (~self).has_right_descent(i)
|
|
1507
|
+
|
|
1508
|
+
def first_descent(self, side='right', index_set=None, positive=False):
|
|
1509
|
+
"""
|
|
1510
|
+
Return the first left (resp. right) descent of self, as
|
|
1511
|
+
an element of ``index_set``, or ``None`` if there is none.
|
|
1512
|
+
|
|
1513
|
+
See :meth:`.descents` for a description of the options.
|
|
1514
|
+
|
|
1515
|
+
EXAMPLES::
|
|
1516
|
+
|
|
1517
|
+
sage: W = CoxeterGroups().example()
|
|
1518
|
+
sage: s = W.simple_reflections()
|
|
1519
|
+
sage: w = s[2]*s[0]
|
|
1520
|
+
sage: w.first_descent()
|
|
1521
|
+
0
|
|
1522
|
+
sage: w = s[0]*s[2]
|
|
1523
|
+
sage: w.first_descent()
|
|
1524
|
+
0
|
|
1525
|
+
sage: w = s[0]*s[1]
|
|
1526
|
+
sage: w.first_descent()
|
|
1527
|
+
1
|
|
1528
|
+
"""
|
|
1529
|
+
if index_set is None:
|
|
1530
|
+
index_set = self.parent().index_set()
|
|
1531
|
+
for i in index_set:
|
|
1532
|
+
if self.has_descent(i, side=side, positive=positive):
|
|
1533
|
+
return i
|
|
1534
|
+
return None
|
|
1535
|
+
|
|
1536
|
+
def descents(self, side='right', index_set=None, positive=False):
|
|
1537
|
+
"""
|
|
1538
|
+
Return the descents of self, as a list of elements of the
|
|
1539
|
+
index_set.
|
|
1540
|
+
|
|
1541
|
+
INPUT:
|
|
1542
|
+
|
|
1543
|
+
- ``index_set`` -- a subset (as a list or iterable) of the nodes of the Dynkin diagram;
|
|
1544
|
+
(default: all of them)
|
|
1545
|
+
- ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``)
|
|
1546
|
+
- ``positive`` -- boolean (default: ``False``)
|
|
1547
|
+
|
|
1548
|
+
The ``index_set`` option can be used to restrict to the
|
|
1549
|
+
parabolic subgroup indexed by ``index_set``.
|
|
1550
|
+
|
|
1551
|
+
If positive is ``True``, then returns the non-descents
|
|
1552
|
+
instead
|
|
1553
|
+
|
|
1554
|
+
.. TODO::
|
|
1555
|
+
|
|
1556
|
+
find a better name for ``positive``: complement? non_descent?
|
|
1557
|
+
|
|
1558
|
+
Caveat: the return type may change to some other iterable
|
|
1559
|
+
(tuple, ...) in the future. Please use keyword arguments
|
|
1560
|
+
also, as the order of the arguments may change as well.
|
|
1561
|
+
|
|
1562
|
+
EXAMPLES::
|
|
1563
|
+
|
|
1564
|
+
sage: W = CoxeterGroups().example()
|
|
1565
|
+
sage: s = W.simple_reflections()
|
|
1566
|
+
sage: w = s[0]*s[1]
|
|
1567
|
+
sage: w.descents()
|
|
1568
|
+
[1]
|
|
1569
|
+
sage: w = s[0]*s[2]
|
|
1570
|
+
sage: w.descents()
|
|
1571
|
+
[0, 2]
|
|
1572
|
+
|
|
1573
|
+
.. TODO:: side, index_set, positive
|
|
1574
|
+
"""
|
|
1575
|
+
if index_set is None:
|
|
1576
|
+
index_set = self.parent().index_set()
|
|
1577
|
+
return [i for i in index_set if self.has_descent(i, side=side,
|
|
1578
|
+
positive=positive)]
|
|
1579
|
+
|
|
1580
|
+
def is_grassmannian(self, side='right') -> bool:
|
|
1581
|
+
"""
|
|
1582
|
+
Return whether ``self`` is Grassmannian.
|
|
1583
|
+
|
|
1584
|
+
INPUT:
|
|
1585
|
+
|
|
1586
|
+
- ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``)
|
|
1587
|
+
|
|
1588
|
+
An element is Grassmannian if it has at
|
|
1589
|
+
most one descent on the right (resp. on the left).
|
|
1590
|
+
|
|
1591
|
+
EXAMPLES::
|
|
1592
|
+
|
|
1593
|
+
sage: W = CoxeterGroups().example(); W
|
|
1594
|
+
The symmetric group on {0, ..., 3}
|
|
1595
|
+
sage: s = W.simple_reflections()
|
|
1596
|
+
sage: W.one().is_grassmannian()
|
|
1597
|
+
True
|
|
1598
|
+
sage: s[1].is_grassmannian()
|
|
1599
|
+
True
|
|
1600
|
+
sage: (s[1]*s[2]).is_grassmannian()
|
|
1601
|
+
True
|
|
1602
|
+
sage: (s[0]*s[1]).is_grassmannian()
|
|
1603
|
+
True
|
|
1604
|
+
sage: (s[1]*s[2]*s[1]).is_grassmannian()
|
|
1605
|
+
False
|
|
1606
|
+
|
|
1607
|
+
sage: (s[0]*s[2]*s[1]).is_grassmannian(side='left')
|
|
1608
|
+
False
|
|
1609
|
+
sage: (s[0]*s[2]*s[1]).is_grassmannian(side='right')
|
|
1610
|
+
True
|
|
1611
|
+
sage: (s[0]*s[2]*s[1]).is_grassmannian()
|
|
1612
|
+
True
|
|
1613
|
+
"""
|
|
1614
|
+
return len(self.descents(side=side)) <= 1
|
|
1615
|
+
|
|
1616
|
+
def is_fully_commutative(self) -> bool:
|
|
1617
|
+
r"""
|
|
1618
|
+
Check if ``self`` is a fully-commutative element.
|
|
1619
|
+
|
|
1620
|
+
We use the characterization that an element `w` in a Coxeter
|
|
1621
|
+
system `(W,S)` is fully-commutative if and only if for every pair
|
|
1622
|
+
of generators `s,t \in S` for which `m(s,t)>2`, no reduced
|
|
1623
|
+
word of `w` contains the 'braid' word `sts...` of length
|
|
1624
|
+
`m(s,t)` as a contiguous subword. See [Ste1996]_.
|
|
1625
|
+
|
|
1626
|
+
EXAMPLES::
|
|
1627
|
+
|
|
1628
|
+
sage: # needs sage.combinat sage.groups
|
|
1629
|
+
sage: W = CoxeterGroup(['A', 3])
|
|
1630
|
+
sage: len([1 for w in W if w.is_fully_commutative()])
|
|
1631
|
+
14
|
|
1632
|
+
sage: W = CoxeterGroup(['B', 3])
|
|
1633
|
+
sage: len([1 for w in W if w.is_fully_commutative()])
|
|
1634
|
+
24
|
|
1635
|
+
|
|
1636
|
+
TESTS::
|
|
1637
|
+
|
|
1638
|
+
sage: W = CoxeterGroup(matrix(2,2,[1,7,7,1]), index_set='ab') # needs sage.combinat sage.groups
|
|
1639
|
+
sage: len([1 for w in W if w.is_fully_commutative()]) # needs sage.combinat sage.groups
|
|
1640
|
+
13
|
|
1641
|
+
"""
|
|
1642
|
+
word = self.reduced_word()
|
|
1643
|
+
from sage.combinat.root_system.braid_orbit import is_fully_commutative as is_fully_comm
|
|
1644
|
+
|
|
1645
|
+
group = self.parent()
|
|
1646
|
+
braid_rels = group.braid_relations()
|
|
1647
|
+
I = group.index_set()
|
|
1648
|
+
|
|
1649
|
+
from sage.rings.integer_ring import ZZ
|
|
1650
|
+
be_careful = any(i not in ZZ for i in I)
|
|
1651
|
+
|
|
1652
|
+
if be_careful:
|
|
1653
|
+
Iinv = {i: j for j, i in enumerate(I)}
|
|
1654
|
+
word = [Iinv[i] for i in word]
|
|
1655
|
+
braid_rels = [[[Iinv[i] for i in l],
|
|
1656
|
+
[Iinv[i] for i in r]] for l, r in braid_rels]
|
|
1657
|
+
|
|
1658
|
+
return is_fully_comm(word, braid_rels)
|
|
1659
|
+
|
|
1660
|
+
def reduced_word_reverse_iterator(self):
|
|
1661
|
+
"""
|
|
1662
|
+
Return a reverse iterator on a reduced word for ``self``.
|
|
1663
|
+
|
|
1664
|
+
EXAMPLES::
|
|
1665
|
+
|
|
1666
|
+
sage: W = CoxeterGroups().example()
|
|
1667
|
+
sage: s = W.simple_reflections()
|
|
1668
|
+
sage: sigma = s[0]*s[1]*s[2]
|
|
1669
|
+
sage: rI=sigma.reduced_word_reverse_iterator()
|
|
1670
|
+
sage: [i for i in rI]
|
|
1671
|
+
[2, 1, 0]
|
|
1672
|
+
sage: s[0]*s[1]*s[2]==sigma
|
|
1673
|
+
True
|
|
1674
|
+
sage: sigma.length()
|
|
1675
|
+
3
|
|
1676
|
+
|
|
1677
|
+
.. SEEALSO::
|
|
1678
|
+
|
|
1679
|
+
:meth:`.reduced_word`
|
|
1680
|
+
|
|
1681
|
+
Default implementation: recursively remove the first right
|
|
1682
|
+
descent until the identity is reached (see :meth:`.first_descent` and
|
|
1683
|
+
:meth:`~sage.categories.complex_reflection_or_generalized_coxeter_groups.ComplexReflectionOrGeneralizedCoxeterGroups.ElementMethods.apply_simple_reflection`).
|
|
1684
|
+
"""
|
|
1685
|
+
while True:
|
|
1686
|
+
i = self.first_descent()
|
|
1687
|
+
if i is None:
|
|
1688
|
+
return
|
|
1689
|
+
self = self.apply_simple_reflection(i, 'right')
|
|
1690
|
+
yield i
|
|
1691
|
+
|
|
1692
|
+
def reduced_word(self):
|
|
1693
|
+
r"""
|
|
1694
|
+
Return a reduced word for ``self``.
|
|
1695
|
+
|
|
1696
|
+
This is a word `[i_1,i_2,\ldots,i_k]` of minimal length
|
|
1697
|
+
such that
|
|
1698
|
+
`s_{i_1} s_{i_2} \cdots s_{i_k} = \operatorname{self}`,
|
|
1699
|
+
where the `s_i` are the simple reflections.
|
|
1700
|
+
|
|
1701
|
+
EXAMPLES::
|
|
1702
|
+
|
|
1703
|
+
sage: W = CoxeterGroups().example()
|
|
1704
|
+
sage: s = W.simple_reflections()
|
|
1705
|
+
sage: w = s[0]*s[1]*s[2]
|
|
1706
|
+
sage: w.reduced_word()
|
|
1707
|
+
[0, 1, 2]
|
|
1708
|
+
sage: w = s[0]*s[2]
|
|
1709
|
+
sage: w.reduced_word()
|
|
1710
|
+
[2, 0]
|
|
1711
|
+
|
|
1712
|
+
.. SEEALSO::
|
|
1713
|
+
|
|
1714
|
+
- :meth:`.reduced_words`, :meth:`.reduced_word_reverse_iterator`,
|
|
1715
|
+
- :meth:`length`, :meth:`reduced_word_graph`
|
|
1716
|
+
"""
|
|
1717
|
+
result = list(self.reduced_word_reverse_iterator())
|
|
1718
|
+
return list(reversed(result))
|
|
1719
|
+
|
|
1720
|
+
def reduced_words_iter(self):
|
|
1721
|
+
r"""
|
|
1722
|
+
Iterate over all reduced words for ``self``.
|
|
1723
|
+
|
|
1724
|
+
See :meth:`reduced_word` for the definition of a reduced
|
|
1725
|
+
word.
|
|
1726
|
+
|
|
1727
|
+
The algorithm uses the Matsumoto property that any two
|
|
1728
|
+
reduced expressions are related by braid relations, see
|
|
1729
|
+
Theorem 3.3.1(ii) in [BB2005]_.
|
|
1730
|
+
|
|
1731
|
+
.. SEEALSO::
|
|
1732
|
+
|
|
1733
|
+
:meth:`braid_orbit_iter`
|
|
1734
|
+
|
|
1735
|
+
EXAMPLES::
|
|
1736
|
+
|
|
1737
|
+
sage: W = CoxeterGroups().example()
|
|
1738
|
+
sage: s = W.simple_reflections()
|
|
1739
|
+
sage: w = s[0] * s[2]
|
|
1740
|
+
sage: sorted(w.reduced_words_iter()) # needs sage.combinat sage.graphs sage.modules
|
|
1741
|
+
[[0, 2], [2, 0]]
|
|
1742
|
+
"""
|
|
1743
|
+
return self.parent().braid_orbit_iter(self.reduced_word())
|
|
1744
|
+
|
|
1745
|
+
def reduced_words(self):
|
|
1746
|
+
r"""
|
|
1747
|
+
Return all reduced words for ``self``.
|
|
1748
|
+
|
|
1749
|
+
See :meth:`reduced_word` for the definition of a reduced
|
|
1750
|
+
word.
|
|
1751
|
+
|
|
1752
|
+
The algorithm uses the Matsumoto property that any two
|
|
1753
|
+
reduced expressions are related by braid relations, see
|
|
1754
|
+
Theorem 3.3.1(ii) in [BB2005]_.
|
|
1755
|
+
|
|
1756
|
+
.. SEEALSO::
|
|
1757
|
+
|
|
1758
|
+
:meth:`braid_orbit`
|
|
1759
|
+
|
|
1760
|
+
EXAMPLES::
|
|
1761
|
+
|
|
1762
|
+
sage: W = CoxeterGroups().example()
|
|
1763
|
+
sage: s = W.simple_reflections()
|
|
1764
|
+
sage: w = s[0] * s[2]
|
|
1765
|
+
sage: sorted(w.reduced_words()) # needs sage.graphs sage.modules
|
|
1766
|
+
[[0, 2], [2, 0]]
|
|
1767
|
+
|
|
1768
|
+
sage: W = WeylGroup(['E', 6]) # needs sage.combinat sage.groups
|
|
1769
|
+
sage: w = W.from_reduced_word([2,3,4,2]) # needs sage.combinat sage.groups
|
|
1770
|
+
sage: sorted(w.reduced_words()) # needs sage.combinat sage.groups
|
|
1771
|
+
[[2, 3, 4, 2], [3, 2, 4, 2], [3, 4, 2, 4]]
|
|
1772
|
+
|
|
1773
|
+
sage: # optional - gap3, needs sage.combinat sage.groups
|
|
1774
|
+
sage: W = ReflectionGroup(['A',3],
|
|
1775
|
+
....: index_set=["AA","BB","5"])
|
|
1776
|
+
sage: w = W.long_element()
|
|
1777
|
+
sage: w.reduced_words()
|
|
1778
|
+
[['BB', '5', 'AA', 'BB', '5', 'AA'],
|
|
1779
|
+
['5', 'BB', '5', 'AA', 'BB', '5'],
|
|
1780
|
+
['BB', 'AA', 'BB', '5', 'BB', 'AA'],
|
|
1781
|
+
['AA', '5', 'BB', 'AA', '5', 'BB'],
|
|
1782
|
+
['5', 'AA', 'BB', 'AA', '5', 'BB'],
|
|
1783
|
+
['AA', 'BB', '5', 'AA', 'BB', 'AA'],
|
|
1784
|
+
['AA', 'BB', 'AA', '5', 'BB', 'AA'],
|
|
1785
|
+
['AA', 'BB', '5', 'BB', 'AA', 'BB'],
|
|
1786
|
+
['BB', 'AA', '5', 'BB', 'AA', '5'],
|
|
1787
|
+
['BB', '5', 'AA', 'BB', 'AA', '5'],
|
|
1788
|
+
['AA', '5', 'BB', '5', 'AA', 'BB'],
|
|
1789
|
+
['5', 'BB', 'AA', '5', 'BB', '5'],
|
|
1790
|
+
['5', 'BB', 'AA', 'BB', '5', 'BB'],
|
|
1791
|
+
['5', 'AA', 'BB', '5', 'AA', 'BB'],
|
|
1792
|
+
['BB', '5', 'BB', 'AA', 'BB', '5'],
|
|
1793
|
+
['BB', 'AA', '5', 'BB', '5', 'AA']]
|
|
1794
|
+
|
|
1795
|
+
.. TODO::
|
|
1796
|
+
|
|
1797
|
+
The result should be full featured finite enumerated set
|
|
1798
|
+
(e.g., counting can be done much faster than iterating).
|
|
1799
|
+
|
|
1800
|
+
.. SEEALSO::
|
|
1801
|
+
|
|
1802
|
+
:meth:`.reduced_word`, :meth:`.reduced_word_reverse_iterator`,
|
|
1803
|
+
:meth:`length`, :meth:`reduced_word_graph`
|
|
1804
|
+
"""
|
|
1805
|
+
return list(self.reduced_words_iter())
|
|
1806
|
+
|
|
1807
|
+
def support(self):
|
|
1808
|
+
r"""
|
|
1809
|
+
Return the support of ``self``, that is the simple reflections that
|
|
1810
|
+
appear in the reduced expressions of ``self``.
|
|
1811
|
+
|
|
1812
|
+
OUTPUT: the support of ``self`` as a set of integers
|
|
1813
|
+
|
|
1814
|
+
EXAMPLES::
|
|
1815
|
+
|
|
1816
|
+
sage: W = CoxeterGroups().example()
|
|
1817
|
+
sage: w = W.from_reduced_word([1,2,1])
|
|
1818
|
+
sage: w.support()
|
|
1819
|
+
{1, 2}
|
|
1820
|
+
"""
|
|
1821
|
+
return set(self.reduced_word())
|
|
1822
|
+
|
|
1823
|
+
def has_full_support(self) -> bool:
|
|
1824
|
+
r"""
|
|
1825
|
+
Return whether ``self`` has full support.
|
|
1826
|
+
|
|
1827
|
+
An element is said to have full support if its support contains
|
|
1828
|
+
all simple reflections.
|
|
1829
|
+
|
|
1830
|
+
EXAMPLES::
|
|
1831
|
+
|
|
1832
|
+
sage: W = CoxeterGroups().example()
|
|
1833
|
+
sage: w = W.from_reduced_word([1,2,1])
|
|
1834
|
+
sage: w.has_full_support()
|
|
1835
|
+
False
|
|
1836
|
+
sage: w = W.from_reduced_word([1,2,1,0,1])
|
|
1837
|
+
sage: w.has_full_support()
|
|
1838
|
+
True
|
|
1839
|
+
"""
|
|
1840
|
+
return self.support() == set(self.parent().index_set())
|
|
1841
|
+
|
|
1842
|
+
def reduced_word_graph(self):
|
|
1843
|
+
r"""
|
|
1844
|
+
Return the reduced word graph of ``self``.
|
|
1845
|
+
|
|
1846
|
+
The reduced word graph of an element `w` in a Coxeter group
|
|
1847
|
+
is the graph whose vertices are the reduced words for `w`
|
|
1848
|
+
(see :meth:`reduced_word` for a definition of this term),
|
|
1849
|
+
and which has an `m`-colored edge between two reduced words
|
|
1850
|
+
`x` and `y` whenever `x` and `y` differ by exactly one
|
|
1851
|
+
length-`m` braid move (with `m \geq 2`).
|
|
1852
|
+
|
|
1853
|
+
This graph is always connected (a theorem due to Tits) and
|
|
1854
|
+
has no multiple edges.
|
|
1855
|
+
|
|
1856
|
+
EXAMPLES::
|
|
1857
|
+
|
|
1858
|
+
sage: # needs sage.combinat sage.graphs sage.groups
|
|
1859
|
+
sage: W = WeylGroup(['A', 3], prefix='s')
|
|
1860
|
+
sage: w0 = W.long_element()
|
|
1861
|
+
sage: G = w0.reduced_word_graph()
|
|
1862
|
+
sage: G.num_verts()
|
|
1863
|
+
16
|
|
1864
|
+
sage: len(w0.reduced_words())
|
|
1865
|
+
16
|
|
1866
|
+
sage: G.num_edges()
|
|
1867
|
+
18
|
|
1868
|
+
sage: len([e for e in G.edges(sort=False) if e[2] == 2])
|
|
1869
|
+
10
|
|
1870
|
+
sage: len([e for e in G.edges(sort=False) if e[2] == 3])
|
|
1871
|
+
8
|
|
1872
|
+
|
|
1873
|
+
TESTS::
|
|
1874
|
+
|
|
1875
|
+
sage: p = Permutation([3,2,4,1])
|
|
1876
|
+
sage: pp = WeylGroup(['A',3]).from_reduced_word(p.reduced_word()) # needs sage.combinat sage.groups
|
|
1877
|
+
sage: pp.reduced_word_graph() # needs sage.combinat sage.graphs sage.groups
|
|
1878
|
+
Graph on 3 vertices
|
|
1879
|
+
|
|
1880
|
+
sage: # needs sage.combinat sage.graphs sage.groups
|
|
1881
|
+
sage: w1 = W.one()
|
|
1882
|
+
sage: G = w1.reduced_word_graph()
|
|
1883
|
+
sage: G.num_verts()
|
|
1884
|
+
1
|
|
1885
|
+
sage: G.num_edges()
|
|
1886
|
+
0
|
|
1887
|
+
|
|
1888
|
+
.. SEEALSO::
|
|
1889
|
+
|
|
1890
|
+
:meth:`.reduced_words`, :meth:`.reduced_word_reverse_iterator`,
|
|
1891
|
+
:meth:`length`, :meth:`reduced_word`
|
|
1892
|
+
"""
|
|
1893
|
+
R = self.reduced_words()
|
|
1894
|
+
from sage.graphs.graph import Graph
|
|
1895
|
+
# Special case for when the graph does not contain any edges
|
|
1896
|
+
if len(R) == 1:
|
|
1897
|
+
return Graph({tuple(R[0]): []}, immutable=True)
|
|
1898
|
+
|
|
1899
|
+
P = self.parent()
|
|
1900
|
+
edges = []
|
|
1901
|
+
for i, x in enumerate(R):
|
|
1902
|
+
x = tuple(x)
|
|
1903
|
+
for y in R[i:]:
|
|
1904
|
+
y = tuple(y)
|
|
1905
|
+
# Check that the reduced expressions differ by only
|
|
1906
|
+
# a single braid move
|
|
1907
|
+
j = 0
|
|
1908
|
+
while j < len(x) and x[j] == y[j]:
|
|
1909
|
+
j += 1
|
|
1910
|
+
if j == len(x):
|
|
1911
|
+
continue
|
|
1912
|
+
a, b = x[j], y[j]
|
|
1913
|
+
m = P.coxeter_matrix()[a, b]
|
|
1914
|
+
subword = [a, b] * (m // 2)
|
|
1915
|
+
subword2 = [b, a] * (m // 2)
|
|
1916
|
+
if m % 2:
|
|
1917
|
+
subword.append(a)
|
|
1918
|
+
subword2.append(b)
|
|
1919
|
+
if (x[j:j + m] != tuple(subword)
|
|
1920
|
+
or y[j:j + m] != tuple(subword2)
|
|
1921
|
+
or x[j + m:] != y[j + m:]):
|
|
1922
|
+
continue
|
|
1923
|
+
edges.append([x, y, m])
|
|
1924
|
+
G = Graph(edges, immutable=True, format='list_of_edges')
|
|
1925
|
+
colors = {2: 'blue', 3: 'red', 4: 'green'}
|
|
1926
|
+
G.set_latex_options(edge_labels=True,
|
|
1927
|
+
color_by_label=lambda x: colors[x])
|
|
1928
|
+
return G
|
|
1929
|
+
|
|
1930
|
+
def length(self):
|
|
1931
|
+
r"""
|
|
1932
|
+
Return the length of ``self``.
|
|
1933
|
+
|
|
1934
|
+
This is the minimal length of
|
|
1935
|
+
a product of simple reflections giving ``self``.
|
|
1936
|
+
|
|
1937
|
+
EXAMPLES::
|
|
1938
|
+
|
|
1939
|
+
sage: W = CoxeterGroups().example()
|
|
1940
|
+
sage: s1 = W.simple_reflection(1)
|
|
1941
|
+
sage: s2 = W.simple_reflection(2)
|
|
1942
|
+
sage: s1.length()
|
|
1943
|
+
1
|
|
1944
|
+
sage: (s1*s2).length()
|
|
1945
|
+
2
|
|
1946
|
+
sage: W = CoxeterGroups().example()
|
|
1947
|
+
sage: s = W.simple_reflections()
|
|
1948
|
+
sage: w = s[0]*s[1]*s[0]
|
|
1949
|
+
sage: w.length()
|
|
1950
|
+
3
|
|
1951
|
+
sage: W = CoxeterGroups().example()
|
|
1952
|
+
sage: R.<x> = ZZ[]
|
|
1953
|
+
sage: s = sum(x^w.length() for w in W)
|
|
1954
|
+
sage: p = prod(sum(x^i for i in range(j)) for j in range(1, 5))
|
|
1955
|
+
sage: s - p
|
|
1956
|
+
0
|
|
1957
|
+
|
|
1958
|
+
.. SEEALSO::
|
|
1959
|
+
|
|
1960
|
+
:meth:`.reduced_word`
|
|
1961
|
+
|
|
1962
|
+
.. TODO::
|
|
1963
|
+
|
|
1964
|
+
Should use reduced_word_iterator (or reverse_iterator)
|
|
1965
|
+
"""
|
|
1966
|
+
return len(self.reduced_word())
|
|
1967
|
+
|
|
1968
|
+
def reflection_length(self):
|
|
1969
|
+
"""
|
|
1970
|
+
Return the reflection length of ``self``.
|
|
1971
|
+
|
|
1972
|
+
The reflection length is the length of the shortest expression
|
|
1973
|
+
of the element as a product of reflections.
|
|
1974
|
+
|
|
1975
|
+
.. SEEALSO::
|
|
1976
|
+
|
|
1977
|
+
:meth:`absolute_length`
|
|
1978
|
+
|
|
1979
|
+
EXAMPLES::
|
|
1980
|
+
|
|
1981
|
+
sage: W = WeylGroup(['A', 3]) # needs sage.combinat sage.groups
|
|
1982
|
+
sage: s = W.simple_reflections() # needs sage.combinat sage.groups
|
|
1983
|
+
sage: (s[1]*s[2]*s[3]).reflection_length() # needs sage.combinat sage.groups
|
|
1984
|
+
3
|
|
1985
|
+
|
|
1986
|
+
sage: W = SymmetricGroup(4) # needs sage.groups
|
|
1987
|
+
sage: s = W.simple_reflections() # needs sage.groups
|
|
1988
|
+
sage: (s[3]*s[2]*s[3]).reflection_length() # needs sage.combinat sage.groups
|
|
1989
|
+
1
|
|
1990
|
+
"""
|
|
1991
|
+
return self.absolute_length()
|
|
1992
|
+
|
|
1993
|
+
def absolute_length(self):
|
|
1994
|
+
"""
|
|
1995
|
+
Return the absolute length of ``self``.
|
|
1996
|
+
|
|
1997
|
+
The absolute length is the length of the shortest expression
|
|
1998
|
+
of the element as a product of reflections. In general,
|
|
1999
|
+
we use Theorem 1.1 in [Dy2001]_.
|
|
2000
|
+
|
|
2001
|
+
.. SEEALSO::
|
|
2002
|
+
|
|
2003
|
+
:meth:`absolute_le`,
|
|
2004
|
+
:meth:`absolute_chain`
|
|
2005
|
+
|
|
2006
|
+
EXAMPLES::
|
|
2007
|
+
|
|
2008
|
+
sage: W = WeylGroup(["A", 3]) # needs sage.combinat sage.groups
|
|
2009
|
+
sage: s = W.simple_reflections() # needs sage.combinat sage.groups
|
|
2010
|
+
sage: (s[1]*s[2]*s[3]).absolute_length() # needs sage.combinat sage.groups
|
|
2011
|
+
3
|
|
2012
|
+
|
|
2013
|
+
sage: W = SymmetricGroup(4) # needs sage.groups
|
|
2014
|
+
sage: s = W.simple_reflections() # needs sage.groups
|
|
2015
|
+
sage: (s[3]*s[2]*s[1]).absolute_length() # needs sage.combinat sage.groups
|
|
2016
|
+
3
|
|
2017
|
+
|
|
2018
|
+
sage: # needs sage.graphs sage.groups
|
|
2019
|
+
sage: W = CoxeterGroup(["A",2,1])
|
|
2020
|
+
sage: (r, s, t) = W.simple_reflections()
|
|
2021
|
+
sage: (r * s * r * t).absolute_length()
|
|
2022
|
+
2
|
|
2023
|
+
sage: W.one().absolute_length()
|
|
2024
|
+
0
|
|
2025
|
+
sage: r.absolute_length()
|
|
2026
|
+
1
|
|
2027
|
+
sage: (r * s).absolute_length()
|
|
2028
|
+
2
|
|
2029
|
+
sage: (r * s * r).absolute_length()
|
|
2030
|
+
1
|
|
2031
|
+
sage: W = CoxeterGroup(['A', 3, 1])
|
|
2032
|
+
sage: (r, s, t, u) = W.simple_reflections()
|
|
2033
|
+
sage: (r * s * t * u).absolute_length()
|
|
2034
|
+
4
|
|
2035
|
+
sage: (r * s * t * u * s).absolute_length()
|
|
2036
|
+
3
|
|
2037
|
+
"""
|
|
2038
|
+
if self.length() <= 2: # trivial cases
|
|
2039
|
+
return self.length()
|
|
2040
|
+
return len(self.absolute_chain_reflections())
|
|
2041
|
+
|
|
2042
|
+
def absolute_chain(self):
|
|
2043
|
+
r"""
|
|
2044
|
+
Return a (saturated) chain in absolute order from ``1``
|
|
2045
|
+
to ``self``.
|
|
2046
|
+
|
|
2047
|
+
.. SEEALSO::
|
|
2048
|
+
|
|
2049
|
+
:meth:`absolute_chain_reflections`
|
|
2050
|
+
|
|
2051
|
+
EXAMPLES::
|
|
2052
|
+
|
|
2053
|
+
sage: # needs sage.graphs sage.groups
|
|
2054
|
+
sage: W = CoxeterGroup(['A', 2, 1])
|
|
2055
|
+
sage: (r, s, t) = W.simple_reflections()
|
|
2056
|
+
sage: (r * s * r * t).absolute_chain()
|
|
2057
|
+
[
|
|
2058
|
+
[1 0 0] [ 0 -1 2] [ 2 1 -2]
|
|
2059
|
+
[0 1 0] [-1 0 2] [ 1 2 -2]
|
|
2060
|
+
[0 0 1], [ 0 0 1], [ 1 1 -1]
|
|
2061
|
+
]
|
|
2062
|
+
"""
|
|
2063
|
+
reflections = self.absolute_chain_reflections()
|
|
2064
|
+
P = self.parent()
|
|
2065
|
+
return [P.prod(reversed(reflections[:i]))
|
|
2066
|
+
for i in range(len(reflections) + 1)]
|
|
2067
|
+
|
|
2068
|
+
def absolute_chain_reflections(self):
|
|
2069
|
+
r"""
|
|
2070
|
+
Return a list of reflection which, when (left) multiplied in order,
|
|
2071
|
+
give ``self``.
|
|
2072
|
+
|
|
2073
|
+
This method is based on Theorem 1.1 in [Dy2001]_, combined with
|
|
2074
|
+
the strong exchange condition. As an example, if `W` is a type
|
|
2075
|
+
`A_2` Coxeter group with simple reflections `a`, `b`, then the
|
|
2076
|
+
absolute chain reflections for the element `w = ab` is the list
|
|
2077
|
+
`[a, aba]` as `w = (aba) a = ab`.
|
|
2078
|
+
|
|
2079
|
+
.. SEEALSO::
|
|
2080
|
+
|
|
2081
|
+
:meth:`absolute_length`,
|
|
2082
|
+
:meth:`absolute_chain`
|
|
2083
|
+
|
|
2084
|
+
EXAMPLES::
|
|
2085
|
+
|
|
2086
|
+
sage: # needs sage.graphs sage.groups
|
|
2087
|
+
sage: W = CoxeterGroup(["A",2,1])
|
|
2088
|
+
sage: W.one().absolute_chain_reflections()
|
|
2089
|
+
[]
|
|
2090
|
+
sage: (r, s, t) = W.simple_reflections()
|
|
2091
|
+
sage: r.absolute_chain_reflections()
|
|
2092
|
+
[
|
|
2093
|
+
[-1 1 1]
|
|
2094
|
+
[ 0 1 0]
|
|
2095
|
+
[ 0 0 1]
|
|
2096
|
+
]
|
|
2097
|
+
sage: (r * s).absolute_chain_reflections()
|
|
2098
|
+
[
|
|
2099
|
+
[-1 1 1] [ 0 -1 2]
|
|
2100
|
+
[ 0 1 0] [-1 0 2]
|
|
2101
|
+
[ 0 0 1], [ 0 0 1]
|
|
2102
|
+
]
|
|
2103
|
+
sage: (r * s * r * t).absolute_chain_reflections()
|
|
2104
|
+
[
|
|
2105
|
+
[ 0 -1 2] [-1 -2 4]
|
|
2106
|
+
[-1 0 2] [-2 -1 4]
|
|
2107
|
+
[ 0 0 1], [-1 -1 3]
|
|
2108
|
+
]
|
|
2109
|
+
sage: W = CoxeterGroup(['A', 3, 1])
|
|
2110
|
+
sage: (r, s, t, u) = W.simple_reflections()
|
|
2111
|
+
sage: (r * s * t * u).absolute_chain_reflections()
|
|
2112
|
+
[
|
|
2113
|
+
[-1 1 0 1] [ 0 -1 1 1] [ 0 0 -1 2] [-3 2 0 2]
|
|
2114
|
+
[ 0 1 0 0] [-1 0 1 1] [-1 1 -1 2] [-2 2 0 1]
|
|
2115
|
+
[ 0 0 1 0] [ 0 0 1 0] [-1 0 0 2] [-2 1 1 1]
|
|
2116
|
+
[ 0 0 0 1], [ 0 0 0 1], [ 0 0 0 1], [-2 1 0 2]
|
|
2117
|
+
]
|
|
2118
|
+
sage: (r * s * t * u * s).absolute_chain_reflections()
|
|
2119
|
+
[
|
|
2120
|
+
[-1 1 0 1] [ 0 0 -1 2] [-3 2 0 2]
|
|
2121
|
+
[ 0 1 0 0] [-1 1 -1 2] [-2 2 0 1]
|
|
2122
|
+
[ 0 0 1 0] [-1 0 0 2] [-2 1 1 1]
|
|
2123
|
+
[ 0 0 0 1], [ 0 0 0 1], [-2 1 0 2]
|
|
2124
|
+
]
|
|
2125
|
+
"""
|
|
2126
|
+
P = self.parent()
|
|
2127
|
+
if self.is_one():
|
|
2128
|
+
return []
|
|
2129
|
+
w = self.reduced_word()
|
|
2130
|
+
n = len(w)
|
|
2131
|
+
|
|
2132
|
+
if n == 1: # trivial case
|
|
2133
|
+
return [self]
|
|
2134
|
+
if n == 2: # trivial case
|
|
2135
|
+
left_refl = P.simple_reflection(w[0])
|
|
2136
|
+
return [left_refl, self * left_refl]
|
|
2137
|
+
|
|
2138
|
+
import itertools
|
|
2139
|
+
s = P.simple_reflections()
|
|
2140
|
+
rev = P.one()
|
|
2141
|
+
cur = P.one()
|
|
2142
|
+
reflections = []
|
|
2143
|
+
for val in w:
|
|
2144
|
+
cur = cur * s[val]
|
|
2145
|
+
reflections.append(cur * rev)
|
|
2146
|
+
rev = s[val] * rev
|
|
2147
|
+
for ell in range(n):
|
|
2148
|
+
for chain in itertools.combinations(reflections, ell):
|
|
2149
|
+
if P.prod(reversed(chain)) == self:
|
|
2150
|
+
return list(chain)
|
|
2151
|
+
# If we get here it's cause ell == n and so we need all of the
|
|
2152
|
+
# refelctions
|
|
2153
|
+
return reflections
|
|
2154
|
+
|
|
2155
|
+
def absolute_le(self, other):
|
|
2156
|
+
r"""
|
|
2157
|
+
Return whether ``self`` is smaller than ``other`` in the absolute
|
|
2158
|
+
order.
|
|
2159
|
+
|
|
2160
|
+
A general reflection is an element of the form `w s_i w^{-1}`,
|
|
2161
|
+
where `s_i` is a simple reflection. The absolute order is defined
|
|
2162
|
+
analogously to the weak order but using general reflections rather
|
|
2163
|
+
than just simple reflections.
|
|
2164
|
+
|
|
2165
|
+
This partial order can be used to define noncrossing partitions
|
|
2166
|
+
associated with this Coxeter group.
|
|
2167
|
+
|
|
2168
|
+
.. SEEALSO::
|
|
2169
|
+
|
|
2170
|
+
:meth:`absolute_length`
|
|
2171
|
+
|
|
2172
|
+
EXAMPLES::
|
|
2173
|
+
|
|
2174
|
+
sage: # needs sage.combinat sage.groups
|
|
2175
|
+
sage: W = WeylGroup(["A", 3])
|
|
2176
|
+
sage: s = W.simple_reflections()
|
|
2177
|
+
sage: w0 = s[1]
|
|
2178
|
+
sage: w1 = s[1]*s[2]*s[3]
|
|
2179
|
+
sage: w0.absolute_le(w1)
|
|
2180
|
+
True
|
|
2181
|
+
sage: w1.absolute_le(w0)
|
|
2182
|
+
False
|
|
2183
|
+
sage: w1.absolute_le(w1)
|
|
2184
|
+
True
|
|
2185
|
+
|
|
2186
|
+
TESTS:
|
|
2187
|
+
|
|
2188
|
+
Check that this is independent of the implementation of the group, see :issue:`34799`::
|
|
2189
|
+
|
|
2190
|
+
sage: # needs sage.combinat sage.groups
|
|
2191
|
+
sage: W1 = WeylGroup(['A', 2])
|
|
2192
|
+
sage: W2 = Permutations(3)
|
|
2193
|
+
sage: P = lambda pi: W2(list(pi.to_permutation()))
|
|
2194
|
+
sage: d1 = set((P(w1), P(w2)) for w1 in W1 for w2 in W1
|
|
2195
|
+
....: if w1.absolute_le(w2))
|
|
2196
|
+
sage: d2 = set((w1, w2) for w1 in W2 for w2 in W2
|
|
2197
|
+
....: if w1.absolute_le(w2))
|
|
2198
|
+
sage: d1 == d2
|
|
2199
|
+
True
|
|
2200
|
+
sage: sage.combinat.permutation.Permutations.options.mult = "r2l"
|
|
2201
|
+
sage: d3 = set((w1, w2)
|
|
2202
|
+
....: for w1 in W2 for w2 in W2 if w1.absolute_le(w2))
|
|
2203
|
+
sage: d1 == d3
|
|
2204
|
+
True
|
|
2205
|
+
sage: sage.combinat.permutation.Permutations.options._reset()
|
|
2206
|
+
|
|
2207
|
+
sage: # needs sage.combinat sage.groups
|
|
2208
|
+
sage: W1 = WeylGroup(['B', 2])
|
|
2209
|
+
sage: W2 = SignedPermutations(2)
|
|
2210
|
+
sage: P = lambda pi: W2(list(pi.to_permutation()))
|
|
2211
|
+
sage: d1 = set((P(w1), P(w2))
|
|
2212
|
+
....: for w1 in W1 for w2 in W1 if w1.absolute_le(w2))
|
|
2213
|
+
sage: d2 = set((w1, w2)
|
|
2214
|
+
....: for w1 in W2 for w2 in W2 if w1.absolute_le(w2))
|
|
2215
|
+
sage: d1 == d2
|
|
2216
|
+
True
|
|
2217
|
+
"""
|
|
2218
|
+
if self == other:
|
|
2219
|
+
return True
|
|
2220
|
+
if self.absolute_length() >= other.absolute_length():
|
|
2221
|
+
return False
|
|
2222
|
+
return self.absolute_length() + (self.inverse() * other).absolute_length() == other.absolute_length()
|
|
2223
|
+
|
|
2224
|
+
def absolute_covers(self):
|
|
2225
|
+
r"""
|
|
2226
|
+
Return the list of covers of ``self`` in absolute order.
|
|
2227
|
+
|
|
2228
|
+
.. SEEALSO::
|
|
2229
|
+
|
|
2230
|
+
:meth:`absolute_length`
|
|
2231
|
+
|
|
2232
|
+
EXAMPLES::
|
|
2233
|
+
|
|
2234
|
+
sage: # needs sage.combinat sage.groups
|
|
2235
|
+
sage: W = WeylGroup(["A", 3])
|
|
2236
|
+
sage: s = W.simple_reflections()
|
|
2237
|
+
sage: w0 = s[1]
|
|
2238
|
+
sage: w1 = s[1]*s[2]*s[3]
|
|
2239
|
+
sage: list(w0.absolute_covers())
|
|
2240
|
+
[
|
|
2241
|
+
[0 0 1 0] [0 1 0 0] [0 1 0 0] [0 0 0 1] [0 1 0 0]
|
|
2242
|
+
[1 0 0 0] [1 0 0 0] [0 0 1 0] [1 0 0 0] [0 0 0 1]
|
|
2243
|
+
[0 1 0 0] [0 0 0 1] [1 0 0 0] [0 0 1 0] [0 0 1 0]
|
|
2244
|
+
[0 0 0 1], [0 0 1 0], [0 0 0 1], [0 1 0 0], [1 0 0 0]
|
|
2245
|
+
]
|
|
2246
|
+
"""
|
|
2247
|
+
W = self.parent()
|
|
2248
|
+
for t in W.reflections():
|
|
2249
|
+
if self.absolute_length() < (self * t).absolute_length():
|
|
2250
|
+
yield self * t
|
|
2251
|
+
|
|
2252
|
+
def canonical_matrix(self):
|
|
2253
|
+
r"""
|
|
2254
|
+
Return the matrix of ``self`` in the canonical faithful
|
|
2255
|
+
representation.
|
|
2256
|
+
|
|
2257
|
+
This is an `n`-dimension real faithful essential representation,
|
|
2258
|
+
where `n` is the number of generators of the Coxeter group.
|
|
2259
|
+
Note that this is not always the most natural matrix
|
|
2260
|
+
representation, for instance in type `A_n`.
|
|
2261
|
+
|
|
2262
|
+
EXAMPLES::
|
|
2263
|
+
|
|
2264
|
+
sage: W = WeylGroup(["A", 3]) # needs sage.combinat sage.groups
|
|
2265
|
+
sage: s = W.simple_reflections() # needs sage.combinat sage.groups
|
|
2266
|
+
sage: (s[1]*s[2]*s[3]).canonical_matrix() # needs sage.combinat sage.groups
|
|
2267
|
+
[ 0 0 -1]
|
|
2268
|
+
[ 1 0 -1]
|
|
2269
|
+
[ 0 1 -1]
|
|
2270
|
+
"""
|
|
2271
|
+
G = self.parent().canonical_representation()
|
|
2272
|
+
return G.prod(G.simple_reflection(i) for i in self.reduced_word()).matrix()
|
|
2273
|
+
|
|
2274
|
+
def coset_representative(self, index_set, side='right'):
|
|
2275
|
+
r"""
|
|
2276
|
+
Return the unique shortest element of the Coxeter group
|
|
2277
|
+
`W` which is in the same left (resp. right) coset as
|
|
2278
|
+
``self``, with respect to the parabolic subgroup `W_I`.
|
|
2279
|
+
|
|
2280
|
+
INPUT:
|
|
2281
|
+
|
|
2282
|
+
- ``index_set`` -- a subset (or iterable) of the nodes of the Dynkin diagram
|
|
2283
|
+
- ``side`` -- ``'left'`` or ``'right'``
|
|
2284
|
+
|
|
2285
|
+
EXAMPLES::
|
|
2286
|
+
|
|
2287
|
+
sage: W = CoxeterGroups().example(5)
|
|
2288
|
+
sage: s = W.simple_reflections()
|
|
2289
|
+
sage: w = s[2]*s[1]*s[3]
|
|
2290
|
+
sage: w.coset_representative([]).reduced_word()
|
|
2291
|
+
[2, 3, 1]
|
|
2292
|
+
sage: w.coset_representative([1]).reduced_word()
|
|
2293
|
+
[2, 3]
|
|
2294
|
+
sage: w.coset_representative([1,2]).reduced_word()
|
|
2295
|
+
[2, 3]
|
|
2296
|
+
sage: w.coset_representative([1,3] ).reduced_word()
|
|
2297
|
+
[2]
|
|
2298
|
+
sage: w.coset_representative([2,3] ).reduced_word()
|
|
2299
|
+
[2, 1]
|
|
2300
|
+
sage: w.coset_representative([1,2,3] ).reduced_word()
|
|
2301
|
+
[]
|
|
2302
|
+
sage: w.coset_representative([], side='left').reduced_word()
|
|
2303
|
+
[2, 3, 1]
|
|
2304
|
+
sage: w.coset_representative([1], side='left').reduced_word()
|
|
2305
|
+
[2, 3, 1]
|
|
2306
|
+
sage: w.coset_representative([1,2], side='left').reduced_word()
|
|
2307
|
+
[3]
|
|
2308
|
+
sage: w.coset_representative([1,3], side='left').reduced_word()
|
|
2309
|
+
[2, 3, 1]
|
|
2310
|
+
sage: w.coset_representative([2,3], side='left').reduced_word()
|
|
2311
|
+
[1]
|
|
2312
|
+
sage: w.coset_representative([1,2,3], side='left').reduced_word()
|
|
2313
|
+
[]
|
|
2314
|
+
"""
|
|
2315
|
+
while True:
|
|
2316
|
+
i = self.first_descent(side=side, index_set=index_set)
|
|
2317
|
+
if i is None:
|
|
2318
|
+
return self
|
|
2319
|
+
self = self.apply_simple_reflection(i, side=side)
|
|
2320
|
+
|
|
2321
|
+
def apply_simple_projection(self, i, side='right', length_increasing=True):
|
|
2322
|
+
r"""
|
|
2323
|
+
Return the result of the application of the simple
|
|
2324
|
+
projection `\pi_i` (resp. `\overline\pi_i`) on ``self``.
|
|
2325
|
+
|
|
2326
|
+
INPUT:
|
|
2327
|
+
|
|
2328
|
+
- ``i`` -- an element of the index set of the Coxeter group
|
|
2329
|
+
- ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``)
|
|
2330
|
+
- ``length_increasing`` -- boolean (default: ``True``);
|
|
2331
|
+
specifying the direction of the projection
|
|
2332
|
+
|
|
2333
|
+
See :meth:`CoxeterGroups.ParentMethods.simple_projections`
|
|
2334
|
+
for the definition of the simple projections.
|
|
2335
|
+
|
|
2336
|
+
EXAMPLES::
|
|
2337
|
+
|
|
2338
|
+
sage: W = CoxeterGroups().example()
|
|
2339
|
+
sage: w = W.an_element()
|
|
2340
|
+
sage: w
|
|
2341
|
+
(1, 2, 3, 0)
|
|
2342
|
+
sage: w.apply_simple_projection(2)
|
|
2343
|
+
(1, 2, 3, 0)
|
|
2344
|
+
sage: w.apply_simple_projection(2, length_increasing=False)
|
|
2345
|
+
(1, 2, 0, 3)
|
|
2346
|
+
|
|
2347
|
+
sage: # needs sage.combinat sage.groups
|
|
2348
|
+
sage: W = WeylGroup(['C', 4], prefix='s')
|
|
2349
|
+
sage: v = W.from_reduced_word([1,2,3,4,3,1])
|
|
2350
|
+
sage: v
|
|
2351
|
+
s1*s2*s3*s4*s3*s1
|
|
2352
|
+
sage: v.apply_simple_projection(2)
|
|
2353
|
+
s1*s2*s3*s4*s3*s1*s2
|
|
2354
|
+
sage: v.apply_simple_projection(2, side='left')
|
|
2355
|
+
s1*s2*s3*s4*s3*s1
|
|
2356
|
+
sage: v.apply_simple_projection(1, length_increasing=False)
|
|
2357
|
+
s1*s2*s3*s4*s3
|
|
2358
|
+
"""
|
|
2359
|
+
if self.has_descent(i, side=side, positive=length_increasing):
|
|
2360
|
+
return self.apply_simple_reflection(i, side=side)
|
|
2361
|
+
return self
|
|
2362
|
+
|
|
2363
|
+
def binary_factorizations(self, predicate=ConstantFunction(True)):
|
|
2364
|
+
"""
|
|
2365
|
+
Return the set of all the factorizations `self = u v` such
|
|
2366
|
+
that `l(self) = l(u) + l(v)`.
|
|
2367
|
+
|
|
2368
|
+
Iterating through this set is Constant Amortized Time
|
|
2369
|
+
(counting arithmetic operations in the Coxeter group as
|
|
2370
|
+
constant time) complexity, and memory linear in the length
|
|
2371
|
+
of ``self``.
|
|
2372
|
+
|
|
2373
|
+
One can pass as optional argument a predicate p such that
|
|
2374
|
+
`p(u)` implies `p(u')` for any `u` left factor of ``self``
|
|
2375
|
+
and `u'` left factor of `u`. Then this returns only the
|
|
2376
|
+
factorizations `self = uv` such `p(u)` holds.
|
|
2377
|
+
|
|
2378
|
+
EXAMPLES:
|
|
2379
|
+
|
|
2380
|
+
We construct the set of all factorizations of the maximal
|
|
2381
|
+
element of the group::
|
|
2382
|
+
|
|
2383
|
+
sage: # needs sage.combinat sage.groups
|
|
2384
|
+
sage: W = WeylGroup(['A', 3])
|
|
2385
|
+
sage: s = W.simple_reflections()
|
|
2386
|
+
sage: w0 = W.from_reduced_word([1,2,3,1,2,1])
|
|
2387
|
+
sage: w0.binary_factorizations().cardinality()
|
|
2388
|
+
24
|
|
2389
|
+
|
|
2390
|
+
The same number of factorizations, by bounded length::
|
|
2391
|
+
|
|
2392
|
+
sage: [w0.binary_factorizations( # needs sage.combinat sage.groups
|
|
2393
|
+
....: lambda u: u.length() <= l
|
|
2394
|
+
....: ).cardinality()
|
|
2395
|
+
....: for l in [-1,0,1,2,3,4,5,6]]
|
|
2396
|
+
[0, 1, 4, 9, 15, 20, 23, 24]
|
|
2397
|
+
|
|
2398
|
+
The number of factorizations of the elements just below
|
|
2399
|
+
the maximal element::
|
|
2400
|
+
|
|
2401
|
+
sage: [(s[i]*w0).binary_factorizations().cardinality() # needs sage.combinat sage.groups
|
|
2402
|
+
....: for i in [1,2,3]]
|
|
2403
|
+
[12, 12, 12]
|
|
2404
|
+
sage: w0.binary_factorizations(lambda u: False).cardinality() # needs sage.combinat sage.groups
|
|
2405
|
+
0
|
|
2406
|
+
|
|
2407
|
+
TESTS::
|
|
2408
|
+
|
|
2409
|
+
sage: w0.binary_factorizations().category() # needs sage.combinat sage.groups
|
|
2410
|
+
Category of finite enumerated sets
|
|
2411
|
+
|
|
2412
|
+
Check that this is independent of the implementation of the group, see :issue:`34799`::
|
|
2413
|
+
|
|
2414
|
+
sage: # needs sage.combinat sage.groups
|
|
2415
|
+
sage: W1 = WeylGroup(['A', 3])
|
|
2416
|
+
sage: W2 = Permutations(4)
|
|
2417
|
+
sage: P = lambda pi: W2(list(pi.to_permutation()))
|
|
2418
|
+
sage: d1 = {P(pi): set((P(w[0]), P(w[1]))
|
|
2419
|
+
....: for w in pi.binary_factorizations())
|
|
2420
|
+
....: for pi in W1}
|
|
2421
|
+
sage: d2 = {pi: set(pi.binary_factorizations()) for pi in W2}
|
|
2422
|
+
sage: d1 == d2
|
|
2423
|
+
True
|
|
2424
|
+
sage: sage.combinat.permutation.Permutations.options.mult = "r2l"
|
|
2425
|
+
sage: d3 = {pi: set(pi.binary_factorizations()) for pi in W2}
|
|
2426
|
+
sage: d1 == d3
|
|
2427
|
+
True
|
|
2428
|
+
sage: sage.combinat.permutation.Permutations.options._reset()
|
|
2429
|
+
"""
|
|
2430
|
+
from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
2431
|
+
W = self.parent()
|
|
2432
|
+
if not predicate(W.one()):
|
|
2433
|
+
from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
|
|
2434
|
+
return FiniteEnumeratedSet([])
|
|
2435
|
+
|
|
2436
|
+
def succ(u_v):
|
|
2437
|
+
u, v = u_v
|
|
2438
|
+
for i in v.descents(side='left'):
|
|
2439
|
+
u1 = u.apply_simple_reflection_right(i)
|
|
2440
|
+
if i == u1.first_descent() and predicate(u1):
|
|
2441
|
+
yield u1, v.apply_simple_reflection_left(i)
|
|
2442
|
+
return RecursivelyEnumeratedSet_forest(((W.one(), self),), succ,
|
|
2443
|
+
category=FiniteEnumeratedSets())
|
|
2444
|
+
|
|
2445
|
+
@cached_in_parent_method
|
|
2446
|
+
def bruhat_lower_covers(self):
|
|
2447
|
+
r"""
|
|
2448
|
+
Return all elements that ``self`` covers in (strong) Bruhat order.
|
|
2449
|
+
|
|
2450
|
+
If ``w = self`` has a descent at `i`, then the elements that
|
|
2451
|
+
`w` covers are exactly `\{ws_i, u_1s_i, u_2s_i,..., u_js_i\}`,
|
|
2452
|
+
where the `u_k` are elements that `ws_i` covers that also
|
|
2453
|
+
do not have a descent at `i`.
|
|
2454
|
+
|
|
2455
|
+
EXAMPLES::
|
|
2456
|
+
|
|
2457
|
+
sage: W = WeylGroup(["A", 3]) # needs sage.combinat sage.groups
|
|
2458
|
+
sage: w = W.from_reduced_word([3,2,3]) # needs sage.combinat sage.groups
|
|
2459
|
+
sage: print([v.reduced_word() for v in w.bruhat_lower_covers()]) # needs sage.combinat sage.groups
|
|
2460
|
+
[[3, 2], [2, 3]]
|
|
2461
|
+
|
|
2462
|
+
sage: # needs sage.combinat sage.groups
|
|
2463
|
+
sage: W = WeylGroup(["A", 3])
|
|
2464
|
+
sage: print([v.reduced_word()
|
|
2465
|
+
....: for v in W.simple_reflection(1).bruhat_lower_covers()])
|
|
2466
|
+
[[]]
|
|
2467
|
+
sage: print([v.reduced_word()
|
|
2468
|
+
....: for v in W.one().bruhat_lower_covers()])
|
|
2469
|
+
[]
|
|
2470
|
+
sage: W = WeylGroup(["B", 4, 1])
|
|
2471
|
+
sage: w = W.from_reduced_word([0,2])
|
|
2472
|
+
sage: print([v.reduced_word() for v in w.bruhat_lower_covers()])
|
|
2473
|
+
[[2], [0]]
|
|
2474
|
+
sage: W = WeylGroup("A3", prefix='s', implementation='permutation')
|
|
2475
|
+
sage: s1, s2, s3 = W.simple_reflections()
|
|
2476
|
+
sage: (s1*s2*s3*s1).bruhat_lower_covers()
|
|
2477
|
+
[s2*s1*s3, s1*s2*s1, s1*s2*s3]
|
|
2478
|
+
|
|
2479
|
+
We now show how to construct the Bruhat poset::
|
|
2480
|
+
|
|
2481
|
+
sage: # needs sage.combinat sage.groups
|
|
2482
|
+
sage: W = WeylGroup(["A", 3])
|
|
2483
|
+
sage: covers = tuple([u, v]
|
|
2484
|
+
....: for v in W for u in v.bruhat_lower_covers())
|
|
2485
|
+
sage: P = Poset((W, covers), cover_relations=True) # needs sage.graphs
|
|
2486
|
+
sage: P.show() # needs sage.graphs sage.plot
|
|
2487
|
+
|
|
2488
|
+
Alternatively, one can just use::
|
|
2489
|
+
|
|
2490
|
+
sage: P = W.bruhat_poset() # needs sage.combinat sage.graphs sage.groups
|
|
2491
|
+
|
|
2492
|
+
The algorithm is taken from Stembridge's 'coxeter/weyl' package for Maple.
|
|
2493
|
+
"""
|
|
2494
|
+
desc = self.first_descent(side='right')
|
|
2495
|
+
if desc is None:
|
|
2496
|
+
return []
|
|
2497
|
+
ww = self.apply_simple_reflection(desc, side='right')
|
|
2498
|
+
return [u.apply_simple_reflection(desc, side='right') for u in ww.bruhat_lower_covers() if not u.has_descent(desc, side='right')] + [ww]
|
|
2499
|
+
|
|
2500
|
+
@cached_in_parent_method
|
|
2501
|
+
def bruhat_upper_covers(self):
|
|
2502
|
+
r"""
|
|
2503
|
+
Return all elements that cover ``self`` in (strong) Bruhat order.
|
|
2504
|
+
|
|
2505
|
+
The algorithm works recursively, using the 'inverse' of the method described for
|
|
2506
|
+
lower covers :meth:`bruhat_lower_covers`. Namely, it runs through all `i` in the
|
|
2507
|
+
index set. Let `w` equal ``self``. If `w` has no right descent `i`, then `w s_i` is a cover;
|
|
2508
|
+
if `w` has a decent at `i`, then `u_j s_i` is a cover of `w` where `u_j` is a cover
|
|
2509
|
+
of `w s_i`.
|
|
2510
|
+
|
|
2511
|
+
EXAMPLES::
|
|
2512
|
+
|
|
2513
|
+
sage: W = WeylGroup(['A', 3, 1], prefix='s') # needs sage.combinat sage.groups
|
|
2514
|
+
sage: w = W.from_reduced_word([1,2,1]) # needs sage.combinat sage.groups
|
|
2515
|
+
sage: w.bruhat_upper_covers() # needs sage.combinat sage.groups
|
|
2516
|
+
[s1*s2*s1*s0, s1*s2*s0*s1, s0*s1*s2*s1, s3*s1*s2*s1, s2*s3*s1*s2, s1*s2*s3*s1]
|
|
2517
|
+
|
|
2518
|
+
sage: W = WeylGroup(['A', 3]) # needs sage.combinat sage.groups
|
|
2519
|
+
sage: w = W.long_element() # needs sage.combinat sage.groups
|
|
2520
|
+
sage: w.bruhat_upper_covers() # needs sage.combinat sage.groups
|
|
2521
|
+
[]
|
|
2522
|
+
|
|
2523
|
+
sage: # needs sage.combinat sage.groups
|
|
2524
|
+
sage: W = WeylGroup(['A', 3])
|
|
2525
|
+
sage: w = W.from_reduced_word([1,2,1])
|
|
2526
|
+
sage: S = [v for v in W if w in v.bruhat_lower_covers()]
|
|
2527
|
+
sage: C = w.bruhat_upper_covers()
|
|
2528
|
+
sage: set(S) == set(C)
|
|
2529
|
+
True
|
|
2530
|
+
"""
|
|
2531
|
+
Covers = set()
|
|
2532
|
+
for i in self.parent().index_set():
|
|
2533
|
+
if i in self.descents(side='right'):
|
|
2534
|
+
Covers.update(x.apply_simple_reflection(i, side='right')
|
|
2535
|
+
for x in self.apply_simple_reflection(i, side='right').bruhat_upper_covers()
|
|
2536
|
+
if i not in x.descents(side='right'))
|
|
2537
|
+
else:
|
|
2538
|
+
Covers.add(self.apply_simple_reflection(i, side='right'))
|
|
2539
|
+
return sorted(Covers)
|
|
2540
|
+
|
|
2541
|
+
@cached_in_parent_method
|
|
2542
|
+
def bruhat_lower_covers_reflections(self):
|
|
2543
|
+
r"""
|
|
2544
|
+
Return all 2-tuples of lower_covers and reflections (``v``, ``r``) where ``v`` is covered by ``self`` and ``r`` is the reflection such that ``self`` = ``v`` ``r``.
|
|
2545
|
+
|
|
2546
|
+
ALGORITHM:
|
|
2547
|
+
|
|
2548
|
+
See :meth:`.bruhat_lower_covers`
|
|
2549
|
+
|
|
2550
|
+
EXAMPLES::
|
|
2551
|
+
|
|
2552
|
+
sage: W = WeylGroup(['A', 3], prefix='s') # needs sage.combinat sage.groups
|
|
2553
|
+
sage: w = W.from_reduced_word([3,1,2,1]) # needs sage.combinat sage.groups
|
|
2554
|
+
sage: w.bruhat_lower_covers_reflections() # needs sage.combinat sage.groups
|
|
2555
|
+
[(s1*s2*s1, s1*s2*s3*s2*s1), (s3*s2*s1, s2), (s3*s1*s2, s1)]
|
|
2556
|
+
|
|
2557
|
+
TESTS:
|
|
2558
|
+
|
|
2559
|
+
Check bug discovered in :issue:`32669` is fixed::
|
|
2560
|
+
|
|
2561
|
+
sage: W = CoxeterGroup(['A', 3], implementation='permutation') # needs sage.combinat sage.groups
|
|
2562
|
+
sage: W.w0.bruhat_lower_covers_reflections() # needs sage.combinat sage.groups
|
|
2563
|
+
[((1,3,7,9)(2,11,6,10)(4,8,5,12), (2,5)(3,9)(4,6)(8,11)(10,12)),
|
|
2564
|
+
((1,11)(3,10)(4,9)(5,7)(6,12), (1,4)(2,8)(3,5)(7,10)(9,11)),
|
|
2565
|
+
((1,9,7,3)(2,10,6,11)(4,12,5,8), (1,7)(2,4)(5,6)(8,10)(11,12))]
|
|
2566
|
+
"""
|
|
2567
|
+
i = self.first_descent(side='right')
|
|
2568
|
+
if i is None:
|
|
2569
|
+
return []
|
|
2570
|
+
wi = self.apply_simple_reflection(i, side='right')
|
|
2571
|
+
return [(u.apply_simple_reflection(i, side='right'),
|
|
2572
|
+
r.apply_conjugation_by_simple_reflection(i))
|
|
2573
|
+
for u, r in wi.bruhat_lower_covers_reflections()
|
|
2574
|
+
if not u.has_descent(i, side='right')] + [
|
|
2575
|
+
(wi, self.parent().simple_reflection(i))]
|
|
2576
|
+
|
|
2577
|
+
def lower_cover_reflections(self, side='right'):
|
|
2578
|
+
r"""
|
|
2579
|
+
Return the reflections ``t`` such that ``self`` covers ``self`` ``t``.
|
|
2580
|
+
|
|
2581
|
+
If ``side`` is 'left', ``self`` covers ``t`` ``self``.
|
|
2582
|
+
|
|
2583
|
+
EXAMPLES::
|
|
2584
|
+
|
|
2585
|
+
sage: # needs sage.combinat sage.groups
|
|
2586
|
+
sage: W = WeylGroup(['A', 3],prefix='s')
|
|
2587
|
+
sage: w = W.from_reduced_word([3,1,2,1])
|
|
2588
|
+
sage: w.lower_cover_reflections()
|
|
2589
|
+
[s1*s2*s3*s2*s1, s2, s1]
|
|
2590
|
+
sage: w.lower_cover_reflections(side='left')
|
|
2591
|
+
[s2*s3*s2, s3, s1]
|
|
2592
|
+
"""
|
|
2593
|
+
if side == 'left':
|
|
2594
|
+
self = self.inverse()
|
|
2595
|
+
return [x[1] for x in self.bruhat_lower_covers_reflections()]
|
|
2596
|
+
|
|
2597
|
+
@cached_in_parent_method
|
|
2598
|
+
def bruhat_upper_covers_reflections(self):
|
|
2599
|
+
r"""
|
|
2600
|
+
Return all 2-tuples of covers and reflections (``v``, ``r``) where ``v`` covers ``self`` and ``r`` is the reflection such that ``self`` = ``v`` ``r``.
|
|
2601
|
+
|
|
2602
|
+
ALGORITHM:
|
|
2603
|
+
|
|
2604
|
+
See :meth:`.bruhat_upper_covers`
|
|
2605
|
+
|
|
2606
|
+
EXAMPLES::
|
|
2607
|
+
|
|
2608
|
+
sage: W = WeylGroup(['A', 4], prefix='s') # needs sage.combinat sage.groups
|
|
2609
|
+
sage: w = W.from_reduced_word([3,1,2,1]) # needs sage.combinat sage.groups
|
|
2610
|
+
sage: w.bruhat_upper_covers_reflections() # needs sage.combinat sage.groups
|
|
2611
|
+
[(s1*s2*s3*s2*s1, s3), (s2*s3*s1*s2*s1, s2*s3*s2),
|
|
2612
|
+
(s3*s4*s1*s2*s1, s4), (s4*s3*s1*s2*s1, s1*s2*s3*s4*s3*s2*s1)]
|
|
2613
|
+
"""
|
|
2614
|
+
Covers = set()
|
|
2615
|
+
for i in self.parent().index_set():
|
|
2616
|
+
wi = self.apply_simple_reflection(i)
|
|
2617
|
+
if i in self.descents():
|
|
2618
|
+
Covers.update((u.apply_simple_reflection(i), r.apply_conjugation_by_simple_reflection(i))
|
|
2619
|
+
for u, r in wi.bruhat_upper_covers_reflections() if i not in u.descents())
|
|
2620
|
+
else:
|
|
2621
|
+
Covers.add((wi, self.parent().simple_reflection(i)))
|
|
2622
|
+
return sorted(Covers)
|
|
2623
|
+
|
|
2624
|
+
def cover_reflections(self, side='right'):
|
|
2625
|
+
r"""
|
|
2626
|
+
Return the set of reflections ``t`` such that ``self`` ``t`` covers ``self``.
|
|
2627
|
+
|
|
2628
|
+
If ``side`` is 'left', ``t`` ``self`` covers ``self``.
|
|
2629
|
+
|
|
2630
|
+
EXAMPLES::
|
|
2631
|
+
|
|
2632
|
+
sage: # needs sage.combinat sage.groups
|
|
2633
|
+
sage: W = WeylGroup(['A', 4], prefix='s')
|
|
2634
|
+
sage: w = W.from_reduced_word([3,1,2,1])
|
|
2635
|
+
sage: w.cover_reflections()
|
|
2636
|
+
[s3, s2*s3*s2, s4, s1*s2*s3*s4*s3*s2*s1]
|
|
2637
|
+
sage: w.cover_reflections(side='left')
|
|
2638
|
+
[s4, s2, s1*s2*s1, s3*s4*s3]
|
|
2639
|
+
"""
|
|
2640
|
+
if side == 'left':
|
|
2641
|
+
self = self.inverse()
|
|
2642
|
+
return [x[1] for x in self.bruhat_upper_covers_reflections()]
|
|
2643
|
+
|
|
2644
|
+
@cached_in_parent_method
|
|
2645
|
+
def bruhat_le(self, other):
|
|
2646
|
+
"""
|
|
2647
|
+
Return whether ``self`` <= ``other`` in the Bruhat order.
|
|
2648
|
+
|
|
2649
|
+
INPUT:
|
|
2650
|
+
|
|
2651
|
+
- ``other`` -- an element of the same Coxeter group
|
|
2652
|
+
|
|
2653
|
+
OUTPUT: boolean
|
|
2654
|
+
|
|
2655
|
+
EXAMPLES::
|
|
2656
|
+
|
|
2657
|
+
sage: # needs sage.combinat sage.groups
|
|
2658
|
+
sage: W = WeylGroup(["A", 3])
|
|
2659
|
+
sage: u = W.from_reduced_word([1,2,1])
|
|
2660
|
+
sage: v = W.from_reduced_word([1,2,3,2,1])
|
|
2661
|
+
sage: u.bruhat_le(u)
|
|
2662
|
+
True
|
|
2663
|
+
sage: u.bruhat_le(v)
|
|
2664
|
+
True
|
|
2665
|
+
sage: v.bruhat_le(u)
|
|
2666
|
+
False
|
|
2667
|
+
sage: v.bruhat_le(v)
|
|
2668
|
+
True
|
|
2669
|
+
sage: s = W.simple_reflections()
|
|
2670
|
+
sage: s[1].bruhat_le(W.one())
|
|
2671
|
+
False
|
|
2672
|
+
|
|
2673
|
+
The implementation uses the equivalent condition that any
|
|
2674
|
+
reduced word for ``other`` contains a reduced word for
|
|
2675
|
+
``self`` as subword. See Stembridge, A short derivation of
|
|
2676
|
+
the Möbius function for the Bruhat order. J. Algebraic
|
|
2677
|
+
Combinatoric 25 (2007), no. 2, 141--148, Proposition 1.1.
|
|
2678
|
+
|
|
2679
|
+
Complexity: `O(l * c)`, where `l` is the minimum of the
|
|
2680
|
+
lengths of `u` and of `v`, and `c` is the cost of the low
|
|
2681
|
+
level methods :meth:`first_descent`, :meth:`has_descent`,
|
|
2682
|
+
:meth:`~sage.categories.complex_reflection_or_generalized_coxeter_groups.ComplexReflectionOrGeneralizedCoxeterGroups.ElementMethods.apply_simple_reflection`),
|
|
2683
|
+
etc. Those are typically `O(n)`, where `n` is the rank of the
|
|
2684
|
+
Coxeter group.
|
|
2685
|
+
|
|
2686
|
+
TESTS:
|
|
2687
|
+
|
|
2688
|
+
We now run consistency tests with permutations and
|
|
2689
|
+
:meth:`bruhat_lower_covers`::
|
|
2690
|
+
|
|
2691
|
+
sage: W = WeylGroup(["A", 3]) # needs sage.combinat sage.groups
|
|
2692
|
+
sage: P4 = Permutations(4)
|
|
2693
|
+
sage: def P4toW(w): return W.from_reduced_word(w.reduced_word())
|
|
2694
|
+
sage: for u in P4: # needs sage.combinat sage.groups
|
|
2695
|
+
....: for v in P4:
|
|
2696
|
+
....: assert u.bruhat_lequal(v) == P4toW(u).bruhat_le(P4toW(v))
|
|
2697
|
+
|
|
2698
|
+
sage: # needs sage.combinat sage.graphs sage.groups
|
|
2699
|
+
sage: W = WeylGroup(["B", 3])
|
|
2700
|
+
sage: P = W.bruhat_poset() # This is built from bruhat_lower_covers
|
|
2701
|
+
sage: Q = Poset((W, attrcall("bruhat_le"))) # long time (10s)
|
|
2702
|
+
sage: all(u.bruhat_le(v) == P.is_lequal(u,v) # long time (7s)
|
|
2703
|
+
....: for u in W for v in W)
|
|
2704
|
+
True
|
|
2705
|
+
sage: all(P.is_lequal(u,v) == Q.is_lequal(u,v) # long time (9s)
|
|
2706
|
+
....: for u in W for v in W)
|
|
2707
|
+
True
|
|
2708
|
+
"""
|
|
2709
|
+
if not have_same_parent(self, other):
|
|
2710
|
+
raise TypeError("%s and %s do not have the same parent" % (self, other))
|
|
2711
|
+
# could first compare the length, when that information is cheap
|
|
2712
|
+
desc = other.first_descent()
|
|
2713
|
+
if desc is not None:
|
|
2714
|
+
return self.apply_simple_projection(desc, length_increasing=False).bruhat_le(other.apply_simple_reflection(desc))
|
|
2715
|
+
return self == other
|
|
2716
|
+
|
|
2717
|
+
@cached_in_parent_method
|
|
2718
|
+
def weak_le(self, other, side='right'):
|
|
2719
|
+
r"""
|
|
2720
|
+
Perform the comparison between ``self`` and ``other`` in
|
|
2721
|
+
weak (Bruhat) order.
|
|
2722
|
+
|
|
2723
|
+
INPUT:
|
|
2724
|
+
|
|
2725
|
+
- ``other`` -- an element of the same Coxeter group
|
|
2726
|
+
- ``side`` -- string (default: ``'right'``); ``'left'`` or ``'right'``
|
|
2727
|
+
|
|
2728
|
+
OUTPUT: boolean
|
|
2729
|
+
|
|
2730
|
+
This returns whether `u \leq v`, where `u` is ``self`` and `v`
|
|
2731
|
+
is ``other``, in left (resp. right) weak order, that is if `v`
|
|
2732
|
+
can be obtained from `u` by length increasing multiplication by
|
|
2733
|
+
simple reflections on the left (resp. right).
|
|
2734
|
+
|
|
2735
|
+
EXAMPLES::
|
|
2736
|
+
|
|
2737
|
+
sage: # needs sage.combinat sage.groups
|
|
2738
|
+
sage: W = WeylGroup(["A", 3])
|
|
2739
|
+
sage: u = W.from_reduced_word([1,2])
|
|
2740
|
+
sage: v = W.from_reduced_word([1,2,3,2])
|
|
2741
|
+
sage: u.weak_le(u)
|
|
2742
|
+
True
|
|
2743
|
+
sage: u.weak_le(v)
|
|
2744
|
+
True
|
|
2745
|
+
sage: v.weak_le(u)
|
|
2746
|
+
False
|
|
2747
|
+
sage: v.weak_le(v)
|
|
2748
|
+
True
|
|
2749
|
+
|
|
2750
|
+
Comparison for left weak order is achieved with the option ``side``::
|
|
2751
|
+
|
|
2752
|
+
sage: u.weak_le(v, side='left') # needs sage.combinat sage.groups
|
|
2753
|
+
False
|
|
2754
|
+
|
|
2755
|
+
The implementation uses the equivalent condition that any
|
|
2756
|
+
reduced word for `u` is a right (resp. left) prefix of
|
|
2757
|
+
some reduced word for `v`.
|
|
2758
|
+
|
|
2759
|
+
Complexity: `O(l * c)`, where `l` is the minimum of the
|
|
2760
|
+
lengths of `u` and of `v`, and `c` is the cost of the low
|
|
2761
|
+
level methods :meth:`first_descent`, :meth:`has_descent`,
|
|
2762
|
+
:meth:`~sage.categories.complex_reflection_or_generalized_coxeter_groups.ComplexReflectionOrGeneralizedCoxeterGroups.ElementMethods.apply_simple_reflection`),
|
|
2763
|
+
etc. Those are typically `O(n)`, where `n` is the rank of the
|
|
2764
|
+
Coxeter group.
|
|
2765
|
+
|
|
2766
|
+
We now run consistency tests with permutations::
|
|
2767
|
+
|
|
2768
|
+
sage: W = WeylGroup(["A", 3]) # needs sage.combinat sage.groups
|
|
2769
|
+
sage: P4 = Permutations(4)
|
|
2770
|
+
sage: def P4toW(w): return W.from_reduced_word(w.reduced_word())
|
|
2771
|
+
sage: for u in P4: # long time (5s on sage.math, 2011), needs sage.combinat sage.groups
|
|
2772
|
+
....: for v in P4:
|
|
2773
|
+
....: assert u.permutohedron_lequal(v) == P4toW(u).weak_le(P4toW(v))
|
|
2774
|
+
....: assert u.permutohedron_lequal(v, side='left') == P4toW(u).weak_le(P4toW(v), side='left')
|
|
2775
|
+
"""
|
|
2776
|
+
if not have_same_parent(self, other):
|
|
2777
|
+
raise TypeError(f"{self} and {other} do not have the same parent")
|
|
2778
|
+
# could first compare the length, when that information is cheap
|
|
2779
|
+
prefix_side = 'left' if side == 'right' else 'right'
|
|
2780
|
+
|
|
2781
|
+
while True:
|
|
2782
|
+
desc = self.first_descent(side=prefix_side)
|
|
2783
|
+
if desc is None:
|
|
2784
|
+
return True
|
|
2785
|
+
if not other.has_descent(desc, side=prefix_side):
|
|
2786
|
+
return False
|
|
2787
|
+
self = self.apply_simple_reflection(desc, side=prefix_side)
|
|
2788
|
+
other = other.apply_simple_reflection(desc, side=prefix_side)
|
|
2789
|
+
|
|
2790
|
+
def weak_covers(self, side='right', index_set=None, positive=False):
|
|
2791
|
+
"""
|
|
2792
|
+
Return all elements that ``self`` covers in weak order.
|
|
2793
|
+
|
|
2794
|
+
INPUT:
|
|
2795
|
+
|
|
2796
|
+
- ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``)
|
|
2797
|
+
- ``positive`` -- boolean (default: ``False``)
|
|
2798
|
+
- ``index_set`` -- list of indices or None
|
|
2799
|
+
|
|
2800
|
+
OUTPUT: list
|
|
2801
|
+
|
|
2802
|
+
EXAMPLES::
|
|
2803
|
+
|
|
2804
|
+
sage: W = WeylGroup(['A', 3]) # needs sage.combinat sage.groups
|
|
2805
|
+
sage: w = W.from_reduced_word([3,2,1]) # needs sage.combinat sage.groups
|
|
2806
|
+
sage: [x.reduced_word() for x in w.weak_covers()] # needs sage.combinat sage.groups
|
|
2807
|
+
[[3, 2]]
|
|
2808
|
+
|
|
2809
|
+
To obtain instead elements that cover self, set ``positive=True``::
|
|
2810
|
+
|
|
2811
|
+
sage: [x.reduced_word() for x in w.weak_covers(positive=True)] # needs sage.combinat sage.groups
|
|
2812
|
+
[[3, 1, 2, 1], [2, 3, 2, 1]]
|
|
2813
|
+
|
|
2814
|
+
To obtain covers for left weak order, set the option side to 'left'::
|
|
2815
|
+
|
|
2816
|
+
sage: # needs sage.combinat sage.groups
|
|
2817
|
+
sage: [x.reduced_word() for x in w.weak_covers(side='left')]
|
|
2818
|
+
[[2, 1]]
|
|
2819
|
+
sage: w = W.from_reduced_word([3,2,3,1])
|
|
2820
|
+
sage: [x.reduced_word() for x in w.weak_covers()]
|
|
2821
|
+
[[2, 3, 2], [3, 2, 1]]
|
|
2822
|
+
sage: [x.reduced_word() for x in w.weak_covers(side='left')]
|
|
2823
|
+
[[3, 2, 1], [2, 3, 1]]
|
|
2824
|
+
|
|
2825
|
+
Covers w.r.t. a parabolic subgroup are obtained with the option ``index_set``::
|
|
2826
|
+
|
|
2827
|
+
sage: [x.reduced_word() for x in w.weak_covers(index_set=[1,2])] # needs sage.combinat sage.groups
|
|
2828
|
+
[[2, 3, 2]]
|
|
2829
|
+
"""
|
|
2830
|
+
return [self.apply_simple_reflection(i, side=side)
|
|
2831
|
+
for i in self.descents(side=side, index_set=index_set,
|
|
2832
|
+
positive=positive)]
|
|
2833
|
+
|
|
2834
|
+
def coxeter_sorting_word(self, c):
|
|
2835
|
+
r"""
|
|
2836
|
+
Return the ``c``-sorting word of ``self``.
|
|
2837
|
+
|
|
2838
|
+
For a Coxeter element `c` and an element `w`, the `c`-sorting
|
|
2839
|
+
word of `w` is the lexicographic minimal reduced expression of
|
|
2840
|
+
`w` in the infinite word `c^\infty`.
|
|
2841
|
+
|
|
2842
|
+
INPUT:
|
|
2843
|
+
|
|
2844
|
+
- ``c`` -- a Coxeter element
|
|
2845
|
+
|
|
2846
|
+
OUTPUT: the ``c``-sorting word of ``self`` as a list of integers
|
|
2847
|
+
|
|
2848
|
+
EXAMPLES::
|
|
2849
|
+
|
|
2850
|
+
sage: W = CoxeterGroups().example()
|
|
2851
|
+
sage: c = W.from_reduced_word([0,2,1])
|
|
2852
|
+
sage: w = W.from_reduced_word([1,2,1,0,1])
|
|
2853
|
+
sage: w.coxeter_sorting_word(c)
|
|
2854
|
+
[2, 1, 2, 0, 1]
|
|
2855
|
+
"""
|
|
2856
|
+
if hasattr(c, "reduced_word"):
|
|
2857
|
+
c = c.reduced_word()
|
|
2858
|
+
elif not isinstance(c, list):
|
|
2859
|
+
c = list(c)
|
|
2860
|
+
n = self.parent().rank()
|
|
2861
|
+
pi = self
|
|
2862
|
+
l = pi.length()
|
|
2863
|
+
i = 0
|
|
2864
|
+
sorting_word = []
|
|
2865
|
+
while l > 0:
|
|
2866
|
+
s = c[i]
|
|
2867
|
+
if pi.has_left_descent(s):
|
|
2868
|
+
pi = pi.apply_simple_reflection_left(s)
|
|
2869
|
+
l -= 1
|
|
2870
|
+
sorting_word.append(s)
|
|
2871
|
+
i += 1
|
|
2872
|
+
if i == n:
|
|
2873
|
+
i = 0
|
|
2874
|
+
return sorting_word
|
|
2875
|
+
|
|
2876
|
+
def is_coxeter_sortable(self, c, sorting_word=None):
|
|
2877
|
+
r"""
|
|
2878
|
+
Return whether ``self`` is ``c``-sortable.
|
|
2879
|
+
|
|
2880
|
+
Given a Coxeter element `c`, an element `w` is `c`-sortable if
|
|
2881
|
+
its `c`-sorting word decomposes into a sequence of weakly
|
|
2882
|
+
decreasing subwords of `c`.
|
|
2883
|
+
|
|
2884
|
+
INPUT:
|
|
2885
|
+
|
|
2886
|
+
- ``c`` -- a Coxeter element
|
|
2887
|
+
- ``sorting_word`` -- sorting word (default: ``None``); used to
|
|
2888
|
+
not recompute the `c`-sorting word if already computed
|
|
2889
|
+
|
|
2890
|
+
EXAMPLES::
|
|
2891
|
+
|
|
2892
|
+
sage: W = CoxeterGroups().example()
|
|
2893
|
+
sage: c = W.from_reduced_word([0,2,1])
|
|
2894
|
+
sage: w = W.from_reduced_word([1,2,1,0,1])
|
|
2895
|
+
sage: w.coxeter_sorting_word(c)
|
|
2896
|
+
[2, 1, 2, 0, 1]
|
|
2897
|
+
sage: w.is_coxeter_sortable(c)
|
|
2898
|
+
False
|
|
2899
|
+
sage: w = W.from_reduced_word([0,2,1,0,2])
|
|
2900
|
+
sage: w.coxeter_sorting_word(c)
|
|
2901
|
+
[2, 0, 1, 2, 0]
|
|
2902
|
+
sage: w.is_coxeter_sortable(c)
|
|
2903
|
+
True
|
|
2904
|
+
|
|
2905
|
+
sage: W = CoxeterGroup(['A', 3]) # needs sage.combinat sage.groups
|
|
2906
|
+
sage: c = W.from_reduced_word([1,2,3]) # needs sage.combinat sage.groups
|
|
2907
|
+
|
|
2908
|
+
Number of `c`-sortable elements in `A_3` (Catalan number)::
|
|
2909
|
+
|
|
2910
|
+
sage: len([w for w in W if w.is_coxeter_sortable(c)]) # needs sage.rings.number_field
|
|
2911
|
+
14
|
|
2912
|
+
|
|
2913
|
+
TESTS::
|
|
2914
|
+
|
|
2915
|
+
sage: W = SymmetricGroup(3) # needs sage.groups
|
|
2916
|
+
sage: c = Permutation((1,2,3))
|
|
2917
|
+
sage: sorted(w for w in W if w.is_coxeter_sortable(c)) # needs sage.combinat sage.groups
|
|
2918
|
+
[(), (2,3), (1,2), (1,3,2), (1,3)]
|
|
2919
|
+
"""
|
|
2920
|
+
if hasattr(c, "reduced_word"):
|
|
2921
|
+
c = c.reduced_word()
|
|
2922
|
+
elif not isinstance(c, list):
|
|
2923
|
+
c = list(c)
|
|
2924
|
+
if sorting_word is None:
|
|
2925
|
+
sorting_word = self.coxeter_sorting_word(c)
|
|
2926
|
+
n = len(c)
|
|
2927
|
+
containment_list = [True] * n
|
|
2928
|
+
l = 0
|
|
2929
|
+
i = 0
|
|
2930
|
+
while l < len(sorting_word):
|
|
2931
|
+
s = c[i]
|
|
2932
|
+
t = sorting_word[l]
|
|
2933
|
+
if s == t:
|
|
2934
|
+
l += 1
|
|
2935
|
+
if not containment_list[i]:
|
|
2936
|
+
return False
|
|
2937
|
+
else:
|
|
2938
|
+
containment_list[i] = False
|
|
2939
|
+
i += 1
|
|
2940
|
+
if i == n:
|
|
2941
|
+
i = 0
|
|
2942
|
+
return True
|
|
2943
|
+
|
|
2944
|
+
def apply_demazure_product(self, element, side='right',
|
|
2945
|
+
length_increasing=True):
|
|
2946
|
+
r"""
|
|
2947
|
+
Return the Demazure or 0-Hecke product of ``self`` with another Coxeter group element.
|
|
2948
|
+
|
|
2949
|
+
See :meth:`CoxeterGroups.ParentMethods.simple_projections`.
|
|
2950
|
+
|
|
2951
|
+
INPUT:
|
|
2952
|
+
|
|
2953
|
+
- ``element`` -- either an element of the same Coxeter
|
|
2954
|
+
group as ``self`` or a tuple or a list (such as a
|
|
2955
|
+
reduced word) of elements from the index set of the
|
|
2956
|
+
Coxeter group.
|
|
2957
|
+
|
|
2958
|
+
- ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``); the
|
|
2959
|
+
side of ``self`` on which the element should be
|
|
2960
|
+
applied. If ``side`` is 'left' then the operation is
|
|
2961
|
+
applied on the left.
|
|
2962
|
+
|
|
2963
|
+
- ``length_increasing`` -- boolean (default: ``True``)
|
|
2964
|
+
whether to act length increasingly or decreasingly
|
|
2965
|
+
|
|
2966
|
+
EXAMPLES::
|
|
2967
|
+
|
|
2968
|
+
sage: # needs sage.combinat sage.groups
|
|
2969
|
+
sage: W = WeylGroup(['C', 4], prefix='s')
|
|
2970
|
+
sage: v = W.from_reduced_word([1,2,3,4,3,1])
|
|
2971
|
+
sage: v.apply_demazure_product([1,3,4,3,3])
|
|
2972
|
+
s4*s1*s2*s3*s4*s3*s1
|
|
2973
|
+
sage: v.apply_demazure_product([1,3,4,3], side='left')
|
|
2974
|
+
s3*s4*s1*s2*s3*s4*s2*s3*s1
|
|
2975
|
+
sage: v.apply_demazure_product((1,3,4,3), side='left')
|
|
2976
|
+
s3*s4*s1*s2*s3*s4*s2*s3*s1
|
|
2977
|
+
sage: v.apply_demazure_product(v)
|
|
2978
|
+
s2*s3*s4*s1*s2*s3*s4*s2*s3*s2*s1
|
|
2979
|
+
"""
|
|
2980
|
+
# if self and element have the same parent
|
|
2981
|
+
if self.parent().is_parent_of(element):
|
|
2982
|
+
the_word = element.reduced_word()
|
|
2983
|
+
else:
|
|
2984
|
+
# check for a list or tuple of elements of the index set
|
|
2985
|
+
if isinstance(element, tuple):
|
|
2986
|
+
element = list(element)
|
|
2987
|
+
elif not isinstance(element, list):
|
|
2988
|
+
raise TypeError(f"Bad Coxeter group element input: {element}")
|
|
2989
|
+
I = self.parent().index_set()
|
|
2990
|
+
if not all(i in I for i in element):
|
|
2991
|
+
raise ValueError("%s does not have all its members in the index set of the %s" % (element, self.parent()))
|
|
2992
|
+
# the copy is so that if we need to reverse the list, the original will not
|
|
2993
|
+
# get reversed
|
|
2994
|
+
the_word = copy(element)
|
|
2995
|
+
if side == 'left':
|
|
2996
|
+
the_word.reverse()
|
|
2997
|
+
for i in the_word:
|
|
2998
|
+
self = self.apply_simple_projection(i, side=side, length_increasing=length_increasing)
|
|
2999
|
+
return self
|
|
3000
|
+
|
|
3001
|
+
def min_demazure_product_greater(self, element):
|
|
3002
|
+
r"""
|
|
3003
|
+
Find the unique Bruhat-minimum element ``u`` such that ``v`` `\le`
|
|
3004
|
+
``w`` * ``u`` where ``v`` is ``self``, ``w`` is ``element`` and
|
|
3005
|
+
``*`` is the Demazure product.
|
|
3006
|
+
|
|
3007
|
+
INPUT:
|
|
3008
|
+
|
|
3009
|
+
- ``element`` -- is either an element of the same Coxeter group as
|
|
3010
|
+
``self`` or a list (such as a reduced word) of elements from the
|
|
3011
|
+
index set of the Coxeter group
|
|
3012
|
+
|
|
3013
|
+
EXAMPLES::
|
|
3014
|
+
|
|
3015
|
+
sage: # needs sage.combinat sage.groups
|
|
3016
|
+
sage: W = WeylGroup(['A', 4], prefix='s')
|
|
3017
|
+
sage: v = W.from_reduced_word([2,3,4,1,2])
|
|
3018
|
+
sage: u = W.from_reduced_word([2,3,2,1])
|
|
3019
|
+
sage: v.min_demazure_product_greater(u)
|
|
3020
|
+
s4*s2
|
|
3021
|
+
sage: v.min_demazure_product_greater([2,3,2,1])
|
|
3022
|
+
s4*s2
|
|
3023
|
+
sage: v.min_demazure_product_greater((2,3,2,1))
|
|
3024
|
+
s4*s2
|
|
3025
|
+
"""
|
|
3026
|
+
# if self and element have the same parent
|
|
3027
|
+
if self.parent().is_parent_of(element):
|
|
3028
|
+
the_word = element.reduced_word()
|
|
3029
|
+
# else require that ``element`` is a list or tuple of index_set elements
|
|
3030
|
+
else:
|
|
3031
|
+
if not isinstance(element, (tuple, list)):
|
|
3032
|
+
raise TypeError("Bad Coxeter group element input: %s" % (element))
|
|
3033
|
+
I = self.parent().index_set()
|
|
3034
|
+
if not all(i in I for i in element):
|
|
3035
|
+
raise ValueError("%s does not have all its members in the index set of the %s" % (element, self.parent()))
|
|
3036
|
+
the_word = element
|
|
3037
|
+
for i in the_word:
|
|
3038
|
+
if self.has_descent(i, side='left'):
|
|
3039
|
+
self = self.apply_simple_reflection(i, side='left')
|
|
3040
|
+
return self
|
|
3041
|
+
|
|
3042
|
+
def deodhar_factor_element(self, w, index_set):
|
|
3043
|
+
r"""
|
|
3044
|
+
Return Deodhar's Bruhat order factoring element.
|
|
3045
|
+
|
|
3046
|
+
INPUT:
|
|
3047
|
+
|
|
3048
|
+
- ``w`` -- an element of the same Coxeter group ``W`` as ``self``
|
|
3049
|
+
- ``index_set`` -- a subset of Dynkin nodes defining a parabolic
|
|
3050
|
+
subgroup ``W'`` of ``W``
|
|
3051
|
+
|
|
3052
|
+
It is assumed that ``v = self`` and ``w`` are minimum length coset representatives
|
|
3053
|
+
for ``W/W'`` such that ``v`` `\le` ``w`` in Bruhat order.
|
|
3054
|
+
|
|
3055
|
+
OUTPUT:
|
|
3056
|
+
|
|
3057
|
+
Deodhar's element ``f(v,w)`` is the unique element of ``W'`` such that,
|
|
3058
|
+
for all ``v'`` and ``w'`` in ``W'``, ``vv'`` `\le` ``ww'`` in ``W`` if and only if
|
|
3059
|
+
``v'`` `\le` ``f(v,w) * w'`` in ``W'`` where ``*`` is the Demazure product.
|
|
3060
|
+
|
|
3061
|
+
EXAMPLES::
|
|
3062
|
+
|
|
3063
|
+
sage: # needs sage.combinat sage.groups
|
|
3064
|
+
sage: W = WeylGroup(['A', 5], prefix='s')
|
|
3065
|
+
sage: v = W.from_reduced_word([5])
|
|
3066
|
+
sage: w = W.from_reduced_word([4,5,2,3,1,2])
|
|
3067
|
+
sage: v.deodhar_factor_element(w, [1,3,4])
|
|
3068
|
+
s3*s1
|
|
3069
|
+
sage: W = WeylGroup(['C', 2])
|
|
3070
|
+
sage: w = W.from_reduced_word([2,1])
|
|
3071
|
+
sage: w.deodhar_factor_element(W.from_reduced_word([2]),[1])
|
|
3072
|
+
Traceback (most recent call last):
|
|
3073
|
+
...
|
|
3074
|
+
ValueError: [2, 1] is not of minimum length in its coset
|
|
3075
|
+
for the parabolic subgroup with index set [1]
|
|
3076
|
+
|
|
3077
|
+
REFERENCES:
|
|
3078
|
+
|
|
3079
|
+
- [Deo1987a]_
|
|
3080
|
+
"""
|
|
3081
|
+
if self != self.coset_representative(index_set):
|
|
3082
|
+
raise ValueError("%s is not of minimum length in its coset for the parabolic subgroup with index set %s" % (self.reduced_word(), index_set))
|
|
3083
|
+
if w != w.coset_representative(index_set):
|
|
3084
|
+
raise ValueError("%s is not of minimum length in its coset for the parabolic subgroup with index set %s" % (w.reduced_word(), index_set))
|
|
3085
|
+
if not self.bruhat_le(w):
|
|
3086
|
+
raise ValueError("Must have %s <= %s" % (self.reduced_word(), w.reduced_word()))
|
|
3087
|
+
if w.is_one():
|
|
3088
|
+
return w
|
|
3089
|
+
i = w.first_descent(side='left')
|
|
3090
|
+
sw = w.apply_simple_reflection(i, side='left')
|
|
3091
|
+
sv = self.apply_simple_reflection(i, side='left')
|
|
3092
|
+
if self.has_descent(i, side='left'):
|
|
3093
|
+
return sv.deodhar_factor_element(sw, index_set)
|
|
3094
|
+
dsp = self.deodhar_factor_element(sw, index_set)
|
|
3095
|
+
des = sv.first_descent(side='right', index_set=index_set)
|
|
3096
|
+
if des is None:
|
|
3097
|
+
return dsp
|
|
3098
|
+
return dsp.apply_simple_projection(des, side='left')
|
|
3099
|
+
|
|
3100
|
+
def deodhar_lift_up(self, w, index_set):
|
|
3101
|
+
r"""
|
|
3102
|
+
Letting ``v = self``, given a Bruhat relation ``v W'`` `\le` ``w W'`` among cosets
|
|
3103
|
+
with respect to the subgroup ``W'`` given by the Dynkin node subset ``index_set``,
|
|
3104
|
+
returns the Bruhat-minimum lift ``x`` of ``wW'`` such that ``v`` `\le` ``x``.
|
|
3105
|
+
|
|
3106
|
+
INPUT:
|
|
3107
|
+
|
|
3108
|
+
- ``w`` -- an element of the same Coxeter group ``W`` as ``self``
|
|
3109
|
+
- ``index_set`` -- a subset of Dynkin nodes defining a parabolic
|
|
3110
|
+
subgroup ``W'``
|
|
3111
|
+
|
|
3112
|
+
OUTPUT:
|
|
3113
|
+
|
|
3114
|
+
The unique Bruhat-minimum element ``x`` in ``W`` such that ``x W' = w W'``
|
|
3115
|
+
and ``v`` `\le` ``x``.
|
|
3116
|
+
|
|
3117
|
+
.. SEEALSO:: :meth:`sage.categories.coxeter_groups.CoxeterGroups.ElementMethods.deodhar_lift_down`
|
|
3118
|
+
|
|
3119
|
+
EXAMPLES::
|
|
3120
|
+
|
|
3121
|
+
sage: # needs sage.combinat sage.groups
|
|
3122
|
+
sage: W = WeylGroup(['A', 3], prefix='s')
|
|
3123
|
+
sage: v = W.from_reduced_word([1,2,3])
|
|
3124
|
+
sage: w = W.from_reduced_word([1,3,2])
|
|
3125
|
+
sage: v.deodhar_lift_up(w, [3])
|
|
3126
|
+
s1*s2*s3*s2
|
|
3127
|
+
"""
|
|
3128
|
+
vmin = self.coset_representative(index_set)
|
|
3129
|
+
wmin = w.coset_representative(index_set)
|
|
3130
|
+
if not vmin.bruhat_le(wmin):
|
|
3131
|
+
raise ValueError("Must have %s <= %s mod the parabolic subgroup with index set %s" % (self.reduced_word(), w.reduced_word(), index_set))
|
|
3132
|
+
vJ = vmin.inverse() * self
|
|
3133
|
+
dsp = vmin.deodhar_factor_element(wmin, index_set)
|
|
3134
|
+
return wmin * vJ.min_demazure_product_greater(dsp)
|
|
3135
|
+
|
|
3136
|
+
def deodhar_lift_down(self, w, index_set):
|
|
3137
|
+
r"""
|
|
3138
|
+
Letting ``v = self``, given a Bruhat relation ``v W'`` `\ge` ``w W'`` among cosets
|
|
3139
|
+
with respect to the subgroup ``W'`` given by the Dynkin node subset ``index_set``,
|
|
3140
|
+
returns the Bruhat-maximum lift ``x`` of ``wW'`` such that ``v`` `\ge` ``x``.
|
|
3141
|
+
|
|
3142
|
+
INPUT:
|
|
3143
|
+
|
|
3144
|
+
- ``w`` -- an element of the same Coxeter group ``W`` as ``self``
|
|
3145
|
+
- ``index_set`` -- a subset of Dynkin nodes defining a parabolic subgroup ``W'``
|
|
3146
|
+
|
|
3147
|
+
OUTPUT:
|
|
3148
|
+
|
|
3149
|
+
The unique Bruhat-maximum element ``x`` in ``W`` such that ``x W' = w W'``
|
|
3150
|
+
and ``v`` `\ge` ``x``.
|
|
3151
|
+
|
|
3152
|
+
.. SEEALSO:: :meth:`sage.categories.coxeter_groups.CoxeterGroups.ElementMethods.deodhar_lift_up`
|
|
3153
|
+
|
|
3154
|
+
EXAMPLES::
|
|
3155
|
+
|
|
3156
|
+
sage: # needs sage.combinat sage.groups
|
|
3157
|
+
sage: W = WeylGroup(['A', 3], prefix='s')
|
|
3158
|
+
sage: v = W.from_reduced_word([1,2,3,2])
|
|
3159
|
+
sage: w = W.from_reduced_word([3,2])
|
|
3160
|
+
sage: v.deodhar_lift_down(w, [3])
|
|
3161
|
+
s2*s3*s2
|
|
3162
|
+
"""
|
|
3163
|
+
vmin = self.coset_representative(index_set)
|
|
3164
|
+
wmin = w.coset_representative(index_set)
|
|
3165
|
+
if not wmin.bruhat_le(vmin):
|
|
3166
|
+
raise ValueError("Must have %s <= %s mod the parabolic subgroup with index set %s" % (w.reduced_word(), self.reduced_word(), index_set))
|
|
3167
|
+
|
|
3168
|
+
vJ = vmin.inverse() * self
|
|
3169
|
+
dsp = wmin.deodhar_factor_element(vmin, index_set)
|
|
3170
|
+
return wmin * dsp.apply_demazure_product(vJ)
|
|
3171
|
+
|
|
3172
|
+
@cached_in_parent_method
|
|
3173
|
+
def inversions_as_reflections(self):
|
|
3174
|
+
r"""
|
|
3175
|
+
Return the set of reflections ``r`` such that ``self`` ``r < self``.
|
|
3176
|
+
|
|
3177
|
+
EXAMPLES::
|
|
3178
|
+
|
|
3179
|
+
sage: W = WeylGroup(['A', 3], prefix='s') # needs sage.combinat sage.groups
|
|
3180
|
+
sage: w = W.from_reduced_word([3,1,2,1]) # needs sage.combinat sage.groups
|
|
3181
|
+
sage: w.inversions_as_reflections() # needs sage.combinat sage.groups
|
|
3182
|
+
[s1, s1*s2*s1, s2, s1*s2*s3*s2*s1]
|
|
3183
|
+
"""
|
|
3184
|
+
i = self.first_descent()
|
|
3185
|
+
if i is None:
|
|
3186
|
+
return []
|
|
3187
|
+
wi = self.apply_simple_reflection(i)
|
|
3188
|
+
return [self.parent().simple_reflection(i)] + [u.apply_conjugation_by_simple_reflection(i) for u in wi.inversions_as_reflections()]
|
|
3189
|
+
|
|
3190
|
+
def left_inversions_as_reflections(self):
|
|
3191
|
+
r"""
|
|
3192
|
+
Return the set of reflections ``r`` such that ``r`` ``self`` < ``self``.
|
|
3193
|
+
|
|
3194
|
+
EXAMPLES::
|
|
3195
|
+
|
|
3196
|
+
sage: W = WeylGroup(['A', 3], prefix='s') # needs sage.combinat sage.groups
|
|
3197
|
+
sage: w = W.from_reduced_word([3,1,2,1]) # needs sage.combinat sage.groups
|
|
3198
|
+
sage: w.left_inversions_as_reflections() # needs sage.combinat sage.groups
|
|
3199
|
+
[s1, s3, s1*s2*s3*s2*s1, s2*s3*s2]
|
|
3200
|
+
"""
|
|
3201
|
+
return self.inverse().inversions_as_reflections()
|
|
3202
|
+
|
|
3203
|
+
def lower_covers(self, side='right', index_set=None):
|
|
3204
|
+
"""
|
|
3205
|
+
Return all elements that ``self`` covers in weak order.
|
|
3206
|
+
|
|
3207
|
+
INPUT:
|
|
3208
|
+
|
|
3209
|
+
- ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``)
|
|
3210
|
+
- ``index_set`` -- list of indices or ``None``
|
|
3211
|
+
|
|
3212
|
+
OUTPUT: list
|
|
3213
|
+
|
|
3214
|
+
EXAMPLES::
|
|
3215
|
+
|
|
3216
|
+
sage: W = WeylGroup(['A', 3]) # needs sage.combinat sage.groups
|
|
3217
|
+
sage: w = W.from_reduced_word([3,2,1]) # needs sage.combinat sage.groups
|
|
3218
|
+
sage: [x.reduced_word() for x in w.lower_covers()] # needs sage.combinat sage.groups
|
|
3219
|
+
[[3, 2]]
|
|
3220
|
+
|
|
3221
|
+
To obtain covers for left weak order, set the option side to 'left'::
|
|
3222
|
+
|
|
3223
|
+
sage: [x.reduced_word() for x in w.lower_covers(side='left')] # needs sage.combinat sage.groups
|
|
3224
|
+
[[2, 1]]
|
|
3225
|
+
sage: w = W.from_reduced_word([3,2,3,1]) # needs sage.combinat sage.groups
|
|
3226
|
+
sage: [x.reduced_word() for x in w.lower_covers()] # needs sage.combinat sage.groups
|
|
3227
|
+
[[2, 3, 2], [3, 2, 1]]
|
|
3228
|
+
|
|
3229
|
+
Covers w.r.t. a parabolic subgroup are obtained with the option ``index_set``::
|
|
3230
|
+
|
|
3231
|
+
sage: [x.reduced_word() for x in w.lower_covers(index_set=[1,2])] # needs sage.combinat sage.groups
|
|
3232
|
+
[[2, 3, 2]]
|
|
3233
|
+
sage: [x.reduced_word() for x in w.lower_covers(side='left')] # needs sage.combinat sage.groups
|
|
3234
|
+
[[3, 2, 1], [2, 3, 1]]
|
|
3235
|
+
"""
|
|
3236
|
+
return self.weak_covers(side=side, index_set=index_set,
|
|
3237
|
+
positive=False)
|
|
3238
|
+
|
|
3239
|
+
def upper_covers(self, side='right', index_set=None):
|
|
3240
|
+
"""
|
|
3241
|
+
Return all elements that cover ``self`` in weak order.
|
|
3242
|
+
|
|
3243
|
+
INPUT:
|
|
3244
|
+
|
|
3245
|
+
- ``side`` -- ``'left'`` or ``'right'`` (default: ``'right'``)
|
|
3246
|
+
- ``index_set`` -- list of indices or ``None``
|
|
3247
|
+
|
|
3248
|
+
OUTPUT: list
|
|
3249
|
+
|
|
3250
|
+
EXAMPLES::
|
|
3251
|
+
|
|
3252
|
+
sage: W = WeylGroup(['A', 3]) # needs sage.combinat sage.groups
|
|
3253
|
+
sage: w = W.from_reduced_word([2,3]) # needs sage.combinat sage.groups
|
|
3254
|
+
sage: [x.reduced_word() for x in w.upper_covers()] # needs sage.combinat sage.groups
|
|
3255
|
+
[[2, 3, 1], [2, 3, 2]]
|
|
3256
|
+
|
|
3257
|
+
To obtain covers for left weak order, set the option ``side`` to 'left'::
|
|
3258
|
+
|
|
3259
|
+
sage: [x.reduced_word() for x in w.upper_covers(side='left')] # needs sage.combinat sage.groups
|
|
3260
|
+
[[1, 2, 3], [2, 3, 2]]
|
|
3261
|
+
|
|
3262
|
+
Covers w.r.t. a parabolic subgroup are obtained with the option ``index_set``::
|
|
3263
|
+
|
|
3264
|
+
sage: [x.reduced_word() for x in w.upper_covers(index_set=[1])] # needs sage.combinat sage.groups
|
|
3265
|
+
[[2, 3, 1]]
|
|
3266
|
+
sage: [x.reduced_word() # needs sage.combinat sage.groups
|
|
3267
|
+
....: for x in w.upper_covers(side='left', index_set=[1])]
|
|
3268
|
+
[[1, 2, 3]]
|
|
3269
|
+
"""
|
|
3270
|
+
return self.weak_covers(side=side, index_set=index_set,
|
|
3271
|
+
positive=True)
|
|
3272
|
+
|
|
3273
|
+
def kazhdan_lusztig_cell(self, side='left'):
|
|
3274
|
+
r"""
|
|
3275
|
+
Compute the left, right, or two-sided Kazhdan-Lusztig cell
|
|
3276
|
+
containing the element ``self`` depending on the specified ``side``.
|
|
3277
|
+
|
|
3278
|
+
Let `C'` denote the Kazhdan-Lusztig `C^{\prime}`-basis of the
|
|
3279
|
+
Iwahori-Hecke algebra `H` of a Coxeter system `(W,S)`. Two elements
|
|
3280
|
+
`x,y` of the Coxeter group `W` are said to lie in the same left
|
|
3281
|
+
Kazhdan-Lusztig cell if there exist sequences `x = w_1, w_2, \ldots,
|
|
3282
|
+
w_k = y` and `y = u_1, u_2, \ldots, u_l = x` such that for all
|
|
3283
|
+
`1 \leq i < k` and all `1 \leq j < l`, there exist some Coxeter
|
|
3284
|
+
generators `s,t \in S` for which `C'_{w_{i+1}}` appears in
|
|
3285
|
+
`C'_s C'_{w_i}` and `C'_{u_{j+1}}` appears in `C'_s C'_{u_j}`
|
|
3286
|
+
in `H`. Right and two-sided Kazhdan-Lusztig cells of `W` are
|
|
3287
|
+
defined similarly; see [Lus2013]_.
|
|
3288
|
+
|
|
3289
|
+
In this function, we compute products in the `C^{\prime}` basis by
|
|
3290
|
+
using :class:`IwahoriHeckeAlgebra.Cp`. As mentioned in that class,
|
|
3291
|
+
installing the optional package ``coxeter3`` is recommended
|
|
3292
|
+
(though not required) before using this function because the
|
|
3293
|
+
package speeds up product computations that are sometimes
|
|
3294
|
+
computationally infeasible without it.
|
|
3295
|
+
|
|
3296
|
+
INPUT:
|
|
3297
|
+
|
|
3298
|
+
- ``w`` -- an element of ``self``
|
|
3299
|
+
|
|
3300
|
+
- ``side`` -- (default: ``'left'``) the kind of cell to compute;
|
|
3301
|
+
must be either ``'left'``, ``'right'``, or ``'two-sided'``
|
|
3302
|
+
|
|
3303
|
+
EXAMPLES:
|
|
3304
|
+
|
|
3305
|
+
We compute the left cell of the generator `s_1` in type `A_3` in
|
|
3306
|
+
three different implementations of the Coxeter group. Note that the
|
|
3307
|
+
choice of implementation affects the representation of elements in
|
|
3308
|
+
the output cell but not the method used for the cell computation::
|
|
3309
|
+
|
|
3310
|
+
sage: W = CoxeterGroup('A3', implementation='permutation') # needs sage.combinat sage.groups
|
|
3311
|
+
sage: s1, s2, s3 = W.simple_reflections() # needs sage.combinat sage.groups
|
|
3312
|
+
sage: s1.kazhdan_lusztig_cell() # needs sage.combinat sage.groups
|
|
3313
|
+
{(1,2,3,12)(4,5,10,11)(6,7,8,9),
|
|
3314
|
+
(1,2,10)(3,6,5)(4,7,8)(9,12,11),
|
|
3315
|
+
(1,7)(2,4)(5,6)(8,10)(11,12)}
|
|
3316
|
+
|
|
3317
|
+
The cell computation uses the optional package ``coxeter3`` in
|
|
3318
|
+
the background if available to speed up the computation,
|
|
3319
|
+
even in the different implementations::
|
|
3320
|
+
|
|
3321
|
+
sage: # optional - coxeter3, needs sage.combinat sage.groups sage.modules
|
|
3322
|
+
sage: W = WeylGroup('A3', prefix='s')
|
|
3323
|
+
sage: s1,s2,s3 = W.simple_reflections()
|
|
3324
|
+
sage: s1.kazhdan_lusztig_cell()
|
|
3325
|
+
{s3*s2*s1, s2*s1, s1}
|
|
3326
|
+
sage: W = CoxeterGroup('A3', implementation='coxeter3')
|
|
3327
|
+
sage: s1,s2,s3 = W.simple_reflections()
|
|
3328
|
+
sage: s1.kazhdan_lusztig_cell()
|
|
3329
|
+
{[1], [2, 1], [3, 2, 1]}
|
|
3330
|
+
|
|
3331
|
+
Next, we compute a right cell and a two-sided cell in `A_3`::
|
|
3332
|
+
|
|
3333
|
+
sage: # optional - coxeter3, needs sage.combinat sage.groups sage.modules
|
|
3334
|
+
sage: W = CoxeterGroup('A3', implementation='coxeter3')
|
|
3335
|
+
sage: s1,s2,s3 = W.simple_reflections()
|
|
3336
|
+
sage: w = s1 * s3
|
|
3337
|
+
sage: w.kazhdan_lusztig_cell(side='right')
|
|
3338
|
+
{[1, 3], [1, 3, 2]}
|
|
3339
|
+
sage: w.kazhdan_lusztig_cell(side='two-sided')
|
|
3340
|
+
{[1, 3], [1, 3, 2], [2, 1, 3], [2, 1, 3, 2]}
|
|
3341
|
+
|
|
3342
|
+
Some slightly longer computations in `B_4`::
|
|
3343
|
+
|
|
3344
|
+
sage: # optional - coxeter3, needs sage.combinat sage.groups sage.modules
|
|
3345
|
+
sage: W = CoxeterGroup('B4', implementation='coxeter3')
|
|
3346
|
+
sage: s1,s2,s3,s4 = W.simple_reflections()
|
|
3347
|
+
sage: s1.kazhdan_lusztig_cell(side='right') # long time (4 seconds)
|
|
3348
|
+
{[1],
|
|
3349
|
+
[1, 2],
|
|
3350
|
+
[1, 2, 3],
|
|
3351
|
+
[1, 2, 3, 4],
|
|
3352
|
+
[1, 2, 3, 4, 3],
|
|
3353
|
+
[1, 2, 3, 4, 3, 2],
|
|
3354
|
+
[1, 2, 3, 4, 3, 2, 1]}
|
|
3355
|
+
sage: (s4*s2*s3*s4).kazhdan_lusztig_cell(side='two-sided') # long time (8 seconds)
|
|
3356
|
+
{[2, 3, 1],
|
|
3357
|
+
[2, 3, 1, 2],
|
|
3358
|
+
[2, 3, 4, 1],
|
|
3359
|
+
[2, 3, 4, 1, 2],
|
|
3360
|
+
[2, 3, 4, 1, 2, 3],
|
|
3361
|
+
[2, 3, 4, 1, 2, 3, 4],
|
|
3362
|
+
[2, 3, 4, 3, 1],
|
|
3363
|
+
[2, 3, 4, 3, 1, 2],
|
|
3364
|
+
...
|
|
3365
|
+
[4, 3, 4, 2, 3, 4, 1, 2, 3, 4]}
|
|
3366
|
+
"""
|
|
3367
|
+
from sage.algebras.iwahori_hecke_algebra import IwahoriHeckeAlgebra
|
|
3368
|
+
from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing
|
|
3369
|
+
from sage.rings.integer_ring import ZZ
|
|
3370
|
+
|
|
3371
|
+
R = LaurentPolynomialRing(ZZ, 'v')
|
|
3372
|
+
v = R.gen(0)
|
|
3373
|
+
H = IwahoriHeckeAlgebra(self.parent(), v**2)
|
|
3374
|
+
Cp = H.Cp()
|
|
3375
|
+
|
|
3376
|
+
w = self.parent()(self)
|
|
3377
|
+
|
|
3378
|
+
vertices, edges = {w}, set()
|
|
3379
|
+
queue = deque([w])
|
|
3380
|
+
|
|
3381
|
+
while queue:
|
|
3382
|
+
x = queue.pop()
|
|
3383
|
+
cp_x = Cp(x)
|
|
3384
|
+
for s in self.parent().simple_reflections():
|
|
3385
|
+
cp_s = Cp(s)
|
|
3386
|
+
terms = []
|
|
3387
|
+
# Determine the Cp basis elements appearing in the product of Cp_s and Cp_w
|
|
3388
|
+
if side == 'left' or side == 'two-sided':
|
|
3389
|
+
terms.extend(list(cp_s * cp_x))
|
|
3390
|
+
if side == 'right' or side == 'two-sided':
|
|
3391
|
+
terms.extend(list(cp_x * cp_s))
|
|
3392
|
+
for y, _ in terms:
|
|
3393
|
+
# the result of multiplication will always have coeff != 0
|
|
3394
|
+
if y != x:
|
|
3395
|
+
edges.add((x, y))
|
|
3396
|
+
if y not in vertices:
|
|
3397
|
+
vertices.add(y)
|
|
3398
|
+
queue.appendleft(y)
|
|
3399
|
+
|
|
3400
|
+
from sage.graphs.digraph import DiGraph
|
|
3401
|
+
g = DiGraph([list(vertices), list(edges)])
|
|
3402
|
+
return set(g.strongly_connected_component_containing_vertex(w))
|