passagemath-combinat 10.6.42__cp314-cp314-musllinux_1_2_x86_64.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_combinat/__init__.py +3 -0
- passagemath_combinat-10.6.42.dist-info/METADATA +160 -0
- passagemath_combinat-10.6.42.dist-info/RECORD +400 -0
- passagemath_combinat-10.6.42.dist-info/WHEEL +5 -0
- passagemath_combinat-10.6.42.dist-info/top_level.txt +3 -0
- passagemath_combinat.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
- passagemath_combinat.libs/libsymmetrica-81fe8739.so.3.0.0 +0 -0
- sage/algebras/affine_nil_temperley_lieb.py +263 -0
- sage/algebras/all.py +24 -0
- sage/algebras/all__sagemath_combinat.py +35 -0
- sage/algebras/askey_wilson.py +935 -0
- sage/algebras/associated_graded.py +345 -0
- sage/algebras/cellular_basis.py +350 -0
- sage/algebras/cluster_algebra.py +2766 -0
- sage/algebras/down_up_algebra.py +860 -0
- sage/algebras/free_algebra.py +1698 -0
- sage/algebras/free_algebra_element.py +345 -0
- sage/algebras/free_algebra_quotient.py +405 -0
- sage/algebras/free_algebra_quotient_element.py +295 -0
- sage/algebras/free_zinbiel_algebra.py +885 -0
- sage/algebras/hall_algebra.py +783 -0
- sage/algebras/hecke_algebras/all.py +4 -0
- sage/algebras/hecke_algebras/ariki_koike_algebra.py +1796 -0
- sage/algebras/hecke_algebras/ariki_koike_specht_modules.py +475 -0
- sage/algebras/hecke_algebras/cubic_hecke_algebra.py +3520 -0
- sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +1473 -0
- sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +1079 -0
- sage/algebras/iwahori_hecke_algebra.py +3095 -0
- sage/algebras/jordan_algebra.py +1773 -0
- sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py +113 -0
- sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py +156 -0
- sage/algebras/lie_conformal_algebras/all.py +18 -0
- sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +134 -0
- sage/algebras/lie_conformal_algebras/examples.py +43 -0
- sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py +131 -0
- sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py +139 -0
- sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py +174 -0
- sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py +167 -0
- sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py +107 -0
- sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py +135 -0
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py +353 -0
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py +236 -0
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py +78 -0
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py +328 -0
- sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py +117 -0
- sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py +86 -0
- sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py +82 -0
- sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +205 -0
- sage/algebras/nil_coxeter_algebra.py +191 -0
- sage/algebras/q_commuting_polynomials.py +673 -0
- sage/algebras/q_system.py +608 -0
- sage/algebras/quantum_clifford.py +959 -0
- sage/algebras/quantum_groups/ace_quantum_onsager.py +693 -0
- sage/algebras/quantum_groups/all.py +9 -0
- sage/algebras/quantum_groups/fock_space.py +2219 -0
- sage/algebras/quantum_groups/q_numbers.py +207 -0
- sage/algebras/quantum_groups/quantum_group_gap.py +2695 -0
- sage/algebras/quantum_groups/representations.py +591 -0
- sage/algebras/quantum_matrix_coordinate_algebra.py +1006 -0
- sage/algebras/quantum_oscillator.py +623 -0
- sage/algebras/quaternion_algebra.py +20 -0
- sage/algebras/quaternion_algebra_element.py +55 -0
- sage/algebras/rational_cherednik_algebra.py +525 -0
- sage/algebras/schur_algebra.py +670 -0
- sage/algebras/shuffle_algebra.py +1011 -0
- sage/algebras/splitting_algebra.py +779 -0
- sage/algebras/tensor_algebra.py +709 -0
- sage/algebras/yangian.py +1082 -0
- sage/algebras/yokonuma_hecke_algebra.py +1018 -0
- sage/all__sagemath_combinat.py +35 -0
- sage/combinat/SJT.py +255 -0
- sage/combinat/affine_permutation.py +2405 -0
- sage/combinat/algebraic_combinatorics.py +55 -0
- sage/combinat/all.py +53 -0
- sage/combinat/all__sagemath_combinat.py +195 -0
- sage/combinat/alternating_sign_matrix.py +2063 -0
- sage/combinat/baxter_permutations.py +346 -0
- sage/combinat/bijectionist.py +3220 -0
- sage/combinat/binary_recurrence_sequences.py +1180 -0
- sage/combinat/blob_algebra.py +685 -0
- sage/combinat/catalog_partitions.py +27 -0
- sage/combinat/chas/all.py +23 -0
- sage/combinat/chas/fsym.py +1180 -0
- sage/combinat/chas/wqsym.py +2601 -0
- sage/combinat/cluster_complex.py +326 -0
- sage/combinat/colored_permutations.py +2039 -0
- sage/combinat/colored_permutations_representations.py +964 -0
- sage/combinat/composition_signed.py +142 -0
- sage/combinat/composition_tableau.py +855 -0
- sage/combinat/constellation.py +1729 -0
- sage/combinat/core.py +751 -0
- sage/combinat/counting.py +12 -0
- sage/combinat/crystals/affine.py +742 -0
- sage/combinat/crystals/affine_factorization.py +518 -0
- sage/combinat/crystals/affinization.py +331 -0
- sage/combinat/crystals/alcove_path.py +2013 -0
- sage/combinat/crystals/all.py +22 -0
- sage/combinat/crystals/bkk_crystals.py +141 -0
- sage/combinat/crystals/catalog.py +115 -0
- sage/combinat/crystals/catalog_elementary_crystals.py +18 -0
- sage/combinat/crystals/catalog_infinity_crystals.py +33 -0
- sage/combinat/crystals/catalog_kirillov_reshetikhin.py +18 -0
- sage/combinat/crystals/crystals.py +257 -0
- sage/combinat/crystals/direct_sum.py +260 -0
- sage/combinat/crystals/elementary_crystals.py +1251 -0
- sage/combinat/crystals/fast_crystals.py +441 -0
- sage/combinat/crystals/fully_commutative_stable_grothendieck.py +1205 -0
- sage/combinat/crystals/generalized_young_walls.py +1076 -0
- sage/combinat/crystals/highest_weight_crystals.py +436 -0
- sage/combinat/crystals/induced_structure.py +695 -0
- sage/combinat/crystals/infinity_crystals.py +730 -0
- sage/combinat/crystals/kac_modules.py +863 -0
- sage/combinat/crystals/kirillov_reshetikhin.py +4196 -0
- sage/combinat/crystals/kyoto_path_model.py +497 -0
- sage/combinat/crystals/letters.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/crystals/letters.pxd +79 -0
- sage/combinat/crystals/letters.pyx +3056 -0
- sage/combinat/crystals/littelmann_path.py +1518 -0
- sage/combinat/crystals/monomial_crystals.py +1262 -0
- sage/combinat/crystals/multisegments.py +462 -0
- sage/combinat/crystals/mv_polytopes.py +467 -0
- sage/combinat/crystals/pbw_crystal.py +511 -0
- sage/combinat/crystals/pbw_datum.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/crystals/pbw_datum.pxd +4 -0
- sage/combinat/crystals/pbw_datum.pyx +487 -0
- sage/combinat/crystals/polyhedral_realization.py +372 -0
- sage/combinat/crystals/spins.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/crystals/spins.pxd +21 -0
- sage/combinat/crystals/spins.pyx +756 -0
- sage/combinat/crystals/star_crystal.py +290 -0
- sage/combinat/crystals/subcrystal.py +464 -0
- sage/combinat/crystals/tensor_product.py +1177 -0
- sage/combinat/crystals/tensor_product_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/crystals/tensor_product_element.pxd +35 -0
- sage/combinat/crystals/tensor_product_element.pyx +1870 -0
- sage/combinat/crystals/virtual_crystal.py +420 -0
- sage/combinat/cyclic_sieving_phenomenon.py +204 -0
- sage/combinat/debruijn_sequence.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/debruijn_sequence.pyx +355 -0
- sage/combinat/decorated_permutation.py +270 -0
- sage/combinat/degree_sequences.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/degree_sequences.pyx +588 -0
- sage/combinat/derangements.py +527 -0
- sage/combinat/descent_algebra.py +1008 -0
- sage/combinat/diagram.py +1551 -0
- sage/combinat/diagram_algebras.py +5886 -0
- sage/combinat/dyck_word.py +4349 -0
- sage/combinat/e_one_star.py +1623 -0
- sage/combinat/enumerated_sets.py +123 -0
- sage/combinat/expnums.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/expnums.pyx +148 -0
- sage/combinat/fast_vector_partitions.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/fast_vector_partitions.pyx +346 -0
- sage/combinat/fqsym.py +1977 -0
- sage/combinat/free_dendriform_algebra.py +954 -0
- sage/combinat/free_prelie_algebra.py +1141 -0
- sage/combinat/fully_commutative_elements.py +1077 -0
- sage/combinat/fully_packed_loop.py +1523 -0
- sage/combinat/gelfand_tsetlin_patterns.py +1409 -0
- sage/combinat/gray_codes.py +311 -0
- sage/combinat/grossman_larson_algebras.py +667 -0
- sage/combinat/growth.py +4352 -0
- sage/combinat/hall_polynomial.py +188 -0
- sage/combinat/hillman_grassl.py +866 -0
- sage/combinat/integer_matrices.py +329 -0
- sage/combinat/integer_vectors_mod_permgroup.py +1238 -0
- sage/combinat/k_tableau.py +4564 -0
- sage/combinat/kazhdan_lusztig.py +215 -0
- sage/combinat/key_polynomial.py +885 -0
- sage/combinat/knutson_tao_puzzles.py +2286 -0
- sage/combinat/lr_tableau.py +311 -0
- sage/combinat/matrices/all.py +24 -0
- sage/combinat/matrices/hadamard_matrix.py +3790 -0
- sage/combinat/matrices/latin.py +2912 -0
- sage/combinat/misc.py +401 -0
- sage/combinat/multiset_partition_into_sets_ordered.py +3541 -0
- sage/combinat/ncsf_qsym/all.py +21 -0
- sage/combinat/ncsf_qsym/combinatorics.py +317 -0
- sage/combinat/ncsf_qsym/generic_basis_code.py +1427 -0
- sage/combinat/ncsf_qsym/ncsf.py +5637 -0
- sage/combinat/ncsf_qsym/qsym.py +4053 -0
- sage/combinat/ncsf_qsym/tutorial.py +447 -0
- sage/combinat/ncsym/all.py +21 -0
- sage/combinat/ncsym/bases.py +855 -0
- sage/combinat/ncsym/dual.py +593 -0
- sage/combinat/ncsym/ncsym.py +2076 -0
- sage/combinat/necklace.py +551 -0
- sage/combinat/non_decreasing_parking_function.py +634 -0
- sage/combinat/nu_dyck_word.py +1474 -0
- sage/combinat/output.py +861 -0
- sage/combinat/parallelogram_polyomino.py +4326 -0
- sage/combinat/parking_functions.py +1602 -0
- sage/combinat/partition_algebra.py +1998 -0
- sage/combinat/partition_kleshchev.py +1982 -0
- sage/combinat/partition_shifting_algebras.py +584 -0
- sage/combinat/partition_tuple.py +3114 -0
- sage/combinat/path_tableaux/all.py +13 -0
- sage/combinat/path_tableaux/catalog.py +29 -0
- sage/combinat/path_tableaux/dyck_path.py +380 -0
- sage/combinat/path_tableaux/frieze.py +476 -0
- sage/combinat/path_tableaux/path_tableau.py +728 -0
- sage/combinat/path_tableaux/semistandard.py +510 -0
- sage/combinat/perfect_matching.py +779 -0
- sage/combinat/plane_partition.py +3300 -0
- sage/combinat/q_bernoulli.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/q_bernoulli.pyx +128 -0
- sage/combinat/quickref.py +81 -0
- sage/combinat/recognizable_series.py +2051 -0
- sage/combinat/regular_sequence.py +4316 -0
- sage/combinat/regular_sequence_bounded.py +543 -0
- sage/combinat/restricted_growth.py +81 -0
- sage/combinat/ribbon.py +20 -0
- sage/combinat/ribbon_shaped_tableau.py +489 -0
- sage/combinat/ribbon_tableau.py +1180 -0
- sage/combinat/rigged_configurations/all.py +46 -0
- sage/combinat/rigged_configurations/bij_abstract_class.py +548 -0
- sage/combinat/rigged_configurations/bij_infinity.py +370 -0
- sage/combinat/rigged_configurations/bij_type_A.py +163 -0
- sage/combinat/rigged_configurations/bij_type_A2_dual.py +338 -0
- sage/combinat/rigged_configurations/bij_type_A2_even.py +218 -0
- sage/combinat/rigged_configurations/bij_type_A2_odd.py +199 -0
- sage/combinat/rigged_configurations/bij_type_B.py +900 -0
- sage/combinat/rigged_configurations/bij_type_C.py +267 -0
- sage/combinat/rigged_configurations/bij_type_D.py +771 -0
- sage/combinat/rigged_configurations/bij_type_D_tri.py +392 -0
- sage/combinat/rigged_configurations/bij_type_D_twisted.py +576 -0
- sage/combinat/rigged_configurations/bij_type_E67.py +402 -0
- sage/combinat/rigged_configurations/bijection.py +143 -0
- sage/combinat/rigged_configurations/kleber_tree.py +1475 -0
- sage/combinat/rigged_configurations/kr_tableaux.py +1898 -0
- sage/combinat/rigged_configurations/rc_crystal.py +461 -0
- sage/combinat/rigged_configurations/rc_infinity.py +540 -0
- sage/combinat/rigged_configurations/rigged_configuration_element.py +2403 -0
- sage/combinat/rigged_configurations/rigged_configurations.py +1918 -0
- sage/combinat/rigged_configurations/rigged_partition.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/rigged_configurations/rigged_partition.pxd +15 -0
- sage/combinat/rigged_configurations/rigged_partition.pyx +680 -0
- sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py +499 -0
- sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element.py +428 -0
- sage/combinat/rsk.py +3438 -0
- sage/combinat/schubert_polynomial.py +508 -0
- sage/combinat/set_partition.py +3318 -0
- sage/combinat/set_partition_iterator.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/set_partition_iterator.pyx +136 -0
- sage/combinat/set_partition_ordered.py +1590 -0
- sage/combinat/sf/abreu_nigro.py +346 -0
- sage/combinat/sf/all.py +52 -0
- sage/combinat/sf/character.py +576 -0
- sage/combinat/sf/classical.py +319 -0
- sage/combinat/sf/dual.py +996 -0
- sage/combinat/sf/elementary.py +549 -0
- sage/combinat/sf/hall_littlewood.py +1028 -0
- sage/combinat/sf/hecke.py +336 -0
- sage/combinat/sf/homogeneous.py +464 -0
- sage/combinat/sf/jack.py +1428 -0
- sage/combinat/sf/k_dual.py +1458 -0
- sage/combinat/sf/kfpoly.py +447 -0
- sage/combinat/sf/llt.py +789 -0
- sage/combinat/sf/macdonald.py +2019 -0
- sage/combinat/sf/monomial.py +525 -0
- sage/combinat/sf/multiplicative.py +113 -0
- sage/combinat/sf/new_kschur.py +1786 -0
- sage/combinat/sf/ns_macdonald.py +964 -0
- sage/combinat/sf/orthogonal.py +246 -0
- sage/combinat/sf/orthotriang.py +355 -0
- sage/combinat/sf/powersum.py +963 -0
- sage/combinat/sf/schur.py +880 -0
- sage/combinat/sf/sf.py +1653 -0
- sage/combinat/sf/sfa.py +7053 -0
- sage/combinat/sf/symplectic.py +253 -0
- sage/combinat/sf/witt.py +721 -0
- sage/combinat/shifted_primed_tableau.py +2735 -0
- sage/combinat/shuffle.py +830 -0
- sage/combinat/sidon_sets.py +146 -0
- sage/combinat/similarity_class_type.py +1721 -0
- sage/combinat/sine_gordon.py +618 -0
- sage/combinat/six_vertex_model.py +784 -0
- sage/combinat/skew_partition.py +2053 -0
- sage/combinat/skew_tableau.py +2989 -0
- sage/combinat/sloane_functions.py +8935 -0
- sage/combinat/specht_module.py +1403 -0
- sage/combinat/species/all.py +48 -0
- sage/combinat/species/characteristic_species.py +321 -0
- sage/combinat/species/composition_species.py +273 -0
- sage/combinat/species/cycle_species.py +284 -0
- sage/combinat/species/empty_species.py +155 -0
- sage/combinat/species/functorial_composition_species.py +148 -0
- sage/combinat/species/generating_series.py +673 -0
- sage/combinat/species/library.py +148 -0
- sage/combinat/species/linear_order_species.py +169 -0
- sage/combinat/species/misc.py +83 -0
- sage/combinat/species/partition_species.py +290 -0
- sage/combinat/species/permutation_species.py +268 -0
- sage/combinat/species/product_species.py +423 -0
- sage/combinat/species/recursive_species.py +476 -0
- sage/combinat/species/set_species.py +192 -0
- sage/combinat/species/species.py +820 -0
- sage/combinat/species/structure.py +539 -0
- sage/combinat/species/subset_species.py +243 -0
- sage/combinat/species/sum_species.py +225 -0
- sage/combinat/subword.py +564 -0
- sage/combinat/subword_complex.py +2122 -0
- sage/combinat/subword_complex_c.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/subword_complex_c.pyx +119 -0
- sage/combinat/super_tableau.py +821 -0
- sage/combinat/superpartition.py +1154 -0
- sage/combinat/symmetric_group_algebra.py +3774 -0
- sage/combinat/symmetric_group_representations.py +1830 -0
- sage/combinat/t_sequences.py +877 -0
- sage/combinat/tableau.py +9506 -0
- sage/combinat/tableau_residues.py +860 -0
- sage/combinat/tableau_tuple.py +5353 -0
- sage/combinat/tiling.py +2432 -0
- sage/combinat/triangles_FHM.py +777 -0
- sage/combinat/tutorial.py +1857 -0
- sage/combinat/vector_partition.py +337 -0
- sage/combinat/words/abstract_word.py +1722 -0
- sage/combinat/words/all.py +59 -0
- sage/combinat/words/alphabet.py +268 -0
- sage/combinat/words/finite_word.py +7201 -0
- sage/combinat/words/infinite_word.py +113 -0
- sage/combinat/words/lyndon_word.py +652 -0
- sage/combinat/words/morphic.py +351 -0
- sage/combinat/words/morphism.py +3878 -0
- sage/combinat/words/paths.py +2932 -0
- sage/combinat/words/shuffle_product.py +278 -0
- sage/combinat/words/suffix_trees.py +1873 -0
- sage/combinat/words/word.py +769 -0
- sage/combinat/words/word_char.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/words/word_char.pyx +847 -0
- sage/combinat/words/word_datatypes.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/words/word_datatypes.pxd +4 -0
- sage/combinat/words/word_datatypes.pyx +1067 -0
- sage/combinat/words/word_generators.py +2026 -0
- sage/combinat/words/word_infinite_datatypes.py +1218 -0
- sage/combinat/words/word_options.py +99 -0
- sage/combinat/words/words.py +2396 -0
- sage/data_structures/all__sagemath_combinat.py +1 -0
- sage/databases/all__sagemath_combinat.py +13 -0
- sage/databases/findstat.py +4897 -0
- sage/databases/oeis.py +2058 -0
- sage/databases/sloane.py +393 -0
- sage/dynamics/all__sagemath_combinat.py +14 -0
- sage/dynamics/cellular_automata/all.py +7 -0
- sage/dynamics/cellular_automata/catalog.py +34 -0
- sage/dynamics/cellular_automata/elementary.py +612 -0
- sage/dynamics/cellular_automata/glca.py +477 -0
- sage/dynamics/cellular_automata/solitons.py +1463 -0
- sage/dynamics/finite_dynamical_system.py +1249 -0
- sage/dynamics/finite_dynamical_system_catalog.py +382 -0
- sage/games/all.py +7 -0
- sage/games/hexad.py +704 -0
- sage/games/quantumino.py +591 -0
- sage/games/sudoku.py +889 -0
- sage/games/sudoku_backtrack.cpython-314-x86_64-linux-musl.so +0 -0
- sage/games/sudoku_backtrack.pyx +189 -0
- sage/groups/all__sagemath_combinat.py +1 -0
- sage/groups/indexed_free_group.py +489 -0
- sage/libs/all__sagemath_combinat.py +6 -0
- sage/libs/lrcalc/__init__.py +1 -0
- sage/libs/lrcalc/lrcalc.py +525 -0
- sage/libs/symmetrica/__init__.py +7 -0
- sage/libs/symmetrica/all.py +101 -0
- sage/libs/symmetrica/kostka.pxi +168 -0
- sage/libs/symmetrica/part.pxi +193 -0
- sage/libs/symmetrica/plet.pxi +42 -0
- sage/libs/symmetrica/sab.pxi +196 -0
- sage/libs/symmetrica/sb.pxi +332 -0
- sage/libs/symmetrica/sc.pxi +192 -0
- sage/libs/symmetrica/schur.pxi +956 -0
- sage/libs/symmetrica/symmetrica.cpython-314-x86_64-linux-musl.so +0 -0
- sage/libs/symmetrica/symmetrica.pxi +1172 -0
- sage/libs/symmetrica/symmetrica.pyx +39 -0
- sage/monoids/all.py +13 -0
- sage/monoids/automatic_semigroup.py +1054 -0
- sage/monoids/free_abelian_monoid.py +315 -0
- sage/monoids/free_abelian_monoid_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/monoids/free_abelian_monoid_element.pxd +16 -0
- sage/monoids/free_abelian_monoid_element.pyx +397 -0
- sage/monoids/free_monoid.py +335 -0
- sage/monoids/free_monoid_element.py +431 -0
- sage/monoids/hecke_monoid.py +65 -0
- sage/monoids/string_monoid.py +817 -0
- sage/monoids/string_monoid_element.py +547 -0
- sage/monoids/string_ops.py +143 -0
- sage/monoids/trace_monoid.py +972 -0
- sage/rings/all__sagemath_combinat.py +2 -0
- sage/sat/all.py +4 -0
- sage/sat/boolean_polynomials.py +405 -0
- sage/sat/converters/__init__.py +6 -0
- sage/sat/converters/anf2cnf.py +14 -0
- sage/sat/converters/polybori.py +611 -0
- sage/sat/solvers/__init__.py +5 -0
- sage/sat/solvers/cryptominisat.py +287 -0
- sage/sat/solvers/dimacs.py +783 -0
- sage/sat/solvers/picosat.py +228 -0
- sage/sat/solvers/sat_lp.py +156 -0
- sage/sat/solvers/satsolver.cpython-314-x86_64-linux-musl.so +0 -0
- sage/sat/solvers/satsolver.pxd +3 -0
- sage/sat/solvers/satsolver.pyx +405 -0
|
@@ -0,0 +1,2405 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-combinat
|
|
2
|
+
# sage.doctest: needs sage.combinat sage.groups
|
|
3
|
+
r"""
|
|
4
|
+
Affine permutations
|
|
5
|
+
"""
|
|
6
|
+
# ****************************************************************************
|
|
7
|
+
# Copyright (C) 2013 Tom Denton <sdenton4@gmail.com>
|
|
8
|
+
#
|
|
9
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
10
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
11
|
+
# the License, or (at your option) any later version.
|
|
12
|
+
# https://www.gnu.org/licenses/
|
|
13
|
+
# ****************************************************************************
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
from itertools import repeat
|
|
16
|
+
|
|
17
|
+
from sage.categories.affine_weyl_groups import AffineWeylGroups
|
|
18
|
+
from sage.combinat.composition import Composition
|
|
19
|
+
from sage.combinat.partition import Partition
|
|
20
|
+
from sage.combinat.root_system.cartan_type import CartanType
|
|
21
|
+
from sage.misc.cachefunc import cached_method
|
|
22
|
+
from sage.misc.constant_function import ConstantFunction
|
|
23
|
+
from sage.misc.lazy_import import lazy_import
|
|
24
|
+
from sage.misc.misc_c import prod
|
|
25
|
+
from sage.misc.prandom import randint
|
|
26
|
+
from sage.rings.integer import Integer
|
|
27
|
+
from sage.structure.list_clone import ClonableArray
|
|
28
|
+
from sage.structure.parent import Parent
|
|
29
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
30
|
+
|
|
31
|
+
lazy_import('sage.combinat.root_system.weyl_group', 'WeylGroup')
|
|
32
|
+
lazy_import('sage.groups.perm_gps.permgroup_named', 'SymmetricGroup')
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class AffinePermutation(ClonableArray):
|
|
36
|
+
r"""
|
|
37
|
+
An affine permutation, represented in the window notation, and
|
|
38
|
+
considered as a bijection from `\ZZ` to `\ZZ`.
|
|
39
|
+
|
|
40
|
+
EXAMPLES::
|
|
41
|
+
|
|
42
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
43
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
44
|
+
sage: p
|
|
45
|
+
Type A affine permutation with window [3, -1, 0, 6, 5, 4, 10, 9]
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def __init__(self, parent, lst, check=True) -> None:
|
|
49
|
+
r"""
|
|
50
|
+
Initialize ``self``.
|
|
51
|
+
|
|
52
|
+
INPUT:
|
|
53
|
+
|
|
54
|
+
- ``parent`` -- the parent affine permutation group
|
|
55
|
+
|
|
56
|
+
- ``lst`` -- list giving the base window of the affine permutation
|
|
57
|
+
|
|
58
|
+
- ``check`` -- whether to test if the affine permutation is valid
|
|
59
|
+
|
|
60
|
+
EXAMPLES::
|
|
61
|
+
|
|
62
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
63
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
64
|
+
sage: p
|
|
65
|
+
Type A affine permutation with window [3, -1, 0, 6, 5, 4, 10, 9]
|
|
66
|
+
sage: TestSuite(p).run()
|
|
67
|
+
|
|
68
|
+
TESTS:
|
|
69
|
+
|
|
70
|
+
Check that :issue:`26436` is fixed::
|
|
71
|
+
|
|
72
|
+
sage: A = AffinePermutationGroup(['A',3,1])
|
|
73
|
+
sage: p = A([-3/1,2/1,3/1,8/1])
|
|
74
|
+
sage: q = ~p
|
|
75
|
+
sage: q * p
|
|
76
|
+
Type A affine permutation with window [1, 2, 3, 4]
|
|
77
|
+
"""
|
|
78
|
+
if check:
|
|
79
|
+
lst = [Integer(val) for val in lst]
|
|
80
|
+
self.k = parent.k
|
|
81
|
+
self.n = self.k + 1
|
|
82
|
+
# This N doesn't matter for type A, but comes up in all other types.
|
|
83
|
+
if parent.cartan_type()[0] == 'A':
|
|
84
|
+
self.N = self.n
|
|
85
|
+
elif parent.cartan_type()[0] in ['B', 'C', 'D']:
|
|
86
|
+
self.N = 2 * self.k + 1
|
|
87
|
+
elif parent.cartan_type()[0] == 'G':
|
|
88
|
+
self.N = 6
|
|
89
|
+
else:
|
|
90
|
+
raise NotImplementedError('unsupported Cartan type')
|
|
91
|
+
ClonableArray.__init__(self, parent, lst, check)
|
|
92
|
+
|
|
93
|
+
def _repr_(self) -> str:
|
|
94
|
+
r"""
|
|
95
|
+
EXAMPLES::
|
|
96
|
+
|
|
97
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
98
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
99
|
+
sage: p
|
|
100
|
+
Type A affine permutation with window [3, -1, 0, 6, 5, 4, 10, 9]
|
|
101
|
+
"""
|
|
102
|
+
return ("Type " + self.parent().cartan_type().letter
|
|
103
|
+
+ " affine permutation with window " + str(list(self)))
|
|
104
|
+
|
|
105
|
+
def __rmul__(self, q) -> AffinePermutation:
|
|
106
|
+
r"""
|
|
107
|
+
Given ``self`` and `q`, returns ``self*q``.
|
|
108
|
+
|
|
109
|
+
INPUT:
|
|
110
|
+
|
|
111
|
+
- ``q`` -- an element of ``self.parent()``
|
|
112
|
+
|
|
113
|
+
EXAMPLES::
|
|
114
|
+
|
|
115
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
116
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
117
|
+
sage: q = A([0, 2, 3, 4, 5, 6, 7, 9])
|
|
118
|
+
sage: p.__rmul__(q)
|
|
119
|
+
Type A affine permutation with window [1, -1, 0, 6, 5, 4, 10, 11]
|
|
120
|
+
"""
|
|
121
|
+
l = [self.value(q.value(i)) for i in range(1, len(self) + 1)]
|
|
122
|
+
return type(self)(self.parent(), l, check=False)
|
|
123
|
+
|
|
124
|
+
def __lmul__(self, q) -> AffinePermutation:
|
|
125
|
+
r"""
|
|
126
|
+
Given ``self`` and `q`, returns ``q*self``.
|
|
127
|
+
|
|
128
|
+
INPUT:
|
|
129
|
+
|
|
130
|
+
- ``q`` -- an element of ``self.parent()``
|
|
131
|
+
|
|
132
|
+
EXAMPLES::
|
|
133
|
+
|
|
134
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
135
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
136
|
+
sage: q = A([0,2,3,4,5,6,7,9])
|
|
137
|
+
sage: p.__lmul__(q)
|
|
138
|
+
Type A affine permutation with window [3, -1, 1, 6, 5, 4, 10, 8]
|
|
139
|
+
"""
|
|
140
|
+
# if self.parent().right_to_left:
|
|
141
|
+
# self,q=q,self
|
|
142
|
+
# ... product rule
|
|
143
|
+
l = [q.value(self.value(i)) for i in range(1, len(self) + 1)]
|
|
144
|
+
return type(self)(self.parent(), l, check=False)
|
|
145
|
+
|
|
146
|
+
def __mul__(self, q) -> AffinePermutation:
|
|
147
|
+
r"""
|
|
148
|
+
Given ``self`` and `q`, returns ``self*q``.
|
|
149
|
+
|
|
150
|
+
INPUT:
|
|
151
|
+
|
|
152
|
+
- ``q`` -- an element of ``self.parent()``
|
|
153
|
+
|
|
154
|
+
EXAMPLES::
|
|
155
|
+
|
|
156
|
+
sage: p = AffinePermutationGroup(['A',7,1])([3, -1, 0, 6, 5, 4, 10, 9])
|
|
157
|
+
sage: s1 = AffinePermutationGroup(['A',7,1]).one().apply_simple_reflection(1)
|
|
158
|
+
sage: p * s1
|
|
159
|
+
Type A affine permutation with window [-1, 3, 0, 6, 5, 4, 10, 9]
|
|
160
|
+
sage: p.apply_simple_reflection(1, 'right')
|
|
161
|
+
Type A affine permutation with window [-1, 3, 0, 6, 5, 4, 10, 9]
|
|
162
|
+
"""
|
|
163
|
+
return self.__rmul__(q)
|
|
164
|
+
|
|
165
|
+
@cached_method
|
|
166
|
+
def __invert__(self) -> AffinePermutation:
|
|
167
|
+
r"""
|
|
168
|
+
Return the inverse affine permutation.
|
|
169
|
+
|
|
170
|
+
EXAMPLES::
|
|
171
|
+
|
|
172
|
+
sage: p = AffinePermutationGroup(['A',7,1])([3, -1, 0, 6, 5, 4, 10, 9])
|
|
173
|
+
sage: p.inverse() # indirect doctest
|
|
174
|
+
Type A affine permutation with window [0, -1, 1, 6, 5, 4, 10, 11]
|
|
175
|
+
"""
|
|
176
|
+
inv = [self.position(i) for i in range(1, len(self) + 1)]
|
|
177
|
+
return type(self)(self.parent(), inv, check=False)
|
|
178
|
+
|
|
179
|
+
def apply_simple_reflection(self, i, side='right') -> AffinePermutation:
|
|
180
|
+
r"""
|
|
181
|
+
Apply a simple reflection.
|
|
182
|
+
|
|
183
|
+
INPUT:
|
|
184
|
+
|
|
185
|
+
- ``i`` -- integer
|
|
186
|
+
- ``side`` -- (default: ``'right'``) determines whether to apply the
|
|
187
|
+
reflection on the ``'right'`` or ``'left'``
|
|
188
|
+
|
|
189
|
+
EXAMPLES::
|
|
190
|
+
|
|
191
|
+
sage: p = AffinePermutationGroup(['A',7,1])([3, -1, 0, 6, 5, 4, 10, 9])
|
|
192
|
+
sage: p.apply_simple_reflection(3)
|
|
193
|
+
Type A affine permutation with window [3, -1, 6, 0, 5, 4, 10, 9]
|
|
194
|
+
sage: p.apply_simple_reflection(11)
|
|
195
|
+
Type A affine permutation with window [3, -1, 6, 0, 5, 4, 10, 9]
|
|
196
|
+
sage: p.apply_simple_reflection(3, 'left')
|
|
197
|
+
Type A affine permutation with window [4, -1, 0, 6, 5, 3, 10, 9]
|
|
198
|
+
sage: p.apply_simple_reflection(11, 'left')
|
|
199
|
+
Type A affine permutation with window [4, -1, 0, 6, 5, 3, 10, 9]
|
|
200
|
+
"""
|
|
201
|
+
if side == 'right':
|
|
202
|
+
return self.apply_simple_reflection_right(i)
|
|
203
|
+
return self.apply_simple_reflection_left(i)
|
|
204
|
+
|
|
205
|
+
def __call__(self, i):
|
|
206
|
+
r"""
|
|
207
|
+
Return the image of the integer ``i`` under this permutation.
|
|
208
|
+
|
|
209
|
+
EXAMPLES::
|
|
210
|
+
|
|
211
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
212
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
213
|
+
sage: p.value(1) #indirect doctest
|
|
214
|
+
3
|
|
215
|
+
sage: p.value(9)
|
|
216
|
+
11
|
|
217
|
+
"""
|
|
218
|
+
return self.value(i)
|
|
219
|
+
|
|
220
|
+
def is_i_grassmannian(self, i=0, side='right') -> bool:
|
|
221
|
+
r"""
|
|
222
|
+
Test whether ``self`` is `i`-grassmannian, i.e., either is the
|
|
223
|
+
identity or has ``i`` as the sole descent.
|
|
224
|
+
|
|
225
|
+
INPUT:
|
|
226
|
+
|
|
227
|
+
- ``i`` -- an element of the index set
|
|
228
|
+
- ``side`` -- determines the side on which to check the descents
|
|
229
|
+
|
|
230
|
+
EXAMPLES::
|
|
231
|
+
|
|
232
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
233
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
234
|
+
sage: p.is_i_grassmannian()
|
|
235
|
+
False
|
|
236
|
+
sage: q = A.from_word([3,2,1,0])
|
|
237
|
+
sage: q.is_i_grassmannian()
|
|
238
|
+
True
|
|
239
|
+
sage: q = A.from_word([2,3,4,5])
|
|
240
|
+
sage: q.is_i_grassmannian(5)
|
|
241
|
+
True
|
|
242
|
+
sage: q.is_i_grassmannian(2, side='left')
|
|
243
|
+
True
|
|
244
|
+
"""
|
|
245
|
+
return self == self.parent().one() or self.descents(side) == [i]
|
|
246
|
+
|
|
247
|
+
def index_set(self) -> tuple[int, ...]:
|
|
248
|
+
r"""
|
|
249
|
+
Index set of the affine permutation group.
|
|
250
|
+
|
|
251
|
+
EXAMPLES::
|
|
252
|
+
|
|
253
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
254
|
+
sage: A.index_set()
|
|
255
|
+
(0, 1, 2, 3, 4, 5, 6, 7)
|
|
256
|
+
"""
|
|
257
|
+
return tuple(range(self.k + 1))
|
|
258
|
+
|
|
259
|
+
def lower_covers(self, side='right') -> list[AffinePermutation]:
|
|
260
|
+
r"""
|
|
261
|
+
Return lower covers of ``self``.
|
|
262
|
+
|
|
263
|
+
The set of affine permutations of one less length related by
|
|
264
|
+
multiplication by a simple transposition on the indicated side.
|
|
265
|
+
These are the elements that ``self`` covers in weak order.
|
|
266
|
+
|
|
267
|
+
EXAMPLES::
|
|
268
|
+
|
|
269
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
270
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
271
|
+
sage: p.lower_covers()
|
|
272
|
+
[Type A affine permutation with window [-1, 3, 0, 6, 5, 4, 10, 9],
|
|
273
|
+
Type A affine permutation with window [3, -1, 0, 5, 6, 4, 10, 9],
|
|
274
|
+
Type A affine permutation with window [3, -1, 0, 6, 4, 5, 10, 9],
|
|
275
|
+
Type A affine permutation with window [3, -1, 0, 6, 5, 4, 9, 10]]
|
|
276
|
+
"""
|
|
277
|
+
S = self.descents(side)
|
|
278
|
+
return [self.apply_simple_reflection(i, side) for i in S]
|
|
279
|
+
|
|
280
|
+
def is_one(self) -> bool:
|
|
281
|
+
r"""
|
|
282
|
+
Test whether the affine permutation is the identity.
|
|
283
|
+
|
|
284
|
+
EXAMPLES::
|
|
285
|
+
|
|
286
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
287
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
288
|
+
sage: p.is_one()
|
|
289
|
+
False
|
|
290
|
+
sage: q = A.one()
|
|
291
|
+
sage: q.is_one()
|
|
292
|
+
True
|
|
293
|
+
"""
|
|
294
|
+
return self == self.parent().one()
|
|
295
|
+
|
|
296
|
+
def reduced_word(self) -> list[int]:
|
|
297
|
+
r"""
|
|
298
|
+
Return a reduced word for the affine permutation.
|
|
299
|
+
|
|
300
|
+
EXAMPLES::
|
|
301
|
+
|
|
302
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
303
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
304
|
+
sage: p.reduced_word()
|
|
305
|
+
[0, 7, 4, 1, 0, 7, 5, 4, 2, 1]
|
|
306
|
+
"""
|
|
307
|
+
# This is about 25% faster than the default algorithm.
|
|
308
|
+
x = self
|
|
309
|
+
i = 0
|
|
310
|
+
word = []
|
|
311
|
+
while not x.is_one():
|
|
312
|
+
if x.has_descent(i):
|
|
313
|
+
x = x.apply_simple_reflection_right(i)
|
|
314
|
+
word.append(i)
|
|
315
|
+
i = (i+1) % (self.k+1)
|
|
316
|
+
word.reverse()
|
|
317
|
+
return word
|
|
318
|
+
|
|
319
|
+
def signature(self) -> int:
|
|
320
|
+
r"""
|
|
321
|
+
Signature of the affine permutation, `(-1)^l`, where `l` is the
|
|
322
|
+
length of the permutation.
|
|
323
|
+
|
|
324
|
+
EXAMPLES::
|
|
325
|
+
|
|
326
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
327
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
328
|
+
sage: p.signature()
|
|
329
|
+
1
|
|
330
|
+
"""
|
|
331
|
+
return (-1)**self.length()
|
|
332
|
+
|
|
333
|
+
@cached_method
|
|
334
|
+
def to_weyl_group_element(self):
|
|
335
|
+
r"""
|
|
336
|
+
The affine Weyl group element corresponding to the affine permutation.
|
|
337
|
+
|
|
338
|
+
EXAMPLES::
|
|
339
|
+
|
|
340
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
341
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
342
|
+
sage: p.to_weyl_group_element()
|
|
343
|
+
[ 0 -1 0 1 0 0 1 0]
|
|
344
|
+
[ 1 -1 0 1 0 0 1 -1]
|
|
345
|
+
[ 1 -1 0 1 0 0 0 0]
|
|
346
|
+
[ 0 0 0 1 0 0 0 0]
|
|
347
|
+
[ 0 0 0 1 0 -1 1 0]
|
|
348
|
+
[ 0 0 0 1 -1 0 1 0]
|
|
349
|
+
[ 0 0 0 0 0 0 1 0]
|
|
350
|
+
[ 0 -1 1 0 0 0 1 0]
|
|
351
|
+
"""
|
|
352
|
+
W = self.parent().weyl_group()
|
|
353
|
+
return W.from_reduced_word(self.reduced_word())
|
|
354
|
+
|
|
355
|
+
def grassmannian_quotient(self, i=0, side='right') -> tuple:
|
|
356
|
+
r"""
|
|
357
|
+
Return the Grassmannian quotient.
|
|
358
|
+
|
|
359
|
+
Factors ``self`` into a unique product of a Grassmannian and a
|
|
360
|
+
finite-type element. Returns a tuple containing the Grassmannian
|
|
361
|
+
and finite elements, in order according to ``side``.
|
|
362
|
+
|
|
363
|
+
INPUT:
|
|
364
|
+
|
|
365
|
+
- ``i`` -- (default: 0) an element of the index set; the descent
|
|
366
|
+
checked for
|
|
367
|
+
|
|
368
|
+
EXAMPLES::
|
|
369
|
+
|
|
370
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
371
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
372
|
+
sage: gq=p.grassmannian_quotient()
|
|
373
|
+
sage: gq
|
|
374
|
+
(Type A affine permutation with window [-1, 0, 3, 4, 5, 6, 9, 10],
|
|
375
|
+
Type A affine permutation with window [3, 1, 2, 6, 5, 4, 8, 7])
|
|
376
|
+
sage: gq[0].is_i_grassmannian()
|
|
377
|
+
True
|
|
378
|
+
sage: 0 not in gq[1].reduced_word()
|
|
379
|
+
True
|
|
380
|
+
sage: prod(gq)==p
|
|
381
|
+
True
|
|
382
|
+
|
|
383
|
+
sage: gqLeft=p.grassmannian_quotient(side='left')
|
|
384
|
+
sage: 0 not in gqLeft[0].reduced_word()
|
|
385
|
+
True
|
|
386
|
+
sage: gqLeft[1].is_i_grassmannian(side='left')
|
|
387
|
+
True
|
|
388
|
+
sage: prod(gqLeft)==p
|
|
389
|
+
True
|
|
390
|
+
"""
|
|
391
|
+
fin = self.parent().one()
|
|
392
|
+
gr = self
|
|
393
|
+
D = gr.descents(side=side)
|
|
394
|
+
while not (D == [i] or D == []):
|
|
395
|
+
m = D[0]
|
|
396
|
+
if m == i:
|
|
397
|
+
m = D[1]
|
|
398
|
+
if side == 'right':
|
|
399
|
+
fin = fin.apply_simple_reflection(m, side='left')
|
|
400
|
+
gr = gr.apply_simple_reflection(m, side='right')
|
|
401
|
+
else:
|
|
402
|
+
fin = fin.apply_simple_reflection(m, side='right')
|
|
403
|
+
gr = gr.apply_simple_reflection(m, side='left')
|
|
404
|
+
D = gr.descents(side=side)
|
|
405
|
+
if side == 'right':
|
|
406
|
+
return (gr, fin)
|
|
407
|
+
else:
|
|
408
|
+
return (fin, gr)
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
class AffinePermutationTypeA(AffinePermutation):
|
|
412
|
+
# ----------------------
|
|
413
|
+
# Type-specific methods.
|
|
414
|
+
# (Methods existing in all types, but with type-specific definition.)
|
|
415
|
+
# ----------------------
|
|
416
|
+
def check(self) -> None:
|
|
417
|
+
r"""
|
|
418
|
+
Check that ``self`` is an affine permutation.
|
|
419
|
+
|
|
420
|
+
EXAMPLES::
|
|
421
|
+
|
|
422
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
423
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
424
|
+
sage: p
|
|
425
|
+
Type A affine permutation with window [3, -1, 0, 6, 5, 4, 10, 9]
|
|
426
|
+
sage: q = A([1,2,3]) # indirect doctest
|
|
427
|
+
Traceback (most recent call last):
|
|
428
|
+
...
|
|
429
|
+
ValueError: length of list must be k+1=8
|
|
430
|
+
sage: q = A([1,2,3,4,5,6,7,0]) # indirect doctest
|
|
431
|
+
Traceback (most recent call last):
|
|
432
|
+
...
|
|
433
|
+
ValueError: window does not sum to 36
|
|
434
|
+
sage: q = A([1,1,3,4,5,6,7,9]) # indirect doctest
|
|
435
|
+
Traceback (most recent call last):
|
|
436
|
+
...
|
|
437
|
+
ValueError: entries must have distinct residues
|
|
438
|
+
"""
|
|
439
|
+
if not self:
|
|
440
|
+
return
|
|
441
|
+
k = self.parent().k
|
|
442
|
+
# Type A
|
|
443
|
+
if len(self) != k + 1:
|
|
444
|
+
raise ValueError(f"length of list must be k+1={k + 1}")
|
|
445
|
+
sigma = (k + 2).binomial(2)
|
|
446
|
+
if sigma != sum(self):
|
|
447
|
+
raise ValueError(f"window does not sum to {sigma}")
|
|
448
|
+
l = sorted(i % (k + 1) for i in self)
|
|
449
|
+
if any(i != j for i, j in enumerate(l)):
|
|
450
|
+
raise ValueError("entries must have distinct residues")
|
|
451
|
+
|
|
452
|
+
def value(self, i, base_window=False):
|
|
453
|
+
r"""
|
|
454
|
+
Return the image of the integer ``i`` under this permutation.
|
|
455
|
+
|
|
456
|
+
INPUT:
|
|
457
|
+
|
|
458
|
+
- ``base_window`` -- boolean; indicating whether ``i`` is in the
|
|
459
|
+
base window; if ``True``, will run a bit faster, but the method
|
|
460
|
+
will screw up if ``i`` is not actually in the index set
|
|
461
|
+
|
|
462
|
+
EXAMPLES::
|
|
463
|
+
|
|
464
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
465
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
466
|
+
sage: p.value(1)
|
|
467
|
+
3
|
|
468
|
+
sage: p.value(9)
|
|
469
|
+
11
|
|
470
|
+
"""
|
|
471
|
+
if base_window:
|
|
472
|
+
self[i-1]
|
|
473
|
+
window = (i-1) // (self.k+1)
|
|
474
|
+
return self[(i-1) % (self.k+1)] + window*(self.k+1)
|
|
475
|
+
|
|
476
|
+
def position(self, i):
|
|
477
|
+
r"""
|
|
478
|
+
Find the position ``j`` such the ``self.value(j) == i``.
|
|
479
|
+
|
|
480
|
+
EXAMPLES::
|
|
481
|
+
|
|
482
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
483
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
484
|
+
sage: p.position(3)
|
|
485
|
+
1
|
|
486
|
+
sage: p.position(11)
|
|
487
|
+
9
|
|
488
|
+
"""
|
|
489
|
+
for r in range(self.k+1):
|
|
490
|
+
if self[r] % (self.k+1) == i % (self.k+1):
|
|
491
|
+
# i sits in position i, but some number of windows away.
|
|
492
|
+
diff = (i-self[r]) // (self.k+1)
|
|
493
|
+
return r + diff*(self.k+1) + 1
|
|
494
|
+
return False
|
|
495
|
+
|
|
496
|
+
def apply_simple_reflection_right(self, i) -> AffinePermutationTypeA:
|
|
497
|
+
r"""
|
|
498
|
+
Apply the simple reflection to positions `i`, `i+1`.
|
|
499
|
+
|
|
500
|
+
INPUT:
|
|
501
|
+
|
|
502
|
+
- ``i`` -- integer
|
|
503
|
+
|
|
504
|
+
EXAMPLES::
|
|
505
|
+
|
|
506
|
+
sage: p = AffinePermutationGroup(['A',7,1])([3, -1, 0, 6, 5, 4, 10, 9])
|
|
507
|
+
sage: p.apply_simple_reflection_right(3)
|
|
508
|
+
Type A affine permutation with window [3, -1, 6, 0, 5, 4, 10, 9]
|
|
509
|
+
sage: p.apply_simple_reflection_right(11)
|
|
510
|
+
Type A affine permutation with window [3, -1, 6, 0, 5, 4, 10, 9]
|
|
511
|
+
"""
|
|
512
|
+
j = i % (self.k+1)
|
|
513
|
+
# Cloning is currently kinda broken, in that caches don't clear which
|
|
514
|
+
# leads to strangeness with the cloned object.
|
|
515
|
+
# The clone approach is quite a bit (2x) faster, though, so this should
|
|
516
|
+
# switch once the caching situation is fixed.
|
|
517
|
+
# with self.clone(check=False) as l:
|
|
518
|
+
l = self[:]
|
|
519
|
+
if j == 0:
|
|
520
|
+
a = l[0]
|
|
521
|
+
l[0] = l[-1] - (self.k+1)
|
|
522
|
+
l[-1] = a + (self.k+1)
|
|
523
|
+
else:
|
|
524
|
+
a = l[j-1]
|
|
525
|
+
l[j-1] = l[j]
|
|
526
|
+
l[j] = a
|
|
527
|
+
return type(self)(self.parent(), l, check=False)
|
|
528
|
+
|
|
529
|
+
def apply_simple_reflection_left(self, i) -> AffinePermutationTypeA:
|
|
530
|
+
r"""
|
|
531
|
+
Apply the simple reflection to the values `i`, `i+1`.
|
|
532
|
+
|
|
533
|
+
EXAMPLES::
|
|
534
|
+
|
|
535
|
+
sage: p = AffinePermutationGroup(['A',7,1])([3, -1, 0, 6, 5, 4, 10, 9])
|
|
536
|
+
sage: p.apply_simple_reflection_left(3)
|
|
537
|
+
Type A affine permutation with window [4, -1, 0, 6, 5, 3, 10, 9]
|
|
538
|
+
sage: p.apply_simple_reflection_left(11)
|
|
539
|
+
Type A affine permutation with window [4, -1, 0, 6, 5, 3, 10, 9]
|
|
540
|
+
"""
|
|
541
|
+
# Here are a couple other methods we tried out, but turned out
|
|
542
|
+
# to be slower than the current implementation.
|
|
543
|
+
# 1) This one was very bad:
|
|
544
|
+
# return self.inverse().apply_simple_reflection_right(i).inverse()
|
|
545
|
+
# 2) Also bad, though not quite so bad:
|
|
546
|
+
# return (self.parent().simple_reflection(i))*self
|
|
547
|
+
i = i % (self.k + 1)
|
|
548
|
+
# Cloning is currently kinda broken, in that caches don't clear which
|
|
549
|
+
# leads to strangeness with the cloned object.
|
|
550
|
+
# The clone approach is quite a bit faster, though,
|
|
551
|
+
# so this should switch once the caching situation is fixed.
|
|
552
|
+
# with self.clone(check=False) as l:
|
|
553
|
+
l = []
|
|
554
|
+
if i != self.k:
|
|
555
|
+
for m in range(self.k + 1):
|
|
556
|
+
res = self[m] % (self.k + 1)
|
|
557
|
+
if res == i:
|
|
558
|
+
l.append(self[m] + 1)
|
|
559
|
+
elif res == i + 1:
|
|
560
|
+
l.append(self[m] - 1)
|
|
561
|
+
else:
|
|
562
|
+
l.append(self[m])
|
|
563
|
+
if i == self.k:
|
|
564
|
+
for m in range(self.k + 1):
|
|
565
|
+
res = self[m] % (self.k + 1)
|
|
566
|
+
if res == i:
|
|
567
|
+
l.append(self[m] + 1)
|
|
568
|
+
elif res == 0:
|
|
569
|
+
l.append(self[m] - 1)
|
|
570
|
+
else:
|
|
571
|
+
l.append(self[m])
|
|
572
|
+
return type(self)(self.parent(), l, check=False)
|
|
573
|
+
|
|
574
|
+
def has_right_descent(self, i) -> bool:
|
|
575
|
+
r"""
|
|
576
|
+
Determine whether there is a descent at ``i``.
|
|
577
|
+
|
|
578
|
+
INPUT:
|
|
579
|
+
|
|
580
|
+
- ``i`` -- integer
|
|
581
|
+
|
|
582
|
+
EXAMPLES::
|
|
583
|
+
|
|
584
|
+
sage: p = AffinePermutationGroup(['A',7,1])([3, -1, 0, 6, 5, 4, 10, 9])
|
|
585
|
+
sage: p.has_right_descent(1)
|
|
586
|
+
True
|
|
587
|
+
sage: p.has_right_descent(9)
|
|
588
|
+
True
|
|
589
|
+
sage: p.has_right_descent(0)
|
|
590
|
+
False
|
|
591
|
+
"""
|
|
592
|
+
return self.value(i) > self.value(i + 1)
|
|
593
|
+
|
|
594
|
+
def has_left_descent(self, i) -> bool:
|
|
595
|
+
r"""
|
|
596
|
+
Determine whether there is a descent at ``i``.
|
|
597
|
+
|
|
598
|
+
INPUT:
|
|
599
|
+
|
|
600
|
+
- ``i`` -- integer
|
|
601
|
+
|
|
602
|
+
EXAMPLES::
|
|
603
|
+
|
|
604
|
+
sage: p = AffinePermutationGroup(['A',7,1])([3, -1, 0, 6, 5, 4, 10, 9])
|
|
605
|
+
sage: p.has_left_descent(1)
|
|
606
|
+
True
|
|
607
|
+
sage: p.has_left_descent(9)
|
|
608
|
+
True
|
|
609
|
+
sage: p.has_left_descent(0)
|
|
610
|
+
True
|
|
611
|
+
"""
|
|
612
|
+
# This is much faster than the default method of taking the inverse and
|
|
613
|
+
# then finding right descents...
|
|
614
|
+
return self.position(i) > self.position(i + 1)
|
|
615
|
+
|
|
616
|
+
def to_type_a(self) -> AffinePermutationTypeA:
|
|
617
|
+
r"""
|
|
618
|
+
Return an embedding of ``self`` into the affine permutation group of
|
|
619
|
+
type `A`. (For type `A`, just returns ``self``.)
|
|
620
|
+
|
|
621
|
+
EXAMPLES::
|
|
622
|
+
|
|
623
|
+
sage: p = AffinePermutationGroup(['A',7,1])([3, -1, 0, 6, 5, 4, 10, 9])
|
|
624
|
+
sage: p.to_type_a() is p
|
|
625
|
+
True
|
|
626
|
+
"""
|
|
627
|
+
return self
|
|
628
|
+
|
|
629
|
+
# ----------------------
|
|
630
|
+
# Type-A-specific methods.
|
|
631
|
+
# Only available in Type A.
|
|
632
|
+
# ----------------------
|
|
633
|
+
|
|
634
|
+
def flip_automorphism(self) -> AffinePermutationTypeA:
|
|
635
|
+
r"""
|
|
636
|
+
The Dynkin diagram automorphism which fixes `s_0` and reverses all
|
|
637
|
+
other indices.
|
|
638
|
+
|
|
639
|
+
EXAMPLES::
|
|
640
|
+
|
|
641
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
642
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
643
|
+
sage: p.flip_automorphism()
|
|
644
|
+
Type A affine permutation with window [0, -1, 5, 4, 3, 9, 10, 6]
|
|
645
|
+
"""
|
|
646
|
+
# Note: There should be a more combinatorial (ie, faster) way to do this.
|
|
647
|
+
w = [(self.k+1-i) % (self.k+1) for i in self.reduced_word()]
|
|
648
|
+
return self.parent().from_word(w)
|
|
649
|
+
|
|
650
|
+
def promotion(self) -> AffinePermutationTypeA:
|
|
651
|
+
r"""
|
|
652
|
+
The Dynkin diagram automorphism which sends `s_i` to `s_{i+1}`.
|
|
653
|
+
|
|
654
|
+
EXAMPLES::
|
|
655
|
+
|
|
656
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
657
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
658
|
+
sage: p.promotion()
|
|
659
|
+
Type A affine permutation with window [2, 4, 0, 1, 7, 6, 5, 11]
|
|
660
|
+
"""
|
|
661
|
+
l = [self[-1] - self.k]
|
|
662
|
+
l.extend(self[i] + 1 for i in range(self.k))
|
|
663
|
+
return type(self)(self.parent(), l)
|
|
664
|
+
|
|
665
|
+
def maximal_cyclic_factor(self, typ='decreasing',
|
|
666
|
+
side='right', verbose=False) -> list:
|
|
667
|
+
r"""
|
|
668
|
+
For an affine permutation `x`, find the unique maximal subset `A`
|
|
669
|
+
of the index set such that `x = yd_A` is a reduced product.
|
|
670
|
+
|
|
671
|
+
INPUT:
|
|
672
|
+
|
|
673
|
+
- ``typ`` -- ``'increasing'`` or ``'decreasing'``
|
|
674
|
+
(default: ``'decreasing'``); chooses whether to find increasing
|
|
675
|
+
or decreasing sets
|
|
676
|
+
|
|
677
|
+
- ``side`` -- ``'right'`` or ``'left'`` (default: ``'right'``); chooses
|
|
678
|
+
whether to find maximal sets starting from the left or the right
|
|
679
|
+
|
|
680
|
+
- ``verbose`` -- boolean; if ``True``, outputs information about how
|
|
681
|
+
the cyclically increasing element was found
|
|
682
|
+
|
|
683
|
+
EXAMPLES::
|
|
684
|
+
|
|
685
|
+
sage: p = AffinePermutationGroup(['A',7,1])([3, -1, 0, 6, 5, 4, 10, 9])
|
|
686
|
+
sage: p.maximal_cyclic_factor()
|
|
687
|
+
[7, 5, 4, 2, 1]
|
|
688
|
+
sage: p.maximal_cyclic_factor(side='left')
|
|
689
|
+
[1, 0, 7, 5, 4]
|
|
690
|
+
sage: p.maximal_cyclic_factor('increasing','right')
|
|
691
|
+
[4, 5, 7, 0, 1]
|
|
692
|
+
sage: p.maximal_cyclic_factor('increasing','left')
|
|
693
|
+
[0, 1, 2, 4, 5]
|
|
694
|
+
"""
|
|
695
|
+
k = self.k
|
|
696
|
+
if side[0] == 'r':
|
|
697
|
+
descents = self.descents(side='right')
|
|
698
|
+
side = 'right'
|
|
699
|
+
else:
|
|
700
|
+
descents = self.descents(side='left')
|
|
701
|
+
side = 'left'
|
|
702
|
+
# for now, assume side is 'right')
|
|
703
|
+
best_T: list[int] = []
|
|
704
|
+
for i in descents:
|
|
705
|
+
y = self.clone().apply_simple_reflection(i, side)
|
|
706
|
+
T = [i]
|
|
707
|
+
j = i
|
|
708
|
+
for _ in range(1, self.k):
|
|
709
|
+
if (typ[0], side[0]) == ('d', 'r'):
|
|
710
|
+
j = (j+1) % (k+1)
|
|
711
|
+
if (typ[0], side[0]) == ('i', 'r'):
|
|
712
|
+
j = (j-1) % (k+1)
|
|
713
|
+
if (typ[0], side[0]) == ('d', 'l'):
|
|
714
|
+
j = (j-1) % (k+1)
|
|
715
|
+
if (typ[0], side[0]) == ('i', 'l'):
|
|
716
|
+
j = (j+1) % (k+1)
|
|
717
|
+
if y.has_descent(j, side):
|
|
718
|
+
y = y.apply_simple_reflection(j, side)
|
|
719
|
+
T.append(j % (k+1))
|
|
720
|
+
if verbose:
|
|
721
|
+
print(i, T)
|
|
722
|
+
if len(T) > len(best_T):
|
|
723
|
+
best_T = T
|
|
724
|
+
# if (typ[0],side[0])==('i','r'): best_T.reverse()
|
|
725
|
+
# if (typ[0],side[0])==('d','l'): best_T.reverse()
|
|
726
|
+
# if typ[0]=='d': best_T.reverse()
|
|
727
|
+
if side[0] == 'r':
|
|
728
|
+
best_T.reverse()
|
|
729
|
+
return best_T
|
|
730
|
+
|
|
731
|
+
def maximal_cyclic_decomposition(self, typ='decreasing', side='right', verbose=False):
|
|
732
|
+
r"""
|
|
733
|
+
Find the unique maximal decomposition of ``self`` into cyclically
|
|
734
|
+
decreasing/increasing elements.
|
|
735
|
+
|
|
736
|
+
INPUT:
|
|
737
|
+
|
|
738
|
+
- ``typ`` -- ``'increasing'`` or ``'decreasing'``
|
|
739
|
+
(default: ``'decreasing'``); chooses whether to find increasing
|
|
740
|
+
or decreasing sets
|
|
741
|
+
|
|
742
|
+
- ``side`` -- ``'right'`` or ``'left'`` (default: ``'right'``) chooses
|
|
743
|
+
whether to find maximal sets starting from the left or the right
|
|
744
|
+
|
|
745
|
+
- ``verbose`` -- boolean (default: ``False``); print extra information
|
|
746
|
+
while finding the decomposition
|
|
747
|
+
|
|
748
|
+
EXAMPLES::
|
|
749
|
+
|
|
750
|
+
sage: p = AffinePermutationGroup(['A',7,1])([3, -1, 0, 6, 5, 4, 10, 9])
|
|
751
|
+
sage: p.maximal_cyclic_decomposition()
|
|
752
|
+
[[0, 7], [4, 1, 0], [7, 5, 4, 2, 1]]
|
|
753
|
+
sage: p.maximal_cyclic_decomposition(side='left')
|
|
754
|
+
[[1, 0, 7, 5, 4], [1, 0, 5], [2, 1]]
|
|
755
|
+
sage: p.maximal_cyclic_decomposition(typ='increasing', side='right')
|
|
756
|
+
[[1], [5, 0, 1, 2], [4, 5, 7, 0, 1]]
|
|
757
|
+
sage: p.maximal_cyclic_decomposition(typ='increasing', side='left')
|
|
758
|
+
[[0, 1, 2, 4, 5], [4, 7, 0, 1], [7]]
|
|
759
|
+
|
|
760
|
+
TESTS::
|
|
761
|
+
|
|
762
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
763
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
764
|
+
sage: S = p.maximal_cyclic_decomposition()
|
|
765
|
+
sage: p == prod(A.from_word(l) for l in S)
|
|
766
|
+
True
|
|
767
|
+
sage: S = p.maximal_cyclic_decomposition(typ='increasing', side='left')
|
|
768
|
+
sage: p == prod(A.from_word(l) for l in S)
|
|
769
|
+
True
|
|
770
|
+
sage: S = p.maximal_cyclic_decomposition(typ='increasing', side='right')
|
|
771
|
+
sage: p == prod(A.from_word(l) for l in S)
|
|
772
|
+
True
|
|
773
|
+
sage: S = p.maximal_cyclic_decomposition(typ='decreasing', side='right')
|
|
774
|
+
sage: p == prod(A.from_word(l) for l in S)
|
|
775
|
+
True
|
|
776
|
+
"""
|
|
777
|
+
y = self.clone()
|
|
778
|
+
listy = []
|
|
779
|
+
if verbose:
|
|
780
|
+
print('length of x:', self.length())
|
|
781
|
+
while not y.is_one():
|
|
782
|
+
S = y.maximal_cyclic_factor(typ, side, verbose)
|
|
783
|
+
listy.append(S[:])
|
|
784
|
+
if side[0] == 'r':
|
|
785
|
+
S.reverse()
|
|
786
|
+
for i in S:
|
|
787
|
+
if side[0] == 'r':
|
|
788
|
+
y = y.apply_simple_reflection_right(i)
|
|
789
|
+
else:
|
|
790
|
+
y = y.apply_simple_reflection_left(i)
|
|
791
|
+
if verbose:
|
|
792
|
+
print(S, y.length())
|
|
793
|
+
if side[0] == 'r':
|
|
794
|
+
listy.reverse()
|
|
795
|
+
return listy
|
|
796
|
+
|
|
797
|
+
def to_lehmer_code(self, typ='decreasing', side='right') -> Composition:
|
|
798
|
+
r"""
|
|
799
|
+
Return the affine Lehmer code.
|
|
800
|
+
|
|
801
|
+
There are four such codes; the options ``typ`` and ``side`` determine
|
|
802
|
+
which code is generated. The codes generated are the shape of the
|
|
803
|
+
maximal cyclic decompositions of ``self`` according to the given
|
|
804
|
+
``typ`` and ``side`` options.
|
|
805
|
+
|
|
806
|
+
INPUT:
|
|
807
|
+
|
|
808
|
+
- ``typ`` -- ``'increasing'`` or ``'decreasing'``
|
|
809
|
+
(default: ``'decreasing'``); chooses whether to find increasing
|
|
810
|
+
or decreasing sets
|
|
811
|
+
|
|
812
|
+
- ``side`` -- ``'right'`` or ``'left'`` (default: ``'right'``) chooses
|
|
813
|
+
whether to find maximal sets starting from the left or the right
|
|
814
|
+
|
|
815
|
+
EXAMPLES::
|
|
816
|
+
|
|
817
|
+
sage: import itertools
|
|
818
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
819
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
820
|
+
sage: orders = ('increasing','decreasing')
|
|
821
|
+
sage: sides = ('left','right')
|
|
822
|
+
sage: for o,s in itertools.product(orders, sides):
|
|
823
|
+
....: p.to_lehmer_code(o,s)
|
|
824
|
+
[2, 3, 2, 0, 1, 2, 0, 0]
|
|
825
|
+
[2, 2, 0, 0, 2, 1, 0, 3]
|
|
826
|
+
[3, 1, 0, 0, 2, 1, 0, 3]
|
|
827
|
+
[0, 3, 3, 0, 1, 2, 0, 1]
|
|
828
|
+
sage: for a in itertools.product(orders, sides):
|
|
829
|
+
....: A.from_lehmer_code(p.to_lehmer_code(a[0],a[1]), a[0],a[1])==p
|
|
830
|
+
True
|
|
831
|
+
True
|
|
832
|
+
True
|
|
833
|
+
True
|
|
834
|
+
"""
|
|
835
|
+
code = [0 for i in range(self.k+1)]
|
|
836
|
+
if typ[0] == 'i' and side[0] == 'r':
|
|
837
|
+
# Find number of positions to the right of position i with smaller
|
|
838
|
+
# value than the number in position i.
|
|
839
|
+
for i in range(self.k+1):
|
|
840
|
+
a = self(i)
|
|
841
|
+
for j in range(i+1, i+self.k+1):
|
|
842
|
+
b = self(j)
|
|
843
|
+
if b < a:
|
|
844
|
+
code[i] += (a-b) // (self.k+1) + 1
|
|
845
|
+
elif typ[0] == 'd' and side[0] == 'r':
|
|
846
|
+
# Find number of positions to the left of position i with larger
|
|
847
|
+
# value than the number in position i. Then cyclically shift
|
|
848
|
+
# the resulting vector.
|
|
849
|
+
for i in range(self.k+1):
|
|
850
|
+
a = self(i)
|
|
851
|
+
for j in range(i-self.k, i):
|
|
852
|
+
b = self(j)
|
|
853
|
+
# A small rotation is necessary for the reduced word from
|
|
854
|
+
# the Lehmer code to match the element.
|
|
855
|
+
if a < b:
|
|
856
|
+
code[i-1] += ((b-a)//(self.k+1)+1)
|
|
857
|
+
elif typ[0] == 'i' and side[0] == 'l':
|
|
858
|
+
# Find number of positions to the right of i smaller than i, then
|
|
859
|
+
# cyclically shift the resulting vector.
|
|
860
|
+
for i in range(self.k+1):
|
|
861
|
+
pos = self.position(i)
|
|
862
|
+
for j in range(pos+1, pos+self.k+1):
|
|
863
|
+
b = self(j)
|
|
864
|
+
# A small rotation is necessary for the reduced word from
|
|
865
|
+
# the lehmer code to match the element.
|
|
866
|
+
if b < i:
|
|
867
|
+
code[i-1] += (i-b) // (self.k+1) + 1
|
|
868
|
+
elif typ[0] == 'd' and side[0] == 'l':
|
|
869
|
+
# Find number of positions to the left of i larger than i.
|
|
870
|
+
for i in range(self.k+1):
|
|
871
|
+
pos = self.position(i)
|
|
872
|
+
for j in range(pos-self.k, pos):
|
|
873
|
+
b = self(j)
|
|
874
|
+
if b > i:
|
|
875
|
+
code[i] += (b-i) // (self.k+1) + 1
|
|
876
|
+
return Composition(code)
|
|
877
|
+
|
|
878
|
+
def is_fully_commutative(self) -> bool:
|
|
879
|
+
r"""
|
|
880
|
+
Determine whether ``self`` is fully commutative.
|
|
881
|
+
|
|
882
|
+
This means that it has no reduced word with a braid.
|
|
883
|
+
|
|
884
|
+
This uses a specific algorithm.
|
|
885
|
+
|
|
886
|
+
EXAMPLES::
|
|
887
|
+
|
|
888
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
889
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
890
|
+
sage: p.is_fully_commutative()
|
|
891
|
+
False
|
|
892
|
+
sage: q = A([-3, -2, 0, 7, 9, 2, 11, 12])
|
|
893
|
+
sage: q.is_fully_commutative()
|
|
894
|
+
True
|
|
895
|
+
"""
|
|
896
|
+
if self == self.parent().one():
|
|
897
|
+
return True
|
|
898
|
+
c = self.to_lehmer_code()
|
|
899
|
+
found = False
|
|
900
|
+
m = -1
|
|
901
|
+
for i in range(self.n):
|
|
902
|
+
if c[i] > 0:
|
|
903
|
+
if not found:
|
|
904
|
+
found = True
|
|
905
|
+
firstnonzero = i
|
|
906
|
+
if m != -1 and c[i] - (i - m) >= c[m]:
|
|
907
|
+
return False
|
|
908
|
+
m = i
|
|
909
|
+
assert found
|
|
910
|
+
# now check m (the last nonzero) against first nonzero.
|
|
911
|
+
d = self.n - (m - firstnonzero)
|
|
912
|
+
return not c[firstnonzero] - d >= c[m]
|
|
913
|
+
|
|
914
|
+
def to_bounded_partition(self, typ='decreasing', side='right') -> Partition:
|
|
915
|
+
r"""
|
|
916
|
+
Return the `k`-bounded partition associated to the dominant element
|
|
917
|
+
obtained by sorting the Lehmer code.
|
|
918
|
+
|
|
919
|
+
INPUT:
|
|
920
|
+
|
|
921
|
+
- ``typ`` -- ``'increasing'`` or ``'decreasing'`` (default: ``'decreasing'``);
|
|
922
|
+
chooses whether to find increasing or decreasing sets
|
|
923
|
+
|
|
924
|
+
- ``side`` -- ``'right'`` or ``'left'`` (default: ``'right'``); chooses
|
|
925
|
+
whether to find maximal sets starting from the left or the right
|
|
926
|
+
|
|
927
|
+
EXAMPLES::
|
|
928
|
+
|
|
929
|
+
sage: A = AffinePermutationGroup(['A',2,1])
|
|
930
|
+
sage: p = A.from_lehmer_code([4,1,0])
|
|
931
|
+
sage: p.to_bounded_partition()
|
|
932
|
+
[2, 1, 1, 1]
|
|
933
|
+
"""
|
|
934
|
+
c = sorted(self.to_lehmer_code(typ, side))
|
|
935
|
+
c.reverse()
|
|
936
|
+
return Partition(c).conjugate()
|
|
937
|
+
|
|
938
|
+
def to_core(self, typ='decreasing', side='right'):
|
|
939
|
+
r"""
|
|
940
|
+
Return the core associated to the dominant element obtained by sorting
|
|
941
|
+
the Lehmer code.
|
|
942
|
+
|
|
943
|
+
INPUT:
|
|
944
|
+
|
|
945
|
+
- ``typ`` -- ``'increasing'`` or ``'decreasing'`` (default: ``'decreasing'``.)
|
|
946
|
+
|
|
947
|
+
- ``side`` -- ``'right'`` or ``'left'`` (default: ``'right'``.) Chooses whether to
|
|
948
|
+
find maximal sets starting from the left or the right
|
|
949
|
+
|
|
950
|
+
EXAMPLES::
|
|
951
|
+
|
|
952
|
+
sage: A = AffinePermutationGroup(['A',2,1])
|
|
953
|
+
sage: p = A.from_lehmer_code([4,1,0])
|
|
954
|
+
sage: p.to_bounded_partition()
|
|
955
|
+
[2, 1, 1, 1]
|
|
956
|
+
sage: p.to_core()
|
|
957
|
+
[4, 2, 1, 1]
|
|
958
|
+
"""
|
|
959
|
+
return self.to_bounded_partition(typ, side).to_core(self.k)
|
|
960
|
+
|
|
961
|
+
def to_dominant(self, typ='decreasing',
|
|
962
|
+
side='right') -> AffinePermutationTypeA:
|
|
963
|
+
r"""
|
|
964
|
+
Find the Lehmer code and then sort it. Return the affine permutation
|
|
965
|
+
with the given sorted Lehmer code.
|
|
966
|
+
|
|
967
|
+
This element is 0-dominant.
|
|
968
|
+
|
|
969
|
+
INPUT:
|
|
970
|
+
|
|
971
|
+
- ``typ`` -- ``'increasing'`` or ``'decreasing'``
|
|
972
|
+
(default: ``'decreasing'``) chooses whether to find increasing
|
|
973
|
+
or decreasing sets
|
|
974
|
+
|
|
975
|
+
- ``side`` -- ``'right'`` or ``'left'`` (default: ``'right'``) chooses
|
|
976
|
+
whether to find maximal sets starting from the left or the right
|
|
977
|
+
|
|
978
|
+
EXAMPLES::
|
|
979
|
+
|
|
980
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
981
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
982
|
+
sage: p.to_dominant()
|
|
983
|
+
Type A affine permutation with window [-2, -1, 1, 3, 4, 8, 10, 13]
|
|
984
|
+
sage: p.to_dominant(typ='increasing', side='left')
|
|
985
|
+
Type A affine permutation with window [3, 4, -1, 5, 0, 9, 6, 10]
|
|
986
|
+
"""
|
|
987
|
+
if self.is_i_grassmannian(side=side):
|
|
988
|
+
return self
|
|
989
|
+
c = sorted(self.to_lehmer_code(typ, side))
|
|
990
|
+
c.reverse()
|
|
991
|
+
return self.parent().from_lehmer_code(c, typ, side)
|
|
992
|
+
|
|
993
|
+
def tableau_of_word(self, w, typ='decreasing', side='right', alpha=None):
|
|
994
|
+
r"""
|
|
995
|
+
Finds a tableau on the Lehmer code of ``self`` corresponding
|
|
996
|
+
to the given reduced word.
|
|
997
|
+
|
|
998
|
+
For a full description of this algorithm, see [Den2012]_.
|
|
999
|
+
|
|
1000
|
+
INPUT:
|
|
1001
|
+
|
|
1002
|
+
- ``w`` -- a reduced word for ``self``
|
|
1003
|
+
- ``typ`` -- ``'increasing'`` or ``'decreasing'``; the type of
|
|
1004
|
+
Lehmer code used
|
|
1005
|
+
- ``side`` -- ``'right'`` or ``'left'``
|
|
1006
|
+
- ``alpha`` -- a content vector; ``w`` should be of type ``alpha``;
|
|
1007
|
+
specifying ``alpha`` produces semistandard tableaux
|
|
1008
|
+
|
|
1009
|
+
EXAMPLES::
|
|
1010
|
+
|
|
1011
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
1012
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
1013
|
+
sage: p.tableau_of_word(p.reduced_word())
|
|
1014
|
+
[[], [1, 6, 9], [2, 7, 10], [], [3], [4, 8], [], [5]]
|
|
1015
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
1016
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
1017
|
+
sage: w = p.reduced_word(); w
|
|
1018
|
+
[0, 7, 4, 1, 0, 7, 5, 4, 2, 1]
|
|
1019
|
+
sage: alpha = [5,3,2]
|
|
1020
|
+
sage: p.tableau_of_word(p.reduced_word(), alpha=alpha)
|
|
1021
|
+
[[], [1, 2, 3], [1, 2, 3], [], [1], [1, 2], [], [1]]
|
|
1022
|
+
sage: p.tableau_of_word(p.reduced_word(), side='left')
|
|
1023
|
+
[[1, 4, 9], [6], [], [], [3, 7], [8], [], [2, 5, 10]]
|
|
1024
|
+
sage: p.tableau_of_word(p.reduced_word(), typ='increasing', side='right')
|
|
1025
|
+
[[9, 10], [1, 2], [], [], [3, 4], [8], [], [5, 6, 7]]
|
|
1026
|
+
sage: p.tableau_of_word(p.reduced_word(), typ='increasing', side='left')
|
|
1027
|
+
[[1, 2], [4, 5, 6], [9, 10], [], [3], [7, 8], [], []]
|
|
1028
|
+
"""
|
|
1029
|
+
g = self.parent().simple_reflections()
|
|
1030
|
+
# Check w is reduced....:should probably throw an exception otherwise.
|
|
1031
|
+
x0 = prod(g[i] for i in w)
|
|
1032
|
+
if x0.length() != len(w):
|
|
1033
|
+
raise ValueError("word was not reduced")
|
|
1034
|
+
if alpha is None:
|
|
1035
|
+
alpha = Composition([1 for i in w])
|
|
1036
|
+
else:
|
|
1037
|
+
if sum(alpha) != len(w):
|
|
1038
|
+
raise ValueError("size of alpha must match length of w")
|
|
1039
|
+
alpha = Composition(alpha)
|
|
1040
|
+
# TODO: We should probably check that w is of type alpha! probably a different function.
|
|
1041
|
+
# Now we actually build the recording tableau.
|
|
1042
|
+
tab: list[list[int]] = [[] for _ in repeat(None, self.k + 1)]
|
|
1043
|
+
label = 1
|
|
1044
|
+
al_index = 0
|
|
1045
|
+
j = 0
|
|
1046
|
+
x = self.parent().one()
|
|
1047
|
+
cx = x.to_lehmer_code(typ, side)
|
|
1048
|
+
n = len(w)-1
|
|
1049
|
+
for i in range(len(w)):
|
|
1050
|
+
if side[0] == 'r':
|
|
1051
|
+
# y=g[w[n-i]]*x
|
|
1052
|
+
y = x.apply_simple_reflection_left(w[n-i])
|
|
1053
|
+
else:
|
|
1054
|
+
y = x.apply_simple_reflection_right(w[i])
|
|
1055
|
+
cy = y.to_lehmer_code(typ, side)
|
|
1056
|
+
for r in range(self.k+1):
|
|
1057
|
+
if cy[r] > cx[r]:
|
|
1058
|
+
tab[r].append(label)
|
|
1059
|
+
j += 1
|
|
1060
|
+
if j == alpha[al_index]:
|
|
1061
|
+
al_index += 1
|
|
1062
|
+
j = 0
|
|
1063
|
+
label += 1
|
|
1064
|
+
break
|
|
1065
|
+
x = y
|
|
1066
|
+
cx = cy
|
|
1067
|
+
return tab
|
|
1068
|
+
|
|
1069
|
+
# -----------------------------------------------------------------------------
|
|
1070
|
+
|
|
1071
|
+
|
|
1072
|
+
class AffinePermutationTypeC(AffinePermutation):
|
|
1073
|
+
# ----------------------
|
|
1074
|
+
# Type-specific methods.
|
|
1075
|
+
# (Methods existing in all types, but with type-specific definition.)
|
|
1076
|
+
# ----------------------
|
|
1077
|
+
def check(self) -> None:
|
|
1078
|
+
r"""
|
|
1079
|
+
Check that ``self`` is an affine permutation.
|
|
1080
|
+
|
|
1081
|
+
EXAMPLES::
|
|
1082
|
+
|
|
1083
|
+
sage: C = AffinePermutationGroup(['C',4,1])
|
|
1084
|
+
sage: x = C([-1,5,3,7])
|
|
1085
|
+
sage: x
|
|
1086
|
+
Type C affine permutation with window [-1, 5, 3, 7]
|
|
1087
|
+
"""
|
|
1088
|
+
if not self:
|
|
1089
|
+
return
|
|
1090
|
+
k = self.parent().k
|
|
1091
|
+
if len(self) != k:
|
|
1092
|
+
raise ValueError("length of list must be k=" + str(k))
|
|
1093
|
+
reslist = []
|
|
1094
|
+
for i in self:
|
|
1095
|
+
r = i % self.N
|
|
1096
|
+
if r == 0:
|
|
1097
|
+
raise ValueError("entries may not have residue 0 mod 2k+1")
|
|
1098
|
+
if r in reslist or self.N - r in reslist:
|
|
1099
|
+
raise ValueError("entries must have distinct residues")
|
|
1100
|
+
reslist.append(r)
|
|
1101
|
+
|
|
1102
|
+
def value(self, i):
|
|
1103
|
+
r"""
|
|
1104
|
+
Return the image of the integer ``i`` under this permutation.
|
|
1105
|
+
|
|
1106
|
+
EXAMPLES::
|
|
1107
|
+
|
|
1108
|
+
sage: C = AffinePermutationGroup(['C',4,1])
|
|
1109
|
+
sage: x = C.one()
|
|
1110
|
+
sage: all(x.value(i) == i for i in range(-10,10))
|
|
1111
|
+
True
|
|
1112
|
+
"""
|
|
1113
|
+
N = 2*self.k + 1
|
|
1114
|
+
window = i // N
|
|
1115
|
+
index = i % N
|
|
1116
|
+
if index == 0:
|
|
1117
|
+
return i
|
|
1118
|
+
if index <= self.k:
|
|
1119
|
+
return self[index-1]+window*N
|
|
1120
|
+
if index > self.k:
|
|
1121
|
+
return -(self[N-index-1]-N)+window*N
|
|
1122
|
+
|
|
1123
|
+
def position(self, i):
|
|
1124
|
+
r"""
|
|
1125
|
+
Find the position `j` such the ``self.value(j)=i``.
|
|
1126
|
+
|
|
1127
|
+
EXAMPLES::
|
|
1128
|
+
|
|
1129
|
+
sage: C = AffinePermutationGroup(['C',4,1])
|
|
1130
|
+
sage: x = C.one()
|
|
1131
|
+
sage: all(x.position(i) == i for i in range(-10,10))
|
|
1132
|
+
True
|
|
1133
|
+
"""
|
|
1134
|
+
N = 2*self.k + 1
|
|
1135
|
+
index = i % N
|
|
1136
|
+
if index == 0:
|
|
1137
|
+
return i
|
|
1138
|
+
for r in range(len(self)):
|
|
1139
|
+
if self[r] % N == index:
|
|
1140
|
+
# i sits in position i, but some number of windows away.
|
|
1141
|
+
diff = (i-self[r]) // N
|
|
1142
|
+
return r + diff*N + 1
|
|
1143
|
+
if self[r] % N == N - index:
|
|
1144
|
+
# then we sit some number of windows from position -r.
|
|
1145
|
+
diff = (i+self[r]) // N
|
|
1146
|
+
return -r + diff*N - 1
|
|
1147
|
+
return False
|
|
1148
|
+
|
|
1149
|
+
def apply_simple_reflection_right(self, i) -> AffinePermutationTypeC:
|
|
1150
|
+
r"""
|
|
1151
|
+
Apply the simple reflection indexed by ``i`` on positions.
|
|
1152
|
+
|
|
1153
|
+
EXAMPLES::
|
|
1154
|
+
|
|
1155
|
+
sage: C = AffinePermutationGroup(['C',4,1])
|
|
1156
|
+
sage: x = C([-1,5,3,7])
|
|
1157
|
+
sage: for i in C.index_set(): x.apply_simple_reflection_right(i)
|
|
1158
|
+
Type C affine permutation with window [1, 5, 3, 7]
|
|
1159
|
+
Type C affine permutation with window [5, -1, 3, 7]
|
|
1160
|
+
Type C affine permutation with window [-1, 3, 5, 7]
|
|
1161
|
+
Type C affine permutation with window [-1, 5, 7, 3]
|
|
1162
|
+
Type C affine permutation with window [-1, 5, 3, 2]
|
|
1163
|
+
"""
|
|
1164
|
+
if i not in self.parent().index_set():
|
|
1165
|
+
raise ValueError('index not in index set')
|
|
1166
|
+
j = i
|
|
1167
|
+
l = self[:]
|
|
1168
|
+
if j != 0 and j != self.k:
|
|
1169
|
+
a = l[j-1]
|
|
1170
|
+
l[j-1] = l[j]
|
|
1171
|
+
l[j] = a
|
|
1172
|
+
elif j == 0:
|
|
1173
|
+
l[0] = -l[0]
|
|
1174
|
+
elif j == self.k:
|
|
1175
|
+
l[self.k-1] = self(self.k+1)
|
|
1176
|
+
# return l
|
|
1177
|
+
return type(self)(self.parent(), l, check=False)
|
|
1178
|
+
|
|
1179
|
+
def apply_simple_reflection_left(self, i) -> AffinePermutationTypeC:
|
|
1180
|
+
r"""
|
|
1181
|
+
Apply the simple reflection indexed by ``i`` on values.
|
|
1182
|
+
|
|
1183
|
+
EXAMPLES::
|
|
1184
|
+
|
|
1185
|
+
sage: C = AffinePermutationGroup(['C',4,1])
|
|
1186
|
+
sage: x = C([-1,5,3,7])
|
|
1187
|
+
sage: for i in C.index_set(): x.apply_simple_reflection_left(i)
|
|
1188
|
+
Type C affine permutation with window [1, 5, 3, 7]
|
|
1189
|
+
Type C affine permutation with window [-2, 5, 3, 8]
|
|
1190
|
+
Type C affine permutation with window [-1, 5, 2, 6]
|
|
1191
|
+
Type C affine permutation with window [-1, 6, 4, 7]
|
|
1192
|
+
Type C affine permutation with window [-1, 4, 3, 7]
|
|
1193
|
+
"""
|
|
1194
|
+
if i not in self.parent().index_set():
|
|
1195
|
+
raise ValueError('index not in index set')
|
|
1196
|
+
j = self.N - i
|
|
1197
|
+
l = []
|
|
1198
|
+
if i != self.k and i != 0:
|
|
1199
|
+
for m in range(self.k):
|
|
1200
|
+
res = self[m] % self.N
|
|
1201
|
+
if res == i:
|
|
1202
|
+
l.append(self[m] + 1)
|
|
1203
|
+
elif res == i + 1:
|
|
1204
|
+
l.append(self[m] - 1)
|
|
1205
|
+
elif res == j:
|
|
1206
|
+
l.append(self[m] - 1)
|
|
1207
|
+
elif res == j - 1:
|
|
1208
|
+
l.append(self[m] + 1)
|
|
1209
|
+
else:
|
|
1210
|
+
l.append(self[m])
|
|
1211
|
+
elif i == 0:
|
|
1212
|
+
for m in range(self.k):
|
|
1213
|
+
res = self[m] % self.N
|
|
1214
|
+
if res == 1:
|
|
1215
|
+
l.append(self[m] - 2)
|
|
1216
|
+
elif res == self.N - 1:
|
|
1217
|
+
l.append(self[m] + 2)
|
|
1218
|
+
else:
|
|
1219
|
+
l.append(self[m])
|
|
1220
|
+
elif i == self.k:
|
|
1221
|
+
for m in range(self.k):
|
|
1222
|
+
res = self[m] % self.N
|
|
1223
|
+
if res == i:
|
|
1224
|
+
l.append(self[m] + 1)
|
|
1225
|
+
elif res == j:
|
|
1226
|
+
l.append(self[m] - 1)
|
|
1227
|
+
else:
|
|
1228
|
+
l.append(self[m])
|
|
1229
|
+
return type(self)(self.parent(), l, check=False)
|
|
1230
|
+
|
|
1231
|
+
def has_right_descent(self, i) -> bool:
|
|
1232
|
+
r"""
|
|
1233
|
+
Determine whether there is a descent at index ``i``.
|
|
1234
|
+
|
|
1235
|
+
INPUT:
|
|
1236
|
+
|
|
1237
|
+
- ``i`` -- integer
|
|
1238
|
+
|
|
1239
|
+
EXAMPLES::
|
|
1240
|
+
|
|
1241
|
+
sage: C = AffinePermutationGroup(['C',4,1])
|
|
1242
|
+
sage: x = C([-1,5,3,7])
|
|
1243
|
+
sage: for i in C.index_set(): x.has_right_descent(i)
|
|
1244
|
+
True
|
|
1245
|
+
False
|
|
1246
|
+
True
|
|
1247
|
+
False
|
|
1248
|
+
True
|
|
1249
|
+
"""
|
|
1250
|
+
return self.value(i) > self.value(i+1)
|
|
1251
|
+
|
|
1252
|
+
def has_left_descent(self, i) -> bool:
|
|
1253
|
+
r"""
|
|
1254
|
+
Determine whether there is a descent at ``i``.
|
|
1255
|
+
|
|
1256
|
+
INPUT:
|
|
1257
|
+
|
|
1258
|
+
- ``i`` -- integer
|
|
1259
|
+
|
|
1260
|
+
EXAMPLES::
|
|
1261
|
+
|
|
1262
|
+
sage: C = AffinePermutationGroup(['C',4,1])
|
|
1263
|
+
sage: x = C([-1,5,3,7])
|
|
1264
|
+
sage: for i in C.index_set(): x.has_left_descent(i)
|
|
1265
|
+
True
|
|
1266
|
+
False
|
|
1267
|
+
True
|
|
1268
|
+
False
|
|
1269
|
+
True
|
|
1270
|
+
"""
|
|
1271
|
+
# This is much faster than the default method of taking the inverse and
|
|
1272
|
+
# then finding right descents...
|
|
1273
|
+
return self.position(i) > self.position(i + 1)
|
|
1274
|
+
|
|
1275
|
+
def to_type_a(self) -> AffinePermutationTypeA:
|
|
1276
|
+
r"""
|
|
1277
|
+
Return an embedding of ``self`` into the affine permutation group of
|
|
1278
|
+
type `A`.
|
|
1279
|
+
|
|
1280
|
+
EXAMPLES::
|
|
1281
|
+
|
|
1282
|
+
sage: C = AffinePermutationGroup(['C',4,1])
|
|
1283
|
+
sage: x = C([-1,5,3,7])
|
|
1284
|
+
sage: x.to_type_a()
|
|
1285
|
+
Type A affine permutation with window [-1, 5, 3, 7, 2, 6, 4, 10, 9]
|
|
1286
|
+
"""
|
|
1287
|
+
A = AffinePermutationGroup(['A', self.N - 1, 1])
|
|
1288
|
+
return A([self.value(i) for i in range(1, self.N + 1)])
|
|
1289
|
+
|
|
1290
|
+
|
|
1291
|
+
class AffinePermutationTypeB(AffinePermutationTypeC):
|
|
1292
|
+
# ----------------------
|
|
1293
|
+
# Type-specific methods.
|
|
1294
|
+
# (Methods existing in all types, but with type-specific definition.)
|
|
1295
|
+
# ----------------------
|
|
1296
|
+
def check(self) -> None:
|
|
1297
|
+
r"""
|
|
1298
|
+
Check that ``self`` is an affine permutation.
|
|
1299
|
+
|
|
1300
|
+
EXAMPLES::
|
|
1301
|
+
|
|
1302
|
+
sage: B = AffinePermutationGroup(['B',4,1])
|
|
1303
|
+
sage: x = B([-5,1,6,-2])
|
|
1304
|
+
sage: x
|
|
1305
|
+
Type B affine permutation with window [-5, 1, 6, -2]
|
|
1306
|
+
"""
|
|
1307
|
+
if not self:
|
|
1308
|
+
return
|
|
1309
|
+
k = self.parent().k
|
|
1310
|
+
# Check window length.
|
|
1311
|
+
if len(self) != k:
|
|
1312
|
+
raise ValueError("length of list must be k=" + str(k))
|
|
1313
|
+
# Check for repeated residues.
|
|
1314
|
+
reslist = []
|
|
1315
|
+
for i in self:
|
|
1316
|
+
r = i % self.N
|
|
1317
|
+
if r == 0:
|
|
1318
|
+
raise ValueError("entries may not have residue 0 mod 2k+1")
|
|
1319
|
+
if r in reslist or self.N - r in reslist:
|
|
1320
|
+
raise ValueError("entries must have distinct residues")
|
|
1321
|
+
reslist.append(r)
|
|
1322
|
+
# Check that we have an even number of 'small' elements right
|
|
1323
|
+
# of the zeroth entry.
|
|
1324
|
+
s = sum(-i // self.N + 1 for j in range(1, self.N + 1)
|
|
1325
|
+
if (i := self.value(j)) < 0)
|
|
1326
|
+
if s % 2:
|
|
1327
|
+
raise ValueError("type B affine permutations have an even number of "
|
|
1328
|
+
"entries less than 0 to the right of the 0th position")
|
|
1329
|
+
|
|
1330
|
+
def apply_simple_reflection_right(self, i) -> AffinePermutationTypeB:
|
|
1331
|
+
r"""
|
|
1332
|
+
Apply the simple reflection indexed by ``i`` on positions.
|
|
1333
|
+
|
|
1334
|
+
EXAMPLES::
|
|
1335
|
+
|
|
1336
|
+
sage: B = AffinePermutationGroup(['B',4,1])
|
|
1337
|
+
sage: p = B([-5,1,6,-2])
|
|
1338
|
+
sage: p.apply_simple_reflection_right(1)
|
|
1339
|
+
Type B affine permutation with window [1, -5, 6, -2]
|
|
1340
|
+
sage: p.apply_simple_reflection_right(0)
|
|
1341
|
+
Type B affine permutation with window [-1, 5, 6, -2]
|
|
1342
|
+
sage: p.apply_simple_reflection_right(4)
|
|
1343
|
+
Type B affine permutation with window [-5, 1, 6, 11]
|
|
1344
|
+
"""
|
|
1345
|
+
if i not in self.parent().index_set():
|
|
1346
|
+
raise ValueError('index not in index set')
|
|
1347
|
+
j = i
|
|
1348
|
+
l = self[:]
|
|
1349
|
+
if j != 0 and j != self.k:
|
|
1350
|
+
# just swap l[j], l[j-1]
|
|
1351
|
+
(l[j-1], l[j]) = (l[j], l[j-1])
|
|
1352
|
+
elif j == 0:
|
|
1353
|
+
l[0] = -self(2)
|
|
1354
|
+
l[1] = -self(1)
|
|
1355
|
+
elif j == self.k:
|
|
1356
|
+
l[self.k-1] = self(self.k+1)
|
|
1357
|
+
return type(self)(self.parent(), l, check=False)
|
|
1358
|
+
|
|
1359
|
+
def apply_simple_reflection_left(self, i) -> AffinePermutationTypeB:
|
|
1360
|
+
r"""
|
|
1361
|
+
Apply the simple reflection indexed by ``i`` on values.
|
|
1362
|
+
|
|
1363
|
+
EXAMPLES::
|
|
1364
|
+
|
|
1365
|
+
sage: B = AffinePermutationGroup(['B',4,1])
|
|
1366
|
+
sage: p = B([-5,1,6,-2])
|
|
1367
|
+
sage: p.apply_simple_reflection_left(0)
|
|
1368
|
+
Type B affine permutation with window [-5, -2, 6, 1]
|
|
1369
|
+
sage: p.apply_simple_reflection_left(2)
|
|
1370
|
+
Type B affine permutation with window [-5, 1, 7, -3]
|
|
1371
|
+
sage: p.apply_simple_reflection_left(4)
|
|
1372
|
+
Type B affine permutation with window [-4, 1, 6, -2]
|
|
1373
|
+
"""
|
|
1374
|
+
if i not in self.parent().index_set():
|
|
1375
|
+
raise ValueError('index not in index set')
|
|
1376
|
+
j = self.N - i
|
|
1377
|
+
l = []
|
|
1378
|
+
if i != self.k and i != 0:
|
|
1379
|
+
for m in range(self.k):
|
|
1380
|
+
res = self[m] % self.N
|
|
1381
|
+
if res == i:
|
|
1382
|
+
l.append(self[m]+1)
|
|
1383
|
+
elif res == i + 1:
|
|
1384
|
+
l.append(self[m]-1)
|
|
1385
|
+
elif res == j:
|
|
1386
|
+
l.append(self[m]-1)
|
|
1387
|
+
elif res == j - 1:
|
|
1388
|
+
l.append(self[m]+1)
|
|
1389
|
+
else:
|
|
1390
|
+
l.append(self[m])
|
|
1391
|
+
elif i == 0:
|
|
1392
|
+
for m in range(self.k):
|
|
1393
|
+
res = self[m] % self.N
|
|
1394
|
+
if res == 1:
|
|
1395
|
+
l.append(self[m]-3)
|
|
1396
|
+
elif res == self.N - 2:
|
|
1397
|
+
l.append(self[m]+3)
|
|
1398
|
+
elif res == 2:
|
|
1399
|
+
l.append(self[m]-3)
|
|
1400
|
+
elif res == self.N - 1:
|
|
1401
|
+
l.append(self[m]+3)
|
|
1402
|
+
else:
|
|
1403
|
+
l.append(self[m])
|
|
1404
|
+
elif i == self.k:
|
|
1405
|
+
for m in range(self.k):
|
|
1406
|
+
res = self[m] % self.N
|
|
1407
|
+
if res == i:
|
|
1408
|
+
l.append(self[m] + 1)
|
|
1409
|
+
elif res == j:
|
|
1410
|
+
l.append(self[m] - 1)
|
|
1411
|
+
else:
|
|
1412
|
+
l.append(self[m])
|
|
1413
|
+
return type(self)(self.parent(), l, check=False)
|
|
1414
|
+
|
|
1415
|
+
def has_right_descent(self, i) -> bool:
|
|
1416
|
+
r"""
|
|
1417
|
+
Determine whether there is a descent at index ``i``.
|
|
1418
|
+
|
|
1419
|
+
INPUT:
|
|
1420
|
+
|
|
1421
|
+
- ``i`` -- integer
|
|
1422
|
+
|
|
1423
|
+
EXAMPLES::
|
|
1424
|
+
|
|
1425
|
+
sage: B = AffinePermutationGroup(['B',4,1])
|
|
1426
|
+
sage: p = B([-5,1,6,-2])
|
|
1427
|
+
sage: [p.has_right_descent(i) for i in B.index_set()]
|
|
1428
|
+
[True, False, False, True, False]
|
|
1429
|
+
"""
|
|
1430
|
+
if i == 0:
|
|
1431
|
+
return self.value(-2) > self.value(1)
|
|
1432
|
+
return self.value(i) > self.value(i+1)
|
|
1433
|
+
|
|
1434
|
+
def has_left_descent(self, i) -> bool:
|
|
1435
|
+
r"""
|
|
1436
|
+
Determine whether there is a descent at ``i``.
|
|
1437
|
+
|
|
1438
|
+
INPUT:
|
|
1439
|
+
|
|
1440
|
+
- ``i`` -- integer
|
|
1441
|
+
|
|
1442
|
+
EXAMPLES::
|
|
1443
|
+
|
|
1444
|
+
sage: B = AffinePermutationGroup(['B',4,1])
|
|
1445
|
+
sage: p = B([-5,1,6,-2])
|
|
1446
|
+
sage: [p.has_left_descent(i) for i in B.index_set()]
|
|
1447
|
+
[True, True, False, False, True]
|
|
1448
|
+
"""
|
|
1449
|
+
if i == 0:
|
|
1450
|
+
return self.position(-2) > self.position(1)
|
|
1451
|
+
return self.position(i) > self.position(i + 1)
|
|
1452
|
+
|
|
1453
|
+
|
|
1454
|
+
class AffinePermutationTypeD(AffinePermutationTypeC):
|
|
1455
|
+
# ----------------------
|
|
1456
|
+
# Type-specific methods.
|
|
1457
|
+
# (Methods existing in all types, but with type-specific definition.)
|
|
1458
|
+
# ----------------------
|
|
1459
|
+
def check(self) -> None:
|
|
1460
|
+
r"""
|
|
1461
|
+
Check that ``self`` is an affine permutation.
|
|
1462
|
+
|
|
1463
|
+
EXAMPLES::
|
|
1464
|
+
|
|
1465
|
+
sage: D = AffinePermutationGroup(['D',4,1])
|
|
1466
|
+
sage: p = D([1,-6,5,-2])
|
|
1467
|
+
sage: p
|
|
1468
|
+
Type D affine permutation with window [1, -6, 5, -2]
|
|
1469
|
+
"""
|
|
1470
|
+
if not self:
|
|
1471
|
+
return
|
|
1472
|
+
k = self.parent().k
|
|
1473
|
+
# Check window length.
|
|
1474
|
+
if len(self) != k:
|
|
1475
|
+
raise ValueError("length of list must be k=" + str(k))
|
|
1476
|
+
# Check for repeated residues.
|
|
1477
|
+
reslist = []
|
|
1478
|
+
for i in self:
|
|
1479
|
+
r = i % self.N
|
|
1480
|
+
if r == 0:
|
|
1481
|
+
raise ValueError("entries may not have residue 0 mod 2k+1")
|
|
1482
|
+
if r in reslist or self.N - r in reslist:
|
|
1483
|
+
raise ValueError("entries must have distinct residues")
|
|
1484
|
+
reslist.append(r)
|
|
1485
|
+
# Check that we have an even number of 'big' elements left of
|
|
1486
|
+
# the kth entry.
|
|
1487
|
+
s = sum(i // self.N + 1 - (i % self.N <= self.k)
|
|
1488
|
+
for j in range(-self.k, self.k + 1)
|
|
1489
|
+
if (i := self.value(j)) > self.k)
|
|
1490
|
+
if s % 2:
|
|
1491
|
+
raise ValueError("type D affine permutations have an even number of entries"
|
|
1492
|
+
" greater than x.k weakly to the left of the x.k position")
|
|
1493
|
+
# Check that we have an even number of 'small' elements right of the zeroth entry.
|
|
1494
|
+
s = sum(-i // self.N + 1 for j in range(1, self.N + 1)
|
|
1495
|
+
if (i := self.value(j)) < 0)
|
|
1496
|
+
if s % 2:
|
|
1497
|
+
raise ValueError("type D affine permutations have an even number of entries"
|
|
1498
|
+
" less than 0 to the right of the 0th position")
|
|
1499
|
+
|
|
1500
|
+
def apply_simple_reflection_right(self, i) -> AffinePermutationTypeD:
|
|
1501
|
+
r"""
|
|
1502
|
+
Apply the simple reflection indexed by ``i`` on positions.
|
|
1503
|
+
|
|
1504
|
+
EXAMPLES::
|
|
1505
|
+
|
|
1506
|
+
sage: D = AffinePermutationGroup(['D',4,1])
|
|
1507
|
+
sage: p = D([1,-6,5,-2])
|
|
1508
|
+
sage: p.apply_simple_reflection_right(0)
|
|
1509
|
+
Type D affine permutation with window [6, -1, 5, -2]
|
|
1510
|
+
sage: p.apply_simple_reflection_right(1)
|
|
1511
|
+
Type D affine permutation with window [-6, 1, 5, -2]
|
|
1512
|
+
sage: p.apply_simple_reflection_right(4)
|
|
1513
|
+
Type D affine permutation with window [1, -6, 11, 4]
|
|
1514
|
+
"""
|
|
1515
|
+
if i not in self.parent().index_set():
|
|
1516
|
+
raise ValueError('index not in index set')
|
|
1517
|
+
j = i
|
|
1518
|
+
l = self[:]
|
|
1519
|
+
if j != 0 and j != self.k:
|
|
1520
|
+
a = l[j-1]
|
|
1521
|
+
l[j-1] = l[j]
|
|
1522
|
+
l[j] = a
|
|
1523
|
+
elif j == 0:
|
|
1524
|
+
c = l[0]
|
|
1525
|
+
l[0] = -l[1]
|
|
1526
|
+
l[1] = -c
|
|
1527
|
+
elif j == self.k:
|
|
1528
|
+
l[self.k-2] = self(self.k+1)
|
|
1529
|
+
l[self.k-1] = self(self.k+2)
|
|
1530
|
+
return type(self)(self.parent(), l, check=False)
|
|
1531
|
+
|
|
1532
|
+
def apply_simple_reflection_left(self, i) -> AffinePermutationTypeD:
|
|
1533
|
+
r"""
|
|
1534
|
+
Apply simple reflection indexed by ``i`` on values.
|
|
1535
|
+
|
|
1536
|
+
EXAMPLES::
|
|
1537
|
+
|
|
1538
|
+
sage: D = AffinePermutationGroup(['D',4,1])
|
|
1539
|
+
sage: p = D([1,-6,5,-2])
|
|
1540
|
+
sage: p.apply_simple_reflection_left(0)
|
|
1541
|
+
Type D affine permutation with window [-2, -6, 5, 1]
|
|
1542
|
+
sage: p.apply_simple_reflection_left(1)
|
|
1543
|
+
Type D affine permutation with window [2, -6, 5, -1]
|
|
1544
|
+
sage: p.apply_simple_reflection_left(4)
|
|
1545
|
+
Type D affine permutation with window [1, -4, 3, -2]
|
|
1546
|
+
"""
|
|
1547
|
+
if i not in self.parent().index_set():
|
|
1548
|
+
raise ValueError('index not in index set')
|
|
1549
|
+
j = self.N - i
|
|
1550
|
+
l = []
|
|
1551
|
+
if i and i != self.k:
|
|
1552
|
+
for m in range(self.k):
|
|
1553
|
+
res = self[m] % self.N
|
|
1554
|
+
if res == i:
|
|
1555
|
+
l.append(self[m]+1)
|
|
1556
|
+
elif res == i+1:
|
|
1557
|
+
l.append(self[m]-1)
|
|
1558
|
+
elif res == j:
|
|
1559
|
+
l.append(self[m]-1)
|
|
1560
|
+
elif res == j-1:
|
|
1561
|
+
l.append(self[m]+1)
|
|
1562
|
+
else:
|
|
1563
|
+
l.append(self[m])
|
|
1564
|
+
elif i == 0:
|
|
1565
|
+
for m in range(self.k):
|
|
1566
|
+
res = self[m] % self.N
|
|
1567
|
+
if res == 1:
|
|
1568
|
+
l.append(self[m]-3)
|
|
1569
|
+
elif res == self.N-2:
|
|
1570
|
+
l.append(self[m]+3)
|
|
1571
|
+
elif res == 2:
|
|
1572
|
+
l.append(self[m]-3)
|
|
1573
|
+
elif res == self.N-1:
|
|
1574
|
+
l.append(self[m]+3)
|
|
1575
|
+
else:
|
|
1576
|
+
l.append(self[m])
|
|
1577
|
+
elif i == self.k:
|
|
1578
|
+
for m in range(self.k):
|
|
1579
|
+
res = self[m] % self.N
|
|
1580
|
+
if res == self.k:
|
|
1581
|
+
l.append(self[m]+2)
|
|
1582
|
+
elif res == self.k+2:
|
|
1583
|
+
l.append(self[m]-2)
|
|
1584
|
+
elif res == self.k-1:
|
|
1585
|
+
l.append(self[m]+2)
|
|
1586
|
+
elif res == self.k+1:
|
|
1587
|
+
l.append(self[m]-2)
|
|
1588
|
+
else:
|
|
1589
|
+
l.append(self[m])
|
|
1590
|
+
return type(self)(self.parent(), l, check=False)
|
|
1591
|
+
|
|
1592
|
+
def has_right_descent(self, i) -> bool:
|
|
1593
|
+
r"""
|
|
1594
|
+
Determine whether there is a descent at index ``i``.
|
|
1595
|
+
|
|
1596
|
+
INPUT:
|
|
1597
|
+
|
|
1598
|
+
- ``i`` -- integer
|
|
1599
|
+
|
|
1600
|
+
EXAMPLES::
|
|
1601
|
+
|
|
1602
|
+
sage: D = AffinePermutationGroup(['D',4,1])
|
|
1603
|
+
sage: p = D([1,-6,5,-2])
|
|
1604
|
+
sage: [p.has_right_descent(i) for i in D.index_set()]
|
|
1605
|
+
[True, True, False, True, False]
|
|
1606
|
+
"""
|
|
1607
|
+
if i == 0:
|
|
1608
|
+
return self.value(-2) > self.value(1)
|
|
1609
|
+
if i == self.k:
|
|
1610
|
+
return self.value(i) > self.value(i+2)
|
|
1611
|
+
return self.value(i) > self.value(i+1)
|
|
1612
|
+
|
|
1613
|
+
def has_left_descent(self, i) -> bool:
|
|
1614
|
+
r"""
|
|
1615
|
+
Determine whether there is a descent at ``i``.
|
|
1616
|
+
|
|
1617
|
+
INPUT:
|
|
1618
|
+
|
|
1619
|
+
- ``i`` -- integer
|
|
1620
|
+
|
|
1621
|
+
EXAMPLES::
|
|
1622
|
+
|
|
1623
|
+
sage: D = AffinePermutationGroup(['D',4,1])
|
|
1624
|
+
sage: p = D([1,-6,5,-2])
|
|
1625
|
+
sage: [p.has_left_descent(i) for i in D.index_set()]
|
|
1626
|
+
[True, True, False, True, True]
|
|
1627
|
+
"""
|
|
1628
|
+
if i == 0:
|
|
1629
|
+
return self.position(-2) > self.position(1)
|
|
1630
|
+
if i == self.k:
|
|
1631
|
+
return self.position(i) > self.position(i+2)
|
|
1632
|
+
return self.position(i) > self.position(i+1)
|
|
1633
|
+
|
|
1634
|
+
|
|
1635
|
+
class AffinePermutationTypeG(AffinePermutation):
|
|
1636
|
+
# ----------------------
|
|
1637
|
+
# Type-specific methods.
|
|
1638
|
+
# (Methods existing in all types, but with type-specific definition.)
|
|
1639
|
+
# ----------------------
|
|
1640
|
+
def check(self) -> None:
|
|
1641
|
+
r"""
|
|
1642
|
+
Check that ``self`` is an affine permutation.
|
|
1643
|
+
|
|
1644
|
+
EXAMPLES::
|
|
1645
|
+
|
|
1646
|
+
sage: G = AffinePermutationGroup(['G',2,1])
|
|
1647
|
+
sage: p = G([2, 10, -5, 12, -3, 5])
|
|
1648
|
+
sage: p
|
|
1649
|
+
Type G affine permutation with window [2, 10, -5, 12, -3, 5]
|
|
1650
|
+
"""
|
|
1651
|
+
if not self:
|
|
1652
|
+
return
|
|
1653
|
+
if not len(self) == 6:
|
|
1654
|
+
raise ValueError("length of list must be 6")
|
|
1655
|
+
# Check that we have an even number of 'big' elements left of the 7th entry.
|
|
1656
|
+
s = sum(i//6 - (i % 6 == 0) for i in self if i > 6)
|
|
1657
|
+
if s % 2:
|
|
1658
|
+
raise ValueError("type G affine permutations have an even number of"
|
|
1659
|
+
" entries greater than 6 to the left of the 7th position")
|
|
1660
|
+
# Check that we have an even number of 'small' elements right of the zeroth entry.
|
|
1661
|
+
s = sum(-i//6 + 1 for i in self if i <= 0)
|
|
1662
|
+
if s % 2:
|
|
1663
|
+
raise ValueError("type G affine permutations have an even number of"
|
|
1664
|
+
" entries less than 0 to the right of the 0th position")
|
|
1665
|
+
|
|
1666
|
+
def value(self, i, base_window=False):
|
|
1667
|
+
r"""
|
|
1668
|
+
Return the image of the integer ``i`` under this permutation.
|
|
1669
|
+
|
|
1670
|
+
INPUT:
|
|
1671
|
+
|
|
1672
|
+
- ``base_window`` -- boolean indicating whether ``i`` is between 1 and
|
|
1673
|
+
`k+1`; if ``True``, will run a bit faster, but the method will screw
|
|
1674
|
+
up if ``i`` is not actually in the index set
|
|
1675
|
+
|
|
1676
|
+
EXAMPLES::
|
|
1677
|
+
|
|
1678
|
+
sage: G = AffinePermutationGroup(['G',2,1])
|
|
1679
|
+
sage: p = G([2, 10, -5, 12, -3, 5])
|
|
1680
|
+
sage: [p.value(i) for i in [1..12]]
|
|
1681
|
+
[2, 10, -5, 12, -3, 5, 8, 16, 1, 18, 3, 11]
|
|
1682
|
+
"""
|
|
1683
|
+
N = 6
|
|
1684
|
+
if base_window:
|
|
1685
|
+
self[i-1]
|
|
1686
|
+
window = (i-1) // N
|
|
1687
|
+
return self[(i-1) % N] + window*(N)
|
|
1688
|
+
|
|
1689
|
+
def position(self, i):
|
|
1690
|
+
r"""
|
|
1691
|
+
Find the position ``j`` such the ``self.value(j) == i``.
|
|
1692
|
+
|
|
1693
|
+
EXAMPLES::
|
|
1694
|
+
|
|
1695
|
+
sage: G = AffinePermutationGroup(['G',2,1])
|
|
1696
|
+
sage: p = G([2, 10, -5, 12, -3, 5])
|
|
1697
|
+
sage: [p.position(i) for i in p]
|
|
1698
|
+
[1, 2, 3, 4, 5, 6]
|
|
1699
|
+
"""
|
|
1700
|
+
N = 6
|
|
1701
|
+
for r in range(N):
|
|
1702
|
+
if self[r] % N == i % N:
|
|
1703
|
+
# i sits in position i, but some number of windows away.
|
|
1704
|
+
diff = (i-self[r]) // N
|
|
1705
|
+
return r + diff*N + 1
|
|
1706
|
+
return False
|
|
1707
|
+
|
|
1708
|
+
def apply_simple_reflection_right(self, i) -> AffinePermutationTypeG:
|
|
1709
|
+
r"""
|
|
1710
|
+
Apply the simple reflection indexed by ``i`` on positions.
|
|
1711
|
+
|
|
1712
|
+
EXAMPLES::
|
|
1713
|
+
|
|
1714
|
+
sage: G = AffinePermutationGroup(['G',2,1])
|
|
1715
|
+
sage: p = G([2, 10, -5, 12, -3, 5])
|
|
1716
|
+
sage: p.apply_simple_reflection_right(0)
|
|
1717
|
+
Type G affine permutation with window [-9, -1, -5, 12, 8, 16]
|
|
1718
|
+
sage: p.apply_simple_reflection_right(1)
|
|
1719
|
+
Type G affine permutation with window [10, 2, 12, -5, 5, -3]
|
|
1720
|
+
sage: p.apply_simple_reflection_right(2)
|
|
1721
|
+
Type G affine permutation with window [2, -5, 10, -3, 12, 5]
|
|
1722
|
+
"""
|
|
1723
|
+
if i not in self.parent().index_set():
|
|
1724
|
+
raise ValueError('index not in index set')
|
|
1725
|
+
j = i
|
|
1726
|
+
l = self[:]
|
|
1727
|
+
if j == 1:
|
|
1728
|
+
l[0] = self(2)
|
|
1729
|
+
l[1] = self(1)
|
|
1730
|
+
l[2] = self(4)
|
|
1731
|
+
l[3] = self(3)
|
|
1732
|
+
l[4] = self(6)
|
|
1733
|
+
l[5] = self(5)
|
|
1734
|
+
elif j == 2:
|
|
1735
|
+
l[1] = self(3)
|
|
1736
|
+
l[2] = self(2)
|
|
1737
|
+
l[3] = self(5)
|
|
1738
|
+
l[4] = self(4)
|
|
1739
|
+
elif j == 0:
|
|
1740
|
+
l[0] = self(-1)
|
|
1741
|
+
l[1] = self(0)
|
|
1742
|
+
l[4] = self(7)
|
|
1743
|
+
l[5] = self(8)
|
|
1744
|
+
return type(self)(self.parent(), l, check=False)
|
|
1745
|
+
|
|
1746
|
+
def apply_simple_reflection_left(self, i) -> AffinePermutationTypeG:
|
|
1747
|
+
r"""
|
|
1748
|
+
Apply simple reflection indexed by `i` on values.
|
|
1749
|
+
|
|
1750
|
+
EXAMPLES::
|
|
1751
|
+
|
|
1752
|
+
sage: G = AffinePermutationGroup(['G',2,1])
|
|
1753
|
+
sage: p = G([2, 10, -5, 12, -3, 5])
|
|
1754
|
+
sage: p.apply_simple_reflection_left(0)
|
|
1755
|
+
Type G affine permutation with window [0, 10, -7, 14, -3, 7]
|
|
1756
|
+
sage: p.apply_simple_reflection_left(1)
|
|
1757
|
+
Type G affine permutation with window [1, 9, -4, 11, -2, 6]
|
|
1758
|
+
sage: p.apply_simple_reflection_left(2)
|
|
1759
|
+
Type G affine permutation with window [3, 11, -5, 12, -4, 4]
|
|
1760
|
+
"""
|
|
1761
|
+
if i not in self.parent().index_set():
|
|
1762
|
+
raise ValueError('index not in index set')
|
|
1763
|
+
l = []
|
|
1764
|
+
if i == 1:
|
|
1765
|
+
for m in range(6):
|
|
1766
|
+
res = self[m] % 6
|
|
1767
|
+
if res == 1 or res == 3 or res == 5:
|
|
1768
|
+
l.append(self[m]+1)
|
|
1769
|
+
elif res == 2 or res == 4 or res == 0:
|
|
1770
|
+
l.append(self[m]-1)
|
|
1771
|
+
else:
|
|
1772
|
+
l.append(self[m])
|
|
1773
|
+
elif i == 2:
|
|
1774
|
+
for m in range(6):
|
|
1775
|
+
res = self[m] % 6
|
|
1776
|
+
if res == 2 or res == 4:
|
|
1777
|
+
l.append(self[m]+1)
|
|
1778
|
+
elif res == 3 or res == 5:
|
|
1779
|
+
l.append(self[m]-1)
|
|
1780
|
+
else:
|
|
1781
|
+
l.append(self[m])
|
|
1782
|
+
elif i == 0:
|
|
1783
|
+
for m in range(6):
|
|
1784
|
+
res = self[m] % 6
|
|
1785
|
+
if res == 1 or res == 2:
|
|
1786
|
+
l.append(self[m]-2)
|
|
1787
|
+
elif res == 5 or res == 0:
|
|
1788
|
+
l.append(self[m]+2)
|
|
1789
|
+
else:
|
|
1790
|
+
l.append(self[m])
|
|
1791
|
+
return type(self)(self.parent(), l, check=False)
|
|
1792
|
+
|
|
1793
|
+
def has_right_descent(self, i) -> bool:
|
|
1794
|
+
r"""
|
|
1795
|
+
Determine whether there is a descent at index `i`.
|
|
1796
|
+
|
|
1797
|
+
INPUT:
|
|
1798
|
+
|
|
1799
|
+
- ``i`` -- integer
|
|
1800
|
+
|
|
1801
|
+
EXAMPLES::
|
|
1802
|
+
|
|
1803
|
+
sage: G = AffinePermutationGroup(['G',2,1])
|
|
1804
|
+
sage: p = G([2, 10, -5, 12, -3, 5])
|
|
1805
|
+
sage: [p.has_right_descent(i) for i in G.index_set()]
|
|
1806
|
+
[False, False, True]
|
|
1807
|
+
"""
|
|
1808
|
+
if i not in self.parent().index_set():
|
|
1809
|
+
raise ValueError('index not in index set')
|
|
1810
|
+
if i == 0:
|
|
1811
|
+
return self.value(0) > self.value(2)
|
|
1812
|
+
return self.value(i) > self.value(i+1)
|
|
1813
|
+
|
|
1814
|
+
def has_left_descent(self, i) -> bool:
|
|
1815
|
+
r"""
|
|
1816
|
+
Determine whether there is a descent at ``i``.
|
|
1817
|
+
|
|
1818
|
+
INPUT:
|
|
1819
|
+
|
|
1820
|
+
- ``i`` -- integer
|
|
1821
|
+
|
|
1822
|
+
EXAMPLES::
|
|
1823
|
+
|
|
1824
|
+
sage: G = AffinePermutationGroup(['G',2,1])
|
|
1825
|
+
sage: p = G([2, 10, -5, 12, -3, 5])
|
|
1826
|
+
sage: [p.has_left_descent(i) for i in G.index_set()]
|
|
1827
|
+
[False, True, False]
|
|
1828
|
+
"""
|
|
1829
|
+
if i not in self.parent().index_set():
|
|
1830
|
+
raise ValueError('index not in index set')
|
|
1831
|
+
if i == 0:
|
|
1832
|
+
return self.position(0) > self.position(2)
|
|
1833
|
+
return self.position(i) > self.position(i+1)
|
|
1834
|
+
|
|
1835
|
+
def to_type_a(self) -> AffinePermutationTypeA:
|
|
1836
|
+
r"""
|
|
1837
|
+
Return an embedding of ``self`` into the affine permutation group of
|
|
1838
|
+
type A.
|
|
1839
|
+
|
|
1840
|
+
EXAMPLES::
|
|
1841
|
+
|
|
1842
|
+
sage: G = AffinePermutationGroup(['G',2,1])
|
|
1843
|
+
sage: p = G([2, 10, -5, 12, -3, 5])
|
|
1844
|
+
sage: p.to_type_a()
|
|
1845
|
+
Type A affine permutation with window [2, 10, -5, 12, -3, 5]
|
|
1846
|
+
"""
|
|
1847
|
+
A = AffinePermutationGroup(['A', 5, 1])
|
|
1848
|
+
return A([self.value(i) for i in range(1, 7)])
|
|
1849
|
+
|
|
1850
|
+
|
|
1851
|
+
# -----------------------------------------------------------------------
|
|
1852
|
+
# Class of all affine permutations.
|
|
1853
|
+
# -----------------------------------------------------------------------
|
|
1854
|
+
|
|
1855
|
+
def AffinePermutationGroup(cartan_type):
|
|
1856
|
+
r"""
|
|
1857
|
+
Wrapper function for specific affine permutation groups.
|
|
1858
|
+
|
|
1859
|
+
These are combinatorial implementations of the affine Weyl groups of
|
|
1860
|
+
types `A`, `B`, `C`, `D`, and `G` as permutations of the set of all integers.
|
|
1861
|
+
the basic algorithms are derived from [BB2005]_ and [Eri1995]_.
|
|
1862
|
+
|
|
1863
|
+
EXAMPLES::
|
|
1864
|
+
|
|
1865
|
+
sage: ct = CartanType(['A',7,1])
|
|
1866
|
+
sage: A = AffinePermutationGroup(ct)
|
|
1867
|
+
sage: A
|
|
1868
|
+
The group of affine permutations of type ['A', 7, 1]
|
|
1869
|
+
|
|
1870
|
+
We define an element of ``A``::
|
|
1871
|
+
|
|
1872
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
1873
|
+
sage: p
|
|
1874
|
+
Type A affine permutation with window [3, -1, 0, 6, 5, 4, 10, 9]
|
|
1875
|
+
|
|
1876
|
+
We find the value `p(1)`, considering `p` as a bijection on the integers.
|
|
1877
|
+
This is the same as calling the
|
|
1878
|
+
:meth:`~sage.combinat.affine_permutation.AffinePermutation.value` method::
|
|
1879
|
+
|
|
1880
|
+
sage: p.value(1)
|
|
1881
|
+
3
|
|
1882
|
+
sage: p(1) == p.value(1)
|
|
1883
|
+
True
|
|
1884
|
+
|
|
1885
|
+
We can also find the position of the integer 3 in `p` considered as a
|
|
1886
|
+
sequence, equivalent to finding `p^{-1}(3)`::
|
|
1887
|
+
|
|
1888
|
+
sage: p.position(3)
|
|
1889
|
+
1
|
|
1890
|
+
sage: (p^-1)(3)
|
|
1891
|
+
1
|
|
1892
|
+
|
|
1893
|
+
Since the affine permutation group is a group, we demonstrate its
|
|
1894
|
+
group properties::
|
|
1895
|
+
|
|
1896
|
+
sage: A.one()
|
|
1897
|
+
Type A affine permutation with window [1, 2, 3, 4, 5, 6, 7, 8]
|
|
1898
|
+
|
|
1899
|
+
sage: q = A([0, 2, 3, 4, 5, 6, 7, 9])
|
|
1900
|
+
sage: p * q
|
|
1901
|
+
Type A affine permutation with window [1, -1, 0, 6, 5, 4, 10, 11]
|
|
1902
|
+
sage: q * p
|
|
1903
|
+
Type A affine permutation with window [3, -1, 1, 6, 5, 4, 10, 8]
|
|
1904
|
+
|
|
1905
|
+
sage: p^-1
|
|
1906
|
+
Type A affine permutation with window [0, -1, 1, 6, 5, 4, 10, 11]
|
|
1907
|
+
sage: p^-1 * p == A.one()
|
|
1908
|
+
True
|
|
1909
|
+
sage: p * p^-1 == A.one()
|
|
1910
|
+
True
|
|
1911
|
+
|
|
1912
|
+
If we decide we prefer the Weyl Group implementation of the affine Weyl
|
|
1913
|
+
group, we can easily get it::
|
|
1914
|
+
|
|
1915
|
+
sage: p.to_weyl_group_element()
|
|
1916
|
+
[ 0 -1 0 1 0 0 1 0]
|
|
1917
|
+
[ 1 -1 0 1 0 0 1 -1]
|
|
1918
|
+
[ 1 -1 0 1 0 0 0 0]
|
|
1919
|
+
[ 0 0 0 1 0 0 0 0]
|
|
1920
|
+
[ 0 0 0 1 0 -1 1 0]
|
|
1921
|
+
[ 0 0 0 1 -1 0 1 0]
|
|
1922
|
+
[ 0 0 0 0 0 0 1 0]
|
|
1923
|
+
[ 0 -1 1 0 0 0 1 0]
|
|
1924
|
+
|
|
1925
|
+
We can find a reduced word and do all of the other things one expects in
|
|
1926
|
+
a Coxeter group::
|
|
1927
|
+
|
|
1928
|
+
sage: p.has_right_descent(1)
|
|
1929
|
+
True
|
|
1930
|
+
sage: p.apply_simple_reflection(1)
|
|
1931
|
+
Type A affine permutation with window [-1, 3, 0, 6, 5, 4, 10, 9]
|
|
1932
|
+
sage: p.apply_simple_reflection(0)
|
|
1933
|
+
Type A affine permutation with window [1, -1, 0, 6, 5, 4, 10, 11]
|
|
1934
|
+
sage: p.reduced_word()
|
|
1935
|
+
[0, 7, 4, 1, 0, 7, 5, 4, 2, 1]
|
|
1936
|
+
sage: p.length()
|
|
1937
|
+
10
|
|
1938
|
+
|
|
1939
|
+
The following methods are particular to type `A`.
|
|
1940
|
+
We can check if the element is fully commutative::
|
|
1941
|
+
|
|
1942
|
+
sage: p.is_fully_commutative()
|
|
1943
|
+
False
|
|
1944
|
+
sage: q.is_fully_commutative()
|
|
1945
|
+
True
|
|
1946
|
+
|
|
1947
|
+
We can also compute the affine Lehmer code of the permutation,
|
|
1948
|
+
a weak composition with `k + 1` entries::
|
|
1949
|
+
|
|
1950
|
+
sage: p.to_lehmer_code()
|
|
1951
|
+
[0, 3, 3, 0, 1, 2, 0, 1]
|
|
1952
|
+
|
|
1953
|
+
Once we have the Lehmer code, we can obtain a `k`-bounded partition by
|
|
1954
|
+
sorting the Lehmer code, and then reading the row lengths.
|
|
1955
|
+
There is a unique 0-Grassmanian (dominant) affine permutation associated
|
|
1956
|
+
to this `k`-bounded partition, and a `k`-core as well. ::
|
|
1957
|
+
|
|
1958
|
+
sage: p.to_bounded_partition()
|
|
1959
|
+
[5, 3, 2]
|
|
1960
|
+
sage: p.to_dominant()
|
|
1961
|
+
Type A affine permutation with window [-2, -1, 1, 3, 4, 8, 10, 13]
|
|
1962
|
+
sage: p.to_core()
|
|
1963
|
+
[5, 3, 2]
|
|
1964
|
+
|
|
1965
|
+
Finally, we can take a reduced word for `p` and insert it to find a
|
|
1966
|
+
standard composition tableau associated uniquely to that word::
|
|
1967
|
+
|
|
1968
|
+
sage: p.tableau_of_word(p.reduced_word())
|
|
1969
|
+
[[], [1, 6, 9], [2, 7, 10], [], [3], [4, 8], [], [5]]
|
|
1970
|
+
|
|
1971
|
+
We can also form affine permutation groups in types `B`, `C`, `D`,
|
|
1972
|
+
and `G`::
|
|
1973
|
+
|
|
1974
|
+
sage: B = AffinePermutationGroup(['B',4,1])
|
|
1975
|
+
sage: B.an_element()
|
|
1976
|
+
Type B affine permutation with window [-1, 3, 4, 11]
|
|
1977
|
+
|
|
1978
|
+
sage: C = AffinePermutationGroup(['C',4,1])
|
|
1979
|
+
sage: C.an_element()
|
|
1980
|
+
Type C affine permutation with window [2, 3, 4, 10]
|
|
1981
|
+
|
|
1982
|
+
sage: D = AffinePermutationGroup(['D',4,1])
|
|
1983
|
+
sage: D.an_element()
|
|
1984
|
+
Type D affine permutation with window [-1, 3, 11, 5]
|
|
1985
|
+
|
|
1986
|
+
sage: G = AffinePermutationGroup(['G',2,1])
|
|
1987
|
+
sage: G.an_element()
|
|
1988
|
+
Type G affine permutation with window [0, 4, -1, 8, 3, 7]
|
|
1989
|
+
"""
|
|
1990
|
+
ct = CartanType(cartan_type)
|
|
1991
|
+
if ct.letter == 'A':
|
|
1992
|
+
return AffinePermutationGroupTypeA(ct)
|
|
1993
|
+
if ct.letter == 'B':
|
|
1994
|
+
return AffinePermutationGroupTypeB(ct)
|
|
1995
|
+
if ct.letter == 'C':
|
|
1996
|
+
return AffinePermutationGroupTypeC(ct)
|
|
1997
|
+
if ct.letter == 'D':
|
|
1998
|
+
return AffinePermutationGroupTypeD(ct)
|
|
1999
|
+
if ct.letter == 'G':
|
|
2000
|
+
return AffinePermutationGroupTypeG(ct)
|
|
2001
|
+
raise NotImplementedError('Cartan type provided is not implemented as an affine permutation group')
|
|
2002
|
+
|
|
2003
|
+
|
|
2004
|
+
class AffinePermutationGroupGeneric(UniqueRepresentation, Parent):
|
|
2005
|
+
"""
|
|
2006
|
+
The generic affine permutation group class, in which we define all type-free
|
|
2007
|
+
methods for the specific affine permutation groups.
|
|
2008
|
+
|
|
2009
|
+
TESTS::
|
|
2010
|
+
|
|
2011
|
+
sage: AffinePermutationGroup(['A',7,1])([3, -1, 0, 6, 5, 4, 10, 9])
|
|
2012
|
+
Type A affine permutation with window [3, -1, 0, 6, 5, 4, 10, 9]
|
|
2013
|
+
"""
|
|
2014
|
+
# ----------------------
|
|
2015
|
+
# Type-free methods.
|
|
2016
|
+
# ----------------------
|
|
2017
|
+
|
|
2018
|
+
def __init__(self, cartan_type) -> None:
|
|
2019
|
+
r"""
|
|
2020
|
+
TESTS::
|
|
2021
|
+
|
|
2022
|
+
sage: AffinePermutationGroup(['A',7,1])
|
|
2023
|
+
The group of affine permutations of type ['A', 7, 1]
|
|
2024
|
+
"""
|
|
2025
|
+
Parent.__init__(self, category=AffineWeylGroups())
|
|
2026
|
+
ct = CartanType(cartan_type)
|
|
2027
|
+
self.k = Integer(ct.n)
|
|
2028
|
+
self.n = ct.rank()
|
|
2029
|
+
# This N doesn't matter for type A, but comes up in all other types.
|
|
2030
|
+
if ct.letter == 'A':
|
|
2031
|
+
self.N = self.k + 1
|
|
2032
|
+
elif ct.letter == 'B' or ct.letter == 'C' or ct.letter == 'D':
|
|
2033
|
+
self.N = 2 * self.k + 1
|
|
2034
|
+
elif ct.letter == 'G':
|
|
2035
|
+
self.N = 6
|
|
2036
|
+
self._cartan_type = ct
|
|
2037
|
+
|
|
2038
|
+
def _repr_(self) -> str:
|
|
2039
|
+
r"""
|
|
2040
|
+
TESTS::
|
|
2041
|
+
|
|
2042
|
+
sage: AffinePermutationGroup(['A',7,1])
|
|
2043
|
+
The group of affine permutations of type ['A', 7, 1]
|
|
2044
|
+
"""
|
|
2045
|
+
return "The group of affine permutations of type " + str(self.cartan_type())
|
|
2046
|
+
|
|
2047
|
+
def _test_enumeration(self, n=4, **options):
|
|
2048
|
+
r"""
|
|
2049
|
+
Test that ``self`` has same number of elements of length ``n`` as the
|
|
2050
|
+
Weyl Group implementation.
|
|
2051
|
+
|
|
2052
|
+
Combined with ``self._test_coxeter_relations`` this shows isomorphism
|
|
2053
|
+
up to length ``n``.
|
|
2054
|
+
|
|
2055
|
+
TESTS::
|
|
2056
|
+
|
|
2057
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
2058
|
+
sage: A._test_enumeration(3)
|
|
2059
|
+
"""
|
|
2060
|
+
tester = self._tester(**options)
|
|
2061
|
+
n1 = len(list(self.elements_of_length(n)))
|
|
2062
|
+
W = self.weyl_group()
|
|
2063
|
+
I = W.weak_order_ideal(ConstantFunction(True), side='right')
|
|
2064
|
+
n2 = len(list(I.elements_of_depth_iterator(n)))
|
|
2065
|
+
tester.assertEqual(n1, n2, "number of (ranked) elements of affine"
|
|
2066
|
+
" permutation group disagrees with Weyl group")
|
|
2067
|
+
|
|
2068
|
+
def weyl_group(self):
|
|
2069
|
+
r"""
|
|
2070
|
+
Return the Weyl Group of the same type as ``self``.
|
|
2071
|
+
|
|
2072
|
+
EXAMPLES::
|
|
2073
|
+
|
|
2074
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
2075
|
+
sage: A.weyl_group()
|
|
2076
|
+
Weyl Group of type ['A', 7, 1] (as a matrix group acting on the root space)
|
|
2077
|
+
"""
|
|
2078
|
+
return WeylGroup(self._cartan_type)
|
|
2079
|
+
|
|
2080
|
+
def classical(self):
|
|
2081
|
+
r"""
|
|
2082
|
+
Return the finite permutation group.
|
|
2083
|
+
|
|
2084
|
+
EXAMPLES::
|
|
2085
|
+
|
|
2086
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
2087
|
+
sage: A.classical()
|
|
2088
|
+
Symmetric group of order 8! as a permutation group
|
|
2089
|
+
"""
|
|
2090
|
+
if self._cartan_type.letter == 'A':
|
|
2091
|
+
return SymmetricGroup(self.k+1)
|
|
2092
|
+
return WeylGroup(self._cartan_type.classical())
|
|
2093
|
+
|
|
2094
|
+
def cartan_type(self):
|
|
2095
|
+
r"""
|
|
2096
|
+
Return the Cartan type of ``self``.
|
|
2097
|
+
|
|
2098
|
+
EXAMPLES::
|
|
2099
|
+
|
|
2100
|
+
sage: AffinePermutationGroup(['A',7,1]).cartan_type()
|
|
2101
|
+
['A', 7, 1]
|
|
2102
|
+
"""
|
|
2103
|
+
return self._cartan_type
|
|
2104
|
+
|
|
2105
|
+
def cartan_matrix(self):
|
|
2106
|
+
r"""
|
|
2107
|
+
Return the Cartan matrix of ``self``.
|
|
2108
|
+
|
|
2109
|
+
EXAMPLES::
|
|
2110
|
+
|
|
2111
|
+
sage: AffinePermutationGroup(['A',7,1]).cartan_matrix()
|
|
2112
|
+
[ 2 -1 0 0 0 0 0 -1]
|
|
2113
|
+
[-1 2 -1 0 0 0 0 0]
|
|
2114
|
+
[ 0 -1 2 -1 0 0 0 0]
|
|
2115
|
+
[ 0 0 -1 2 -1 0 0 0]
|
|
2116
|
+
[ 0 0 0 -1 2 -1 0 0]
|
|
2117
|
+
[ 0 0 0 0 -1 2 -1 0]
|
|
2118
|
+
[ 0 0 0 0 0 -1 2 -1]
|
|
2119
|
+
[-1 0 0 0 0 0 -1 2]
|
|
2120
|
+
"""
|
|
2121
|
+
return self.cartan_type().cartan_matrix()
|
|
2122
|
+
|
|
2123
|
+
def is_crystallographic(self) -> bool:
|
|
2124
|
+
r"""
|
|
2125
|
+
Tell whether the affine permutation group is crystallographic.
|
|
2126
|
+
|
|
2127
|
+
EXAMPLES::
|
|
2128
|
+
|
|
2129
|
+
sage: AffinePermutationGroup(['A',7,1]).is_crystallographic()
|
|
2130
|
+
True
|
|
2131
|
+
"""
|
|
2132
|
+
return self.cartan_type().is_crystallographic()
|
|
2133
|
+
|
|
2134
|
+
def index_set(self):
|
|
2135
|
+
r"""
|
|
2136
|
+
EXAMPLES::
|
|
2137
|
+
|
|
2138
|
+
sage: AffinePermutationGroup(['A',7,1]).index_set()
|
|
2139
|
+
(0, 1, 2, 3, 4, 5, 6, 7)
|
|
2140
|
+
"""
|
|
2141
|
+
return self.cartan_type().index_set()
|
|
2142
|
+
|
|
2143
|
+
_index_set = index_set
|
|
2144
|
+
|
|
2145
|
+
def reflection_index_set(self):
|
|
2146
|
+
r"""
|
|
2147
|
+
EXAMPLES::
|
|
2148
|
+
|
|
2149
|
+
sage: AffinePermutationGroup(['A',7,1]).reflection_index_set()
|
|
2150
|
+
(0, 1, 2, 3, 4, 5, 6, 7)
|
|
2151
|
+
"""
|
|
2152
|
+
return self.cartan_type().index_set()
|
|
2153
|
+
|
|
2154
|
+
def rank(self):
|
|
2155
|
+
r"""
|
|
2156
|
+
Rank of the affine permutation group, equal to `k+1`.
|
|
2157
|
+
|
|
2158
|
+
EXAMPLES::
|
|
2159
|
+
|
|
2160
|
+
sage: AffinePermutationGroup(['A',7,1]).rank()
|
|
2161
|
+
8
|
|
2162
|
+
"""
|
|
2163
|
+
return self.k + 1
|
|
2164
|
+
|
|
2165
|
+
def random_element(self, n=None) -> AffinePermutation:
|
|
2166
|
+
r"""
|
|
2167
|
+
Return a random affine permutation of length ``n``.
|
|
2168
|
+
|
|
2169
|
+
If ``n`` is not specified, then ``n`` is chosen as a random
|
|
2170
|
+
nonnegative integer in `[0, 1000]`.
|
|
2171
|
+
|
|
2172
|
+
Starts at the identity, then chooses an upper cover at random.
|
|
2173
|
+
Not very uniform: actually constructs a uniformly random reduced word
|
|
2174
|
+
of length `n`. Thus we most likely get elements with lots of reduced
|
|
2175
|
+
words!
|
|
2176
|
+
|
|
2177
|
+
For the actual code, see
|
|
2178
|
+
:meth:`sage.categories.coxeter_group.random_element_of_length`.
|
|
2179
|
+
|
|
2180
|
+
EXAMPLES::
|
|
2181
|
+
|
|
2182
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
2183
|
+
sage: A.random_element() # random
|
|
2184
|
+
Type A affine permutation with window [-12, 16, 19, -1, -2, 10, -3, 9]
|
|
2185
|
+
sage: p = A.random_element(10)
|
|
2186
|
+
sage: p.length() == 10
|
|
2187
|
+
True
|
|
2188
|
+
"""
|
|
2189
|
+
if n is None:
|
|
2190
|
+
n = randint(0, 1000)
|
|
2191
|
+
return self.random_element_of_length(n)
|
|
2192
|
+
|
|
2193
|
+
def from_word(self, w) -> AffinePermutation:
|
|
2194
|
+
r"""
|
|
2195
|
+
Build an affine permutation from a given word.
|
|
2196
|
+
Note: Already in category as ``from_reduced_word``, but this is less
|
|
2197
|
+
typing!
|
|
2198
|
+
|
|
2199
|
+
EXAMPLES::
|
|
2200
|
+
|
|
2201
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
2202
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
2203
|
+
sage: A.from_word([0, 7, 4, 1, 0, 7, 5, 4, 2, 1])
|
|
2204
|
+
Type A affine permutation with window [3, -1, 0, 6, 5, 4, 10, 9]
|
|
2205
|
+
"""
|
|
2206
|
+
return self.from_reduced_word(w)
|
|
2207
|
+
|
|
2208
|
+
@cached_method
|
|
2209
|
+
def _an_element_(self) -> AffinePermutation:
|
|
2210
|
+
r"""
|
|
2211
|
+
Return a Coxeter element.
|
|
2212
|
+
|
|
2213
|
+
EXAMPLES::
|
|
2214
|
+
|
|
2215
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
2216
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
2217
|
+
sage: A.from_word([0, 7, 4, 1, 0, 7, 5, 4, 2, 1])
|
|
2218
|
+
Type A affine permutation with window [3, -1, 0, 6, 5, 4, 10, 9]
|
|
2219
|
+
"""
|
|
2220
|
+
return self.from_reduced_word(self.index_set())
|
|
2221
|
+
|
|
2222
|
+
|
|
2223
|
+
class AffinePermutationGroupTypeA(AffinePermutationGroupGeneric):
|
|
2224
|
+
# ------------------------
|
|
2225
|
+
# Type-specific methods.
|
|
2226
|
+
# (Methods in all types, but with specific definition.)
|
|
2227
|
+
# ------------------------
|
|
2228
|
+
|
|
2229
|
+
@cached_method
|
|
2230
|
+
def one(self) -> AffinePermutation:
|
|
2231
|
+
r"""
|
|
2232
|
+
Return the identity element.
|
|
2233
|
+
|
|
2234
|
+
EXAMPLES::
|
|
2235
|
+
|
|
2236
|
+
sage: AffinePermutationGroup(['A',7,1]).one()
|
|
2237
|
+
Type A affine permutation with window [1, 2, 3, 4, 5, 6, 7, 8]
|
|
2238
|
+
|
|
2239
|
+
TESTS::
|
|
2240
|
+
|
|
2241
|
+
sage: A = AffinePermutationGroup(['A',5,1])
|
|
2242
|
+
sage: A == loads(dumps(A))
|
|
2243
|
+
True
|
|
2244
|
+
sage: TestSuite(A).run()
|
|
2245
|
+
"""
|
|
2246
|
+
return self(range(1, self.k + 2))
|
|
2247
|
+
|
|
2248
|
+
# ------------------------
|
|
2249
|
+
# Type-unique methods.
|
|
2250
|
+
# (Methods which do not exist in all types.)
|
|
2251
|
+
# ------------------------
|
|
2252
|
+
def from_lehmer_code(self, C, typ='decreasing',
|
|
2253
|
+
side='right') -> AffinePermutation:
|
|
2254
|
+
r"""
|
|
2255
|
+
Return the affine permutation with the supplied Lehmer code (a weak
|
|
2256
|
+
composition with `k+1` parts, at least one of which is 0).
|
|
2257
|
+
|
|
2258
|
+
INPUT:
|
|
2259
|
+
|
|
2260
|
+
- ``typ`` -- ``'increasing'`` or ``'decreasing'``
|
|
2261
|
+
(default: ``'decreasing'``); type of product
|
|
2262
|
+
- ``side`` -- ``'right'`` or ``'left'`` (default: ``'right'``);
|
|
2263
|
+
whether the decomposition is from the right or left
|
|
2264
|
+
|
|
2265
|
+
EXAMPLES::
|
|
2266
|
+
|
|
2267
|
+
sage: import itertools
|
|
2268
|
+
sage: A = AffinePermutationGroup(['A',7,1])
|
|
2269
|
+
sage: p = A([3, -1, 0, 6, 5, 4, 10, 9])
|
|
2270
|
+
sage: p.to_lehmer_code()
|
|
2271
|
+
[0, 3, 3, 0, 1, 2, 0, 1]
|
|
2272
|
+
sage: A.from_lehmer_code(p.to_lehmer_code()) == p
|
|
2273
|
+
True
|
|
2274
|
+
sage: orders = ('increasing','decreasing')
|
|
2275
|
+
sage: sides = ('left','right')
|
|
2276
|
+
sage: all(A.from_lehmer_code(p.to_lehmer_code(o,s),o,s) == p
|
|
2277
|
+
....: for o,s in itertools.product(orders,sides))
|
|
2278
|
+
True
|
|
2279
|
+
"""
|
|
2280
|
+
if len(C) - 1 != self.k:
|
|
2281
|
+
raise ValueError("composition must have {} entries".format(self.k+1))
|
|
2282
|
+
if 0 not in C:
|
|
2283
|
+
raise ValueError("composition must contain a zero entry")
|
|
2284
|
+
k = self.k
|
|
2285
|
+
# Find a zero entry in C.
|
|
2286
|
+
for r in range(self.k+1):
|
|
2287
|
+
if C[r] == 0:
|
|
2288
|
+
break
|
|
2289
|
+
D = list(C)
|
|
2290
|
+
# The s0 and t0 are +-1, dependent on typ and side.
|
|
2291
|
+
if (typ[0], side[0]) == ('d', 'r'):
|
|
2292
|
+
t0, s0 = (-1, 1)
|
|
2293
|
+
elif (typ[0], side[0]) == ('i', 'r'):
|
|
2294
|
+
t0, s0 = (1, 1)
|
|
2295
|
+
elif (typ[0], side[0]) == ('d', 'l'):
|
|
2296
|
+
t0, s0 = (-1, -1)
|
|
2297
|
+
elif (typ[0], side[0]) == ('i', 'l'):
|
|
2298
|
+
t0, s0 = (1, -1)
|
|
2299
|
+
else:
|
|
2300
|
+
raise RuntimeError
|
|
2301
|
+
row = 0
|
|
2302
|
+
# Method is to build a reduced word from the composition.
|
|
2303
|
+
# We create a list of cyclically in/decreasing words appearing in
|
|
2304
|
+
# the decomposition corresponding to the composition C,
|
|
2305
|
+
# and then build the element.
|
|
2306
|
+
listy = []
|
|
2307
|
+
while sum(D) > 0:
|
|
2308
|
+
l = ['x'] * (self.k + 1)
|
|
2309
|
+
ll = []
|
|
2310
|
+
# read off a row of C.
|
|
2311
|
+
for j in range(self.k+1):
|
|
2312
|
+
pos = (r + s0*t0*j) % (k+1)
|
|
2313
|
+
residue = (r + s0*t0*(row + j)) % (k+1)
|
|
2314
|
+
if D[pos] != 0:
|
|
2315
|
+
ll.append(residue)
|
|
2316
|
+
l[pos] = [residue]
|
|
2317
|
+
D[pos] -= 1
|
|
2318
|
+
if side[0] == 'l':
|
|
2319
|
+
ll.reverse()
|
|
2320
|
+
listy.append(ll)
|
|
2321
|
+
row += 1
|
|
2322
|
+
if side[0] == 'r':
|
|
2323
|
+
listy.reverse()
|
|
2324
|
+
x = self.one()
|
|
2325
|
+
for ll in listy:
|
|
2326
|
+
for i in ll:
|
|
2327
|
+
x = x.apply_simple_reflection_right(i)
|
|
2328
|
+
return x
|
|
2329
|
+
|
|
2330
|
+
Element = AffinePermutationTypeA
|
|
2331
|
+
|
|
2332
|
+
|
|
2333
|
+
class AffinePermutationGroupTypeC(AffinePermutationGroupGeneric):
|
|
2334
|
+
# ------------------------
|
|
2335
|
+
# Type-specific methods.
|
|
2336
|
+
# (Methods in all types, but with specific definition.)
|
|
2337
|
+
# ------------------------
|
|
2338
|
+
|
|
2339
|
+
@cached_method
|
|
2340
|
+
def one(self) -> AffinePermutation:
|
|
2341
|
+
r"""
|
|
2342
|
+
Return the identity element.
|
|
2343
|
+
|
|
2344
|
+
EXAMPLES::
|
|
2345
|
+
|
|
2346
|
+
sage: ct = CartanType(['C',4,1])
|
|
2347
|
+
sage: C = AffinePermutationGroup(ct)
|
|
2348
|
+
sage: C.one()
|
|
2349
|
+
Type C affine permutation with window [1, 2, 3, 4]
|
|
2350
|
+
sage: C.one()*C.one()==C.one()
|
|
2351
|
+
True
|
|
2352
|
+
|
|
2353
|
+
TESTS::
|
|
2354
|
+
|
|
2355
|
+
sage: C = AffinePermutationGroup(['C',4,1])
|
|
2356
|
+
sage: C == loads(dumps(C))
|
|
2357
|
+
True
|
|
2358
|
+
sage: TestSuite(C).run()
|
|
2359
|
+
"""
|
|
2360
|
+
return self(range(1, self.k + 1))
|
|
2361
|
+
|
|
2362
|
+
Element = AffinePermutationTypeC
|
|
2363
|
+
|
|
2364
|
+
|
|
2365
|
+
class AffinePermutationGroupTypeB(AffinePermutationGroupTypeC):
|
|
2366
|
+
# ------------------------
|
|
2367
|
+
# Type-specific methods.
|
|
2368
|
+
# (Methods in all types, but with specific definition.)
|
|
2369
|
+
# ------------------------
|
|
2370
|
+
Element = AffinePermutationTypeB
|
|
2371
|
+
|
|
2372
|
+
|
|
2373
|
+
class AffinePermutationGroupTypeD(AffinePermutationGroupTypeC):
|
|
2374
|
+
# ------------------------
|
|
2375
|
+
# Type-specific methods.
|
|
2376
|
+
# (Methods in all types, but with specific definition.)
|
|
2377
|
+
# ------------------------
|
|
2378
|
+
Element = AffinePermutationTypeD
|
|
2379
|
+
|
|
2380
|
+
|
|
2381
|
+
class AffinePermutationGroupTypeG(AffinePermutationGroupGeneric):
|
|
2382
|
+
# ------------------------
|
|
2383
|
+
# Type-specific methods.
|
|
2384
|
+
# (Methods in all types, but with specific definition.)
|
|
2385
|
+
# ------------------------
|
|
2386
|
+
@cached_method
|
|
2387
|
+
def one(self) -> AffinePermutation:
|
|
2388
|
+
r"""
|
|
2389
|
+
Return the identity element.
|
|
2390
|
+
|
|
2391
|
+
EXAMPLES::
|
|
2392
|
+
|
|
2393
|
+
sage: AffinePermutationGroup(['G',2,1]).one()
|
|
2394
|
+
Type G affine permutation with window [1, 2, 3, 4, 5, 6]
|
|
2395
|
+
|
|
2396
|
+
TESTS::
|
|
2397
|
+
|
|
2398
|
+
sage: G = AffinePermutationGroup(['G',2,1])
|
|
2399
|
+
sage: G == loads(dumps(G))
|
|
2400
|
+
True
|
|
2401
|
+
sage: TestSuite(G).run()
|
|
2402
|
+
"""
|
|
2403
|
+
return self([1, 2, 3, 4, 5, 6])
|
|
2404
|
+
|
|
2405
|
+
Element = AffinePermutationTypeG
|