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,1729 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-combinat
|
|
2
|
+
# sage.doctest: needs sage.combinat sage.groups
|
|
3
|
+
r"""
|
|
4
|
+
Constellations
|
|
5
|
+
|
|
6
|
+
A constellation is a tuple `(g_0, g_1, \dots, g_k)` of permutations
|
|
7
|
+
such that the product `g_0 g_1 ... g_k` is the identity. One often
|
|
8
|
+
assumes that the group generated by `g_0, g_1, \dots, g_k` acts
|
|
9
|
+
transitively ([LZ2004]_ definition 1). Geometrically, it corresponds
|
|
10
|
+
to a covering of the 2-sphere ramified over `k` points (the transitivity
|
|
11
|
+
condition corresponds to the connectivity of the covering).
|
|
12
|
+
|
|
13
|
+
EXAMPLES::
|
|
14
|
+
|
|
15
|
+
sage: c = Constellation(['(1,2)', '(1,3)', None])
|
|
16
|
+
sage: c
|
|
17
|
+
Constellation of length 3 and degree 3
|
|
18
|
+
g0 (1,2)(3)
|
|
19
|
+
g1 (1,3)(2)
|
|
20
|
+
g2 (1,3,2)
|
|
21
|
+
sage: C = Constellations(3,4); C
|
|
22
|
+
Connected constellations of length 3 and degree 4 on {1, 2, 3, 4}
|
|
23
|
+
sage: C.cardinality() # long time
|
|
24
|
+
426
|
|
25
|
+
|
|
26
|
+
sage: C = Constellations(3, 4, domain=('a', 'b', 'c', 'd'))
|
|
27
|
+
sage: C
|
|
28
|
+
Connected constellations of length 3 and degree 4 on {'a', 'b', 'c', 'd'}
|
|
29
|
+
sage: c = C(('a','c'),(('b','c'),('a','d')), None)
|
|
30
|
+
sage: c
|
|
31
|
+
Constellation of length 3 and degree 4
|
|
32
|
+
g0 ('a','c')('b')('d')
|
|
33
|
+
g1 ('a','d')('b','c')
|
|
34
|
+
g2 ('a','d','c','b')
|
|
35
|
+
sage: c.is_connected()
|
|
36
|
+
True
|
|
37
|
+
sage: c.euler_characteristic()
|
|
38
|
+
2
|
|
39
|
+
sage: TestSuite(C).run()
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
# ****************************************************************************
|
|
43
|
+
# Copyright (C) 2015-2016 Vincent Delecroix <20100.delecroix@gmail.com>
|
|
44
|
+
# Frédéric Chapoton <fchapoton2@gmail.com>
|
|
45
|
+
#
|
|
46
|
+
# This program is free software: you can redistribute it and/or modify
|
|
47
|
+
# it under the terms of the GNU General Public License as published by
|
|
48
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
49
|
+
# (at your option) any later version.
|
|
50
|
+
# https://www.gnu.org/licenses/
|
|
51
|
+
# ****************************************************************************
|
|
52
|
+
from itertools import repeat, product
|
|
53
|
+
|
|
54
|
+
from sage.structure.element import parent
|
|
55
|
+
from sage.structure.parent import Parent
|
|
56
|
+
from sage.structure.element import Element
|
|
57
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
58
|
+
from sage.structure.richcmp import (op_NE, op_EQ, richcmp_not_equal,
|
|
59
|
+
rich_to_bool)
|
|
60
|
+
|
|
61
|
+
from sage.rings.integer import Integer
|
|
62
|
+
from sage.combinat.partition import Partition
|
|
63
|
+
from sage.misc.misc_c import prod
|
|
64
|
+
from sage.misc.lazy_import import lazy_import
|
|
65
|
+
from sage.categories.groups import Groups
|
|
66
|
+
|
|
67
|
+
lazy_import('sage.graphs.graph', 'Graph')
|
|
68
|
+
lazy_import('sage.graphs.digraph', 'DiGraph')
|
|
69
|
+
lazy_import('sage.groups.perm_gps.permgroup_named', 'SymmetricGroup')
|
|
70
|
+
|
|
71
|
+
# constructors
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def Constellations(*data, **options):
|
|
75
|
+
r"""
|
|
76
|
+
Build a set of constellations.
|
|
77
|
+
|
|
78
|
+
INPUT:
|
|
79
|
+
|
|
80
|
+
- ``profile`` -- an optional profile
|
|
81
|
+
|
|
82
|
+
- ``length`` -- an optional length
|
|
83
|
+
|
|
84
|
+
- ``degree`` -- an optional degree
|
|
85
|
+
|
|
86
|
+
- ``connected`` -- an optional boolean
|
|
87
|
+
|
|
88
|
+
EXAMPLES::
|
|
89
|
+
|
|
90
|
+
sage: Constellations(4,2)
|
|
91
|
+
Connected constellations of length 4 and degree 2 on {1, 2}
|
|
92
|
+
|
|
93
|
+
sage: Constellations([[3,2,1],[3,3],[3,3]])
|
|
94
|
+
Connected constellations with profile ([3, 2, 1], [3, 3], [3, 3]) on {1, 2, 3, 4, 5, 6}
|
|
95
|
+
"""
|
|
96
|
+
profile = options.get('profile', None)
|
|
97
|
+
length = options.get('length', None)
|
|
98
|
+
degree = options.get('degree', None)
|
|
99
|
+
connected = options.get('connected', True)
|
|
100
|
+
domain = options.get('domain', None)
|
|
101
|
+
if domain is not None:
|
|
102
|
+
domain = tuple(domain)
|
|
103
|
+
|
|
104
|
+
if data:
|
|
105
|
+
if len(data) == 1:
|
|
106
|
+
if isinstance(data[0], (tuple, list)):
|
|
107
|
+
profile = data[0]
|
|
108
|
+
else:
|
|
109
|
+
length = Integer(data[0])
|
|
110
|
+
elif len(data) == 2:
|
|
111
|
+
length = Integer(data[0])
|
|
112
|
+
degree = Integer(data[1])
|
|
113
|
+
|
|
114
|
+
if profile:
|
|
115
|
+
profile = tuple(map(Partition, profile))
|
|
116
|
+
return Constellations_p(profile, domain, bool(connected))
|
|
117
|
+
elif degree is not None and length is not None:
|
|
118
|
+
if domain is None:
|
|
119
|
+
sym = SymmetricGroup(degree)
|
|
120
|
+
else:
|
|
121
|
+
sym = SymmetricGroup(domain)
|
|
122
|
+
if len(sym.domain()) != degree:
|
|
123
|
+
raise ValueError("the size of the domain should be equal to the degree")
|
|
124
|
+
|
|
125
|
+
return Constellations_ld(Integer(length), Integer(degree),
|
|
126
|
+
sym, bool(connected))
|
|
127
|
+
else:
|
|
128
|
+
raise ValueError("you must either provide a profile or a pair (length, degree)")
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def Constellation(g=None, mutable=False, connected=True, check=True):
|
|
132
|
+
r"""
|
|
133
|
+
Constellation.
|
|
134
|
+
|
|
135
|
+
INPUT:
|
|
136
|
+
|
|
137
|
+
- ``g`` -- list of permutations
|
|
138
|
+
|
|
139
|
+
- ``mutable`` -- boolean (default: ``False``); whether the result is
|
|
140
|
+
mutable or not
|
|
141
|
+
|
|
142
|
+
- ``connected`` -- boolean (default: ``True``); whether the result should
|
|
143
|
+
be connected
|
|
144
|
+
|
|
145
|
+
- ``check`` -- boolean (default: ``True``); whether or not to check. If it
|
|
146
|
+
is ``True``, then the list ``g`` must contain no ``None``.
|
|
147
|
+
|
|
148
|
+
EXAMPLES:
|
|
149
|
+
|
|
150
|
+
Simple initialization::
|
|
151
|
+
|
|
152
|
+
sage: Constellation(['(0,1)','(0,3)(1,2)','(0,3,1,2)'])
|
|
153
|
+
Constellation of length 3 and degree 4
|
|
154
|
+
g0 (0,1)(2)(3)
|
|
155
|
+
g1 (0,3)(1,2)
|
|
156
|
+
g2 (0,3,1,2)
|
|
157
|
+
|
|
158
|
+
One of the permutation can be omitted::
|
|
159
|
+
|
|
160
|
+
sage: Constellation(['(0,1)', None, '(0,4)(1,2,3)'])
|
|
161
|
+
Constellation of length 3 and degree 5
|
|
162
|
+
g0 (0,1)(2)(3)(4)
|
|
163
|
+
g1 (0,3,2,1,4)
|
|
164
|
+
g2 (0,4)(1,2,3)
|
|
165
|
+
|
|
166
|
+
One can define mutable constellations::
|
|
167
|
+
|
|
168
|
+
sage: Constellation(([0,2,1], [2,1,0], [1,2,0]), mutable=True)
|
|
169
|
+
Constellation of length 3 and degree 3
|
|
170
|
+
g0 (0)(1,2)
|
|
171
|
+
g1 (0,2)(1)
|
|
172
|
+
g2 (0,1,2)
|
|
173
|
+
"""
|
|
174
|
+
l = len(g)
|
|
175
|
+
sym, _ = perms_sym_init([x for x in g if x is not None])
|
|
176
|
+
d = len(sym.domain())
|
|
177
|
+
return Constellations(l, d,
|
|
178
|
+
domain=sym.domain(),
|
|
179
|
+
connected=connected)(g, mutable=mutable, check=check)
|
|
180
|
+
|
|
181
|
+
# classes
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class Constellation_class(Element):
|
|
185
|
+
r"""
|
|
186
|
+
Constellation.
|
|
187
|
+
|
|
188
|
+
A constellation or a tuple of permutations `(g_0,g_1,...,g_k)`
|
|
189
|
+
such that the product `g_0 g_1 ... g_k` is the identity.
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
def __init__(self, parent, g, connected, mutable, check):
|
|
193
|
+
r"""
|
|
194
|
+
TESTS::
|
|
195
|
+
|
|
196
|
+
sage: c = Constellation([[1,2,0],[0,2,1],[1,0,2],None])
|
|
197
|
+
sage: c == loads(dumps(c))
|
|
198
|
+
True
|
|
199
|
+
sage: g0 = '(0,1)(2,4)'
|
|
200
|
+
sage: g1 = '(0,3)(1,4)'
|
|
201
|
+
sage: g2 = '(2,4,3)'
|
|
202
|
+
sage: g3 = '(0,3)(1,2)'
|
|
203
|
+
sage: c0 = Constellation([g0,g1,g2,g3])
|
|
204
|
+
sage: c0 == Constellation([None,g1,g2,g3])
|
|
205
|
+
True
|
|
206
|
+
sage: c0 == Constellation([g0,None,g2,g3])
|
|
207
|
+
True
|
|
208
|
+
sage: c0 == Constellation([g0,g1,None,g3])
|
|
209
|
+
True
|
|
210
|
+
sage: c0 == Constellation([g0,g1,g2,None])
|
|
211
|
+
True
|
|
212
|
+
"""
|
|
213
|
+
Element.__init__(self, parent)
|
|
214
|
+
self._connected = connected
|
|
215
|
+
self._mutable = mutable
|
|
216
|
+
self._g = g
|
|
217
|
+
if check:
|
|
218
|
+
self._check()
|
|
219
|
+
|
|
220
|
+
def __hash__(self):
|
|
221
|
+
r"""
|
|
222
|
+
Return a hash for ``self``.
|
|
223
|
+
|
|
224
|
+
EXAMPLES::
|
|
225
|
+
|
|
226
|
+
sage: c = Constellation(([0,2,1],[2,1,0],[1,2,0]), mutable=False)
|
|
227
|
+
sage: hash(c) == hash(tuple(c._g))
|
|
228
|
+
True
|
|
229
|
+
"""
|
|
230
|
+
if self._mutable:
|
|
231
|
+
raise ValueError("cannot hash mutable constellation")
|
|
232
|
+
return hash(tuple(self._g))
|
|
233
|
+
|
|
234
|
+
def set_immutable(self):
|
|
235
|
+
r"""
|
|
236
|
+
Do nothing, as ``self`` is already immutable.
|
|
237
|
+
|
|
238
|
+
EXAMPLES::
|
|
239
|
+
|
|
240
|
+
sage: c = Constellation(([0,2,1],[2,1,0],[1,2,0]), mutable=False)
|
|
241
|
+
sage: c.set_immutable()
|
|
242
|
+
sage: c.is_mutable()
|
|
243
|
+
False
|
|
244
|
+
"""
|
|
245
|
+
self._mutable = False
|
|
246
|
+
|
|
247
|
+
def is_mutable(self):
|
|
248
|
+
r"""
|
|
249
|
+
Return ``False`` as ``self`` is immutable.
|
|
250
|
+
|
|
251
|
+
EXAMPLES::
|
|
252
|
+
|
|
253
|
+
sage: c = Constellation(([0,2,1],[2,1,0],[1,2,0]), mutable=False)
|
|
254
|
+
sage: c.is_mutable()
|
|
255
|
+
False
|
|
256
|
+
"""
|
|
257
|
+
return self._mutable
|
|
258
|
+
|
|
259
|
+
def switch(self, i, j0, j1):
|
|
260
|
+
r"""
|
|
261
|
+
Perform the multiplication by the transposition `(j0, j1)` between the
|
|
262
|
+
permutations `g_i` and `g_{i+1}`.
|
|
263
|
+
|
|
264
|
+
The modification is local in the sense that it modifies `g_i`
|
|
265
|
+
and `g_{i+1}` but does not modify the product `g_i g_{i+1}`. The new
|
|
266
|
+
constellation is
|
|
267
|
+
|
|
268
|
+
.. MATH::
|
|
269
|
+
|
|
270
|
+
(g_0, \ldots, g_{i-1}, g_{i} (j0 j1), (j0 j1) g_{i+1}, g_{i+2}, \ldots, g_k)
|
|
271
|
+
|
|
272
|
+
EXAMPLES::
|
|
273
|
+
|
|
274
|
+
sage: c = Constellation(['(0,1)(2,3,4)','(1,4)',None], mutable=True); c
|
|
275
|
+
Constellation of length 3 and degree 5
|
|
276
|
+
g0 (0,1)(2,3,4)
|
|
277
|
+
g1 (0)(1,4)(2)(3)
|
|
278
|
+
g2 (0,1,3,2,4)
|
|
279
|
+
sage: c.is_mutable()
|
|
280
|
+
True
|
|
281
|
+
sage: c.switch(1,2,3); c
|
|
282
|
+
Constellation of length 3 and degree 5
|
|
283
|
+
g0 (0,1)(2,3,4)
|
|
284
|
+
g1 (0)(1,4)(2,3)
|
|
285
|
+
g2 (0,1,3,4)(2)
|
|
286
|
+
sage: c._check()
|
|
287
|
+
sage: c.switch(2,1,3); c
|
|
288
|
+
Constellation of length 3 and degree 5
|
|
289
|
+
g0 (0,1,4,2,3)
|
|
290
|
+
g1 (0)(1,4)(2,3)
|
|
291
|
+
g2 (0,3,4)(1)(2)
|
|
292
|
+
sage: c._check()
|
|
293
|
+
sage: c.switch(0,0,1); c
|
|
294
|
+
Constellation of length 3 and degree 5
|
|
295
|
+
g0 (0)(1,4,2,3)
|
|
296
|
+
g1 (0,4,1)(2,3)
|
|
297
|
+
g2 (0,3,4)(1)(2)
|
|
298
|
+
sage: c._check()
|
|
299
|
+
"""
|
|
300
|
+
if not self._mutable:
|
|
301
|
+
raise ValueError("this constellation is immutable."
|
|
302
|
+
" Take a mutable copy first.")
|
|
303
|
+
S = SymmetricGroup(list(range(self.degree())))
|
|
304
|
+
tr = S((j0, j1))
|
|
305
|
+
i = int(i)
|
|
306
|
+
if i < 0 or i >= len(self._g):
|
|
307
|
+
raise ValueError("index out of range")
|
|
308
|
+
|
|
309
|
+
ii = i + 1
|
|
310
|
+
if ii == len(self._g):
|
|
311
|
+
ii = 0
|
|
312
|
+
self._g[i] = self._g[i] * tr
|
|
313
|
+
self._g[ii] = tr * self._g[ii]
|
|
314
|
+
|
|
315
|
+
def euler_characteristic(self):
|
|
316
|
+
r"""
|
|
317
|
+
Return the Euler characteristic of the surface.
|
|
318
|
+
|
|
319
|
+
ALGORITHM:
|
|
320
|
+
|
|
321
|
+
Hurwitz formula
|
|
322
|
+
|
|
323
|
+
EXAMPLES::
|
|
324
|
+
|
|
325
|
+
sage: c = Constellation(['(0,1)', '(0,2)', None])
|
|
326
|
+
sage: c.euler_characteristic()
|
|
327
|
+
2
|
|
328
|
+
|
|
329
|
+
sage: c = Constellation(['(0,1,2,3)','(1,3,0,2)', '(0,3,1,2)', None])
|
|
330
|
+
sage: c.euler_characteristic()
|
|
331
|
+
-4
|
|
332
|
+
|
|
333
|
+
TESTS::
|
|
334
|
+
|
|
335
|
+
sage: parent(c.euler_characteristic())
|
|
336
|
+
Integer Ring
|
|
337
|
+
"""
|
|
338
|
+
return Integer(self.degree() * 2 -
|
|
339
|
+
sum(sum(j - 1 for j in self.profile(i))
|
|
340
|
+
for i in range(self.length())))
|
|
341
|
+
|
|
342
|
+
def genus(self):
|
|
343
|
+
r"""
|
|
344
|
+
Return the genus of the surface.
|
|
345
|
+
|
|
346
|
+
EXAMPLES::
|
|
347
|
+
|
|
348
|
+
sage: c = Constellation(['(0,1)', '(0,2)', None])
|
|
349
|
+
sage: c.genus()
|
|
350
|
+
0
|
|
351
|
+
|
|
352
|
+
sage: c = Constellation(['(0,1)(2,3,4)','(1,3,4)(2,0)', None])
|
|
353
|
+
sage: c.genus()
|
|
354
|
+
1
|
|
355
|
+
|
|
356
|
+
TESTS::
|
|
357
|
+
|
|
358
|
+
sage: parent(c.genus())
|
|
359
|
+
Integer Ring
|
|
360
|
+
"""
|
|
361
|
+
return 1 - self.euler_characteristic() // 2
|
|
362
|
+
|
|
363
|
+
def _check(self):
|
|
364
|
+
r"""
|
|
365
|
+
Check that the constellation is valid and if not raise
|
|
366
|
+
:exc:`ValueError`.
|
|
367
|
+
|
|
368
|
+
TESTS::
|
|
369
|
+
|
|
370
|
+
sage: c = Constellation([[0,1],[1,0]], mutable=True, check=False)
|
|
371
|
+
sage: c._check()
|
|
372
|
+
Traceback (most recent call last):
|
|
373
|
+
...
|
|
374
|
+
ValueError: the product is not identity
|
|
375
|
+
|
|
376
|
+
sage: c = Constellation([[0,1],[0,1]], mutable=True, check=False)
|
|
377
|
+
sage: c._check()
|
|
378
|
+
Traceback (most recent call last):
|
|
379
|
+
...
|
|
380
|
+
ValueError: not connected
|
|
381
|
+
"""
|
|
382
|
+
d = self.degree()
|
|
383
|
+
Sd = self.parent()._sym
|
|
384
|
+
|
|
385
|
+
if prod(self._g, Sd.one()) != Sd.one():
|
|
386
|
+
raise ValueError("the product is not identity")
|
|
387
|
+
|
|
388
|
+
if self._connected and not perms_are_connected(self._g, d):
|
|
389
|
+
raise ValueError("not connected")
|
|
390
|
+
|
|
391
|
+
def __copy__(self):
|
|
392
|
+
r"""
|
|
393
|
+
Return a copy of ``self``.
|
|
394
|
+
|
|
395
|
+
TESTS::
|
|
396
|
+
|
|
397
|
+
sage: c = Constellation([[0,2,1],[1,0,2],[2,1,0],None])
|
|
398
|
+
sage: c == copy(c)
|
|
399
|
+
True
|
|
400
|
+
sage: c is copy(c)
|
|
401
|
+
False
|
|
402
|
+
sage: c = Constellation([[0,2,1],[1,0,2],[2,1,0],None],mutable=True)
|
|
403
|
+
sage: c == copy(c)
|
|
404
|
+
True
|
|
405
|
+
sage: c is copy(c)
|
|
406
|
+
False
|
|
407
|
+
"""
|
|
408
|
+
return self.parent()(list(self._g),
|
|
409
|
+
check=False,
|
|
410
|
+
mutable=self._mutable)
|
|
411
|
+
|
|
412
|
+
copy = __copy__
|
|
413
|
+
|
|
414
|
+
def mutable_copy(self):
|
|
415
|
+
r"""
|
|
416
|
+
Return a mutable copy of ``self``.
|
|
417
|
+
|
|
418
|
+
EXAMPLES::
|
|
419
|
+
|
|
420
|
+
sage: c = Constellation(([0,2,1],[2,1,0],[1,2,0]), mutable=False)
|
|
421
|
+
sage: d = c.mutable_copy()
|
|
422
|
+
sage: d.is_mutable()
|
|
423
|
+
True
|
|
424
|
+
"""
|
|
425
|
+
return self.parent()(list(self._g),
|
|
426
|
+
check=False,
|
|
427
|
+
mutable=True)
|
|
428
|
+
|
|
429
|
+
# GENERAL PROPERTIES
|
|
430
|
+
|
|
431
|
+
def is_connected(self):
|
|
432
|
+
r"""
|
|
433
|
+
Test of connectedness.
|
|
434
|
+
|
|
435
|
+
EXAMPLES::
|
|
436
|
+
|
|
437
|
+
sage: c = Constellation(['(0,1)(2)', None, '(0,1)(2)'], connected=False)
|
|
438
|
+
sage: c.is_connected()
|
|
439
|
+
False
|
|
440
|
+
sage: c = Constellation(['(0,1,2)', None], connected=False)
|
|
441
|
+
sage: c.is_connected()
|
|
442
|
+
True
|
|
443
|
+
"""
|
|
444
|
+
if self._connected:
|
|
445
|
+
return True
|
|
446
|
+
else:
|
|
447
|
+
return perms_are_connected(self._g, self.degree())
|
|
448
|
+
|
|
449
|
+
def connected_components(self):
|
|
450
|
+
"""
|
|
451
|
+
Return the connected components.
|
|
452
|
+
|
|
453
|
+
OUTPUT: list of connected constellations
|
|
454
|
+
|
|
455
|
+
EXAMPLES::
|
|
456
|
+
|
|
457
|
+
sage: c = Constellation(['(0,1)(2)', None, '(0,1)(2)'], connected=False)
|
|
458
|
+
sage: cc = c.connected_components(); cc
|
|
459
|
+
[Constellation of length 3 and degree 2
|
|
460
|
+
g0 (0,1)
|
|
461
|
+
g1 (0)(1)
|
|
462
|
+
g2 (0,1),
|
|
463
|
+
Constellation of length 3 and degree 1
|
|
464
|
+
g0 (0)
|
|
465
|
+
g1 (0)
|
|
466
|
+
g2 (0)]
|
|
467
|
+
sage: all(c2.is_connected() for c2 in cc)
|
|
468
|
+
True
|
|
469
|
+
|
|
470
|
+
sage: c = Constellation(['(0,1,2)', None], connected=False)
|
|
471
|
+
sage: c.connected_components()
|
|
472
|
+
[Constellation of length 2 and degree 3
|
|
473
|
+
g0 (0,1,2)
|
|
474
|
+
g1 (0,2,1)]
|
|
475
|
+
"""
|
|
476
|
+
if self._connected:
|
|
477
|
+
return [self]
|
|
478
|
+
G = Graph()
|
|
479
|
+
G.add_vertices(list(range(self.degree())))
|
|
480
|
+
for p in self._g:
|
|
481
|
+
G.add_edges(enumerate(p.domain()), loops=False)
|
|
482
|
+
m = G.connected_components(sort=False)
|
|
483
|
+
if len(m) == 1:
|
|
484
|
+
return [self]
|
|
485
|
+
for mm in m:
|
|
486
|
+
mm.sort()
|
|
487
|
+
m.sort()
|
|
488
|
+
g = [[] for _ in repeat(None, len(m))]
|
|
489
|
+
m_inv = [None] * self.degree()
|
|
490
|
+
for t, mt in enumerate(m):
|
|
491
|
+
for i, mti in enumerate(mt):
|
|
492
|
+
m_inv[mti] = i
|
|
493
|
+
for k in range(self.length()):
|
|
494
|
+
tmp = [None] * len(mt)
|
|
495
|
+
for i, mti in enumerate(mt):
|
|
496
|
+
tmp[i] = m_inv[self._g[k](mti)]
|
|
497
|
+
g[t].append(tmp)
|
|
498
|
+
return [Constellation(g=g[i], check=False) for i in range(len(m))]
|
|
499
|
+
|
|
500
|
+
def _richcmp_(self, other, op):
|
|
501
|
+
r"""
|
|
502
|
+
Do the comparison.
|
|
503
|
+
|
|
504
|
+
TESTS::
|
|
505
|
+
|
|
506
|
+
sage: Constellation(['(0,1,2)', None]) == Constellation(['(0,1,2)', None])
|
|
507
|
+
True
|
|
508
|
+
sage: Constellation(['(0,1)','(0,2)',None]) == Constellation(['(0,1)',None,'(0,2)'])
|
|
509
|
+
False
|
|
510
|
+
|
|
511
|
+
sage: Constellation(['(0,1,2)', None]) != Constellation(['(0,1,2)', None])
|
|
512
|
+
False
|
|
513
|
+
sage: Constellation(['(0,1)','(0,2)',None]) != Constellation(['(0,1)',None,'(0,2)'])
|
|
514
|
+
True
|
|
515
|
+
|
|
516
|
+
sage: c1 = Constellation([[1,2,0],None])
|
|
517
|
+
sage: c2 = Constellation([[2,0,1],None])
|
|
518
|
+
sage: c1 < c2
|
|
519
|
+
True
|
|
520
|
+
sage: c2 > c1
|
|
521
|
+
True
|
|
522
|
+
"""
|
|
523
|
+
if not isinstance(other, Constellation_class):
|
|
524
|
+
return op == op_NE
|
|
525
|
+
if op == op_EQ:
|
|
526
|
+
return self._g == other._g
|
|
527
|
+
if op == op_NE:
|
|
528
|
+
return self._g != other._g
|
|
529
|
+
|
|
530
|
+
lx = self.length()
|
|
531
|
+
rx = other.length()
|
|
532
|
+
if lx != rx:
|
|
533
|
+
return richcmp_not_equal(lx, rx, op)
|
|
534
|
+
|
|
535
|
+
lx = self.degree()
|
|
536
|
+
rx = other.degree()
|
|
537
|
+
if lx != rx:
|
|
538
|
+
return richcmp_not_equal(lx, rx, op)
|
|
539
|
+
|
|
540
|
+
for i in range(self.length() - 1):
|
|
541
|
+
lx = self._g[i]
|
|
542
|
+
rx = other._g[i]
|
|
543
|
+
if lx != rx:
|
|
544
|
+
return richcmp_not_equal(lx, rx, op)
|
|
545
|
+
return rich_to_bool(op, 0)
|
|
546
|
+
|
|
547
|
+
def is_isomorphic(self, other, return_map=False):
|
|
548
|
+
r"""
|
|
549
|
+
Test of isomorphism.
|
|
550
|
+
|
|
551
|
+
Return ``True`` if the constellations are isomorphic
|
|
552
|
+
(*i.e.* related by a common conjugacy) and return the permutation that
|
|
553
|
+
conjugate the two permutations if ``return_map`` is ``True`` in
|
|
554
|
+
such a way that ``self.relabel(m) == other``.
|
|
555
|
+
|
|
556
|
+
ALGORITHM:
|
|
557
|
+
|
|
558
|
+
uses canonical labels obtained from the method :meth:`relabel`.
|
|
559
|
+
|
|
560
|
+
EXAMPLES::
|
|
561
|
+
|
|
562
|
+
sage: c = Constellation([[1,0,2],[2,1,0],[0,2,1],None])
|
|
563
|
+
sage: d = Constellation([[2,1,0],[0,2,1],[1,0,2],None])
|
|
564
|
+
sage: answer, mapping = c.is_isomorphic(d,return_map=True)
|
|
565
|
+
sage: answer
|
|
566
|
+
True
|
|
567
|
+
sage: c.relabel(mapping) == d
|
|
568
|
+
True
|
|
569
|
+
"""
|
|
570
|
+
if return_map:
|
|
571
|
+
if not (self.degree() == other.degree() and
|
|
572
|
+
self.length() == other.length()):
|
|
573
|
+
return False, None
|
|
574
|
+
sn, sn_map = self.relabel(return_map=True)
|
|
575
|
+
on, on_map = other.relabel(return_map=True)
|
|
576
|
+
if sn != on:
|
|
577
|
+
return False, None
|
|
578
|
+
return True, sn_map * ~on_map
|
|
579
|
+
|
|
580
|
+
return (self.degree() == other.degree() and
|
|
581
|
+
self.length() == other.length() and
|
|
582
|
+
self.relabel() == other.relabel())
|
|
583
|
+
|
|
584
|
+
def _repr_(self):
|
|
585
|
+
r"""
|
|
586
|
+
Return a string representation.
|
|
587
|
+
|
|
588
|
+
EXAMPLES::
|
|
589
|
+
|
|
590
|
+
sage: c = Constellation([[1,0,2],[2,1,0],[0,2,1],None])
|
|
591
|
+
sage: c._repr_()
|
|
592
|
+
'Constellation of length 4 and degree 3\ng0 (0,1)(2)\ng1 (0,2)(1)\ng2 (0)(1,2)\ng3 (0,2)(1)'
|
|
593
|
+
"""
|
|
594
|
+
s = "Constellation of length {} and degree {}".format(self.length(),
|
|
595
|
+
self.degree())
|
|
596
|
+
for i in range(self.length()):
|
|
597
|
+
s += "\ng{} {}".format(i, self._g[i].cycle_string(True))
|
|
598
|
+
return s
|
|
599
|
+
|
|
600
|
+
def degree(self):
|
|
601
|
+
r"""
|
|
602
|
+
Return the degree of the constellation.
|
|
603
|
+
|
|
604
|
+
The degree of a constellation is the number `n` that
|
|
605
|
+
corresponds to the symmetric group `S(n)` in which the
|
|
606
|
+
permutations of the constellation are defined.
|
|
607
|
+
|
|
608
|
+
EXAMPLES::
|
|
609
|
+
|
|
610
|
+
sage: c = Constellation([])
|
|
611
|
+
sage: c.degree()
|
|
612
|
+
0
|
|
613
|
+
sage: c = Constellation(['(0,1)',None])
|
|
614
|
+
sage: c.degree()
|
|
615
|
+
2
|
|
616
|
+
sage: c = Constellation(['(0,1)','(0,3,2)(1,5)',None,'(4,3,2,1)'])
|
|
617
|
+
sage: c.degree()
|
|
618
|
+
6
|
|
619
|
+
|
|
620
|
+
TESTS::
|
|
621
|
+
|
|
622
|
+
sage: parent(c.degree())
|
|
623
|
+
Integer Ring
|
|
624
|
+
"""
|
|
625
|
+
return self.parent()._degree
|
|
626
|
+
|
|
627
|
+
def length(self):
|
|
628
|
+
r"""
|
|
629
|
+
Return the number of permutations.
|
|
630
|
+
|
|
631
|
+
EXAMPLES::
|
|
632
|
+
|
|
633
|
+
sage: c = Constellation(['(0,1)','(0,2)','(0,3)',None])
|
|
634
|
+
sage: c.length()
|
|
635
|
+
4
|
|
636
|
+
sage: c = Constellation(['(0,1,3)',None,'(1,2)'])
|
|
637
|
+
sage: c.length()
|
|
638
|
+
3
|
|
639
|
+
|
|
640
|
+
TESTS::
|
|
641
|
+
|
|
642
|
+
sage: parent(c.length())
|
|
643
|
+
Integer Ring
|
|
644
|
+
"""
|
|
645
|
+
return Integer(len(self._g))
|
|
646
|
+
|
|
647
|
+
def profile(self, i=None):
|
|
648
|
+
r"""
|
|
649
|
+
Return the profile of ``self``.
|
|
650
|
+
|
|
651
|
+
The profile of a constellation is the tuple of partitions
|
|
652
|
+
associated to the conjugacy classes of the permutations of the
|
|
653
|
+
constellation.
|
|
654
|
+
|
|
655
|
+
This is also called the passport.
|
|
656
|
+
|
|
657
|
+
EXAMPLES::
|
|
658
|
+
|
|
659
|
+
sage: c = Constellation(['(0,1,2)(3,4)','(0,3)',None])
|
|
660
|
+
sage: c.profile()
|
|
661
|
+
([3, 2], [2, 1, 1, 1], [5])
|
|
662
|
+
"""
|
|
663
|
+
if i is None:
|
|
664
|
+
return tuple(self.profile(j) for j in range(self.length()))
|
|
665
|
+
else:
|
|
666
|
+
parts = [len(cy) for cy in self._g[i].cycle_tuples(True)]
|
|
667
|
+
return Partition(sorted(parts, reverse=True))
|
|
668
|
+
|
|
669
|
+
passport = profile
|
|
670
|
+
|
|
671
|
+
# ACCESS TO INDIVIDUAL PERMUTATION
|
|
672
|
+
|
|
673
|
+
def g(self, i=None):
|
|
674
|
+
r"""
|
|
675
|
+
Return the permutation `g_i` of the constellation.
|
|
676
|
+
|
|
677
|
+
INPUT:
|
|
678
|
+
|
|
679
|
+
- ``i`` -- integer or ``None`` (default)
|
|
680
|
+
|
|
681
|
+
If ``None`` , return instead the list of all `g_i`.
|
|
682
|
+
|
|
683
|
+
EXAMPLES::
|
|
684
|
+
|
|
685
|
+
sage: c = Constellation(['(0,1,2)(3,4)','(0,3)',None])
|
|
686
|
+
sage: c.g(0)
|
|
687
|
+
(0,1,2)(3,4)
|
|
688
|
+
sage: c.g(1)
|
|
689
|
+
(0,3)
|
|
690
|
+
sage: c.g(2)
|
|
691
|
+
(0,4,3,2,1)
|
|
692
|
+
sage: c.g()
|
|
693
|
+
[(0,1,2)(3,4), (0,3), (0,4,3,2,1)]
|
|
694
|
+
"""
|
|
695
|
+
from copy import copy
|
|
696
|
+
if i is None:
|
|
697
|
+
return copy(self._g)
|
|
698
|
+
else:
|
|
699
|
+
gi = self._g[i]
|
|
700
|
+
return gi.parent()(gi)
|
|
701
|
+
|
|
702
|
+
def relabel(self, perm=None, return_map=False):
|
|
703
|
+
r"""
|
|
704
|
+
Relabel ``self``.
|
|
705
|
+
|
|
706
|
+
If ``perm`` is provided then relabel with respect to ``perm``. Otherwise
|
|
707
|
+
use canonical labels. In that case, if ``return_map`` is provided, the
|
|
708
|
+
return also the map used for canonical labels.
|
|
709
|
+
|
|
710
|
+
Algorithm:
|
|
711
|
+
|
|
712
|
+
the cycle for g(0) are adjacent and the cycle are joined with
|
|
713
|
+
respect to the other permutations. The minimum is taken for
|
|
714
|
+
all possible renumerotations.
|
|
715
|
+
|
|
716
|
+
EXAMPLES::
|
|
717
|
+
|
|
718
|
+
sage: c = Constellation(['(0,1)(2,3,4)','(1,4)',None]); c
|
|
719
|
+
Constellation of length 3 and degree 5
|
|
720
|
+
g0 (0,1)(2,3,4)
|
|
721
|
+
g1 (0)(1,4)(2)(3)
|
|
722
|
+
g2 (0,1,3,2,4)
|
|
723
|
+
sage: c2 = c.relabel(); c2
|
|
724
|
+
Constellation of length 3 and degree 5
|
|
725
|
+
g0 (0,1)(2,3,4)
|
|
726
|
+
g1 (0)(1,2)(3)(4)
|
|
727
|
+
g2 (0,1,4,3,2)
|
|
728
|
+
|
|
729
|
+
The map returned when the option ``return_map`` is set to
|
|
730
|
+
``True`` can be used to set the relabelling::
|
|
731
|
+
|
|
732
|
+
sage: c3, perm = c.relabel(return_map=True)
|
|
733
|
+
sage: c3 == c2 and c3 == c.relabel(perm=perm)
|
|
734
|
+
True
|
|
735
|
+
|
|
736
|
+
sage: S5 = SymmetricGroup(range(5))
|
|
737
|
+
sage: d = c.relabel(S5([4,3,1,0,2])); d
|
|
738
|
+
Constellation of length 3 and degree 5
|
|
739
|
+
g0 (0,2,1)(3,4)
|
|
740
|
+
g1 (0)(1)(2,3)(4)
|
|
741
|
+
g2 (0,1,2,4,3)
|
|
742
|
+
sage: d.is_isomorphic(c)
|
|
743
|
+
True
|
|
744
|
+
|
|
745
|
+
We check that after a random relabelling the new constellation is
|
|
746
|
+
isomorphic to the initial one::
|
|
747
|
+
|
|
748
|
+
sage: c = Constellation(['(0,1)(2,3,4)','(1,4)',None])
|
|
749
|
+
sage: p = S5.random_element()
|
|
750
|
+
sage: cc = c.relabel(perm=p)
|
|
751
|
+
sage: cc.is_isomorphic(c)
|
|
752
|
+
True
|
|
753
|
+
|
|
754
|
+
Check that it works for "non standard" labels::
|
|
755
|
+
|
|
756
|
+
sage: c = Constellation([(('a','b'),('c','d','e')),('b','d'), None])
|
|
757
|
+
sage: c.relabel()
|
|
758
|
+
Constellation of length 3 and degree 5
|
|
759
|
+
g0 ('a','b')('c','d','e')
|
|
760
|
+
g1 ('a')('b','c')('d')('e')
|
|
761
|
+
g2 ('a','b','e','d','c')
|
|
762
|
+
"""
|
|
763
|
+
if perm is not None:
|
|
764
|
+
g = [[None] * self.degree() for _ in range(self.length())]
|
|
765
|
+
for i in range(len(perm.domain())):
|
|
766
|
+
for k in range(self.length()):
|
|
767
|
+
g[k][perm(i)] = perm(self._g[k](i))
|
|
768
|
+
return Constellation(g=g, check=False, mutable=self.is_mutable())
|
|
769
|
+
|
|
770
|
+
if return_map:
|
|
771
|
+
try:
|
|
772
|
+
return self._normal_form, self._normal_form_map
|
|
773
|
+
except AttributeError:
|
|
774
|
+
pass
|
|
775
|
+
else:
|
|
776
|
+
try:
|
|
777
|
+
return self._normal_form
|
|
778
|
+
except AttributeError:
|
|
779
|
+
pass
|
|
780
|
+
|
|
781
|
+
# compute canonical labels
|
|
782
|
+
if not self.is_connected():
|
|
783
|
+
raise ValueError("no canonical labels implemented for"
|
|
784
|
+
" non connected constellation")
|
|
785
|
+
|
|
786
|
+
# get the permutations on {0, 1, ..., d-1}
|
|
787
|
+
# compute the canonical labels
|
|
788
|
+
# map it back to the domain
|
|
789
|
+
# TODO: a lot of time is lost here!
|
|
790
|
+
domain = list(self.parent()._sym.domain())
|
|
791
|
+
index = {e: i for i, e in enumerate(domain)}
|
|
792
|
+
g = [[index[gg(i)] for i in domain] for gg in self._g]
|
|
793
|
+
c_win, m_win = perms_canonical_labels(g)
|
|
794
|
+
c_win = [[domain[i] for i in gg] for gg in c_win]
|
|
795
|
+
m_win = self.parent()._sym([domain[i] for i in m_win])
|
|
796
|
+
c_win = self.parent()(c_win, mutable=False, check=False)
|
|
797
|
+
|
|
798
|
+
if not self.is_mutable():
|
|
799
|
+
self._normal_form = c_win
|
|
800
|
+
self._normal_form_map = m_win
|
|
801
|
+
|
|
802
|
+
c_win._normal_form = c_win
|
|
803
|
+
c_win._normal_form_map = m_win
|
|
804
|
+
|
|
805
|
+
if return_map:
|
|
806
|
+
return c_win, m_win
|
|
807
|
+
else:
|
|
808
|
+
return c_win
|
|
809
|
+
|
|
810
|
+
# BRAID GROUP ACTION
|
|
811
|
+
|
|
812
|
+
def braid_group_action(self, i):
|
|
813
|
+
r"""
|
|
814
|
+
Act on ``self`` as the braid group generator that exchanges
|
|
815
|
+
position `i` and `i+1`.
|
|
816
|
+
|
|
817
|
+
INPUT:
|
|
818
|
+
|
|
819
|
+
- ``i`` -- integer in `[0, n-1]` where `n` is the length of ``self``
|
|
820
|
+
|
|
821
|
+
EXAMPLES::
|
|
822
|
+
|
|
823
|
+
sage: sigma = lambda c, i: c.braid_group_action(i)
|
|
824
|
+
|
|
825
|
+
sage: c = Constellation(['(0,1)(2,3,4)','(1,4)',None]); c
|
|
826
|
+
Constellation of length 3 and degree 5
|
|
827
|
+
g0 (0,1)(2,3,4)
|
|
828
|
+
g1 (0)(1,4)(2)(3)
|
|
829
|
+
g2 (0,1,3,2,4)
|
|
830
|
+
sage: sigma(c, 1)
|
|
831
|
+
Constellation of length 3 and degree 5
|
|
832
|
+
g0 (0,1)(2,3,4)
|
|
833
|
+
g1 (0,1,3,2,4)
|
|
834
|
+
g2 (0,3)(1)(2)(4)
|
|
835
|
+
|
|
836
|
+
Check the commutation relation::
|
|
837
|
+
|
|
838
|
+
sage: c = Constellation(['(0,1)(2,3,4)','(1,4)','(2,5)(0,4)',None])
|
|
839
|
+
sage: d = Constellation(['(0,1,3,5)','(2,3,4)','(0,3,5)',None])
|
|
840
|
+
sage: c13 = sigma(sigma(c, 0), 2)
|
|
841
|
+
sage: c31 = sigma(sigma(c, 2), 0)
|
|
842
|
+
sage: c13 == c31
|
|
843
|
+
True
|
|
844
|
+
sage: d13 = sigma(sigma(d, 0), 2)
|
|
845
|
+
sage: d31 = sigma(sigma(d, 2), 0)
|
|
846
|
+
sage: d13 == d31
|
|
847
|
+
True
|
|
848
|
+
|
|
849
|
+
Check the braid relation::
|
|
850
|
+
|
|
851
|
+
sage: c121 = sigma(sigma(sigma(c, 1), 2), 1)
|
|
852
|
+
sage: c212 = sigma(sigma(sigma(c, 2), 1), 2)
|
|
853
|
+
sage: c121 == c212
|
|
854
|
+
True
|
|
855
|
+
sage: d121 = sigma(sigma(sigma(d, 1), 2), 1)
|
|
856
|
+
sage: d212 = sigma(sigma(sigma(d, 2), 1), 2)
|
|
857
|
+
sage: d121 == d212
|
|
858
|
+
True
|
|
859
|
+
"""
|
|
860
|
+
if i < 0 or i >= self.length():
|
|
861
|
+
txt = "i should be between 0 and {}"
|
|
862
|
+
raise ValueError(txt.format(self.length() - 1))
|
|
863
|
+
j = i + 1
|
|
864
|
+
if j == self.length(): # wrap around the cylinder
|
|
865
|
+
j = 0
|
|
866
|
+
h = self.copy()
|
|
867
|
+
si = self._g[i]
|
|
868
|
+
sj = self._g[j]
|
|
869
|
+
h._g[i] = sj
|
|
870
|
+
h._g[j] = (~sj * si) * sj
|
|
871
|
+
return h
|
|
872
|
+
|
|
873
|
+
def braid_group_orbit(self):
|
|
874
|
+
r"""
|
|
875
|
+
Return the graph of the action of the braid group.
|
|
876
|
+
|
|
877
|
+
The action is considered up to isomorphism of constellation.
|
|
878
|
+
|
|
879
|
+
EXAMPLES::
|
|
880
|
+
|
|
881
|
+
sage: c = Constellation(['(0,1)(2,3,4)','(1,4)',None]); c
|
|
882
|
+
Constellation of length 3 and degree 5
|
|
883
|
+
g0 (0,1)(2,3,4)
|
|
884
|
+
g1 (0)(1,4)(2)(3)
|
|
885
|
+
g2 (0,1,3,2,4)
|
|
886
|
+
sage: G = c.braid_group_orbit()
|
|
887
|
+
sage: G.num_verts()
|
|
888
|
+
4
|
|
889
|
+
sage: G.num_edges()
|
|
890
|
+
12
|
|
891
|
+
"""
|
|
892
|
+
G = DiGraph(multiedges=True, loops=True)
|
|
893
|
+
waiting = [self.relabel()]
|
|
894
|
+
|
|
895
|
+
while waiting:
|
|
896
|
+
c = waiting.pop()
|
|
897
|
+
G.add_vertex(c)
|
|
898
|
+
for i in range(self.length()):
|
|
899
|
+
cc = self.braid_group_action(i).relabel()
|
|
900
|
+
if cc not in G:
|
|
901
|
+
waiting.append(cc)
|
|
902
|
+
G.add_edge(c, cc, i)
|
|
903
|
+
return G
|
|
904
|
+
|
|
905
|
+
|
|
906
|
+
class Constellations_ld(UniqueRepresentation, Parent):
|
|
907
|
+
r"""
|
|
908
|
+
Constellations of given length and degree.
|
|
909
|
+
|
|
910
|
+
EXAMPLES::
|
|
911
|
+
|
|
912
|
+
sage: C = Constellations(2,3); C
|
|
913
|
+
Connected constellations of length 2 and degree 3 on {1, 2, 3}
|
|
914
|
+
sage: C([[2,3,1],[3,1,2]])
|
|
915
|
+
Constellation of length 2 and degree 3
|
|
916
|
+
g0 (1,2,3)
|
|
917
|
+
g1 (1,3,2)
|
|
918
|
+
sage: C.cardinality()
|
|
919
|
+
2
|
|
920
|
+
sage: Constellations(2,3,connected=False).cardinality()
|
|
921
|
+
6
|
|
922
|
+
"""
|
|
923
|
+
Element = Constellation_class
|
|
924
|
+
|
|
925
|
+
def __init__(self, length, degree, sym=None, connected=True):
|
|
926
|
+
"""
|
|
927
|
+
TESTS::
|
|
928
|
+
|
|
929
|
+
sage: TestSuite(Constellations(length=6,degree=4)).run(skip='_test_cardinality')
|
|
930
|
+
"""
|
|
931
|
+
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
|
|
932
|
+
Parent.__init__(self, category=FiniteEnumeratedSets())
|
|
933
|
+
self._length = length
|
|
934
|
+
self._degree = degree
|
|
935
|
+
if self._length < 0:
|
|
936
|
+
raise ValueError("length should be a nonnegative integer")
|
|
937
|
+
if self._degree < 0:
|
|
938
|
+
raise ValueError("degree should be a nonnegative integer")
|
|
939
|
+
|
|
940
|
+
self._sym = sym
|
|
941
|
+
|
|
942
|
+
self._connected = bool(connected)
|
|
943
|
+
|
|
944
|
+
def is_empty(self):
|
|
945
|
+
r"""
|
|
946
|
+
Return whether this set of constellations is empty.
|
|
947
|
+
|
|
948
|
+
EXAMPLES::
|
|
949
|
+
|
|
950
|
+
sage: Constellations(2, 3).is_empty()
|
|
951
|
+
False
|
|
952
|
+
sage: Constellations(1, 2).is_empty()
|
|
953
|
+
True
|
|
954
|
+
sage: Constellations(1, 2, connected=False).is_empty()
|
|
955
|
+
False
|
|
956
|
+
"""
|
|
957
|
+
return self._connected and self._length == 1 and self._degree > 1
|
|
958
|
+
|
|
959
|
+
def __contains__(self, elt):
|
|
960
|
+
r"""
|
|
961
|
+
TESTS::
|
|
962
|
+
|
|
963
|
+
sage: C = Constellations(2, 3, connected=True)
|
|
964
|
+
sage: D = Constellations(2, 3, connected=False)
|
|
965
|
+
sage: e1 = [[3,1,2], None]
|
|
966
|
+
sage: e2 = [[1,2,3], None]
|
|
967
|
+
sage: C(e1) in C
|
|
968
|
+
True
|
|
969
|
+
sage: D(e1) in C
|
|
970
|
+
True
|
|
971
|
+
sage: D(e1) in D
|
|
972
|
+
True
|
|
973
|
+
sage: D(e2) in C
|
|
974
|
+
False
|
|
975
|
+
sage: D(e2) in D
|
|
976
|
+
True
|
|
977
|
+
|
|
978
|
+
sage: e1 in C and e1 in D
|
|
979
|
+
True
|
|
980
|
+
sage: e2 in C
|
|
981
|
+
False
|
|
982
|
+
sage: e2 in D
|
|
983
|
+
True
|
|
984
|
+
"""
|
|
985
|
+
if isinstance(elt, (tuple, list)):
|
|
986
|
+
try:
|
|
987
|
+
self(elt, check=True)
|
|
988
|
+
except (ValueError, TypeError):
|
|
989
|
+
return False
|
|
990
|
+
else:
|
|
991
|
+
return True
|
|
992
|
+
elif not isinstance(elt, Constellation_class):
|
|
993
|
+
return False
|
|
994
|
+
return (elt.parent() is self or
|
|
995
|
+
(elt.length() == self._length and
|
|
996
|
+
elt.degree() == self._degree and
|
|
997
|
+
(not self._connected or elt.is_connected())))
|
|
998
|
+
|
|
999
|
+
def _repr_(self):
|
|
1000
|
+
"""
|
|
1001
|
+
TESTS::
|
|
1002
|
+
|
|
1003
|
+
sage: Constellations(3,3)._repr_()
|
|
1004
|
+
'Connected constellations of length 3 and degree 3 on {1, 2, 3}'
|
|
1005
|
+
sage: Constellations(3,3,connected=False)._repr_()
|
|
1006
|
+
'Constellations of length 3 and degree 3 on {1, 2, 3}'
|
|
1007
|
+
"""
|
|
1008
|
+
s = "of length {} and degree {} on {}".format(self._length,
|
|
1009
|
+
self._degree,
|
|
1010
|
+
self._sym.domain())
|
|
1011
|
+
if self._connected:
|
|
1012
|
+
return "Connected constellations " + s
|
|
1013
|
+
else:
|
|
1014
|
+
return "Constellations " + s
|
|
1015
|
+
|
|
1016
|
+
def __iter__(self):
|
|
1017
|
+
"""
|
|
1018
|
+
Iterator over all constellations of given degree and length.
|
|
1019
|
+
|
|
1020
|
+
EXAMPLES::
|
|
1021
|
+
|
|
1022
|
+
sage: const = Constellations(3,3); const
|
|
1023
|
+
Connected constellations of length 3 and degree 3 on {1, 2, 3}
|
|
1024
|
+
sage: len([v for v in const])
|
|
1025
|
+
26
|
|
1026
|
+
|
|
1027
|
+
One can check the first few terms of sequence :oeis:`220754`::
|
|
1028
|
+
|
|
1029
|
+
sage: Constellations(4,1).cardinality()
|
|
1030
|
+
1
|
|
1031
|
+
sage: Constellations(4,2).cardinality()
|
|
1032
|
+
7
|
|
1033
|
+
sage: Constellations(4,3).cardinality()
|
|
1034
|
+
194
|
|
1035
|
+
sage: Constellations(4,4).cardinality() # long time
|
|
1036
|
+
12858
|
|
1037
|
+
"""
|
|
1038
|
+
from itertools import product
|
|
1039
|
+
|
|
1040
|
+
if self._length == 1:
|
|
1041
|
+
if self._degree == 1:
|
|
1042
|
+
yield self([[0]])
|
|
1043
|
+
return
|
|
1044
|
+
|
|
1045
|
+
S = self._sym
|
|
1046
|
+
for p in product(S, repeat=self._length - 1):
|
|
1047
|
+
if self._connected and not perms_are_connected(p, self._degree):
|
|
1048
|
+
continue
|
|
1049
|
+
yield self(list(p) + [None], check=False)
|
|
1050
|
+
|
|
1051
|
+
def random_element(self, mutable=False):
|
|
1052
|
+
r"""
|
|
1053
|
+
Return a random element.
|
|
1054
|
+
|
|
1055
|
+
This is found by trial and rejection, starting from
|
|
1056
|
+
a random list of permutations.
|
|
1057
|
+
|
|
1058
|
+
EXAMPLES::
|
|
1059
|
+
|
|
1060
|
+
sage: const = Constellations(3,3)
|
|
1061
|
+
sage: const.random_element()
|
|
1062
|
+
Constellation of length 3 and degree 3
|
|
1063
|
+
...
|
|
1064
|
+
...
|
|
1065
|
+
...
|
|
1066
|
+
sage: c = const.random_element()
|
|
1067
|
+
sage: c.degree() == 3 and c.length() == 3
|
|
1068
|
+
True
|
|
1069
|
+
"""
|
|
1070
|
+
from sage.groups.perm_gps.permgroup import PermutationGroup
|
|
1071
|
+
|
|
1072
|
+
l = self._length
|
|
1073
|
+
d = self._degree
|
|
1074
|
+
Sd = self._sym
|
|
1075
|
+
|
|
1076
|
+
g = [Sd.random_element() for _ in range(l - 1)]
|
|
1077
|
+
G = PermutationGroup(g)
|
|
1078
|
+
while not G.degree() == d or (self._connected and
|
|
1079
|
+
not G.is_transitive()):
|
|
1080
|
+
g = [Sd.random_element() for _ in range(l - 1)]
|
|
1081
|
+
G = PermutationGroup(g)
|
|
1082
|
+
|
|
1083
|
+
return self([sigma.domain() for sigma in g] + [None], mutable=mutable)
|
|
1084
|
+
|
|
1085
|
+
def _element_constructor_(self, *data, **options):
|
|
1086
|
+
r"""
|
|
1087
|
+
Build an element of ``self``.
|
|
1088
|
+
|
|
1089
|
+
EXAMPLES::
|
|
1090
|
+
|
|
1091
|
+
sage: C = Constellations(2,3)
|
|
1092
|
+
sage: C([[2,3,1],[3,1,2]])
|
|
1093
|
+
Constellation of length 2 and degree 3
|
|
1094
|
+
g0 (1,2,3)
|
|
1095
|
+
g1 (1,3,2)
|
|
1096
|
+
sage: C([[3,2,1],[3,2,1]])
|
|
1097
|
+
Traceback (most recent call last):
|
|
1098
|
+
...
|
|
1099
|
+
ValueError: not connected
|
|
1100
|
+
"""
|
|
1101
|
+
if len(data) == 1 and isinstance(data[0], (list, tuple)) and \
|
|
1102
|
+
len(data[0]) == self._length:
|
|
1103
|
+
g = list(data[0])
|
|
1104
|
+
else:
|
|
1105
|
+
g = list(data)
|
|
1106
|
+
|
|
1107
|
+
if len(g) != self._length:
|
|
1108
|
+
raise ValueError("must be a list of length {}".format(self._length))
|
|
1109
|
+
|
|
1110
|
+
if g.count(None) == 0:
|
|
1111
|
+
i = None
|
|
1112
|
+
elif g.count(None) == 1:
|
|
1113
|
+
i = g.index(None)
|
|
1114
|
+
del g[i]
|
|
1115
|
+
else:
|
|
1116
|
+
raise ValueError("at most one permutation can be None")
|
|
1117
|
+
|
|
1118
|
+
g = [self._sym(w) for w in g]
|
|
1119
|
+
|
|
1120
|
+
if i is not None:
|
|
1121
|
+
h = self._sym.one()
|
|
1122
|
+
for p in g[i:]:
|
|
1123
|
+
h *= p
|
|
1124
|
+
for p in g[:i]:
|
|
1125
|
+
h *= p
|
|
1126
|
+
g.insert(i, ~h)
|
|
1127
|
+
|
|
1128
|
+
mutable = options.pop('mutable', False)
|
|
1129
|
+
if options.pop('check', True):
|
|
1130
|
+
c = self.element_class(self, g, self._connected, mutable, True)
|
|
1131
|
+
if c.degree() != self._degree:
|
|
1132
|
+
raise ValueError("degree is not {}".format(self._degree))
|
|
1133
|
+
if c.length() != self._length:
|
|
1134
|
+
raise ValueError("length is not {}".format(self._length))
|
|
1135
|
+
return c
|
|
1136
|
+
else:
|
|
1137
|
+
return self.element_class(self, g, self._connected, mutable, False)
|
|
1138
|
+
|
|
1139
|
+
def _an_element_(self):
|
|
1140
|
+
r"""
|
|
1141
|
+
Return a constellation in ``self``.
|
|
1142
|
+
|
|
1143
|
+
EXAMPLES::
|
|
1144
|
+
|
|
1145
|
+
sage: Constellations(2, 3).an_element()
|
|
1146
|
+
Constellation of length 2 and degree 3
|
|
1147
|
+
g0 (1,3,2)
|
|
1148
|
+
g1 (1,2,3)
|
|
1149
|
+
|
|
1150
|
+
sage: Constellations(3, 5,domain='abcde').an_element()
|
|
1151
|
+
Constellation of length 3 and degree 5
|
|
1152
|
+
g0 ('a','e','d','c','b')
|
|
1153
|
+
g1 ('a','b','c','d','e')
|
|
1154
|
+
g2 ('a')('b')('c')('d')('e')
|
|
1155
|
+
|
|
1156
|
+
sage: Constellations(0, 0).an_element()
|
|
1157
|
+
Constellation of length 0 and degree 0
|
|
1158
|
+
|
|
1159
|
+
sage: Constellations(1, 1).an_element()
|
|
1160
|
+
Constellation of length 1 and degree 1
|
|
1161
|
+
g0 (1)
|
|
1162
|
+
|
|
1163
|
+
sage: Constellations(1, 2).an_element()
|
|
1164
|
+
Traceback (most recent call last):
|
|
1165
|
+
...
|
|
1166
|
+
EmptySetError
|
|
1167
|
+
"""
|
|
1168
|
+
if self.is_empty():
|
|
1169
|
+
from sage.categories.sets_cat import EmptySetError
|
|
1170
|
+
raise EmptySetError
|
|
1171
|
+
|
|
1172
|
+
if self._degree == 0 and self._length == 0:
|
|
1173
|
+
return self([])
|
|
1174
|
+
elif self._length == 1:
|
|
1175
|
+
return self(self._sym.one())
|
|
1176
|
+
|
|
1177
|
+
d = self._degree
|
|
1178
|
+
domain = self._sym.domain().list()
|
|
1179
|
+
if self._connected:
|
|
1180
|
+
g = [[domain[d - 1]] + domain[:d - 1], domain[1:] + [domain[0]]]
|
|
1181
|
+
g += [domain[:]] * (self._length - 2)
|
|
1182
|
+
else:
|
|
1183
|
+
g = [domain[:]] * self._length
|
|
1184
|
+
return self(g)
|
|
1185
|
+
|
|
1186
|
+
def braid_group_action(self):
|
|
1187
|
+
r"""
|
|
1188
|
+
Return a list of graphs that corresponds to the braid group action on
|
|
1189
|
+
``self`` up to isomorphism.
|
|
1190
|
+
|
|
1191
|
+
OUTPUT: list of graphs
|
|
1192
|
+
|
|
1193
|
+
EXAMPLES::
|
|
1194
|
+
|
|
1195
|
+
sage: C = Constellations(3,3)
|
|
1196
|
+
sage: C.braid_group_action()
|
|
1197
|
+
[Looped multi-digraph on 3 vertices,
|
|
1198
|
+
Looped multi-digraph on 1 vertex,
|
|
1199
|
+
Looped multi-digraph on 3 vertices]
|
|
1200
|
+
"""
|
|
1201
|
+
G = []
|
|
1202
|
+
for c in self:
|
|
1203
|
+
c = c.relabel()
|
|
1204
|
+
if any(c in g for g in G):
|
|
1205
|
+
continue
|
|
1206
|
+
G.append(c.braid_group_orbit())
|
|
1207
|
+
return G
|
|
1208
|
+
|
|
1209
|
+
def braid_group_orbits(self):
|
|
1210
|
+
r"""
|
|
1211
|
+
Return the orbits under the action of braid group.
|
|
1212
|
+
|
|
1213
|
+
EXAMPLES::
|
|
1214
|
+
|
|
1215
|
+
sage: C = Constellations(3,3)
|
|
1216
|
+
sage: O = C.braid_group_orbits()
|
|
1217
|
+
sage: len(O)
|
|
1218
|
+
3
|
|
1219
|
+
sage: [x.profile() for x in O[0]]
|
|
1220
|
+
[([1, 1, 1], [3], [3]), ([3], [1, 1, 1], [3]), ([3], [3], [1, 1, 1])]
|
|
1221
|
+
sage: [x.profile() for x in O[1]]
|
|
1222
|
+
[([3], [3], [3])]
|
|
1223
|
+
sage: [x.profile() for x in O[2]]
|
|
1224
|
+
[([2, 1], [2, 1], [3]), ([2, 1], [3], [2, 1]), ([3], [2, 1], [2, 1])]
|
|
1225
|
+
"""
|
|
1226
|
+
return [g.vertices(sort=True) for g in self.braid_group_action()]
|
|
1227
|
+
|
|
1228
|
+
|
|
1229
|
+
class Constellations_p(UniqueRepresentation, Parent):
|
|
1230
|
+
r"""
|
|
1231
|
+
Constellations with fixed profile.
|
|
1232
|
+
|
|
1233
|
+
EXAMPLES::
|
|
1234
|
+
|
|
1235
|
+
sage: C = Constellations([[3,1],[3,1],[2,2]]); C
|
|
1236
|
+
Connected constellations with profile ([3, 1], [3, 1], [2, 2]) on {1, 2, 3, 4}
|
|
1237
|
+
sage: C.cardinality()
|
|
1238
|
+
24
|
|
1239
|
+
sage: C.first()
|
|
1240
|
+
Constellation of length 3 and degree 4
|
|
1241
|
+
g0 (1)(2,3,4)
|
|
1242
|
+
g1 (1,2,3)(4)
|
|
1243
|
+
g2 (1,2)(3,4)
|
|
1244
|
+
sage: C.last()
|
|
1245
|
+
Constellation of length 3 and degree 4
|
|
1246
|
+
g0 (1,4,3)(2)
|
|
1247
|
+
g1 (1,4,2)(3)
|
|
1248
|
+
g2 (1,2)(3,4)
|
|
1249
|
+
|
|
1250
|
+
Note that the cardinality can also be computed using characters of the
|
|
1251
|
+
symmetric group (Frobenius formula)::
|
|
1252
|
+
|
|
1253
|
+
sage: P = Partitions(4)
|
|
1254
|
+
sage: p1 = Partition([3,1])
|
|
1255
|
+
sage: p2 = Partition([3,1])
|
|
1256
|
+
sage: p3 = Partition([2,2])
|
|
1257
|
+
sage: i1 = P.cardinality() - P.rank(p1) - 1
|
|
1258
|
+
sage: i2 = P.cardinality() - P.rank(p2) - 1
|
|
1259
|
+
sage: i3 = P.cardinality() - P.rank(p3) - 1
|
|
1260
|
+
sage: s = 0
|
|
1261
|
+
sage: for c in SymmetricGroup(4).irreducible_characters():
|
|
1262
|
+
....: v = c.values()
|
|
1263
|
+
....: s += v[i1] * v[i2] * v[i3] / v[0]
|
|
1264
|
+
sage: c1 = p1.conjugacy_class_size()
|
|
1265
|
+
sage: c2 = p2.conjugacy_class_size()
|
|
1266
|
+
sage: c3 = p3.conjugacy_class_size()
|
|
1267
|
+
sage: c1 * c2 * c3 / factorial(4)**2 * s
|
|
1268
|
+
1
|
|
1269
|
+
|
|
1270
|
+
The number obtained above is up to isomorphism. And we can check::
|
|
1271
|
+
|
|
1272
|
+
sage: len(C.isomorphism_representatives())
|
|
1273
|
+
1
|
|
1274
|
+
"""
|
|
1275
|
+
|
|
1276
|
+
def __init__(self, profile, domain=None, connected=True):
|
|
1277
|
+
r"""
|
|
1278
|
+
OPTIONS:
|
|
1279
|
+
|
|
1280
|
+
- ``profile`` -- list of integer partitions of the same integer
|
|
1281
|
+
|
|
1282
|
+
- ``connected`` -- boolean (default: ``True``); whether we consider
|
|
1283
|
+
only connected constellations
|
|
1284
|
+
|
|
1285
|
+
TESTS::
|
|
1286
|
+
|
|
1287
|
+
sage: C = Constellations([(3,1),(3,1),(2,2)])
|
|
1288
|
+
sage: TestSuite(C).run()
|
|
1289
|
+
"""
|
|
1290
|
+
l = Integer(len(profile))
|
|
1291
|
+
d = Integer(sum(profile[0]))
|
|
1292
|
+
for p in profile:
|
|
1293
|
+
if sum(p) != d:
|
|
1294
|
+
raise ValueError("all partition in the passport should "
|
|
1295
|
+
"have the same sum.")
|
|
1296
|
+
if domain is None:
|
|
1297
|
+
sym = SymmetricGroup(d)
|
|
1298
|
+
else:
|
|
1299
|
+
sym = SymmetricGroup(domain)
|
|
1300
|
+
if len(sym.domain()) != d:
|
|
1301
|
+
raise ValueError("the size of the domain should be equal to the degree")
|
|
1302
|
+
|
|
1303
|
+
self._cd = Constellations_ld(l, d, sym, connected)
|
|
1304
|
+
self._profile = profile
|
|
1305
|
+
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
|
|
1306
|
+
Parent.__init__(self, category=FiniteEnumeratedSets())
|
|
1307
|
+
|
|
1308
|
+
def _repr_(self):
|
|
1309
|
+
r"""
|
|
1310
|
+
TESTS::
|
|
1311
|
+
|
|
1312
|
+
sage: Constellations(profile=[[3,2,1],[3,3],[3,3]])
|
|
1313
|
+
Connected constellations with profile ([3, 2, 1], [3, 3], [3, 3]) on {1, 2, 3, 4, 5, 6}
|
|
1314
|
+
"""
|
|
1315
|
+
s = "with profile {} on {}".format(self._profile,
|
|
1316
|
+
self._cd._sym.domain())
|
|
1317
|
+
if self._cd._connected:
|
|
1318
|
+
return "Connected constellations " + s
|
|
1319
|
+
return "Constellations " + s
|
|
1320
|
+
|
|
1321
|
+
def isomorphism_representatives(self):
|
|
1322
|
+
r"""
|
|
1323
|
+
Return a set of isomorphism representative of ``self``.
|
|
1324
|
+
|
|
1325
|
+
EXAMPLES::
|
|
1326
|
+
|
|
1327
|
+
sage: C = Constellations([[5], [4,1], [3,2]])
|
|
1328
|
+
sage: C.cardinality()
|
|
1329
|
+
240
|
|
1330
|
+
sage: ir = sorted(C.isomorphism_representatives())
|
|
1331
|
+
sage: len(ir)
|
|
1332
|
+
2
|
|
1333
|
+
sage: ir[0]
|
|
1334
|
+
Constellation of length 3 and degree 5
|
|
1335
|
+
g0 (1,2,3,4,5)
|
|
1336
|
+
g1 (1)(2,3,4,5)
|
|
1337
|
+
g2 (1,5,3)(2,4)
|
|
1338
|
+
sage: ir[1]
|
|
1339
|
+
Constellation of length 3 and degree 5
|
|
1340
|
+
g0 (1,2,3,4,5)
|
|
1341
|
+
g1 (1)(2,5,3,4)
|
|
1342
|
+
g2 (1,5)(2,3,4)
|
|
1343
|
+
"""
|
|
1344
|
+
result = set()
|
|
1345
|
+
for c in self:
|
|
1346
|
+
cc = c.relabel()
|
|
1347
|
+
if cc not in result:
|
|
1348
|
+
result.add(cc)
|
|
1349
|
+
return result
|
|
1350
|
+
|
|
1351
|
+
def _element_constructor_(self, *data, **options):
|
|
1352
|
+
r"""
|
|
1353
|
+
Build an element of ``self``.
|
|
1354
|
+
|
|
1355
|
+
TESTS::
|
|
1356
|
+
|
|
1357
|
+
sage: C = Constellations([(3,1),(3,1),(2,2)])
|
|
1358
|
+
sage: c = C([(2,3,4),(1,2,3),((1,2),(3,4))]); c
|
|
1359
|
+
Constellation of length 3 and degree 4
|
|
1360
|
+
g0 (1)(2,3,4)
|
|
1361
|
+
g1 (1,2,3)(4)
|
|
1362
|
+
g2 (1,2)(3,4)
|
|
1363
|
+
sage: C([(1,2,3),(3,2,4),None])
|
|
1364
|
+
Traceback (most recent call last):
|
|
1365
|
+
...
|
|
1366
|
+
ValueError: wrong profile
|
|
1367
|
+
"""
|
|
1368
|
+
c = self._cd(*data, **options)
|
|
1369
|
+
if options.get('check', True) and c.profile() != self._profile:
|
|
1370
|
+
raise ValueError("wrong profile")
|
|
1371
|
+
return c
|
|
1372
|
+
|
|
1373
|
+
def __iter__(self):
|
|
1374
|
+
r"""
|
|
1375
|
+
Iterator of the elements in ``self``.
|
|
1376
|
+
|
|
1377
|
+
TESTS::
|
|
1378
|
+
|
|
1379
|
+
sage: C = Constellations([(3,1),(3,1),(2,2)])
|
|
1380
|
+
sage: for c in C: print(c)
|
|
1381
|
+
Constellation of length 3 and degree 4
|
|
1382
|
+
g0 (1)(2,3,4)
|
|
1383
|
+
g1 (1,2,3)(4)
|
|
1384
|
+
g2 (1,2)(3,4)
|
|
1385
|
+
Constellation of length 3 and degree 4
|
|
1386
|
+
g0 (1)(2,3,4)
|
|
1387
|
+
g1 (1,4,2)(3)
|
|
1388
|
+
g2 (1,4)(2,3)
|
|
1389
|
+
...
|
|
1390
|
+
Constellation of length 3 and degree 4
|
|
1391
|
+
g0 (1,4,3)(2)
|
|
1392
|
+
g1 (1,2,3)(4)
|
|
1393
|
+
g2 (1,4)(2,3)
|
|
1394
|
+
Constellation of length 3 and degree 4
|
|
1395
|
+
g0 (1,4,3)(2)
|
|
1396
|
+
g1 (1,4,2)(3)
|
|
1397
|
+
g2 (1,2)(3,4)
|
|
1398
|
+
|
|
1399
|
+
sage: C = Constellations([(3,1),(3,1),(2,2)], domain='abcd')
|
|
1400
|
+
sage: for c in sorted(C): print(c)
|
|
1401
|
+
Constellation of length 3 and degree 4
|
|
1402
|
+
g0 ('a')('b','c','d')
|
|
1403
|
+
g1 ('a','b','c')('d')
|
|
1404
|
+
g2 ('a','b')('c','d')
|
|
1405
|
+
...
|
|
1406
|
+
Constellation of length 3 and degree 4
|
|
1407
|
+
g0 ('a','d','c')('b')
|
|
1408
|
+
g1 ('a','d','b')('c')
|
|
1409
|
+
g2 ('a','b')('c','d')
|
|
1410
|
+
"""
|
|
1411
|
+
if self._cd._length == 1:
|
|
1412
|
+
if self._cd._degree == 1:
|
|
1413
|
+
yield self([[0]])
|
|
1414
|
+
return
|
|
1415
|
+
|
|
1416
|
+
S = self._cd._sym
|
|
1417
|
+
profile = list(self._profile)[:-1]
|
|
1418
|
+
for p in product(*[S.conjugacy_class(pi) for pi in profile]):
|
|
1419
|
+
if self._cd._connected and not perms_are_connected(p, self._cd._degree):
|
|
1420
|
+
continue
|
|
1421
|
+
c = self._cd(list(p) + [None], check=False)
|
|
1422
|
+
if c.profile() == self._profile:
|
|
1423
|
+
yield c
|
|
1424
|
+
|
|
1425
|
+
# *************************************************************************
|
|
1426
|
+
# auxiliary functions
|
|
1427
|
+
# *************************************************************************
|
|
1428
|
+
|
|
1429
|
+
|
|
1430
|
+
def perm_sym_domain(g):
|
|
1431
|
+
r"""
|
|
1432
|
+
Return the domain of a single permutation (before initialization).
|
|
1433
|
+
|
|
1434
|
+
EXAMPLES::
|
|
1435
|
+
|
|
1436
|
+
sage: from sage.combinat.constellation import perm_sym_domain
|
|
1437
|
+
sage: perm_sym_domain([1,2,3,4])
|
|
1438
|
+
{1, 2, 3, 4}
|
|
1439
|
+
sage: perm_sym_domain(((1,2),(0,4)))
|
|
1440
|
+
{0, 1, 2, 4}
|
|
1441
|
+
sage: sorted(perm_sym_domain('(1,2,0,5)'))
|
|
1442
|
+
[0, 1, 2, 5]
|
|
1443
|
+
"""
|
|
1444
|
+
if isinstance(g, (tuple, list)):
|
|
1445
|
+
if isinstance(g[0], tuple):
|
|
1446
|
+
return set().union(*g)
|
|
1447
|
+
else:
|
|
1448
|
+
return set(g)
|
|
1449
|
+
elif isinstance(g, str): # perms given as strings of cycles
|
|
1450
|
+
assert g.startswith('(') and g.endswith(')')
|
|
1451
|
+
domain = set().union(*[a for cyc in g[1:-1].split(')(')
|
|
1452
|
+
for a in cyc.split(',')])
|
|
1453
|
+
if all(s.isdigit() for s in domain):
|
|
1454
|
+
return [int(x) for x in domain]
|
|
1455
|
+
else:
|
|
1456
|
+
return domain
|
|
1457
|
+
elif parent(g) in Groups:
|
|
1458
|
+
return g.domain()
|
|
1459
|
+
else:
|
|
1460
|
+
raise TypeError
|
|
1461
|
+
|
|
1462
|
+
|
|
1463
|
+
def perms_sym_init(g, sym=None):
|
|
1464
|
+
r"""
|
|
1465
|
+
Initialize a list of permutations (in the same symmetric group).
|
|
1466
|
+
|
|
1467
|
+
OUTPUT:
|
|
1468
|
+
|
|
1469
|
+
- ``sym`` -- a symmetric group
|
|
1470
|
+
|
|
1471
|
+
- ``gg`` -- list of permutations
|
|
1472
|
+
|
|
1473
|
+
EXAMPLES::
|
|
1474
|
+
|
|
1475
|
+
sage: from sage.combinat.constellation import perms_sym_init
|
|
1476
|
+
sage: S, g = perms_sym_init([[0,2,1,3], [1,3,2,0]])
|
|
1477
|
+
sage: S.domain()
|
|
1478
|
+
{0, 1, 2, 3}
|
|
1479
|
+
sage: g
|
|
1480
|
+
[(1,2), (0,1,3)]
|
|
1481
|
+
|
|
1482
|
+
sage: S, g = perms_sym_init(['(2,1)', '(0,3)'])
|
|
1483
|
+
sage: S.domain()
|
|
1484
|
+
{0, 1, 2, 3}
|
|
1485
|
+
sage: g
|
|
1486
|
+
[(1,2), (0,3)]
|
|
1487
|
+
|
|
1488
|
+
sage: S, g = perms_sym_init([(1,0), (2,1)])
|
|
1489
|
+
sage: S.domain()
|
|
1490
|
+
{0, 1, 2}
|
|
1491
|
+
sage: g
|
|
1492
|
+
[(0,1), (1,2)]
|
|
1493
|
+
|
|
1494
|
+
sage: S, g = perms_sym_init([((1,0),(2,3)), '(0,1,4)'])
|
|
1495
|
+
sage: S.domain()
|
|
1496
|
+
{0, 1, 2, 3, 4}
|
|
1497
|
+
sage: g
|
|
1498
|
+
[(0,1)(2,3), (0,1,4)]
|
|
1499
|
+
"""
|
|
1500
|
+
if g is None or len(g) == 0:
|
|
1501
|
+
if sym is None:
|
|
1502
|
+
sym = SymmetricGroup(0)
|
|
1503
|
+
return sym, [sym([])]
|
|
1504
|
+
|
|
1505
|
+
if sym is None:
|
|
1506
|
+
domain = set().union(*[perm_sym_domain(gg) for gg in g])
|
|
1507
|
+
if all(isinstance(s, (int, Integer)) and s > 0
|
|
1508
|
+
for s in domain):
|
|
1509
|
+
domain = max(domain)
|
|
1510
|
+
else:
|
|
1511
|
+
domain = sorted(domain)
|
|
1512
|
+
sym = SymmetricGroup(domain)
|
|
1513
|
+
|
|
1514
|
+
try:
|
|
1515
|
+
return sym, [sym(u) for u in g]
|
|
1516
|
+
except (ValueError, TypeError):
|
|
1517
|
+
return sym, None
|
|
1518
|
+
|
|
1519
|
+
|
|
1520
|
+
def perms_are_connected(g, n):
|
|
1521
|
+
"""
|
|
1522
|
+
Check that the action of the generated group is transitive.
|
|
1523
|
+
|
|
1524
|
+
INPUT:
|
|
1525
|
+
|
|
1526
|
+
- ``g`` -- list of permutations of `[0, n-1]` (in a SymmetricGroup)
|
|
1527
|
+
|
|
1528
|
+
- ``n`` -- integer
|
|
1529
|
+
|
|
1530
|
+
EXAMPLES::
|
|
1531
|
+
|
|
1532
|
+
sage: from sage.combinat.constellation import perms_are_connected
|
|
1533
|
+
sage: S = SymmetricGroup(range(3))
|
|
1534
|
+
sage: perms_are_connected([S([0,1,2]),S([0,2,1])],3)
|
|
1535
|
+
False
|
|
1536
|
+
sage: perms_are_connected([S([0,1,2]),S([1,2,0])],3)
|
|
1537
|
+
True
|
|
1538
|
+
"""
|
|
1539
|
+
G = Graph()
|
|
1540
|
+
if g:
|
|
1541
|
+
G.add_vertices(g[0].domain())
|
|
1542
|
+
for p in g:
|
|
1543
|
+
G.add_edges(p.dict().items(), loops=False)
|
|
1544
|
+
return G.is_connected()
|
|
1545
|
+
|
|
1546
|
+
|
|
1547
|
+
def perms_canonical_labels_from(x, y, j0, verbose=False):
|
|
1548
|
+
r"""
|
|
1549
|
+
Return canonical labels for ``x``, ``y`` that starts at ``j0``.
|
|
1550
|
+
|
|
1551
|
+
.. WARNING::
|
|
1552
|
+
|
|
1553
|
+
The group generated by ``x`` and the elements of ``y`` should be
|
|
1554
|
+
transitive.
|
|
1555
|
+
|
|
1556
|
+
INPUT:
|
|
1557
|
+
|
|
1558
|
+
- ``x`` -- list; a permutation of `[0, ..., n]` as a list
|
|
1559
|
+
|
|
1560
|
+
- ``y`` -- list of permutations of `[0, ..., n]` as a list of lists
|
|
1561
|
+
|
|
1562
|
+
- ``j0`` -- an index in [0, ..., n]
|
|
1563
|
+
|
|
1564
|
+
OUTPUT: mapping: a permutation that specify the new labels
|
|
1565
|
+
|
|
1566
|
+
EXAMPLES::
|
|
1567
|
+
|
|
1568
|
+
sage: from sage.combinat.constellation import perms_canonical_labels_from
|
|
1569
|
+
sage: perms_canonical_labels_from([0,1,2],[[1,2,0]], 0)
|
|
1570
|
+
[0, 1, 2]
|
|
1571
|
+
sage: perms_canonical_labels_from([1,0,2], [[2,0,1]], 0)
|
|
1572
|
+
[0, 1, 2]
|
|
1573
|
+
sage: perms_canonical_labels_from([1,0,2], [[2,0,1]], 1)
|
|
1574
|
+
[1, 0, 2]
|
|
1575
|
+
sage: perms_canonical_labels_from([1,0,2], [[2,0,1]], 2)
|
|
1576
|
+
[2, 1, 0]
|
|
1577
|
+
"""
|
|
1578
|
+
n = len(x)
|
|
1579
|
+
|
|
1580
|
+
k = 0
|
|
1581
|
+
mapping = [None] * n
|
|
1582
|
+
waiting = [[] for _ in repeat(None, len(y))]
|
|
1583
|
+
|
|
1584
|
+
while k < n:
|
|
1585
|
+
if verbose:
|
|
1586
|
+
print("complete from {}".format(j0))
|
|
1587
|
+
# initialize at j0
|
|
1588
|
+
mapping[j0] = k
|
|
1589
|
+
waiting[0].append(j0)
|
|
1590
|
+
k += 1
|
|
1591
|
+
# complete x cycle from j0
|
|
1592
|
+
j = x[j0]
|
|
1593
|
+
while j != j0:
|
|
1594
|
+
mapping[j] = k
|
|
1595
|
+
waiting[0].append(j)
|
|
1596
|
+
k += 1
|
|
1597
|
+
j = x[j]
|
|
1598
|
+
if verbose:
|
|
1599
|
+
print("completed cycle mapping = {}".format(mapping))
|
|
1600
|
+
|
|
1601
|
+
# find another guy
|
|
1602
|
+
if verbose:
|
|
1603
|
+
print("try to find somebody in {}".format(waiting))
|
|
1604
|
+
l = 0
|
|
1605
|
+
while l < len(waiting):
|
|
1606
|
+
i = 0
|
|
1607
|
+
while i < len(waiting[l]):
|
|
1608
|
+
j1 = waiting[l][i]
|
|
1609
|
+
if mapping[y[l][j1]] is None:
|
|
1610
|
+
break
|
|
1611
|
+
i += 1
|
|
1612
|
+
|
|
1613
|
+
if i == len(waiting[l]): # not found: go further in waiting
|
|
1614
|
+
if l < len(waiting) - 1:
|
|
1615
|
+
waiting[l + 1].extend(waiting[l])
|
|
1616
|
+
waiting[l] = []
|
|
1617
|
+
l += 1
|
|
1618
|
+
i = 0
|
|
1619
|
+
|
|
1620
|
+
else: # found: complete cycle from new guy
|
|
1621
|
+
j0 = y[l][j1]
|
|
1622
|
+
if l < len(waiting) - 1:
|
|
1623
|
+
waiting[l + 1].extend(waiting[l][:i + 1])
|
|
1624
|
+
del waiting[l][:i + 1]
|
|
1625
|
+
break
|
|
1626
|
+
|
|
1627
|
+
return mapping
|
|
1628
|
+
|
|
1629
|
+
|
|
1630
|
+
def perm_invert(p):
|
|
1631
|
+
"""
|
|
1632
|
+
Return the inverse of the permutation `p`.
|
|
1633
|
+
|
|
1634
|
+
INPUT:
|
|
1635
|
+
|
|
1636
|
+
- ``p`` -- a permutation of {0,..,n-1} given by a list of values
|
|
1637
|
+
|
|
1638
|
+
OUTPUT: a permutation of {0,..,n-1} given by a list of values
|
|
1639
|
+
|
|
1640
|
+
EXAMPLES::
|
|
1641
|
+
|
|
1642
|
+
sage: from sage.combinat.constellation import perm_invert
|
|
1643
|
+
sage: perm_invert([3,2,0,1])
|
|
1644
|
+
[2, 3, 1, 0]
|
|
1645
|
+
"""
|
|
1646
|
+
q = [None] * len(p)
|
|
1647
|
+
for i, j in enumerate(p):
|
|
1648
|
+
q[j] = i
|
|
1649
|
+
return q
|
|
1650
|
+
|
|
1651
|
+
|
|
1652
|
+
def perm_conjugate(p, s):
|
|
1653
|
+
"""
|
|
1654
|
+
Return the conjugate of the permutation `p` by the permutation `s`.
|
|
1655
|
+
|
|
1656
|
+
INPUT:
|
|
1657
|
+
|
|
1658
|
+
- ``p``, ``s`` -- two permutations of {0,..,n-1} given by lists of values
|
|
1659
|
+
|
|
1660
|
+
OUTPUT: a permutation of {0,..,n-1} given by a list of values
|
|
1661
|
+
|
|
1662
|
+
EXAMPLES::
|
|
1663
|
+
|
|
1664
|
+
sage: from sage.combinat.constellation import perm_conjugate
|
|
1665
|
+
sage: perm_conjugate([3,1,2,0], [3,2,0,1])
|
|
1666
|
+
[0, 3, 2, 1]
|
|
1667
|
+
"""
|
|
1668
|
+
q = [None] * len(p)
|
|
1669
|
+
for i in range(len(p)):
|
|
1670
|
+
q[s[i]] = s[p[i]]
|
|
1671
|
+
return q
|
|
1672
|
+
|
|
1673
|
+
|
|
1674
|
+
def perms_canonical_labels(p, e=None):
|
|
1675
|
+
"""
|
|
1676
|
+
Relabel a list with a common conjugation such that two conjugated
|
|
1677
|
+
lists are relabeled the same way.
|
|
1678
|
+
|
|
1679
|
+
INPUT:
|
|
1680
|
+
|
|
1681
|
+
- ``p`` -- list of at least 2 permutations
|
|
1682
|
+
|
|
1683
|
+
- ``e`` -- ``None`` or a list of integer in the domain of the
|
|
1684
|
+
permutations. If provided, then the renumbering algorithm is
|
|
1685
|
+
only performed from the elements of ``e``.
|
|
1686
|
+
|
|
1687
|
+
OUTPUT: a pair made of a list of permutations (as a list of lists) and a
|
|
1688
|
+
list that corresponds to the conjugacy used.
|
|
1689
|
+
|
|
1690
|
+
EXAMPLES::
|
|
1691
|
+
|
|
1692
|
+
sage: from sage.combinat.constellation import perms_canonical_labels
|
|
1693
|
+
sage: l0 = [[2,0,3,1], [3,1,2,0], [0,2,1,3]]
|
|
1694
|
+
sage: l, m = perms_canonical_labels(l0); l
|
|
1695
|
+
[[1, 2, 3, 0], [0, 3, 2, 1], [2, 1, 0, 3]]
|
|
1696
|
+
|
|
1697
|
+
sage: S = SymmetricGroup(range(4))
|
|
1698
|
+
sage: [~S(m) * S(u) * S(m) for u in l0] == list(map(S, l))
|
|
1699
|
+
True
|
|
1700
|
+
|
|
1701
|
+
sage: perms_canonical_labels([])
|
|
1702
|
+
Traceback (most recent call last):
|
|
1703
|
+
...
|
|
1704
|
+
ValueError: input must have length >= 2
|
|
1705
|
+
"""
|
|
1706
|
+
if not len(p) > 1:
|
|
1707
|
+
raise ValueError('input must have length >= 2')
|
|
1708
|
+
|
|
1709
|
+
n = len(p[0])
|
|
1710
|
+
|
|
1711
|
+
c_win = None
|
|
1712
|
+
m_win = list(range(n))
|
|
1713
|
+
|
|
1714
|
+
x = p[0]
|
|
1715
|
+
y = p[1:]
|
|
1716
|
+
|
|
1717
|
+
if e is None:
|
|
1718
|
+
e = list(range(n))
|
|
1719
|
+
|
|
1720
|
+
# get canonical label from i in to_test and compare
|
|
1721
|
+
while e:
|
|
1722
|
+
i = e.pop()
|
|
1723
|
+
m_test = perms_canonical_labels_from(x, y, i)
|
|
1724
|
+
c_test = [perm_conjugate(u, m_test) for u in p]
|
|
1725
|
+
if c_win is None or c_test < c_win:
|
|
1726
|
+
c_win = c_test
|
|
1727
|
+
m_win = m_test
|
|
1728
|
+
|
|
1729
|
+
return c_win, m_win
|