passagemath-combinat 10.6.42__cp314-cp314t-win_amd64.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/DELVEWHEEL +2 -0
- passagemath_combinat-10.6.42.dist-info/METADATA +160 -0
- passagemath_combinat-10.6.42.dist-info/RECORD +401 -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-10-3a5f019e2510aeaad918cab2b57a689d.dll +0 -0
- passagemath_combinat.libs/libsymmetrica-3-7dcf900932804d0df5fd0919b4668720.dll +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 +44 -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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +0 -0
- sage/combinat/debruijn_sequence.pyx +355 -0
- sage/combinat/decorated_permutation.py +270 -0
- sage/combinat/degree_sequences.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +0 -0
- sage/combinat/expnums.pyx +148 -0
- sage/combinat/fast_vector_partitions.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +0 -0
- sage/combinat/words/word_char.pyx +847 -0
- sage/combinat/words/word_datatypes.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +0 -0
- sage/sat/solvers/satsolver.pxd +3 -0
- sage/sat/solvers/satsolver.pyx +405 -0
|
@@ -0,0 +1,2286 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-combinat
|
|
2
|
+
r"""
|
|
3
|
+
Knutson-Tao puzzles
|
|
4
|
+
|
|
5
|
+
This module implements a generic algorithm to solve Knutson-Tao puzzles. An
|
|
6
|
+
instance of this class will be callable: the arguments are the labels of
|
|
7
|
+
north-east and north-west sides of the puzzle boundary; the output is the list
|
|
8
|
+
of the fillings of the puzzle with the specified pieces.
|
|
9
|
+
|
|
10
|
+
Acknowledgements
|
|
11
|
+
----------------
|
|
12
|
+
|
|
13
|
+
This code was written during Sage Days 45 at ICERM with Franco Saliola, Anne
|
|
14
|
+
Schilling, and Avinash Dalal in discussions with Allen Knutson. The code was
|
|
15
|
+
tested afterwards by Liz Beazley and Ed Richmond.
|
|
16
|
+
|
|
17
|
+
.. TODO::
|
|
18
|
+
|
|
19
|
+
Functionality to add:
|
|
20
|
+
|
|
21
|
+
- plotter will not plot edge labels higher than 2; e.g. in BK puzzles, the labels are
|
|
22
|
+
1,..., n and so in 3-step examples, none of the edge labels with 3 appear
|
|
23
|
+
|
|
24
|
+
- we should also have a 3-step puzzle pieces constructor, taken from p22 of
|
|
25
|
+
:arxiv:`math/0610538`
|
|
26
|
+
|
|
27
|
+
- implement the bijection from puzzles to tableaux; see for example
|
|
28
|
+
R. Vakil, A geometric Littlewood-Richardson rule, :arxiv:`math/0302294`
|
|
29
|
+
or K. Purbhoo, Puzzles, Tableaux and Mosaics, :arxiv:`0705.1184`.
|
|
30
|
+
"""
|
|
31
|
+
# ****************************************************************************
|
|
32
|
+
# Copyright (C) 2013 Franco Saliola <saliola@gmail.com>,
|
|
33
|
+
# 2013 Allen Knutson,
|
|
34
|
+
# 2013 Avinash Dalal,
|
|
35
|
+
# 2013 Anne Schilling,
|
|
36
|
+
# 2013 Elizabeth Beazley,
|
|
37
|
+
# 2013 Ed Richmond
|
|
38
|
+
#
|
|
39
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
40
|
+
# https://www.gnu.org/licenses/
|
|
41
|
+
# ****************************************************************************
|
|
42
|
+
from __future__ import annotations
|
|
43
|
+
|
|
44
|
+
from sage.misc.lazy_import import lazy_import
|
|
45
|
+
lazy_import("sage.plot.graphics", "Graphics")
|
|
46
|
+
lazy_import("sage.plot.polygon", "polygon")
|
|
47
|
+
lazy_import("sage.plot.line", "line")
|
|
48
|
+
lazy_import("sage.plot.text", "text")
|
|
49
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
50
|
+
from sage.rings.finite_rings.integer_mod_ring import Integers
|
|
51
|
+
lazy_import("sage.plot.plot", "graphics_array")
|
|
52
|
+
from sage.misc.cachefunc import cached_method
|
|
53
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class PuzzlePiece:
|
|
57
|
+
r"""
|
|
58
|
+
Abstract class for puzzle pieces.
|
|
59
|
+
|
|
60
|
+
This abstract class contains information on how to test equality of
|
|
61
|
+
puzzle pieces, and sets color and plotting options.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
def __eq__(self, other) -> bool:
|
|
65
|
+
r"""
|
|
66
|
+
TESTS::
|
|
67
|
+
|
|
68
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece
|
|
69
|
+
sage: delta = DeltaPiece('a','b','c')
|
|
70
|
+
sage: delta1 = DeltaPiece('a','b','c')
|
|
71
|
+
sage: delta == delta1
|
|
72
|
+
True
|
|
73
|
+
sage: delta1 = DeltaPiece('A','b','c')
|
|
74
|
+
sage: delta == delta1
|
|
75
|
+
False
|
|
76
|
+
"""
|
|
77
|
+
if isinstance(other, PuzzlePiece):
|
|
78
|
+
return self.border() == other.border()
|
|
79
|
+
else:
|
|
80
|
+
return False
|
|
81
|
+
|
|
82
|
+
def __hash__(self):
|
|
83
|
+
r"""
|
|
84
|
+
TESTS::
|
|
85
|
+
|
|
86
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece
|
|
87
|
+
sage: delta = DeltaPiece('a','b','c')
|
|
88
|
+
sage: hash(delta) == hash(delta)
|
|
89
|
+
True
|
|
90
|
+
"""
|
|
91
|
+
return hash((type(self), self.border()))
|
|
92
|
+
|
|
93
|
+
def border(self) -> tuple:
|
|
94
|
+
r"""
|
|
95
|
+
Return the border of ``self``.
|
|
96
|
+
|
|
97
|
+
EXAMPLES::
|
|
98
|
+
|
|
99
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece
|
|
100
|
+
sage: delta = DeltaPiece('a','b','c')
|
|
101
|
+
sage: sorted(delta.border())
|
|
102
|
+
['a', 'b', 'c']
|
|
103
|
+
"""
|
|
104
|
+
return tuple(self.edge_label(edge) for edge in self.edges())
|
|
105
|
+
|
|
106
|
+
def color(self) -> str:
|
|
107
|
+
r"""
|
|
108
|
+
Return the color of ``self``.
|
|
109
|
+
|
|
110
|
+
EXAMPLES::
|
|
111
|
+
|
|
112
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece
|
|
113
|
+
sage: delta = DeltaPiece('a','b','c')
|
|
114
|
+
sage: delta.color()
|
|
115
|
+
'white'
|
|
116
|
+
sage: delta = DeltaPiece('0','0','0')
|
|
117
|
+
sage: delta.color()
|
|
118
|
+
'red'
|
|
119
|
+
sage: delta = DeltaPiece('1','1','1')
|
|
120
|
+
sage: delta.color()
|
|
121
|
+
'blue'
|
|
122
|
+
sage: delta = DeltaPiece('2','2','2')
|
|
123
|
+
sage: delta.color()
|
|
124
|
+
'green'
|
|
125
|
+
sage: delta = DeltaPiece('2','K','2')
|
|
126
|
+
sage: delta.color()
|
|
127
|
+
'orange'
|
|
128
|
+
sage: delta = DeltaPiece('2','T1/2','2')
|
|
129
|
+
sage: delta.color()
|
|
130
|
+
'yellow'
|
|
131
|
+
"""
|
|
132
|
+
colors = {('0', '0', '0'): 'red',
|
|
133
|
+
('1', '1', '1'): 'blue',
|
|
134
|
+
('2', '2', '2'): 'green'}
|
|
135
|
+
border = self.border()
|
|
136
|
+
if border in colors:
|
|
137
|
+
color = colors[border]
|
|
138
|
+
elif 'K' in border:
|
|
139
|
+
color = 'orange'
|
|
140
|
+
elif '10' in border:
|
|
141
|
+
color = 'white'
|
|
142
|
+
elif any(label.startswith('T') for label in border):
|
|
143
|
+
color = 'yellow'
|
|
144
|
+
else:
|
|
145
|
+
color = 'white'
|
|
146
|
+
return color
|
|
147
|
+
|
|
148
|
+
def _plot_label(self, label, coords, fontcolor=(0.3, 0.3, 0.3),
|
|
149
|
+
fontsize=15, rotation=0):
|
|
150
|
+
r"""
|
|
151
|
+
TESTS::
|
|
152
|
+
|
|
153
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece
|
|
154
|
+
sage: delta = DeltaPiece('2','K','2')
|
|
155
|
+
sage: delta._plot_label('1',(1,1)) # not tested
|
|
156
|
+
"""
|
|
157
|
+
if label in ('0', '1', '2'):
|
|
158
|
+
return text(label, coords, color=fontcolor, fontsize=fontsize, rotation=rotation)
|
|
159
|
+
else:
|
|
160
|
+
return Graphics()
|
|
161
|
+
|
|
162
|
+
def _plot_piece(self, coords, border_color=(0.5, 0.5, 0.5),
|
|
163
|
+
border_thickness=1, style='fill'):
|
|
164
|
+
r"""
|
|
165
|
+
TESTS::
|
|
166
|
+
|
|
167
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece
|
|
168
|
+
sage: delta = DeltaPiece('2','K','2')
|
|
169
|
+
sage: delta._plot_piece([(1,1),(1,2),(2,2)]) # not tested
|
|
170
|
+
"""
|
|
171
|
+
if style == 'fill':
|
|
172
|
+
P = polygon(coords, color=self.color())
|
|
173
|
+
P += polygon(coords, fill=False, color=border_color, thickness=border_thickness)
|
|
174
|
+
return P
|
|
175
|
+
elif style == 'edges':
|
|
176
|
+
if isinstance(self, DeltaPiece):
|
|
177
|
+
edges = ('north_west', 'south', 'north_east')
|
|
178
|
+
elif isinstance(self, NablaPiece):
|
|
179
|
+
edges = ('south_west', 'north', 'south_east')
|
|
180
|
+
else:
|
|
181
|
+
edges = self.edges()
|
|
182
|
+
P = Graphics()
|
|
183
|
+
for (i, edge) in enumerate(edges):
|
|
184
|
+
P += line([coords[i], coords[(i + 1) % 3]],
|
|
185
|
+
color=self.edge_color(edge),
|
|
186
|
+
thickness=border_thickness)
|
|
187
|
+
return P
|
|
188
|
+
else:
|
|
189
|
+
return NotImplemented
|
|
190
|
+
|
|
191
|
+
def edge_color(self, edge) -> str:
|
|
192
|
+
r"""
|
|
193
|
+
Color of the specified edge of ``self`` (to be used when plotting the
|
|
194
|
+
piece).
|
|
195
|
+
|
|
196
|
+
EXAMPLES::
|
|
197
|
+
|
|
198
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece
|
|
199
|
+
sage: delta = DeltaPiece('1','0','10')
|
|
200
|
+
sage: delta.edge_color('south')
|
|
201
|
+
'blue'
|
|
202
|
+
sage: delta.edge_color('north_west')
|
|
203
|
+
'red'
|
|
204
|
+
sage: delta.edge_color('north_east')
|
|
205
|
+
'white'
|
|
206
|
+
"""
|
|
207
|
+
edge_label = self.edge_label(edge)
|
|
208
|
+
colors = {'1': 'blue', '0': 'red'}
|
|
209
|
+
if edge_label in colors:
|
|
210
|
+
color = colors[edge_label]
|
|
211
|
+
elif 'K' in edge_label:
|
|
212
|
+
color = 'orange'
|
|
213
|
+
elif edge_label.startswith('T'):
|
|
214
|
+
color = 'yellow'
|
|
215
|
+
else:
|
|
216
|
+
color = 'white'
|
|
217
|
+
return color
|
|
218
|
+
|
|
219
|
+
def edge_label(self, edge) -> str:
|
|
220
|
+
r"""
|
|
221
|
+
Return the edge label of ``edge``.
|
|
222
|
+
|
|
223
|
+
EXAMPLES::
|
|
224
|
+
|
|
225
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece
|
|
226
|
+
sage: delta = DeltaPiece('2','K','2')
|
|
227
|
+
sage: delta.edge_label('south')
|
|
228
|
+
'2'
|
|
229
|
+
sage: delta.edge_label('north_east')
|
|
230
|
+
'2'
|
|
231
|
+
sage: delta.edge_label('north_west')
|
|
232
|
+
'K'
|
|
233
|
+
"""
|
|
234
|
+
return self._edge_labels[edge]
|
|
235
|
+
|
|
236
|
+
__getitem__ = edge_label
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class NablaPiece(PuzzlePiece):
|
|
240
|
+
r"""
|
|
241
|
+
Nabla Piece takes as input three labels, inputted as strings. They label
|
|
242
|
+
the North, Southeast and Southwest edges, respectively.
|
|
243
|
+
|
|
244
|
+
EXAMPLES::
|
|
245
|
+
|
|
246
|
+
sage: from sage.combinat.knutson_tao_puzzles import NablaPiece
|
|
247
|
+
sage: NablaPiece('a','b','c')
|
|
248
|
+
c\a/b
|
|
249
|
+
"""
|
|
250
|
+
|
|
251
|
+
def __init__(self, north, south_east, south_west):
|
|
252
|
+
r"""
|
|
253
|
+
INPUT:
|
|
254
|
+
|
|
255
|
+
- ``north``, ``south_east``, ``south_west`` -- strings, which label the edges
|
|
256
|
+
|
|
257
|
+
EXAMPLES::
|
|
258
|
+
|
|
259
|
+
sage: from sage.combinat.knutson_tao_puzzles import NablaPiece
|
|
260
|
+
sage: NablaPiece('1','2','3')
|
|
261
|
+
3\1/2
|
|
262
|
+
"""
|
|
263
|
+
self._edge_labels = dict(north=north, south_east=south_east, south_west=south_west)
|
|
264
|
+
|
|
265
|
+
def __eq__(self, other) -> bool:
|
|
266
|
+
r"""
|
|
267
|
+
TESTS::
|
|
268
|
+
|
|
269
|
+
sage: from sage.combinat.knutson_tao_puzzles import NablaPiece
|
|
270
|
+
sage: n = NablaPiece('a','b','c')
|
|
271
|
+
sage: n1 = NablaPiece('a','b','c')
|
|
272
|
+
sage: n == n1
|
|
273
|
+
True
|
|
274
|
+
sage: n1 = NablaPiece('A','b','c')
|
|
275
|
+
sage: n == n1
|
|
276
|
+
False
|
|
277
|
+
"""
|
|
278
|
+
if isinstance(other, NablaPiece):
|
|
279
|
+
return (self.border() == other.border() and
|
|
280
|
+
self._edge_labels == other._edge_labels)
|
|
281
|
+
else:
|
|
282
|
+
return False
|
|
283
|
+
|
|
284
|
+
def __hash__(self):
|
|
285
|
+
r"""
|
|
286
|
+
TESTS::
|
|
287
|
+
|
|
288
|
+
sage: from sage.combinat.knutson_tao_puzzles import NablaPiece
|
|
289
|
+
sage: n = NablaPiece('a','b','c')
|
|
290
|
+
sage: hash(n) == hash(n)
|
|
291
|
+
True
|
|
292
|
+
"""
|
|
293
|
+
return hash((NablaPiece, self.border()))
|
|
294
|
+
|
|
295
|
+
def __repr__(self) -> str:
|
|
296
|
+
r"""
|
|
297
|
+
Print the labels of the Nabla piece.
|
|
298
|
+
|
|
299
|
+
EXAMPLES::
|
|
300
|
+
|
|
301
|
+
sage: from sage.combinat.knutson_tao_puzzles import NablaPiece
|
|
302
|
+
sage: NablaPiece('1','2','3')
|
|
303
|
+
3\1/2
|
|
304
|
+
"""
|
|
305
|
+
return r"%s\%s/%s" % (self['south_west'],
|
|
306
|
+
self['north'],
|
|
307
|
+
self['south_east'])
|
|
308
|
+
|
|
309
|
+
def clockwise_rotation(self) -> NablaPiece:
|
|
310
|
+
r"""
|
|
311
|
+
Rotate the Nabla piece by 120 degree clockwise.
|
|
312
|
+
|
|
313
|
+
OUTPUT: Nabla piece
|
|
314
|
+
|
|
315
|
+
EXAMPLES::
|
|
316
|
+
|
|
317
|
+
sage: from sage.combinat.knutson_tao_puzzles import NablaPiece
|
|
318
|
+
sage: nabla = NablaPiece('1','2','3')
|
|
319
|
+
sage: nabla.clockwise_rotation()
|
|
320
|
+
2\3/1
|
|
321
|
+
"""
|
|
322
|
+
return NablaPiece(north=self['south_west'],
|
|
323
|
+
south_east=self['north'],
|
|
324
|
+
south_west=self['south_east'])
|
|
325
|
+
|
|
326
|
+
def half_turn_rotation(self) -> DeltaPiece:
|
|
327
|
+
r"""
|
|
328
|
+
Rotate the Nabla piece by 180 degree.
|
|
329
|
+
|
|
330
|
+
OUTPUT: Delta piece
|
|
331
|
+
|
|
332
|
+
EXAMPLES::
|
|
333
|
+
|
|
334
|
+
sage: from sage.combinat.knutson_tao_puzzles import NablaPiece
|
|
335
|
+
sage: nabla = NablaPiece('1','2','3')
|
|
336
|
+
sage: nabla.half_turn_rotation()
|
|
337
|
+
2/1\3
|
|
338
|
+
"""
|
|
339
|
+
return DeltaPiece(south=self['north'],
|
|
340
|
+
north_west=self['south_east'],
|
|
341
|
+
north_east=self['south_west'])
|
|
342
|
+
|
|
343
|
+
def edges(self) -> tuple:
|
|
344
|
+
r"""
|
|
345
|
+
Return the tuple of edge names.
|
|
346
|
+
|
|
347
|
+
EXAMPLES::
|
|
348
|
+
|
|
349
|
+
sage: from sage.combinat.knutson_tao_puzzles import NablaPiece
|
|
350
|
+
sage: nabla = NablaPiece('1','2','3')
|
|
351
|
+
sage: nabla.edges()
|
|
352
|
+
('north', 'south_east', 'south_west')
|
|
353
|
+
"""
|
|
354
|
+
return ('north', 'south_east', 'south_west')
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
class DeltaPiece(PuzzlePiece):
|
|
358
|
+
r"""
|
|
359
|
+
Delta Piece takes as input three labels, inputted as strings. They label
|
|
360
|
+
the South, Northwest and Northeast edges, respectively.
|
|
361
|
+
|
|
362
|
+
EXAMPLES::
|
|
363
|
+
|
|
364
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece
|
|
365
|
+
sage: DeltaPiece('a','b','c')
|
|
366
|
+
b/a\c
|
|
367
|
+
"""
|
|
368
|
+
|
|
369
|
+
def __init__(self, south, north_west, north_east):
|
|
370
|
+
r"""
|
|
371
|
+
INPUT:
|
|
372
|
+
|
|
373
|
+
- ``south``, ``north_west``, ``north_east`` -- strings, which label the edges
|
|
374
|
+
|
|
375
|
+
EXAMPLES::
|
|
376
|
+
|
|
377
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece
|
|
378
|
+
sage: DeltaPiece('1','2','3')
|
|
379
|
+
2/1\3
|
|
380
|
+
"""
|
|
381
|
+
self._edge_labels = dict(south=south, north_west=north_west, north_east=north_east)
|
|
382
|
+
|
|
383
|
+
def __eq__(self, other) -> bool:
|
|
384
|
+
r"""
|
|
385
|
+
TESTS::
|
|
386
|
+
|
|
387
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece
|
|
388
|
+
sage: delta = DeltaPiece('a','b','c')
|
|
389
|
+
sage: delta1 = DeltaPiece('a','b','c')
|
|
390
|
+
sage: delta == delta1
|
|
391
|
+
True
|
|
392
|
+
sage: delta1 = DeltaPiece('A','b','c')
|
|
393
|
+
sage: delta == delta1
|
|
394
|
+
False
|
|
395
|
+
"""
|
|
396
|
+
if isinstance(other, DeltaPiece):
|
|
397
|
+
return (self.border() == other.border() and
|
|
398
|
+
self._edge_labels == other._edge_labels)
|
|
399
|
+
else:
|
|
400
|
+
return False
|
|
401
|
+
|
|
402
|
+
def __hash__(self):
|
|
403
|
+
r"""
|
|
404
|
+
TESTS::
|
|
405
|
+
|
|
406
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece
|
|
407
|
+
sage: delta = DeltaPiece('a','b','c')
|
|
408
|
+
sage: hash(delta) == hash(delta)
|
|
409
|
+
True
|
|
410
|
+
"""
|
|
411
|
+
return hash((DeltaPiece, self.border()))
|
|
412
|
+
|
|
413
|
+
def __repr__(self) -> str:
|
|
414
|
+
r"""
|
|
415
|
+
Print the labels of the Delta piece.
|
|
416
|
+
|
|
417
|
+
EXAMPLES::
|
|
418
|
+
|
|
419
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece
|
|
420
|
+
sage: DeltaPiece('1','2','3')
|
|
421
|
+
2/1\3
|
|
422
|
+
"""
|
|
423
|
+
return r"%s/%s\%s" % (self['north_west'],
|
|
424
|
+
self['south'],
|
|
425
|
+
self['north_east'])
|
|
426
|
+
|
|
427
|
+
def clockwise_rotation(self) -> DeltaPiece:
|
|
428
|
+
r"""
|
|
429
|
+
Rotate the Delta piece by 120 degree clockwise.
|
|
430
|
+
|
|
431
|
+
OUTPUT: Delta piece
|
|
432
|
+
|
|
433
|
+
EXAMPLES::
|
|
434
|
+
|
|
435
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece
|
|
436
|
+
sage: delta = DeltaPiece('1','2','3')
|
|
437
|
+
sage: delta.clockwise_rotation()
|
|
438
|
+
1/3\2
|
|
439
|
+
"""
|
|
440
|
+
return DeltaPiece(south=self['north_east'],
|
|
441
|
+
north_west=self['south'],
|
|
442
|
+
north_east=self['north_west'])
|
|
443
|
+
|
|
444
|
+
def half_turn_rotation(self) -> NablaPiece:
|
|
445
|
+
r"""
|
|
446
|
+
Rotate the Delta piece by 180 degree.
|
|
447
|
+
|
|
448
|
+
OUTPUT: Nabla piece
|
|
449
|
+
|
|
450
|
+
EXAMPLES::
|
|
451
|
+
|
|
452
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece
|
|
453
|
+
sage: delta = DeltaPiece('1','2','3')
|
|
454
|
+
sage: delta.half_turn_rotation()
|
|
455
|
+
3\1/2
|
|
456
|
+
"""
|
|
457
|
+
return NablaPiece(north=self['south'],
|
|
458
|
+
south_east=self['north_west'],
|
|
459
|
+
south_west=self['north_east'])
|
|
460
|
+
|
|
461
|
+
def edges(self) -> tuple:
|
|
462
|
+
r"""
|
|
463
|
+
Return the tuple of edge names.
|
|
464
|
+
|
|
465
|
+
EXAMPLES::
|
|
466
|
+
|
|
467
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece
|
|
468
|
+
sage: delta = DeltaPiece('1','2','3')
|
|
469
|
+
sage: delta.edges()
|
|
470
|
+
('south', 'north_west', 'north_east')
|
|
471
|
+
"""
|
|
472
|
+
return ('south', 'north_west', 'north_east')
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
class RhombusPiece(PuzzlePiece):
|
|
476
|
+
r"""
|
|
477
|
+
Class of rhombi pieces.
|
|
478
|
+
|
|
479
|
+
To construct a rhombus piece we input a delta and a nabla piece.
|
|
480
|
+
The delta and nabla pieces are joined along the south and north edge,
|
|
481
|
+
respectively.
|
|
482
|
+
|
|
483
|
+
EXAMPLES::
|
|
484
|
+
|
|
485
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece, NablaPiece, RhombusPiece
|
|
486
|
+
sage: delta = DeltaPiece('1','2','3')
|
|
487
|
+
sage: nabla = NablaPiece('4','5','6')
|
|
488
|
+
sage: RhombusPiece(delta,nabla)
|
|
489
|
+
2/\3 6\/5
|
|
490
|
+
"""
|
|
491
|
+
|
|
492
|
+
def __init__(self, north_piece, south_piece):
|
|
493
|
+
r"""
|
|
494
|
+
EXAMPLES::
|
|
495
|
+
|
|
496
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece, NablaPiece, RhombusPiece
|
|
497
|
+
sage: delta = DeltaPiece('1','2','3')
|
|
498
|
+
sage: nabla = NablaPiece('4','5','6')
|
|
499
|
+
sage: RhombusPiece(delta,nabla)
|
|
500
|
+
2/\3 6\/5
|
|
501
|
+
"""
|
|
502
|
+
self._north_piece = north_piece
|
|
503
|
+
self._south_piece = south_piece
|
|
504
|
+
self._edge_labels = dict(north_west=north_piece['north_west'],
|
|
505
|
+
north_east=north_piece['north_east'],
|
|
506
|
+
south_east=south_piece['south_east'],
|
|
507
|
+
south_west=south_piece['south_west'])
|
|
508
|
+
|
|
509
|
+
def __eq__(self, other) -> bool:
|
|
510
|
+
r"""
|
|
511
|
+
TESTS::
|
|
512
|
+
|
|
513
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece, NablaPiece, RhombusPiece
|
|
514
|
+
sage: delta = DeltaPiece('1','2','3')
|
|
515
|
+
sage: nabla = NablaPiece('4','5','6')
|
|
516
|
+
sage: r = RhombusPiece(delta,nabla)
|
|
517
|
+
sage: r == r
|
|
518
|
+
True
|
|
519
|
+
sage: delta1 = DeltaPiece('A','b','c')
|
|
520
|
+
sage: r == RhombusPiece(delta1,nabla)
|
|
521
|
+
False
|
|
522
|
+
"""
|
|
523
|
+
if isinstance(other, RhombusPiece):
|
|
524
|
+
return (self.border() == other.border() and
|
|
525
|
+
self._north_piece == other._north_piece and
|
|
526
|
+
self._south_piece == other._south_piece and
|
|
527
|
+
self._edge_labels == other._edge_labels)
|
|
528
|
+
else:
|
|
529
|
+
return False
|
|
530
|
+
|
|
531
|
+
def __hash__(self):
|
|
532
|
+
r"""
|
|
533
|
+
TESTS::
|
|
534
|
+
|
|
535
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece, NablaPiece, RhombusPiece
|
|
536
|
+
sage: delta = DeltaPiece('1','2','3')
|
|
537
|
+
sage: nabla = NablaPiece('4','5','6')
|
|
538
|
+
sage: r = RhombusPiece(delta,nabla)
|
|
539
|
+
sage: hash(r) == hash(r)
|
|
540
|
+
True
|
|
541
|
+
"""
|
|
542
|
+
return hash((RhombusPiece, self.border()))
|
|
543
|
+
|
|
544
|
+
def __iter__(self):
|
|
545
|
+
r"""
|
|
546
|
+
Return the list of the north and south piece.
|
|
547
|
+
|
|
548
|
+
EXAMPLES::
|
|
549
|
+
|
|
550
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece, NablaPiece, RhombusPiece
|
|
551
|
+
sage: delta = DeltaPiece('1','2','3')
|
|
552
|
+
sage: nabla = NablaPiece('4','5','6')
|
|
553
|
+
sage: r = RhombusPiece(delta,nabla)
|
|
554
|
+
sage: list(r)
|
|
555
|
+
[2/1\3, 6\4/5]
|
|
556
|
+
"""
|
|
557
|
+
yield self._north_piece
|
|
558
|
+
yield self._south_piece
|
|
559
|
+
|
|
560
|
+
def north_piece(self) -> DeltaPiece:
|
|
561
|
+
r"""
|
|
562
|
+
Return the north piece.
|
|
563
|
+
|
|
564
|
+
EXAMPLES::
|
|
565
|
+
|
|
566
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece, NablaPiece, RhombusPiece
|
|
567
|
+
sage: delta = DeltaPiece('1','2','3')
|
|
568
|
+
sage: nabla = NablaPiece('4','5','6')
|
|
569
|
+
sage: r = RhombusPiece(delta,nabla)
|
|
570
|
+
sage: r.north_piece()
|
|
571
|
+
2/1\3
|
|
572
|
+
"""
|
|
573
|
+
return self._north_piece
|
|
574
|
+
|
|
575
|
+
def south_piece(self) -> NablaPiece:
|
|
576
|
+
r"""
|
|
577
|
+
Return the south piece.
|
|
578
|
+
|
|
579
|
+
EXAMPLES::
|
|
580
|
+
|
|
581
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece, NablaPiece, RhombusPiece
|
|
582
|
+
sage: delta = DeltaPiece('1','2','3')
|
|
583
|
+
sage: nabla = NablaPiece('4','5','6')
|
|
584
|
+
sage: r = RhombusPiece(delta,nabla)
|
|
585
|
+
sage: r.south_piece()
|
|
586
|
+
6\4/5
|
|
587
|
+
"""
|
|
588
|
+
return self._south_piece
|
|
589
|
+
|
|
590
|
+
def __repr__(self) -> str:
|
|
591
|
+
r"""
|
|
592
|
+
EXAMPLES::
|
|
593
|
+
|
|
594
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece, NablaPiece, RhombusPiece
|
|
595
|
+
sage: delta = DeltaPiece('1','2','3')
|
|
596
|
+
sage: nabla = NablaPiece('4','5','6')
|
|
597
|
+
sage: RhombusPiece(delta,nabla)
|
|
598
|
+
2/\3 6\/5
|
|
599
|
+
"""
|
|
600
|
+
return r"%s/\%s %s\/%s" % (self['north_west'], self['north_east'],
|
|
601
|
+
self['south_west'], self['south_east'])
|
|
602
|
+
|
|
603
|
+
def edges(self) -> tuple:
|
|
604
|
+
r"""
|
|
605
|
+
Return the tuple of edge names.
|
|
606
|
+
|
|
607
|
+
EXAMPLES::
|
|
608
|
+
|
|
609
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece, NablaPiece, RhombusPiece
|
|
610
|
+
sage: delta = DeltaPiece('1','2','3')
|
|
611
|
+
sage: nabla = NablaPiece('4','5','6')
|
|
612
|
+
sage: RhombusPiece(delta,nabla).edges()
|
|
613
|
+
('north_west', 'north_east', 'south_east', 'south_west')
|
|
614
|
+
"""
|
|
615
|
+
return ('north_west', 'north_east', 'south_east', 'south_west')
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
class PuzzlePieces:
|
|
619
|
+
r"""
|
|
620
|
+
Construct a valid set of puzzle pieces.
|
|
621
|
+
|
|
622
|
+
This class constructs the set of valid puzzle pieces. It can take a list of
|
|
623
|
+
forbidden border labels as input. These labels are forbidden from appearing
|
|
624
|
+
on the south edge of a puzzle filling. The user can add valid nabla or
|
|
625
|
+
delta pieces and specify which rotations of these pieces are legal. For
|
|
626
|
+
example, ``rotations=0`` does not add any additional pieces (only the piece
|
|
627
|
+
itself), ``rotations=60`` adds six pieces (the pieces and its rotations by
|
|
628
|
+
60, 120, 180, 240, 300), etc..
|
|
629
|
+
|
|
630
|
+
EXAMPLES::
|
|
631
|
+
|
|
632
|
+
sage: from sage.combinat.knutson_tao_puzzles import PuzzlePieces, NablaPiece
|
|
633
|
+
sage: forbidden_border_labels = ['10']
|
|
634
|
+
sage: pieces = PuzzlePieces(forbidden_border_labels)
|
|
635
|
+
sage: pieces.add_piece(NablaPiece('0','0','0'), rotations=60)
|
|
636
|
+
sage: pieces.add_piece(NablaPiece('1','1','1'), rotations=60)
|
|
637
|
+
sage: pieces.add_piece(NablaPiece('1','0','10'), rotations=60)
|
|
638
|
+
sage: pieces
|
|
639
|
+
Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1]
|
|
640
|
+
Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1]
|
|
641
|
+
|
|
642
|
+
The user can obtain the list of valid rhombi pieces as follows::
|
|
643
|
+
|
|
644
|
+
sage: sorted([p for p in pieces.rhombus_pieces()], key=str)
|
|
645
|
+
[0/\0 0\/0, 0/\0 1\/10, 0/\10 10\/0, 0/\10 1\/1, 1/\0 0\/1,
|
|
646
|
+
1/\1 10\/0, 1/\1 1\/1, 10/\1 0\/0, 10/\1 1\/10]
|
|
647
|
+
"""
|
|
648
|
+
|
|
649
|
+
def __init__(self, forbidden_border_labels=None):
|
|
650
|
+
r"""
|
|
651
|
+
INPUT:
|
|
652
|
+
|
|
653
|
+
- ``forbidden_border_labels`` -- list of forbidden border labels given as strings
|
|
654
|
+
|
|
655
|
+
TESTS::
|
|
656
|
+
|
|
657
|
+
sage: from sage.combinat.knutson_tao_puzzles import PuzzlePieces
|
|
658
|
+
sage: forbidden_border_labels = ['10']
|
|
659
|
+
sage: pieces = PuzzlePieces(forbidden_border_labels)
|
|
660
|
+
sage: pieces
|
|
661
|
+
Nablas : []
|
|
662
|
+
Deltas : []
|
|
663
|
+
|
|
664
|
+
sage: PuzzlePieces('10')
|
|
665
|
+
Traceback (most recent call last):
|
|
666
|
+
...
|
|
667
|
+
TypeError: Input must be a list
|
|
668
|
+
"""
|
|
669
|
+
self._nabla_pieces = set()
|
|
670
|
+
self._delta_pieces = set()
|
|
671
|
+
if forbidden_border_labels is None:
|
|
672
|
+
forbidden_border_labels = []
|
|
673
|
+
if not isinstance(forbidden_border_labels, list):
|
|
674
|
+
raise TypeError("Input must be a list")
|
|
675
|
+
self._forbidden_border_labels = forbidden_border_labels
|
|
676
|
+
|
|
677
|
+
def __eq__(self, other) -> bool:
|
|
678
|
+
r"""
|
|
679
|
+
TESTS::
|
|
680
|
+
|
|
681
|
+
sage: from sage.combinat.knutson_tao_puzzles import H_grassmannian_pieces
|
|
682
|
+
sage: x = H_grassmannian_pieces()
|
|
683
|
+
sage: y = H_grassmannian_pieces()
|
|
684
|
+
sage: x == y
|
|
685
|
+
True
|
|
686
|
+
"""
|
|
687
|
+
if isinstance(other, type(self)):
|
|
688
|
+
return self.__dict__ == other.__dict__
|
|
689
|
+
else:
|
|
690
|
+
return False
|
|
691
|
+
|
|
692
|
+
def __hash__(self):
|
|
693
|
+
r"""
|
|
694
|
+
TESTS::
|
|
695
|
+
|
|
696
|
+
sage: from sage.combinat.knutson_tao_puzzles import H_grassmannian_pieces
|
|
697
|
+
sage: x = H_grassmannian_pieces()
|
|
698
|
+
sage: hash(x) == hash(x)
|
|
699
|
+
True
|
|
700
|
+
"""
|
|
701
|
+
return hash((type(self), repr(self)))
|
|
702
|
+
|
|
703
|
+
def add_piece(self, piece, rotations=120):
|
|
704
|
+
r"""
|
|
705
|
+
Add ``piece`` to the list of pieces.
|
|
706
|
+
|
|
707
|
+
INPUT:
|
|
708
|
+
|
|
709
|
+
- ``piece`` -- a nabla piece or a delta piece
|
|
710
|
+
- ``rotations`` -- (default: 120) 0, 60, 120, 180
|
|
711
|
+
|
|
712
|
+
The user can add valid nabla or delta pieces and specify
|
|
713
|
+
which rotations of these pieces are legal. For example, ``rotations=0``
|
|
714
|
+
does not add any additional pieces (only the piece itself), ``rotations=60`` adds
|
|
715
|
+
six pieces (namely three delta and three nabla pieces), while
|
|
716
|
+
``rotations=120`` adds only delta or nabla (depending on which piece ``self`` is).
|
|
717
|
+
``rotations=180`` adds the piece and its 180 degree rotation, i.e. one delta and one
|
|
718
|
+
nabla piece.
|
|
719
|
+
|
|
720
|
+
EXAMPLES::
|
|
721
|
+
|
|
722
|
+
sage: from sage.combinat.knutson_tao_puzzles import PuzzlePieces, DeltaPiece
|
|
723
|
+
sage: delta = DeltaPiece('a','b','c')
|
|
724
|
+
sage: pieces = PuzzlePieces()
|
|
725
|
+
sage: pieces
|
|
726
|
+
Nablas : []
|
|
727
|
+
Deltas : []
|
|
728
|
+
sage: pieces.add_piece(delta)
|
|
729
|
+
sage: pieces
|
|
730
|
+
Nablas : []
|
|
731
|
+
Deltas : [a/c\b, b/a\c, c/b\a]
|
|
732
|
+
|
|
733
|
+
sage: pieces = PuzzlePieces()
|
|
734
|
+
sage: pieces.add_piece(delta,rotations=0)
|
|
735
|
+
sage: pieces
|
|
736
|
+
Nablas : []
|
|
737
|
+
Deltas : [b/a\c]
|
|
738
|
+
|
|
739
|
+
sage: pieces = PuzzlePieces()
|
|
740
|
+
sage: pieces.add_piece(delta,rotations=60)
|
|
741
|
+
sage: pieces
|
|
742
|
+
Nablas : [a\b/c, b\c/a, c\a/b]
|
|
743
|
+
Deltas : [a/c\b, b/a\c, c/b\a]
|
|
744
|
+
"""
|
|
745
|
+
if isinstance(piece, NablaPiece):
|
|
746
|
+
pieces_list = self._nabla_pieces
|
|
747
|
+
else:
|
|
748
|
+
pieces_list = self._delta_pieces
|
|
749
|
+
pieces_list.add(piece)
|
|
750
|
+
if rotations == 120:
|
|
751
|
+
pieces_list.add(piece.clockwise_rotation())
|
|
752
|
+
pieces_list.add(piece.clockwise_rotation().clockwise_rotation())
|
|
753
|
+
elif rotations == 180:
|
|
754
|
+
self.add_piece(piece.half_turn_rotation(), rotations=0)
|
|
755
|
+
elif rotations == 60:
|
|
756
|
+
self.add_piece(piece, rotations=120)
|
|
757
|
+
self.add_piece(piece.half_turn_rotation(), rotations=120)
|
|
758
|
+
|
|
759
|
+
def add_forbidden_label(self, label):
|
|
760
|
+
r"""
|
|
761
|
+
Add forbidden border labels.
|
|
762
|
+
|
|
763
|
+
INPUT:
|
|
764
|
+
|
|
765
|
+
- ``label`` -- string specifying a new forbidden label
|
|
766
|
+
|
|
767
|
+
EXAMPLES::
|
|
768
|
+
|
|
769
|
+
sage: from sage.combinat.knutson_tao_puzzles import PuzzlePieces
|
|
770
|
+
sage: pieces = PuzzlePieces()
|
|
771
|
+
sage: pieces.add_forbidden_label('1')
|
|
772
|
+
sage: pieces._forbidden_border_labels
|
|
773
|
+
['1']
|
|
774
|
+
sage: pieces.add_forbidden_label('2')
|
|
775
|
+
sage: pieces._forbidden_border_labels
|
|
776
|
+
['1', '2']
|
|
777
|
+
"""
|
|
778
|
+
self._forbidden_border_labels.append(label)
|
|
779
|
+
|
|
780
|
+
def add_T_piece(self, label1, label2):
|
|
781
|
+
r"""
|
|
782
|
+
Add a nabla and delta piece with ``label1`` and ``label2``.
|
|
783
|
+
|
|
784
|
+
This method adds a nabla piece with edges ``label2``\ T``label1``|``label2`` / ``label1``.
|
|
785
|
+
and a delta piece with edges ``label1``/ T``label1``|``label2`` \ ``label2``.
|
|
786
|
+
It also adds T``label1``|``label2`` to the forbidden list.
|
|
787
|
+
|
|
788
|
+
EXAMPLES::
|
|
789
|
+
|
|
790
|
+
sage: from sage.combinat.knutson_tao_puzzles import PuzzlePieces
|
|
791
|
+
sage: pieces = PuzzlePieces()
|
|
792
|
+
sage: pieces.add_T_piece('1','3')
|
|
793
|
+
sage: pieces
|
|
794
|
+
Nablas : [3\T1|3/1]
|
|
795
|
+
Deltas : [1/T1|3\3]
|
|
796
|
+
sage: pieces._forbidden_border_labels
|
|
797
|
+
['T1|3']
|
|
798
|
+
"""
|
|
799
|
+
self.add_forbidden_label('T%s|%s' % (label1, label2))
|
|
800
|
+
self.add_piece(NablaPiece('T%s|%s' % (label1, label2), label1, label2), rotations=180)
|
|
801
|
+
|
|
802
|
+
def __repr__(self) -> str:
|
|
803
|
+
r"""
|
|
804
|
+
TESTS::
|
|
805
|
+
|
|
806
|
+
sage: from sage.combinat.knutson_tao_puzzles import PuzzlePieces, DeltaPiece
|
|
807
|
+
sage: pieces = PuzzlePieces()
|
|
808
|
+
sage: delta = DeltaPiece('a','b','c')
|
|
809
|
+
sage: pieces.add_piece(delta,rotations=60)
|
|
810
|
+
sage: pieces
|
|
811
|
+
Nablas : [a\b/c, b\c/a, c\a/b]
|
|
812
|
+
Deltas : [a/c\b, b/a\c, c/b\a]
|
|
813
|
+
"""
|
|
814
|
+
s = "Nablas : %s\n" % sorted(self._nabla_pieces, key=str)
|
|
815
|
+
s += "Deltas : %s" % sorted(self._delta_pieces, key=str)
|
|
816
|
+
return s
|
|
817
|
+
|
|
818
|
+
def delta_pieces(self):
|
|
819
|
+
r"""
|
|
820
|
+
Return the delta pieces as a set.
|
|
821
|
+
|
|
822
|
+
EXAMPLES::
|
|
823
|
+
|
|
824
|
+
sage: from sage.combinat.knutson_tao_puzzles import PuzzlePieces, DeltaPiece
|
|
825
|
+
sage: pieces = PuzzlePieces()
|
|
826
|
+
sage: delta = DeltaPiece('a','b','c')
|
|
827
|
+
sage: pieces.add_piece(delta,rotations=60)
|
|
828
|
+
sage: sorted([p for p in pieces.delta_pieces()], key=str)
|
|
829
|
+
[a/c\b, b/a\c, c/b\a]
|
|
830
|
+
"""
|
|
831
|
+
return self._delta_pieces
|
|
832
|
+
|
|
833
|
+
def nabla_pieces(self):
|
|
834
|
+
r"""
|
|
835
|
+
Return the nabla pieces as a set.
|
|
836
|
+
|
|
837
|
+
EXAMPLES::
|
|
838
|
+
|
|
839
|
+
sage: from sage.combinat.knutson_tao_puzzles import PuzzlePieces, DeltaPiece
|
|
840
|
+
sage: pieces = PuzzlePieces()
|
|
841
|
+
sage: delta = DeltaPiece('a','b','c')
|
|
842
|
+
sage: pieces.add_piece(delta,rotations=60)
|
|
843
|
+
sage: sorted([p for p in pieces.nabla_pieces()], key=str)
|
|
844
|
+
[a\b/c, b\c/a, c\a/b]
|
|
845
|
+
"""
|
|
846
|
+
return self._nabla_pieces
|
|
847
|
+
|
|
848
|
+
def rhombus_pieces(self) -> set:
|
|
849
|
+
r"""
|
|
850
|
+
Return a set of all allowable rhombus pieces.
|
|
851
|
+
|
|
852
|
+
Allowable rhombus pieces are those where the south edge of the delta
|
|
853
|
+
piece equals the north edge of the nabla piece.
|
|
854
|
+
|
|
855
|
+
EXAMPLES::
|
|
856
|
+
|
|
857
|
+
sage: from sage.combinat.knutson_tao_puzzles import PuzzlePieces, DeltaPiece
|
|
858
|
+
sage: pieces = PuzzlePieces()
|
|
859
|
+
sage: delta = DeltaPiece('a','b','c')
|
|
860
|
+
sage: pieces.add_piece(delta,rotations=60)
|
|
861
|
+
sage: sorted([p for p in pieces.rhombus_pieces()], key=str)
|
|
862
|
+
[a/\b b\/a, b/\c c\/b, c/\a a\/c]
|
|
863
|
+
"""
|
|
864
|
+
rhombi = set()
|
|
865
|
+
for nabla in self._nabla_pieces:
|
|
866
|
+
for delta in self._delta_pieces:
|
|
867
|
+
if delta['south'] == nabla['north']:
|
|
868
|
+
rhombi.add(RhombusPiece(delta, nabla))
|
|
869
|
+
return rhombi
|
|
870
|
+
|
|
871
|
+
def boundary_deltas(self) -> tuple:
|
|
872
|
+
r"""
|
|
873
|
+
Return deltas with south edges not in the forbidden list.
|
|
874
|
+
|
|
875
|
+
EXAMPLES::
|
|
876
|
+
|
|
877
|
+
sage: from sage.combinat.knutson_tao_puzzles import PuzzlePieces, DeltaPiece
|
|
878
|
+
sage: pieces = PuzzlePieces(['a'])
|
|
879
|
+
sage: delta = DeltaPiece('a','b','c')
|
|
880
|
+
sage: pieces.add_piece(delta,rotations=60)
|
|
881
|
+
sage: sorted([p for p in pieces.boundary_deltas()], key=str)
|
|
882
|
+
[a/c\b, c/b\a]
|
|
883
|
+
"""
|
|
884
|
+
return tuple(delta for delta in self.delta_pieces()
|
|
885
|
+
if delta['south'] not in self._forbidden_border_labels)
|
|
886
|
+
|
|
887
|
+
|
|
888
|
+
def H_grassmannian_pieces():
|
|
889
|
+
r"""
|
|
890
|
+
Define the puzzle pieces used in computing the cohomology of the Grassmannian.
|
|
891
|
+
|
|
892
|
+
REFERENCES:
|
|
893
|
+
|
|
894
|
+
.. [KTW] Allen Knutson, Terence Tao, Christopher Woodward,
|
|
895
|
+
The honeycomb model of GL(n) tensor products II: Puzzles determine facets of the Littlewood-Richardson cone,
|
|
896
|
+
:arxiv:`math/0107011`
|
|
897
|
+
|
|
898
|
+
EXAMPLES::
|
|
899
|
+
|
|
900
|
+
sage: from sage.combinat.knutson_tao_puzzles import H_grassmannian_pieces
|
|
901
|
+
sage: H_grassmannian_pieces()
|
|
902
|
+
Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1]
|
|
903
|
+
Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1]
|
|
904
|
+
"""
|
|
905
|
+
forbidden_border_labels = ['10']
|
|
906
|
+
pieces = PuzzlePieces(forbidden_border_labels)
|
|
907
|
+
pieces.add_piece(NablaPiece('0', '0', '0'), rotations=60)
|
|
908
|
+
pieces.add_piece(NablaPiece('1', '1', '1'), rotations=60)
|
|
909
|
+
pieces.add_piece(NablaPiece('1', '0', '10'), rotations=60)
|
|
910
|
+
return pieces
|
|
911
|
+
|
|
912
|
+
|
|
913
|
+
def HT_grassmannian_pieces():
|
|
914
|
+
r"""
|
|
915
|
+
Define the puzzle pieces used in computing the torus-equivariant cohomology of the Grassmannian.
|
|
916
|
+
|
|
917
|
+
REFERENCES:
|
|
918
|
+
|
|
919
|
+
.. [KT2003] Allen Knutson, Terence Tao, Puzzles and (equivariant) cohomology of Grassmannians,
|
|
920
|
+
Duke Math. J. 119 (2003) 221
|
|
921
|
+
|
|
922
|
+
EXAMPLES::
|
|
923
|
+
|
|
924
|
+
sage: from sage.combinat.knutson_tao_puzzles import HT_grassmannian_pieces
|
|
925
|
+
sage: HT_grassmannian_pieces()
|
|
926
|
+
Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1, 1\T0|1/0]
|
|
927
|
+
Deltas : [0/0\0, 0/1\10, 0/T0|1\1, 1/10\0, 1/1\1, 10/0\1]
|
|
928
|
+
"""
|
|
929
|
+
pieces = H_grassmannian_pieces()
|
|
930
|
+
pieces.add_T_piece('0', '1')
|
|
931
|
+
return pieces
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
def K_grassmannian_pieces():
|
|
935
|
+
r"""
|
|
936
|
+
Define the puzzle pieces used in computing the K-theory of the Grassmannian.
|
|
937
|
+
|
|
938
|
+
REFERENCES:
|
|
939
|
+
|
|
940
|
+
.. [Buch00] \A. Buch, A Littlewood-Richardson rule for the K-theory of Grassmannians, :arxiv:`math.AG/0004137`
|
|
941
|
+
|
|
942
|
+
EXAMPLES::
|
|
943
|
+
|
|
944
|
+
sage: from sage.combinat.knutson_tao_puzzles import K_grassmannian_pieces
|
|
945
|
+
sage: K_grassmannian_pieces()
|
|
946
|
+
Nablas : [0\0/0, 0\10/1, 0\K/1, 10\1/0, 1\0/10, 1\0/K, 1\1/1, K\1/0]
|
|
947
|
+
Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1, K/K\K]
|
|
948
|
+
"""
|
|
949
|
+
pieces = H_grassmannian_pieces()
|
|
950
|
+
pieces.add_forbidden_label('K')
|
|
951
|
+
pieces.add_piece(NablaPiece('0', 'K', '1'), rotations=120)
|
|
952
|
+
pieces.add_piece(DeltaPiece('K', 'K', 'K'), rotations=0)
|
|
953
|
+
return pieces
|
|
954
|
+
|
|
955
|
+
|
|
956
|
+
def H_two_step_pieces():
|
|
957
|
+
r"""
|
|
958
|
+
Define the puzzle pieces used in two step flags.
|
|
959
|
+
|
|
960
|
+
This rule is currently only conjecturally true. See [BuchKreschTamvakis03]_.
|
|
961
|
+
|
|
962
|
+
REFERENCES:
|
|
963
|
+
|
|
964
|
+
.. [BuchKreschTamvakis03] \A. Buch, A. Kresch, H. Tamvakis, Gromov-Witten invariants on Grassmannian, :arxiv:`math/0306388`
|
|
965
|
+
|
|
966
|
+
EXAMPLES::
|
|
967
|
+
|
|
968
|
+
sage: from sage.combinat.knutson_tao_puzzles import H_two_step_pieces
|
|
969
|
+
sage: H_two_step_pieces()
|
|
970
|
+
Nablas : [(21)0\21/0, 0\(21)0/21, 0\0/0, 0\10/1, 0\20/2, 10\1/0, 10\2(10)/2, 1\0/10, 1\1/1, 1\21/2,
|
|
971
|
+
2(10)\2/10, 20\2/0, 21\0/(21)0, 21\2/1, 2\0/20, 2\1/21, 2\10/2(10), 2\2/2]
|
|
972
|
+
Deltas : [(21)0/0\21, 0/0\0, 0/1\10, 0/21\(21)0, 0/2\20, 1/10\0, 1/1\1, 1/2\21, 10/0\1, 10/2\2(10),
|
|
973
|
+
2(10)/10\2, 2/2(10)\10, 2/20\0, 2/21\1, 2/2\2, 20/0\2, 21/(21)0\0, 21/1\2]
|
|
974
|
+
"""
|
|
975
|
+
forbidden_border_labels = ['10', '20', '21', '(21)0', '2(10)']
|
|
976
|
+
pieces = PuzzlePieces(forbidden_border_labels)
|
|
977
|
+
for i in ('0', '1', '2'):
|
|
978
|
+
pieces.add_piece(DeltaPiece(i, i, i), rotations=60)
|
|
979
|
+
for i, j in (('1', '0'), ('2', '0'), ('2', '1')):
|
|
980
|
+
pieces.add_piece(DeltaPiece(i + j, i, j), rotations=60)
|
|
981
|
+
pieces.add_piece(DeltaPiece('(21)0', '21', '0'), rotations=60)
|
|
982
|
+
pieces.add_piece(DeltaPiece('2(10)', '2', '10'), rotations=60)
|
|
983
|
+
return pieces
|
|
984
|
+
|
|
985
|
+
|
|
986
|
+
def HT_two_step_pieces():
|
|
987
|
+
r"""
|
|
988
|
+
Define the puzzle pieces used in computing the equivariant two step puzzle pieces.
|
|
989
|
+
|
|
990
|
+
For the puzzle pieces, see Figure 26 on page 22 of [CoskunVakil06]_.
|
|
991
|
+
|
|
992
|
+
REFERENCES:
|
|
993
|
+
|
|
994
|
+
.. [CoskunVakil06] \I. Coskun, R. Vakil, Geometric positivity in the cohomology of homogeneous spaces
|
|
995
|
+
and generalized Schubert calculus, :arxiv:`math/0610538`
|
|
996
|
+
|
|
997
|
+
EXAMPLES::
|
|
998
|
+
|
|
999
|
+
sage: from sage.combinat.knutson_tao_puzzles import HT_two_step_pieces
|
|
1000
|
+
sage: HT_two_step_pieces()
|
|
1001
|
+
Nablas : [(21)0\21/0, 0\(21)0/21, 0\0/0, 0\10/1, 0\20/2, 10\1/0, 10\2(10)/2,
|
|
1002
|
+
1\0/10, 1\1/1, 1\21/2, 1\T0|1/0, 2(10)\2/10, 20\2/0, 21\0/(21)0, 21\2/1, 21\T0|21/0,
|
|
1003
|
+
21\T10|21/10, 2\0/20, 2\1/21, 2\10/2(10), 2\2/2, 2\T0|2/0, 2\T10|2/10, 2\T1|2/1]
|
|
1004
|
+
Deltas : [(21)0/0\21, 0/0\0, 0/1\10, 0/21\(21)0, 0/2\20, 0/T0|1\1, 0/T0|21\21, 0/T0|2\2,
|
|
1005
|
+
1/10\0, 1/1\1, 1/2\21, 1/T1|2\2, 10/0\1, 10/2\2(10), 10/T10|21\21, 10/T10|2\2, 2(10)/10\2,
|
|
1006
|
+
2/2(10)\10, 2/20\0, 2/21\1, 2/2\2, 20/0\2, 21/(21)0\0, 21/1\2]
|
|
1007
|
+
"""
|
|
1008
|
+
pieces = H_two_step_pieces()
|
|
1009
|
+
for label1, label2 in (('0', '1'), ('0', '2'), ('1', '2'),
|
|
1010
|
+
('10', '2'), ('0', '21'), ('10', '21')):
|
|
1011
|
+
pieces.add_T_piece(label1, label2)
|
|
1012
|
+
return pieces
|
|
1013
|
+
|
|
1014
|
+
|
|
1015
|
+
def BK_pieces(max_letter):
|
|
1016
|
+
r"""
|
|
1017
|
+
The puzzle pieces used in computing the Belkale-Kumar coefficients for any
|
|
1018
|
+
partial flag variety in type `A`.
|
|
1019
|
+
|
|
1020
|
+
There are two types of puzzle pieces:
|
|
1021
|
+
|
|
1022
|
+
- a triangle, with each edge labeled with the same letter;
|
|
1023
|
+
- a rhombus, with edges labeled `i`, `j`, `i`, `j` in clockwise order with
|
|
1024
|
+
`i > j`.
|
|
1025
|
+
|
|
1026
|
+
Each of these is rotated by 60 degrees, but not reflected.
|
|
1027
|
+
|
|
1028
|
+
We model the rhombus pieces as two triangles: a delta piece north-west
|
|
1029
|
+
label `i`, north-east label `j` and south label `i(j)`; and a nabla piece
|
|
1030
|
+
with south-east label `i`, south-west label `j` and north label `i(j)`.
|
|
1031
|
+
|
|
1032
|
+
INPUT:
|
|
1033
|
+
|
|
1034
|
+
- ``max_letter`` -- positive integer specifying the number of steps in the
|
|
1035
|
+
partial flag variety, equivalently, the number of elements in the
|
|
1036
|
+
alphabet for the edge labels. The smallest label is `1`.
|
|
1037
|
+
|
|
1038
|
+
REFERENCES:
|
|
1039
|
+
|
|
1040
|
+
.. [KnutsonPurbhoo10] \A. Knutson, K. Purbhoo, Product and puzzle formulae
|
|
1041
|
+
for `GL_n` Belkale-Kumar coefficients, :arxiv:`1008.4979`
|
|
1042
|
+
|
|
1043
|
+
EXAMPLES::
|
|
1044
|
+
|
|
1045
|
+
sage: from sage.combinat.knutson_tao_puzzles import BK_pieces
|
|
1046
|
+
sage: BK_pieces(3)
|
|
1047
|
+
Nablas : [1\1/1, 1\2(1)/2, 1\3(1)/3, 2(1)\2/1, 2\1/2(1), 2\2/2, 2\3(2)/3, 3(1)\3/1, 3(2)\3/2, 3\1/3(1), 3\2/3(2), 3\3/3]
|
|
1048
|
+
Deltas : [1/1\1, 1/2\2(1), 1/3\3(1), 2(1)/1\2, 2/2(1)\1, 2/2\2, 2/3\3(2), 3(1)/1\3, 3(2)/2\3, 3/3(1)\1, 3/3(2)\2, 3/3\3]
|
|
1049
|
+
"""
|
|
1050
|
+
forbidden_border_labels = ['%s(%s)' % (i, j)
|
|
1051
|
+
for i in range(1, max_letter + 1)
|
|
1052
|
+
for j in range(1, i)]
|
|
1053
|
+
pieces = PuzzlePieces(forbidden_border_labels)
|
|
1054
|
+
for i in range(1, max_letter + 1):
|
|
1055
|
+
piece = DeltaPiece('%s' % i, '%s' % i, '%s' % i)
|
|
1056
|
+
pieces.add_piece(piece, rotations=60)
|
|
1057
|
+
for j in range(1, i):
|
|
1058
|
+
piece = DeltaPiece(north_west='%s' % i, north_east='%s' % j,
|
|
1059
|
+
south='%s(%s)' % (i, j))
|
|
1060
|
+
pieces.add_piece(piece, rotations=60)
|
|
1061
|
+
return pieces
|
|
1062
|
+
|
|
1063
|
+
|
|
1064
|
+
class PuzzleFilling:
|
|
1065
|
+
r"""
|
|
1066
|
+
Create partial puzzles and provides methods to build puzzles from them.
|
|
1067
|
+
"""
|
|
1068
|
+
|
|
1069
|
+
def __init__(self, north_west_labels, north_east_labels):
|
|
1070
|
+
r"""
|
|
1071
|
+
TESTS::
|
|
1072
|
+
|
|
1073
|
+
sage: from sage.combinat.knutson_tao_puzzles import PuzzleFilling
|
|
1074
|
+
sage: P = PuzzleFilling('0101','0101')
|
|
1075
|
+
sage: P
|
|
1076
|
+
{}
|
|
1077
|
+
"""
|
|
1078
|
+
self._nw_labels = tuple(north_west_labels)
|
|
1079
|
+
self._ne_labels = tuple(north_east_labels)
|
|
1080
|
+
self._squares = {}
|
|
1081
|
+
self._n = len(self._nw_labels)
|
|
1082
|
+
self._kink_coordinates = (1, self._n)
|
|
1083
|
+
|
|
1084
|
+
def __getitem__(self, key):
|
|
1085
|
+
r"""
|
|
1086
|
+
TESTS::
|
|
1087
|
+
|
|
1088
|
+
sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver
|
|
1089
|
+
sage: ps = KnutsonTaoPuzzleSolver("H")
|
|
1090
|
+
sage: puzzle = ps('0101','1001')[0]
|
|
1091
|
+
sage: puzzle
|
|
1092
|
+
{(1, 1): 0/1\10,
|
|
1093
|
+
(1, 2): 1/\1 10\/0,
|
|
1094
|
+
(1, 3): 0/\10 1\/1,
|
|
1095
|
+
(1, 4): 1/\1 10\/0,
|
|
1096
|
+
(2, 2): 0/0\0,
|
|
1097
|
+
(2, 3): 1/\0 0\/1,
|
|
1098
|
+
(2, 4): 0/\0 0\/0,
|
|
1099
|
+
(3, 3): 1/1\1,
|
|
1100
|
+
(3, 4): 0/\0 1\/10,
|
|
1101
|
+
(4, 4): 10/0\1}
|
|
1102
|
+
sage: puzzle[(1,2)] # indirect doctest
|
|
1103
|
+
1/\1 10\/0
|
|
1104
|
+
"""
|
|
1105
|
+
return self._squares[key]
|
|
1106
|
+
|
|
1107
|
+
def kink_coordinates(self) -> tuple:
|
|
1108
|
+
r"""
|
|
1109
|
+
Provide the coordinates of the kinks.
|
|
1110
|
+
|
|
1111
|
+
The kink coordinates are the coordinates up to which the puzzle has already
|
|
1112
|
+
been built. The kink starts in the north corner and then moves down the diagonals
|
|
1113
|
+
as the puzzles is built.
|
|
1114
|
+
|
|
1115
|
+
EXAMPLES::
|
|
1116
|
+
|
|
1117
|
+
sage: from sage.combinat.knutson_tao_puzzles import PuzzleFilling
|
|
1118
|
+
sage: P = PuzzleFilling('0101','0101')
|
|
1119
|
+
sage: P
|
|
1120
|
+
{}
|
|
1121
|
+
sage: P.kink_coordinates()
|
|
1122
|
+
(1, 4)
|
|
1123
|
+
"""
|
|
1124
|
+
return self._kink_coordinates
|
|
1125
|
+
|
|
1126
|
+
def is_in_south_edge(self) -> bool:
|
|
1127
|
+
r"""
|
|
1128
|
+
Check whether kink coordinates of partial puzzle is in south corner.
|
|
1129
|
+
|
|
1130
|
+
EXAMPLES::
|
|
1131
|
+
|
|
1132
|
+
sage: from sage.combinat.knutson_tao_puzzles import PuzzleFilling
|
|
1133
|
+
sage: P = PuzzleFilling('0101','0101')
|
|
1134
|
+
sage: P.is_in_south_edge()
|
|
1135
|
+
False
|
|
1136
|
+
"""
|
|
1137
|
+
i, j = self.kink_coordinates()
|
|
1138
|
+
return i == j
|
|
1139
|
+
|
|
1140
|
+
def north_west_label_of_kink(self):
|
|
1141
|
+
r"""
|
|
1142
|
+
Return north-west label of kink.
|
|
1143
|
+
|
|
1144
|
+
EXAMPLES::
|
|
1145
|
+
|
|
1146
|
+
sage: from sage.combinat.knutson_tao_puzzles import PuzzleFilling
|
|
1147
|
+
sage: P = PuzzleFilling('0101','0101')
|
|
1148
|
+
sage: P.north_west_label_of_kink()
|
|
1149
|
+
'1'
|
|
1150
|
+
"""
|
|
1151
|
+
(i, j) = self.kink_coordinates()
|
|
1152
|
+
if i == 1:
|
|
1153
|
+
return self._nw_labels[j - 1]
|
|
1154
|
+
else:
|
|
1155
|
+
return self._squares[i - 1, j]['south_east']
|
|
1156
|
+
|
|
1157
|
+
def north_east_label_of_kink(self):
|
|
1158
|
+
r"""
|
|
1159
|
+
Return north east label of kink.
|
|
1160
|
+
|
|
1161
|
+
EXAMPLES::
|
|
1162
|
+
|
|
1163
|
+
sage: from sage.combinat.knutson_tao_puzzles import PuzzleFilling
|
|
1164
|
+
sage: P = PuzzleFilling('0101','0101')
|
|
1165
|
+
sage: P.north_east_label_of_kink()
|
|
1166
|
+
'0'
|
|
1167
|
+
"""
|
|
1168
|
+
(i, j) = self.kink_coordinates()
|
|
1169
|
+
if j == self._n:
|
|
1170
|
+
return self._ne_labels[i - 1]
|
|
1171
|
+
else:
|
|
1172
|
+
return self._squares[i, j + 1]['south_west']
|
|
1173
|
+
|
|
1174
|
+
def is_completed(self):
|
|
1175
|
+
r"""
|
|
1176
|
+
Whether partial puzzle is complete (completely filled) or not.
|
|
1177
|
+
|
|
1178
|
+
EXAMPLES::
|
|
1179
|
+
|
|
1180
|
+
sage: from sage.combinat.knutson_tao_puzzles import PuzzleFilling
|
|
1181
|
+
sage: P = PuzzleFilling('0101','0101')
|
|
1182
|
+
sage: P.is_completed()
|
|
1183
|
+
False
|
|
1184
|
+
|
|
1185
|
+
sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver
|
|
1186
|
+
sage: ps = KnutsonTaoPuzzleSolver("H")
|
|
1187
|
+
sage: puzzle = ps('0101','1001')[0]
|
|
1188
|
+
sage: puzzle.is_completed()
|
|
1189
|
+
True
|
|
1190
|
+
"""
|
|
1191
|
+
i, _ = self.kink_coordinates()
|
|
1192
|
+
return i == self._n + 1
|
|
1193
|
+
|
|
1194
|
+
def south_labels(self):
|
|
1195
|
+
r"""
|
|
1196
|
+
Return south labels for completed puzzle.
|
|
1197
|
+
|
|
1198
|
+
EXAMPLES::
|
|
1199
|
+
|
|
1200
|
+
sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver
|
|
1201
|
+
sage: ps = KnutsonTaoPuzzleSolver("H")
|
|
1202
|
+
sage: ps('0101','1001')[0].south_labels()
|
|
1203
|
+
('1', '0', '1', '0')
|
|
1204
|
+
"""
|
|
1205
|
+
# TODO: return ''.join(self[i, i]['south'] for i in range(1, self._n + 1))
|
|
1206
|
+
return tuple([self[i, i]['south'] for i in range(1, self._n + 1)])
|
|
1207
|
+
|
|
1208
|
+
def add_piece(self, piece):
|
|
1209
|
+
r"""
|
|
1210
|
+
Add ``piece`` to partial puzzle.
|
|
1211
|
+
|
|
1212
|
+
EXAMPLES::
|
|
1213
|
+
|
|
1214
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece, PuzzleFilling
|
|
1215
|
+
sage: piece = DeltaPiece('0','1','0')
|
|
1216
|
+
sage: P = PuzzleFilling('0101','0101'); P
|
|
1217
|
+
{}
|
|
1218
|
+
sage: P.add_piece(piece); P
|
|
1219
|
+
{(1, 4): 1/0\0}
|
|
1220
|
+
"""
|
|
1221
|
+
i, j = self.kink_coordinates()
|
|
1222
|
+
self._squares[i, j] = piece
|
|
1223
|
+
if isinstance(piece, DeltaPiece):
|
|
1224
|
+
i += 1
|
|
1225
|
+
j = self._n
|
|
1226
|
+
else:
|
|
1227
|
+
j -= 1
|
|
1228
|
+
self._kink_coordinates = (i, j)
|
|
1229
|
+
|
|
1230
|
+
def add_pieces(self, pieces):
|
|
1231
|
+
r"""
|
|
1232
|
+
Add ``piece`` to partial puzzle.
|
|
1233
|
+
|
|
1234
|
+
INPUT:
|
|
1235
|
+
|
|
1236
|
+
- ``pieces`` -- tuple of pieces
|
|
1237
|
+
|
|
1238
|
+
EXAMPLES::
|
|
1239
|
+
|
|
1240
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece, PuzzleFilling
|
|
1241
|
+
sage: P = PuzzleFilling('0101','0101'); P
|
|
1242
|
+
{}
|
|
1243
|
+
sage: piece = DeltaPiece('0','1','0')
|
|
1244
|
+
sage: pieces = [piece,piece]
|
|
1245
|
+
sage: P.add_pieces(pieces)
|
|
1246
|
+
sage: P
|
|
1247
|
+
{(1, 4): 1/0\0, (2, 4): 1/0\0}
|
|
1248
|
+
"""
|
|
1249
|
+
i, j = self.kink_coordinates()
|
|
1250
|
+
for piece in pieces:
|
|
1251
|
+
self._squares[i, j] = piece
|
|
1252
|
+
if isinstance(piece, DeltaPiece):
|
|
1253
|
+
i += 1
|
|
1254
|
+
j = self._n
|
|
1255
|
+
else:
|
|
1256
|
+
j -= 1
|
|
1257
|
+
self._kink_coordinates = (i, j)
|
|
1258
|
+
|
|
1259
|
+
def copy(self):
|
|
1260
|
+
r"""
|
|
1261
|
+
Return copy of ``self``.
|
|
1262
|
+
|
|
1263
|
+
EXAMPLES::
|
|
1264
|
+
|
|
1265
|
+
|
|
1266
|
+
sage: from sage.combinat.knutson_tao_puzzles import DeltaPiece, PuzzleFilling
|
|
1267
|
+
sage: piece = DeltaPiece('0','1','0')
|
|
1268
|
+
sage: P = PuzzleFilling('0101','0101'); P
|
|
1269
|
+
{}
|
|
1270
|
+
sage: PP = P.copy()
|
|
1271
|
+
sage: P.add_piece(piece); P
|
|
1272
|
+
{(1, 4): 1/0\0}
|
|
1273
|
+
sage: PP
|
|
1274
|
+
{}
|
|
1275
|
+
"""
|
|
1276
|
+
PP = PuzzleFilling(self._nw_labels, self._ne_labels)
|
|
1277
|
+
PP._squares = self._squares.copy()
|
|
1278
|
+
PP._kink_coordinates = self._kink_coordinates
|
|
1279
|
+
PP._n = self._n
|
|
1280
|
+
return PP
|
|
1281
|
+
|
|
1282
|
+
def contribution(self):
|
|
1283
|
+
r"""
|
|
1284
|
+
Return equivariant contributions from ``self`` in polynomial ring.
|
|
1285
|
+
|
|
1286
|
+
EXAMPLES::
|
|
1287
|
+
|
|
1288
|
+
sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver
|
|
1289
|
+
sage: ps = KnutsonTaoPuzzleSolver("HT")
|
|
1290
|
+
sage: puzzles = ps('0101','1001')
|
|
1291
|
+
sage: sorted([p.contribution() for p in puzzles], key=str)
|
|
1292
|
+
[1, y1 - y3]
|
|
1293
|
+
"""
|
|
1294
|
+
R = PolynomialRing(Integers(), 'y', self._n + 1)
|
|
1295
|
+
y = R.gens()
|
|
1296
|
+
z = R.one()
|
|
1297
|
+
for i in range(1, self._n + 1):
|
|
1298
|
+
for j in range(i + 1, self._n + 1):
|
|
1299
|
+
if self[i, j].north_piece()['south'].startswith('T'):
|
|
1300
|
+
z *= y[i] - y[j]
|
|
1301
|
+
if self[i, j].north_piece()['south'].startswith('K'):
|
|
1302
|
+
z *= -1
|
|
1303
|
+
return z
|
|
1304
|
+
|
|
1305
|
+
def __repr__(self):
|
|
1306
|
+
r"""
|
|
1307
|
+
TESTS::
|
|
1308
|
+
|
|
1309
|
+
sage: from sage.combinat.knutson_tao_puzzles import H_grassmannian_pieces, PuzzleFilling
|
|
1310
|
+
sage: P = PuzzleFilling('0101','0101'); P
|
|
1311
|
+
{}
|
|
1312
|
+
sage: P.__repr__()
|
|
1313
|
+
'{}'
|
|
1314
|
+
"""
|
|
1315
|
+
from pprint import pformat
|
|
1316
|
+
return pformat(self._squares)
|
|
1317
|
+
|
|
1318
|
+
def __iter__(self):
|
|
1319
|
+
r"""
|
|
1320
|
+
Iterator.
|
|
1321
|
+
|
|
1322
|
+
TESTS::
|
|
1323
|
+
|
|
1324
|
+
sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver
|
|
1325
|
+
sage: ps = KnutsonTaoPuzzleSolver("H")
|
|
1326
|
+
sage: puzzle = ps('0101','1001')[0]
|
|
1327
|
+
sage: puzzle
|
|
1328
|
+
{(1, 1): 0/1\10,
|
|
1329
|
+
(1, 2): 1/\1 10\/0,
|
|
1330
|
+
(1, 3): 0/\10 1\/1,
|
|
1331
|
+
(1, 4): 1/\1 10\/0,
|
|
1332
|
+
(2, 2): 0/0\0,
|
|
1333
|
+
(2, 3): 1/\0 0\/1,
|
|
1334
|
+
(2, 4): 0/\0 0\/0,
|
|
1335
|
+
(3, 3): 1/1\1,
|
|
1336
|
+
(3, 4): 0/\0 1\/10,
|
|
1337
|
+
(4, 4): 10/0\1}
|
|
1338
|
+
sage: [p for p in puzzle]
|
|
1339
|
+
[1/\1 10\/0,
|
|
1340
|
+
0/\10 1\/1,
|
|
1341
|
+
0/\0 0\/0,
|
|
1342
|
+
1/\1 10\/0,
|
|
1343
|
+
1/\0 0\/1,
|
|
1344
|
+
0/\0 1\/10,
|
|
1345
|
+
0/1\10,
|
|
1346
|
+
0/0\0,
|
|
1347
|
+
1/1\1,
|
|
1348
|
+
10/0\1]
|
|
1349
|
+
"""
|
|
1350
|
+
for d in range(self._n):
|
|
1351
|
+
for k in range(d + 1):
|
|
1352
|
+
yield self[k + 1, self._n - d + k]
|
|
1353
|
+
|
|
1354
|
+
def plot(self, labels=True, style='fill'):
|
|
1355
|
+
r"""
|
|
1356
|
+
Plot completed puzzle.
|
|
1357
|
+
|
|
1358
|
+
EXAMPLES::
|
|
1359
|
+
|
|
1360
|
+
sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver
|
|
1361
|
+
sage: ps = KnutsonTaoPuzzleSolver("H")
|
|
1362
|
+
sage: puzzle = ps('0101','1001')[0]
|
|
1363
|
+
sage: puzzle.plot() #not tested
|
|
1364
|
+
sage: puzzle.plot(style='fill') #not tested
|
|
1365
|
+
sage: puzzle.plot(style='edges') #not tested
|
|
1366
|
+
"""
|
|
1367
|
+
P = Graphics()
|
|
1368
|
+
coords = [(k, -d) for d in range(self._n) for k in range(-d, d + 1, 2)]
|
|
1369
|
+
for ((k, d), piece) in zip(coords, self):
|
|
1370
|
+
if isinstance(piece, RhombusPiece):
|
|
1371
|
+
for (i, triangle) in enumerate(piece):
|
|
1372
|
+
P += triangle._plot_piece([(k, d - 2 * i), (k - 1, d - 1), (k + 1, d - 1)], style=style)
|
|
1373
|
+
if labels:
|
|
1374
|
+
P += piece._plot_label(piece['north_west'], (k - 0.5, d - 0.5), rotation=60)
|
|
1375
|
+
P += piece._plot_label(piece['north_east'], (k + 0.5, d - 0.5), rotation=-60)
|
|
1376
|
+
P += piece._plot_label(piece.north_piece()['south'], (k, d - 1))
|
|
1377
|
+
else:
|
|
1378
|
+
P += piece._plot_piece([(k, d), (k - 1, d - 1), (k + 1, d - 1)], style=style)
|
|
1379
|
+
if labels:
|
|
1380
|
+
P += piece._plot_label(piece['north_west'], (k - 0.5, d - 0.5), rotation=60)
|
|
1381
|
+
P += piece._plot_label(piece['north_east'], (k + 0.5, d - 0.5), rotation=-60)
|
|
1382
|
+
P += piece._plot_label(piece['south'], (k, d - 1))
|
|
1383
|
+
P.set_aspect_ratio(1.73)
|
|
1384
|
+
P.axes(False)
|
|
1385
|
+
return P
|
|
1386
|
+
|
|
1387
|
+
def _latex_(self):
|
|
1388
|
+
r"""
|
|
1389
|
+
Return latex version of ``self``.
|
|
1390
|
+
|
|
1391
|
+
Note that you might need to add tikz to the preamble::
|
|
1392
|
+
|
|
1393
|
+
sage: latex.extra_preamble(r'''\usepackage{tikz}''')
|
|
1394
|
+
sage: from sage.combinat.knutson_tao_puzzles import *
|
|
1395
|
+
|
|
1396
|
+
sage: ps = KnutsonTaoPuzzleSolver(H_grassmannian_pieces())
|
|
1397
|
+
sage: solns = ps('0101', '0101')
|
|
1398
|
+
sage: view(solns[0], viewer='pdf') # not tested
|
|
1399
|
+
|
|
1400
|
+
sage: ps = KnutsonTaoPuzzleSolver(HT_two_step_pieces())
|
|
1401
|
+
sage: solns = ps(list('10212'), list('12012'))
|
|
1402
|
+
sage: view(solns[0], viewer='pdf') # not tested
|
|
1403
|
+
|
|
1404
|
+
sage: ps = KnutsonTaoPuzzleSolver(K_grassmannian_pieces())
|
|
1405
|
+
sage: solns = ps('0101', '0101')
|
|
1406
|
+
sage: view(solns[0], viewer='pdf') # not tested
|
|
1407
|
+
"""
|
|
1408
|
+
from collections import defaultdict
|
|
1409
|
+
label_colors = defaultdict(lambda: None)
|
|
1410
|
+
label_colors.update({'0': 'red', '1': 'blue', '2': 'green'})
|
|
1411
|
+
edge_colors = defaultdict(lambda: None)
|
|
1412
|
+
edge_colors.update({'0': 'red', '1': 'blue',
|
|
1413
|
+
'2': 'green', 'K': 'orange'})
|
|
1414
|
+
|
|
1415
|
+
s = r"""\begin{tikzpicture}[yscale=1.73]"""
|
|
1416
|
+
coords = [(k, -d) for d in range(self._n) for k in range(-d, d + 1, 2)]
|
|
1417
|
+
|
|
1418
|
+
def tikztriangle_fill(color, k, d, i, *args):
|
|
1419
|
+
s = r"""\path[color=%s, fill=%s!10]""" % (color, color)
|
|
1420
|
+
s += r"""(%s, %s) -- (%s, %s)""" % (k, d - 2 * i, k - 1, d - 1)
|
|
1421
|
+
s += r"""-- (%s, %s)""" % (k + 1, d - 1)
|
|
1422
|
+
s += r"""-- (%s, %s)""" % (k, d - 2 * i)
|
|
1423
|
+
s += ";\n"
|
|
1424
|
+
return s
|
|
1425
|
+
|
|
1426
|
+
def tikztriangle_edges(color, k, d, i, label1, label2, label3):
|
|
1427
|
+
s = ""
|
|
1428
|
+
if i == 1:
|
|
1429
|
+
return s
|
|
1430
|
+
tikzcmd = r"""\draw[color=%s, fill=none] (%s, %s) -- (%s, %s);""" + "\n"
|
|
1431
|
+
if edge_colors[label1]:
|
|
1432
|
+
s += tikzcmd % (edge_colors[label1], k - 1, d - 1, k + 1, d - 1)
|
|
1433
|
+
if edge_colors[label2]:
|
|
1434
|
+
s += tikzcmd % (edge_colors[label2], k, d - 2 * i, k - 1, d - 1)
|
|
1435
|
+
if edge_colors[label3]:
|
|
1436
|
+
s += tikzcmd % (edge_colors[label3], k + 1, d - 1, k, d - 2 * i)
|
|
1437
|
+
return s
|
|
1438
|
+
|
|
1439
|
+
def tikzlabels(color, k, d, i, label1, label2, label3):
|
|
1440
|
+
s = r"""\path[] (%s, %s)""" % (k, d - 2 * i)
|
|
1441
|
+
s += r"""-- (%s, %s) """ % (k - 1, d - 1)
|
|
1442
|
+
if label_colors[label2]:
|
|
1443
|
+
s += r"""node[midway, color=%s] {$%s$} """ % (label_colors[label2], label2)
|
|
1444
|
+
s += r"""-- (%s, %s) """ % (k + 1, d - 1)
|
|
1445
|
+
if label_colors[label1]:
|
|
1446
|
+
s += r"""node[midway, color=%s] {$%s$} """ % (label_colors[label1], label1)
|
|
1447
|
+
s += r"""-- (%s, %s) """ % (k, d - 2 * i)
|
|
1448
|
+
if label_colors[label3]:
|
|
1449
|
+
s += r"""node[midway, color=%s] {$%s$} """ % (label_colors[label3], label3)
|
|
1450
|
+
s += ";\n"
|
|
1451
|
+
return s
|
|
1452
|
+
|
|
1453
|
+
for ((k, d), piece) in zip(coords, self):
|
|
1454
|
+
for tikzcmd in (tikztriangle_fill, tikztriangle_edges, tikzlabels):
|
|
1455
|
+
if isinstance(piece, RhombusPiece):
|
|
1456
|
+
for (i, triangle) in enumerate([piece.north_piece(), piece.south_piece()]):
|
|
1457
|
+
if i == 0:
|
|
1458
|
+
s += tikzcmd(triangle.color(), k, d, i, *triangle.border())
|
|
1459
|
+
else:
|
|
1460
|
+
s += tikzcmd(triangle.color(), k, d, i, "", "", "")
|
|
1461
|
+
else:
|
|
1462
|
+
color = piece.color()
|
|
1463
|
+
s += tikzcmd(color, k, d, 0, *piece.border())
|
|
1464
|
+
|
|
1465
|
+
s += r"""\end{tikzpicture}"""
|
|
1466
|
+
|
|
1467
|
+
return s
|
|
1468
|
+
|
|
1469
|
+
|
|
1470
|
+
class KnutsonTaoPuzzleSolver(UniqueRepresentation):
|
|
1471
|
+
r"""
|
|
1472
|
+
Return puzzle solver function used to create all puzzles with given boundary conditions.
|
|
1473
|
+
|
|
1474
|
+
This class implements a generic algorithm to solve Knutson-Tao puzzles.
|
|
1475
|
+
An instance of this class will be callable: the arguments are the
|
|
1476
|
+
labels of north-east and north-west sides of the puzzle boundary; the
|
|
1477
|
+
output is the list of the fillings of the puzzle with the specified
|
|
1478
|
+
pieces.
|
|
1479
|
+
|
|
1480
|
+
INPUT:
|
|
1481
|
+
|
|
1482
|
+
- ``puzzle_pieces`` -- takes either a collection of puzzle pieces or
|
|
1483
|
+
a string indicating a pre-programmed collection of puzzle pieces:
|
|
1484
|
+
|
|
1485
|
+
- ``H`` -- cohomology of the Grassmannian
|
|
1486
|
+
- ``HT`` -- equivariant cohomology of the Grassmannian
|
|
1487
|
+
- ``K`` -- K-theory
|
|
1488
|
+
- ``H2step`` -- cohomology of the *2-step* Grassmannian
|
|
1489
|
+
- ``HT2step`` -- equivariant cohomology of the *2-step* Grassmannian
|
|
1490
|
+
- ``BK`` -- Belkale-Kumar puzzle pieces
|
|
1491
|
+
|
|
1492
|
+
- ``max_letter`` -- ``None`` or a positive integer(default: ``None``); this
|
|
1493
|
+
is only required for Belkale-Kumar puzzles
|
|
1494
|
+
|
|
1495
|
+
EXAMPLES:
|
|
1496
|
+
|
|
1497
|
+
Each puzzle piece is an edge-labelled triangle oriented in such a way
|
|
1498
|
+
that it has a south edge (called a *delta* piece) or a north edge
|
|
1499
|
+
(called a *nabla* piece). For example, the puzzle pieces corresponding
|
|
1500
|
+
to the cohomology of the Grassmannian are the following::
|
|
1501
|
+
|
|
1502
|
+
sage: from sage.combinat.knutson_tao_puzzles import H_grassmannian_pieces
|
|
1503
|
+
sage: H_grassmannian_pieces()
|
|
1504
|
+
Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1]
|
|
1505
|
+
Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1]
|
|
1506
|
+
|
|
1507
|
+
In the string representation, the nabla pieces are depicted as
|
|
1508
|
+
``c\a/b``, where `a` is the label of the north edge, `b` is the label
|
|
1509
|
+
of the south-east edge, `c` is the label of the south-west edge.
|
|
1510
|
+
A similar string representation exists for the delta pieces.
|
|
1511
|
+
|
|
1512
|
+
To create a puzzle solver, one specifies a collection of puzzle pieces::
|
|
1513
|
+
|
|
1514
|
+
sage: KnutsonTaoPuzzleSolver(H_grassmannian_pieces())
|
|
1515
|
+
Knutson-Tao puzzle solver with pieces:
|
|
1516
|
+
Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1]
|
|
1517
|
+
Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1]
|
|
1518
|
+
|
|
1519
|
+
The following shorthand to create the above puzzle solver is also supported::
|
|
1520
|
+
|
|
1521
|
+
sage: KnutsonTaoPuzzleSolver('H')
|
|
1522
|
+
Knutson-Tao puzzle solver with pieces:
|
|
1523
|
+
Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1]
|
|
1524
|
+
Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1]
|
|
1525
|
+
|
|
1526
|
+
The solver will compute all fillings of the puzzle with the given
|
|
1527
|
+
puzzle pieces. The user specifies the labels of north-east and
|
|
1528
|
+
north-west sides of the puzzle boundary and the output is a list of the
|
|
1529
|
+
fillings of the puzzle with the specified pieces. For example, there is
|
|
1530
|
+
one solution to the puzzle whose north-west and north-east edges are
|
|
1531
|
+
both labeled '0'::
|
|
1532
|
+
|
|
1533
|
+
sage: ps = KnutsonTaoPuzzleSolver('H')
|
|
1534
|
+
sage: ps('0', '0')
|
|
1535
|
+
[{(1, 1): 0/0\0}]
|
|
1536
|
+
|
|
1537
|
+
There are two solutions to the puzzle whose north-west and north-east
|
|
1538
|
+
edges are both labeled '0101'::
|
|
1539
|
+
|
|
1540
|
+
sage: ps = KnutsonTaoPuzzleSolver('H')
|
|
1541
|
+
sage: solns = ps('0101', '0101')
|
|
1542
|
+
sage: len(solns)
|
|
1543
|
+
2
|
|
1544
|
+
sage: solns.sort(key=str)
|
|
1545
|
+
sage: solns
|
|
1546
|
+
[{(1, 1): 0/0\0,
|
|
1547
|
+
(1, 2): 1/\0 0\/1,
|
|
1548
|
+
(1, 3): 0/\0 0\/0,
|
|
1549
|
+
(1, 4): 1/\0 0\/1,
|
|
1550
|
+
(2, 2): 1/1\1,
|
|
1551
|
+
(2, 3): 0/\10 1\/1,
|
|
1552
|
+
(2, 4): 1/\1 10\/0,
|
|
1553
|
+
(3, 3): 1/1\1,
|
|
1554
|
+
(3, 4): 0/\0 1\/10,
|
|
1555
|
+
(4, 4): 10/0\1}, {(1, 1): 0/1\10,
|
|
1556
|
+
(1, 2): 1/\1 10\/0,
|
|
1557
|
+
(1, 3): 0/\0 1\/10,
|
|
1558
|
+
(1, 4): 1/\0 0\/1,
|
|
1559
|
+
(2, 2): 0/0\0,
|
|
1560
|
+
(2, 3): 10/\1 0\/0,
|
|
1561
|
+
(2, 4): 1/\1 1\/1,
|
|
1562
|
+
(3, 3): 0/0\0,
|
|
1563
|
+
(3, 4): 1/\0 0\/1,
|
|
1564
|
+
(4, 4): 1/1\1}]
|
|
1565
|
+
|
|
1566
|
+
The pieces in a puzzle filling are indexed by pairs of nonnegative
|
|
1567
|
+
integers `(i, j)` with `1 \leq i \leq j \leq n`, where `n` is the
|
|
1568
|
+
length of the word labelling the triangle edge. The pieces indexed by
|
|
1569
|
+
`(i, i)` are the triangles along the south edge of the puzzle. ::
|
|
1570
|
+
|
|
1571
|
+
sage: f = solns[0]
|
|
1572
|
+
sage: [f[i, i] for i in range(1,5)]
|
|
1573
|
+
[0/0\0, 1/1\1, 1/1\1, 10/0\1]
|
|
1574
|
+
|
|
1575
|
+
The pieces indexed by `(i, j)` for `j > i` are a pair consisting of
|
|
1576
|
+
a delta piece and nabla piece glued together along the south edge and
|
|
1577
|
+
north edge, respectively (these pairs are called *rhombi*). ::
|
|
1578
|
+
|
|
1579
|
+
sage: f = solns[0]
|
|
1580
|
+
sage: f[1, 2]
|
|
1581
|
+
1/\0 0\/1
|
|
1582
|
+
|
|
1583
|
+
There are various methods and options to display puzzle solutions.
|
|
1584
|
+
A single puzzle can be displayed using the plot method of the puzzle::
|
|
1585
|
+
|
|
1586
|
+
sage: ps = KnutsonTaoPuzzleSolver("H")
|
|
1587
|
+
sage: puzzle = ps('0101','1001')[0]
|
|
1588
|
+
sage: puzzle.plot() #not tested
|
|
1589
|
+
sage: puzzle.plot(style='fill') #not tested
|
|
1590
|
+
sage: puzzle.plot(style='edges') #not tested
|
|
1591
|
+
|
|
1592
|
+
To plot several puzzle solutions, use the plot method of the puzzle
|
|
1593
|
+
solver::
|
|
1594
|
+
|
|
1595
|
+
sage: ps = KnutsonTaoPuzzleSolver('K')
|
|
1596
|
+
sage: solns = ps('0101', '0101')
|
|
1597
|
+
sage: ps.plot(solns) # not tested
|
|
1598
|
+
|
|
1599
|
+
The code can also generate a PDF of a puzzle (using LaTeX and *tikz*)::
|
|
1600
|
+
|
|
1601
|
+
sage: latex.extra_preamble(r'''\usepackage{tikz}''')
|
|
1602
|
+
sage: ps = KnutsonTaoPuzzleSolver('H')
|
|
1603
|
+
sage: solns = ps('0101', '0101')
|
|
1604
|
+
sage: view(solns[0], viewer='pdf') # not tested
|
|
1605
|
+
|
|
1606
|
+
|
|
1607
|
+
Below are examples of using each of the currently supported puzzles.
|
|
1608
|
+
|
|
1609
|
+
Cohomology of the Grassmannian::
|
|
1610
|
+
|
|
1611
|
+
sage: ps = KnutsonTaoPuzzleSolver("H")
|
|
1612
|
+
sage: solns = ps('0101', '0101')
|
|
1613
|
+
sage: sorted(solns, key=str)
|
|
1614
|
+
[{(1, 1): 0/0\0,
|
|
1615
|
+
(1, 2): 1/\0 0\/1,
|
|
1616
|
+
(1, 3): 0/\0 0\/0,
|
|
1617
|
+
(1, 4): 1/\0 0\/1,
|
|
1618
|
+
(2, 2): 1/1\1,
|
|
1619
|
+
(2, 3): 0/\10 1\/1,
|
|
1620
|
+
(2, 4): 1/\1 10\/0,
|
|
1621
|
+
(3, 3): 1/1\1,
|
|
1622
|
+
(3, 4): 0/\0 1\/10,
|
|
1623
|
+
(4, 4): 10/0\1}, {(1, 1): 0/1\10,
|
|
1624
|
+
(1, 2): 1/\1 10\/0,
|
|
1625
|
+
(1, 3): 0/\0 1\/10,
|
|
1626
|
+
(1, 4): 1/\0 0\/1,
|
|
1627
|
+
(2, 2): 0/0\0,
|
|
1628
|
+
(2, 3): 10/\1 0\/0,
|
|
1629
|
+
(2, 4): 1/\1 1\/1,
|
|
1630
|
+
(3, 3): 0/0\0,
|
|
1631
|
+
(3, 4): 1/\0 0\/1,
|
|
1632
|
+
(4, 4): 1/1\1}]
|
|
1633
|
+
|
|
1634
|
+
Equivariant puzzles::
|
|
1635
|
+
|
|
1636
|
+
sage: ps = KnutsonTaoPuzzleSolver("HT")
|
|
1637
|
+
sage: solns = ps('0101', '0101')
|
|
1638
|
+
sage: sorted(solns, key=str)
|
|
1639
|
+
[{(1, 1): 0/0\0,
|
|
1640
|
+
(1, 2): 1/\0 0\/1,
|
|
1641
|
+
(1, 3): 0/\0 0\/0,
|
|
1642
|
+
(1, 4): 1/\0 0\/1,
|
|
1643
|
+
(2, 2): 1/1\1,
|
|
1644
|
+
(2, 3): 0/\1 1\/0,
|
|
1645
|
+
(2, 4): 1/\1 1\/1,
|
|
1646
|
+
(3, 3): 0/0\0,
|
|
1647
|
+
(3, 4): 1/\0 0\/1,
|
|
1648
|
+
(4, 4): 1/1\1}, {(1, 1): 0/0\0,
|
|
1649
|
+
(1, 2): 1/\0 0\/1,
|
|
1650
|
+
(1, 3): 0/\0 0\/0,
|
|
1651
|
+
(1, 4): 1/\0 0\/1,
|
|
1652
|
+
(2, 2): 1/1\1,
|
|
1653
|
+
(2, 3): 0/\10 1\/1,
|
|
1654
|
+
(2, 4): 1/\1 10\/0,
|
|
1655
|
+
(3, 3): 1/1\1,
|
|
1656
|
+
(3, 4): 0/\0 1\/10,
|
|
1657
|
+
(4, 4): 10/0\1}, {(1, 1): 0/1\10,
|
|
1658
|
+
(1, 2): 1/\1 10\/0,
|
|
1659
|
+
(1, 3): 0/\0 1\/10,
|
|
1660
|
+
(1, 4): 1/\0 0\/1,
|
|
1661
|
+
(2, 2): 0/0\0,
|
|
1662
|
+
(2, 3): 10/\1 0\/0,
|
|
1663
|
+
(2, 4): 1/\1 1\/1,
|
|
1664
|
+
(3, 3): 0/0\0,
|
|
1665
|
+
(3, 4): 1/\0 0\/1,
|
|
1666
|
+
(4, 4): 1/1\1}]
|
|
1667
|
+
|
|
1668
|
+
K-Theory puzzles::
|
|
1669
|
+
|
|
1670
|
+
sage: ps = KnutsonTaoPuzzleSolver("K")
|
|
1671
|
+
sage: solns = ps('0101', '0101')
|
|
1672
|
+
sage: sorted(solns, key=str)
|
|
1673
|
+
[{(1, 1): 0/0\0,
|
|
1674
|
+
(1, 2): 1/\0 0\/1,
|
|
1675
|
+
(1, 3): 0/\0 0\/0,
|
|
1676
|
+
(1, 4): 1/\0 0\/1,
|
|
1677
|
+
(2, 2): 1/1\1,
|
|
1678
|
+
(2, 3): 0/\10 1\/1,
|
|
1679
|
+
(2, 4): 1/\1 10\/0,
|
|
1680
|
+
(3, 3): 1/1\1,
|
|
1681
|
+
(3, 4): 0/\0 1\/10,
|
|
1682
|
+
(4, 4): 10/0\1}, {(1, 1): 0/1\10,
|
|
1683
|
+
(1, 2): 1/\1 10\/0,
|
|
1684
|
+
(1, 3): 0/\0 1\/10,
|
|
1685
|
+
(1, 4): 1/\0 0\/1,
|
|
1686
|
+
(2, 2): 0/0\0,
|
|
1687
|
+
(2, 3): 10/\1 0\/0,
|
|
1688
|
+
(2, 4): 1/\1 1\/1,
|
|
1689
|
+
(3, 3): 0/0\0,
|
|
1690
|
+
(3, 4): 1/\0 0\/1,
|
|
1691
|
+
(4, 4): 1/1\1}, {(1, 1): 0/1\10,
|
|
1692
|
+
(1, 2): 1/\1 10\/0,
|
|
1693
|
+
(1, 3): 0/\0 1\/K,
|
|
1694
|
+
(1, 4): 1/\0 0\/1,
|
|
1695
|
+
(2, 2): 0/0\0,
|
|
1696
|
+
(2, 3): K/\K 0\/1,
|
|
1697
|
+
(2, 4): 1/\1 K\/0,
|
|
1698
|
+
(3, 3): 1/1\1,
|
|
1699
|
+
(3, 4): 0/\0 1\/10,
|
|
1700
|
+
(4, 4): 10/0\1}]
|
|
1701
|
+
|
|
1702
|
+
Two-step puzzles::
|
|
1703
|
+
|
|
1704
|
+
sage: ps = KnutsonTaoPuzzleSolver("H2step")
|
|
1705
|
+
sage: solns = ps('01201', '01021')
|
|
1706
|
+
sage: sorted(solns, key=str)
|
|
1707
|
+
[{(1, 1): 0/0\0,
|
|
1708
|
+
(1, 2): 1/\0 0\/1,
|
|
1709
|
+
(1, 3): 2/\0 0\/2,
|
|
1710
|
+
(1, 4): 0/\0 0\/0,
|
|
1711
|
+
(1, 5): 1/\0 0\/1,
|
|
1712
|
+
(2, 2): 1/2\21,
|
|
1713
|
+
(2, 3): 2/\2 21\/1,
|
|
1714
|
+
(2, 4): 0/\10 2\/21,
|
|
1715
|
+
(2, 5): 1/\1 10\/0,
|
|
1716
|
+
(3, 3): 1/1\1,
|
|
1717
|
+
(3, 4): 21/\2 1\/1,
|
|
1718
|
+
(3, 5): 0/\0 2\/20,
|
|
1719
|
+
(4, 4): 1/1\1,
|
|
1720
|
+
(4, 5): 20/\2 1\/10,
|
|
1721
|
+
(5, 5): 10/0\1}, {(1, 1): 0/1\10,
|
|
1722
|
+
(1, 2): 1/\1 10\/0,
|
|
1723
|
+
(1, 3): 2/\1 1\/2,
|
|
1724
|
+
(1, 4): 0/\0 1\/10,
|
|
1725
|
+
(1, 5): 1/\0 0\/1,
|
|
1726
|
+
(2, 2): 0/2\20,
|
|
1727
|
+
(2, 3): 2/\2 20\/0,
|
|
1728
|
+
(2, 4): 10/\1 2\/20,
|
|
1729
|
+
(2, 5): 1/\1 1\/1,
|
|
1730
|
+
(3, 3): 0/0\0,
|
|
1731
|
+
(3, 4): 20/\2 0\/0,
|
|
1732
|
+
(3, 5): 1/\0 2\/2(10),
|
|
1733
|
+
(4, 4): 0/0\0,
|
|
1734
|
+
(4, 5): 2(10)/\2 0\/1,
|
|
1735
|
+
(5, 5): 1/1\1}, {(1, 1): 0/2\20,
|
|
1736
|
+
(1, 2): 1/\21 20\/0,
|
|
1737
|
+
(1, 3): 2/\2 21\/1,
|
|
1738
|
+
(1, 4): 0/\0 2\/20,
|
|
1739
|
+
(1, 5): 1/\0 0\/1,
|
|
1740
|
+
(2, 2): 0/0\0,
|
|
1741
|
+
(2, 3): 1/\0 0\/1,
|
|
1742
|
+
(2, 4): 20/\2 0\/0,
|
|
1743
|
+
(2, 5): 1/\1 2\/21,
|
|
1744
|
+
(3, 3): 1/1\1,
|
|
1745
|
+
(3, 4): 0/\0 1\/10,
|
|
1746
|
+
(3, 5): 21/\0 0\/21,
|
|
1747
|
+
(4, 4): 10/0\1,
|
|
1748
|
+
(4, 5): 21/\2 1\/1,
|
|
1749
|
+
(5, 5): 1/1\1}]
|
|
1750
|
+
|
|
1751
|
+
Two-step equivariant puzzles::
|
|
1752
|
+
|
|
1753
|
+
sage: ps = KnutsonTaoPuzzleSolver("HT2step")
|
|
1754
|
+
sage: solns = ps('10212', '12012')
|
|
1755
|
+
sage: sorted(solns, key=str)
|
|
1756
|
+
[{(1, 1): 1/1\1,
|
|
1757
|
+
(1, 2): 0/\(21)0 1\/2,
|
|
1758
|
+
(1, 3): 2/\1 (21)0\/0,
|
|
1759
|
+
(1, 4): 1/\1 1\/1,
|
|
1760
|
+
(1, 5): 2/\1 1\/2,
|
|
1761
|
+
(2, 2): 2/2\2,
|
|
1762
|
+
(2, 3): 0/\2 2\/0,
|
|
1763
|
+
(2, 4): 1/\2 2\/1,
|
|
1764
|
+
(2, 5): 2/\2 2\/2,
|
|
1765
|
+
(3, 3): 0/0\0,
|
|
1766
|
+
(3, 4): 1/\0 0\/1,
|
|
1767
|
+
(3, 5): 2/\0 0\/2,
|
|
1768
|
+
(4, 4): 1/1\1,
|
|
1769
|
+
(4, 5): 2/\1 1\/2,
|
|
1770
|
+
(5, 5): 2/2\2}, {(1, 1): 1/1\1,
|
|
1771
|
+
(1, 2): 0/\(21)0 1\/2,
|
|
1772
|
+
(1, 3): 2/\1 (21)0\/0,
|
|
1773
|
+
(1, 4): 1/\1 1\/1,
|
|
1774
|
+
(1, 5): 2/\1 1\/2,
|
|
1775
|
+
(2, 2): 2/2\2,
|
|
1776
|
+
(2, 3): 0/\2 2\/0,
|
|
1777
|
+
(2, 4): 1/\21 2\/2,
|
|
1778
|
+
(2, 5): 2/\2 21\/1,
|
|
1779
|
+
(3, 3): 0/0\0,
|
|
1780
|
+
(3, 4): 2/\0 0\/2,
|
|
1781
|
+
(3, 5): 1/\0 0\/1,
|
|
1782
|
+
(4, 4): 2/2\2,
|
|
1783
|
+
(4, 5): 1/\1 2\/21,
|
|
1784
|
+
(5, 5): 21/1\2}, {(1, 1): 1/1\1,
|
|
1785
|
+
(1, 2): 0/\(21)0 1\/2,
|
|
1786
|
+
(1, 3): 2/\1 (21)0\/0,
|
|
1787
|
+
(1, 4): 1/\1 1\/1,
|
|
1788
|
+
(1, 5): 2/\1 1\/2,
|
|
1789
|
+
(2, 2): 2/2\2,
|
|
1790
|
+
(2, 3): 0/\20 2\/2,
|
|
1791
|
+
(2, 4): 1/\21 20\/0,
|
|
1792
|
+
(2, 5): 2/\2 21\/1,
|
|
1793
|
+
(3, 3): 2/2\2,
|
|
1794
|
+
(3, 4): 0/\0 2\/20,
|
|
1795
|
+
(3, 5): 1/\0 0\/1,
|
|
1796
|
+
(4, 4): 20/0\2,
|
|
1797
|
+
(4, 5): 1/\1 2\/21,
|
|
1798
|
+
(5, 5): 21/1\2}, {(1, 1): 1/1\1,
|
|
1799
|
+
(1, 2): 0/\1 1\/0,
|
|
1800
|
+
(1, 3): 2/\1 1\/2,
|
|
1801
|
+
(1, 4): 1/\1 1\/1,
|
|
1802
|
+
(1, 5): 2/\1 1\/2,
|
|
1803
|
+
(2, 2): 0/2\20,
|
|
1804
|
+
(2, 3): 2/\2 20\/0,
|
|
1805
|
+
(2, 4): 1/\2 2\/1,
|
|
1806
|
+
(2, 5): 2/\2 2\/2,
|
|
1807
|
+
(3, 3): 0/0\0,
|
|
1808
|
+
(3, 4): 1/\0 0\/1,
|
|
1809
|
+
(3, 5): 2/\0 0\/2,
|
|
1810
|
+
(4, 4): 1/1\1,
|
|
1811
|
+
(4, 5): 2/\1 1\/2,
|
|
1812
|
+
(5, 5): 2/2\2}, {(1, 1): 1/1\1,
|
|
1813
|
+
(1, 2): 0/\1 1\/0,
|
|
1814
|
+
(1, 3): 2/\1 1\/2,
|
|
1815
|
+
(1, 4): 1/\1 1\/1,
|
|
1816
|
+
(1, 5): 2/\1 1\/2,
|
|
1817
|
+
(2, 2): 0/2\20,
|
|
1818
|
+
(2, 3): 2/\2 20\/0,
|
|
1819
|
+
(2, 4): 1/\21 2\/2,
|
|
1820
|
+
(2, 5): 2/\2 21\/1,
|
|
1821
|
+
(3, 3): 0/0\0,
|
|
1822
|
+
(3, 4): 2/\0 0\/2,
|
|
1823
|
+
(3, 5): 1/\0 0\/1,
|
|
1824
|
+
(4, 4): 2/2\2,
|
|
1825
|
+
(4, 5): 1/\1 2\/21,
|
|
1826
|
+
(5, 5): 21/1\2}, {(1, 1): 1/1\1,
|
|
1827
|
+
(1, 2): 0/\10 1\/1,
|
|
1828
|
+
(1, 3): 2/\10 10\/2,
|
|
1829
|
+
(1, 4): 1/\1 10\/0,
|
|
1830
|
+
(1, 5): 2/\1 1\/2,
|
|
1831
|
+
(2, 2): 1/2\21,
|
|
1832
|
+
(2, 3): 2/\2 21\/1,
|
|
1833
|
+
(2, 4): 0/\2 2\/0,
|
|
1834
|
+
(2, 5): 2/\2 2\/2,
|
|
1835
|
+
(3, 3): 1/1\1,
|
|
1836
|
+
(3, 4): 0/\0 1\/10,
|
|
1837
|
+
(3, 5): 2/\0 0\/2,
|
|
1838
|
+
(4, 4): 10/0\1,
|
|
1839
|
+
(4, 5): 2/\1 1\/2,
|
|
1840
|
+
(5, 5): 2/2\2}, {(1, 1): 1/1\1,
|
|
1841
|
+
(1, 2): 0/\10 1\/1,
|
|
1842
|
+
(1, 3): 2/\10 10\/2,
|
|
1843
|
+
(1, 4): 1/\1 10\/0,
|
|
1844
|
+
(1, 5): 2/\1 1\/2,
|
|
1845
|
+
(2, 2): 1/2\21,
|
|
1846
|
+
(2, 3): 2/\2 21\/1,
|
|
1847
|
+
(2, 4): 0/\20 2\/2,
|
|
1848
|
+
(2, 5): 2/\2 20\/0,
|
|
1849
|
+
(3, 3): 1/1\1,
|
|
1850
|
+
(3, 4): 2/\1 1\/2,
|
|
1851
|
+
(3, 5): 0/\0 1\/10,
|
|
1852
|
+
(4, 4): 2/2\2,
|
|
1853
|
+
(4, 5): 10/\1 2\/20,
|
|
1854
|
+
(5, 5): 20/0\2}, {(1, 1): 1/2\21,
|
|
1855
|
+
(1, 2): 0/\20 21\/1,
|
|
1856
|
+
(1, 3): 2/\2 20\/0,
|
|
1857
|
+
(1, 4): 1/\1 2\/21,
|
|
1858
|
+
(1, 5): 2/\1 1\/2,
|
|
1859
|
+
(2, 2): 1/1\1,
|
|
1860
|
+
(2, 3): 0/\1 1\/0,
|
|
1861
|
+
(2, 4): 21/\2 1\/1,
|
|
1862
|
+
(2, 5): 2/\2 2\/2,
|
|
1863
|
+
(3, 3): 0/0\0,
|
|
1864
|
+
(3, 4): 1/\0 0\/1,
|
|
1865
|
+
(3, 5): 2/\0 0\/2,
|
|
1866
|
+
(4, 4): 1/1\1,
|
|
1867
|
+
(4, 5): 2/\1 1\/2,
|
|
1868
|
+
(5, 5): 2/2\2}, {(1, 1): 1/2\21,
|
|
1869
|
+
(1, 2): 0/\20 21\/1,
|
|
1870
|
+
(1, 3): 2/\2 20\/0,
|
|
1871
|
+
(1, 4): 1/\1 2\/21,
|
|
1872
|
+
(1, 5): 2/\1 1\/2,
|
|
1873
|
+
(2, 2): 1/1\1,
|
|
1874
|
+
(2, 3): 0/\10 1\/1,
|
|
1875
|
+
(2, 4): 21/\2 10\/0,
|
|
1876
|
+
(2, 5): 2/\2 2\/2,
|
|
1877
|
+
(3, 3): 1/1\1,
|
|
1878
|
+
(3, 4): 0/\0 1\/10,
|
|
1879
|
+
(3, 5): 2/\0 0\/2,
|
|
1880
|
+
(4, 4): 10/0\1,
|
|
1881
|
+
(4, 5): 2/\1 1\/2,
|
|
1882
|
+
(5, 5): 2/2\2}, {(1, 1): 1/2\21,
|
|
1883
|
+
(1, 2): 0/\21 21\/0,
|
|
1884
|
+
(1, 3): 2/\2 21\/1,
|
|
1885
|
+
(1, 4): 1/\1 2\/21,
|
|
1886
|
+
(1, 5): 2/\1 1\/2,
|
|
1887
|
+
(2, 2): 0/1\10,
|
|
1888
|
+
(2, 3): 1/\1 10\/0,
|
|
1889
|
+
(2, 4): 21/\2 1\/1,
|
|
1890
|
+
(2, 5): 2/\2 2\/2,
|
|
1891
|
+
(3, 3): 0/0\0,
|
|
1892
|
+
(3, 4): 1/\0 0\/1,
|
|
1893
|
+
(3, 5): 2/\0 0\/2,
|
|
1894
|
+
(4, 4): 1/1\1,
|
|
1895
|
+
(4, 5): 2/\1 1\/2,
|
|
1896
|
+
(5, 5): 2/2\2}]
|
|
1897
|
+
|
|
1898
|
+
|
|
1899
|
+
Belkale-Kumar puzzles (the following example is Figure 2 of [KnutsonPurbhoo10]_)::
|
|
1900
|
+
|
|
1901
|
+
sage: ps = KnutsonTaoPuzzleSolver('BK', 3)
|
|
1902
|
+
sage: solns = ps('12132', '23112')
|
|
1903
|
+
sage: len(solns)
|
|
1904
|
+
1
|
|
1905
|
+
sage: solns[0].south_labels()
|
|
1906
|
+
('3', '2', '1', '2', '1')
|
|
1907
|
+
sage: solns
|
|
1908
|
+
[{(1, 1): 1/3\3(1),
|
|
1909
|
+
(1, 2): 2/\3(2) 3(1)\/1,
|
|
1910
|
+
(1, 3): 1/\3(1) 3(2)\/2,
|
|
1911
|
+
(1, 4): 3/\3 3(1)\/1,
|
|
1912
|
+
(1, 5): 2/\2 3\/3(2),
|
|
1913
|
+
(2, 2): 1/2\2(1),
|
|
1914
|
+
(2, 3): 2/\2 2(1)\/1,
|
|
1915
|
+
(2, 4): 1/\2(1) 2\/2,
|
|
1916
|
+
(2, 5): 3(2)/\3 2(1)\/1,
|
|
1917
|
+
(3, 3): 1/1\1,
|
|
1918
|
+
(3, 4): 2/\1 1\/2,
|
|
1919
|
+
(3, 5): 1/\1 1\/1,
|
|
1920
|
+
(4, 4): 2/2\2,
|
|
1921
|
+
(4, 5): 1/\1 2\/2(1),
|
|
1922
|
+
(5, 5): 2(1)/1\2}]
|
|
1923
|
+
"""
|
|
1924
|
+
|
|
1925
|
+
def __init__(self, puzzle_pieces):
|
|
1926
|
+
r"""
|
|
1927
|
+
Knutson-Tao puzzle solver.
|
|
1928
|
+
|
|
1929
|
+
TESTS:
|
|
1930
|
+
|
|
1931
|
+
Check that UniqueRepresentation works::
|
|
1932
|
+
|
|
1933
|
+
sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver, H_grassmannian_pieces
|
|
1934
|
+
sage: ps = KnutsonTaoPuzzleSolver(H_grassmannian_pieces())
|
|
1935
|
+
sage: qs = KnutsonTaoPuzzleSolver("H")
|
|
1936
|
+
sage: ps
|
|
1937
|
+
Knutson-Tao puzzle solver with pieces:
|
|
1938
|
+
Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1]
|
|
1939
|
+
Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1]
|
|
1940
|
+
sage: qs
|
|
1941
|
+
Knutson-Tao puzzle solver with pieces:
|
|
1942
|
+
Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1]
|
|
1943
|
+
Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1]
|
|
1944
|
+
sage: ps == qs
|
|
1945
|
+
True
|
|
1946
|
+
"""
|
|
1947
|
+
self._puzzle_pieces = puzzle_pieces
|
|
1948
|
+
self._rhombus_pieces = tuple(puzzle_pieces.rhombus_pieces())
|
|
1949
|
+
self._bottom_deltas = tuple(puzzle_pieces.boundary_deltas())
|
|
1950
|
+
|
|
1951
|
+
@staticmethod
|
|
1952
|
+
def __classcall_private__(cls, puzzle_pieces, max_letter=None):
|
|
1953
|
+
r"""
|
|
1954
|
+
TESTS::
|
|
1955
|
+
|
|
1956
|
+
sage: from sage.combinat.knutson_tao_puzzles import *
|
|
1957
|
+
sage: KnutsonTaoPuzzleSolver(H_grassmannian_pieces()) == KnutsonTaoPuzzleSolver("H") # indirect doctest
|
|
1958
|
+
True
|
|
1959
|
+
sage: KnutsonTaoPuzzleSolver(HT_grassmannian_pieces()) == KnutsonTaoPuzzleSolver("HT")
|
|
1960
|
+
True
|
|
1961
|
+
sage: KnutsonTaoPuzzleSolver(K_grassmannian_pieces()) == KnutsonTaoPuzzleSolver("K")
|
|
1962
|
+
True
|
|
1963
|
+
sage: KnutsonTaoPuzzleSolver(H_two_step_pieces()) == KnutsonTaoPuzzleSolver("H2step")
|
|
1964
|
+
True
|
|
1965
|
+
sage: KnutsonTaoPuzzleSolver(HT_two_step_pieces()) == KnutsonTaoPuzzleSolver("HT2step")
|
|
1966
|
+
True
|
|
1967
|
+
sage: KnutsonTaoPuzzleSolver(BK_pieces(3)) == KnutsonTaoPuzzleSolver("BK",3)
|
|
1968
|
+
True
|
|
1969
|
+
"""
|
|
1970
|
+
if isinstance(puzzle_pieces, str):
|
|
1971
|
+
if puzzle_pieces == "H":
|
|
1972
|
+
puzzle_pieces = H_grassmannian_pieces()
|
|
1973
|
+
elif puzzle_pieces == "HT":
|
|
1974
|
+
puzzle_pieces = HT_grassmannian_pieces()
|
|
1975
|
+
elif puzzle_pieces == "K":
|
|
1976
|
+
puzzle_pieces = K_grassmannian_pieces()
|
|
1977
|
+
elif puzzle_pieces == "H2step":
|
|
1978
|
+
puzzle_pieces = H_two_step_pieces()
|
|
1979
|
+
elif puzzle_pieces == "HT2step":
|
|
1980
|
+
puzzle_pieces = HT_two_step_pieces()
|
|
1981
|
+
elif puzzle_pieces == "BK":
|
|
1982
|
+
if max_letter is not None:
|
|
1983
|
+
puzzle_pieces = BK_pieces(max_letter)
|
|
1984
|
+
else:
|
|
1985
|
+
raise ValueError("max_letter needs to be specified")
|
|
1986
|
+
return super().__classcall__(cls, puzzle_pieces)
|
|
1987
|
+
|
|
1988
|
+
def __call__(self, lamda, mu, algorithm='strips'):
|
|
1989
|
+
r"""
|
|
1990
|
+
TESTS::
|
|
1991
|
+
|
|
1992
|
+
sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver
|
|
1993
|
+
sage: ps = KnutsonTaoPuzzleSolver("H")
|
|
1994
|
+
sage: ps('0101','1001')
|
|
1995
|
+
[{(1, 1): 0/1\10,
|
|
1996
|
+
(1, 2): 1/\1 10\/0,
|
|
1997
|
+
(1, 3): 0/\10 1\/1,
|
|
1998
|
+
(1, 4): 1/\1 10\/0,
|
|
1999
|
+
(2, 2): 0/0\0,
|
|
2000
|
+
(2, 3): 1/\0 0\/1,
|
|
2001
|
+
(2, 4): 0/\0 0\/0,
|
|
2002
|
+
(3, 3): 1/1\1,
|
|
2003
|
+
(3, 4): 0/\0 1\/10,
|
|
2004
|
+
(4, 4): 10/0\1}]
|
|
2005
|
+
sage: ps('0101','1001',algorithm='pieces')
|
|
2006
|
+
[{(1, 1): 0/1\10,
|
|
2007
|
+
(1, 2): 1/\1 10\/0,
|
|
2008
|
+
(1, 3): 0/\10 1\/1,
|
|
2009
|
+
(1, 4): 1/\1 10\/0,
|
|
2010
|
+
(2, 2): 0/0\0,
|
|
2011
|
+
(2, 3): 1/\0 0\/1,
|
|
2012
|
+
(2, 4): 0/\0 0\/0,
|
|
2013
|
+
(3, 3): 1/1\1,
|
|
2014
|
+
(3, 4): 0/\0 1\/10,
|
|
2015
|
+
(4, 4): 10/0\1}]
|
|
2016
|
+
"""
|
|
2017
|
+
lamda, mu = tuple(lamda), tuple(mu)
|
|
2018
|
+
if algorithm == 'pieces':
|
|
2019
|
+
return list(self._fill_puzzle_by_pieces(lamda, mu))
|
|
2020
|
+
elif algorithm == 'strips':
|
|
2021
|
+
return list(self._fill_puzzle_by_strips(lamda, mu))
|
|
2022
|
+
|
|
2023
|
+
solutions = __call__
|
|
2024
|
+
|
|
2025
|
+
def __repr__(self) -> str:
|
|
2026
|
+
r"""
|
|
2027
|
+
EXAMPLES::
|
|
2028
|
+
|
|
2029
|
+
sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver
|
|
2030
|
+
sage: KnutsonTaoPuzzleSolver('H')
|
|
2031
|
+
Knutson-Tao puzzle solver with pieces:
|
|
2032
|
+
Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1]
|
|
2033
|
+
Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1]
|
|
2034
|
+
"""
|
|
2035
|
+
return "Knutson-Tao puzzle solver with pieces:\n%s" % self._puzzle_pieces
|
|
2036
|
+
|
|
2037
|
+
def puzzle_pieces(self):
|
|
2038
|
+
r"""
|
|
2039
|
+
The puzzle pieces used for filling in the puzzles.
|
|
2040
|
+
|
|
2041
|
+
EXAMPLES::
|
|
2042
|
+
|
|
2043
|
+
sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver
|
|
2044
|
+
sage: ps = KnutsonTaoPuzzleSolver('H')
|
|
2045
|
+
sage: ps.puzzle_pieces()
|
|
2046
|
+
Nablas : [0\0/0, 0\10/1, 10\1/0, 1\0/10, 1\1/1]
|
|
2047
|
+
Deltas : [0/0\0, 0/1\10, 1/10\0, 1/1\1, 10/0\1]
|
|
2048
|
+
"""
|
|
2049
|
+
return self._puzzle_pieces
|
|
2050
|
+
|
|
2051
|
+
def _fill_piece(self, nw_label, ne_label, pieces) -> list[PuzzlePiece]:
|
|
2052
|
+
r"""
|
|
2053
|
+
Fillings of a piece.
|
|
2054
|
+
|
|
2055
|
+
INPUT:
|
|
2056
|
+
|
|
2057
|
+
- ``nw_label``, ``nw_label`` -- label
|
|
2058
|
+
- ``pieces`` -- puzzle pieces used for the filling
|
|
2059
|
+
|
|
2060
|
+
OUTPUT: list of the fillings
|
|
2061
|
+
|
|
2062
|
+
EXAMPLES::
|
|
2063
|
+
|
|
2064
|
+
sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver
|
|
2065
|
+
sage: ps = KnutsonTaoPuzzleSolver('H')
|
|
2066
|
+
sage: ps._fill_piece('0', '0', ps._bottom_deltas)
|
|
2067
|
+
[0/0\0]
|
|
2068
|
+
"""
|
|
2069
|
+
return [piece for piece in pieces
|
|
2070
|
+
if (piece['north_west'] == nw_label and
|
|
2071
|
+
piece['north_east'] == ne_label)]
|
|
2072
|
+
|
|
2073
|
+
@cached_method
|
|
2074
|
+
def _fill_strip(self, nw_labels, ne_label, pieces, final_pieces=None):
|
|
2075
|
+
r"""
|
|
2076
|
+
Fillings of a strip of height 1.
|
|
2077
|
+
|
|
2078
|
+
INPUT:
|
|
2079
|
+
|
|
2080
|
+
- ``nw_labels`` -- tuple of labels
|
|
2081
|
+
- ``nw_label`` -- label
|
|
2082
|
+
- ``pieces`` -- puzzle pieces used for the filling
|
|
2083
|
+
- ``final_pieces`` -- pieces used for the last piece to be filled in
|
|
2084
|
+
|
|
2085
|
+
OUTPUT: list of lists of the fillings
|
|
2086
|
+
|
|
2087
|
+
EXAMPLES::
|
|
2088
|
+
|
|
2089
|
+
sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver
|
|
2090
|
+
sage: ps = KnutsonTaoPuzzleSolver('H')
|
|
2091
|
+
sage: ps._fill_strip(('0',), '0', ps._rhombus_pieces, ps._bottom_deltas)
|
|
2092
|
+
[[0/0\0]]
|
|
2093
|
+
sage: ps._fill_strip(('0','0'), '0', ps._rhombus_pieces, ps._bottom_deltas)
|
|
2094
|
+
[[0/\0 0\/0, 0/0\0]]
|
|
2095
|
+
sage: sorted(ps._fill_strip(('0',), '0', ps._rhombus_pieces), key=str)
|
|
2096
|
+
[[0/\0 0\/0], [0/\0 1\/10]]
|
|
2097
|
+
sage: sorted(ps._fill_strip(('0','1'), '0', ps._rhombus_pieces), key=str)
|
|
2098
|
+
[[1/\0 0\/1, 0/\0 0\/0], [1/\0 0\/1, 0/\0 1\/10]]
|
|
2099
|
+
|
|
2100
|
+
TESTS::
|
|
2101
|
+
|
|
2102
|
+
sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver
|
|
2103
|
+
sage: ps = KnutsonTaoPuzzleSolver('H')
|
|
2104
|
+
sage: ps._fill_strip(('0',), 'goo', ps._rhombus_pieces)
|
|
2105
|
+
[]
|
|
2106
|
+
"""
|
|
2107
|
+
if final_pieces is None:
|
|
2108
|
+
final_pieces = pieces
|
|
2109
|
+
|
|
2110
|
+
output = []
|
|
2111
|
+
if len(nw_labels) == 1:
|
|
2112
|
+
X = self._fill_piece(nw_labels[0], ne_label, final_pieces)
|
|
2113
|
+
if X:
|
|
2114
|
+
output = [[x] for x in X]
|
|
2115
|
+
else:
|
|
2116
|
+
partial_fillings = self._fill_strip(nw_labels[1:], ne_label, pieces)
|
|
2117
|
+
for partial_filling in partial_fillings:
|
|
2118
|
+
ne_label = partial_filling[-1]['south_west']
|
|
2119
|
+
for piece in self._fill_piece(nw_labels[0], ne_label, final_pieces):
|
|
2120
|
+
output.append(partial_filling + [piece])
|
|
2121
|
+
return output
|
|
2122
|
+
|
|
2123
|
+
def _fill_puzzle_by_pieces(self, lamda, mu):
|
|
2124
|
+
r"""
|
|
2125
|
+
Fill puzzle pieces for given outer labels ``lambda`` and ``mu``.
|
|
2126
|
+
|
|
2127
|
+
EXAMPLES::
|
|
2128
|
+
|
|
2129
|
+
sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver
|
|
2130
|
+
sage: ps = KnutsonTaoPuzzleSolver('H')
|
|
2131
|
+
sage: list(ps._fill_puzzle_by_pieces('0', '0'))
|
|
2132
|
+
[{(1, 1): 0/0\0}]
|
|
2133
|
+
"""
|
|
2134
|
+
queue = [PuzzleFilling(lamda, mu)]
|
|
2135
|
+
while queue:
|
|
2136
|
+
PP = queue.pop()
|
|
2137
|
+
ne_label = PP.north_east_label_of_kink()
|
|
2138
|
+
nw_label = PP.north_west_label_of_kink()
|
|
2139
|
+
if PP.is_in_south_edge():
|
|
2140
|
+
pieces = self._bottom_deltas
|
|
2141
|
+
else:
|
|
2142
|
+
pieces = self._rhombus_pieces
|
|
2143
|
+
for piece in self._fill_piece(nw_label, ne_label, pieces):
|
|
2144
|
+
PPcopy = PP.copy()
|
|
2145
|
+
PPcopy.add_piece(piece)
|
|
2146
|
+
if PPcopy.is_completed():
|
|
2147
|
+
yield PPcopy
|
|
2148
|
+
else:
|
|
2149
|
+
queue.append(PPcopy)
|
|
2150
|
+
|
|
2151
|
+
def _fill_puzzle_by_strips(self, lamda, mu):
|
|
2152
|
+
r"""
|
|
2153
|
+
Fill puzzle pieces by strips for given outer labels ``lambda`` and ``mu``.
|
|
2154
|
+
|
|
2155
|
+
EXAMPLES::
|
|
2156
|
+
|
|
2157
|
+
sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver
|
|
2158
|
+
sage: ps = KnutsonTaoPuzzleSolver('H')
|
|
2159
|
+
sage: list(ps._fill_puzzle_by_strips('0', '0'))
|
|
2160
|
+
[{(1, 1): 0/0\0}]
|
|
2161
|
+
sage: list(ps._fill_puzzle_by_strips('01', '01'))
|
|
2162
|
+
[{(1, 1): 0/0\0, (1, 2): 1/\0 0\/1, (2, 2): 1/1\1}]
|
|
2163
|
+
"""
|
|
2164
|
+
queue = [PuzzleFilling(lamda, mu)]
|
|
2165
|
+
while queue:
|
|
2166
|
+
PP = queue.pop()
|
|
2167
|
+
i, _ = PP.kink_coordinates()
|
|
2168
|
+
|
|
2169
|
+
# grab nw labels
|
|
2170
|
+
if i == 1:
|
|
2171
|
+
nw_labels = PP._nw_labels
|
|
2172
|
+
else:
|
|
2173
|
+
nw_labels = tuple(PP._squares[i - 1, k]['south_east']
|
|
2174
|
+
for k in range(i, len(lamda) + 1))
|
|
2175
|
+
|
|
2176
|
+
# grab ne labels
|
|
2177
|
+
ne_label = PP._ne_labels[i - 1]
|
|
2178
|
+
|
|
2179
|
+
deltas = self._bottom_deltas
|
|
2180
|
+
rhombi = self._rhombus_pieces
|
|
2181
|
+
for row in self._fill_strip(nw_labels, ne_label, rhombi, deltas):
|
|
2182
|
+
PPcopy = PP.copy()
|
|
2183
|
+
PPcopy.add_pieces(row)
|
|
2184
|
+
if PPcopy.is_completed():
|
|
2185
|
+
yield PPcopy
|
|
2186
|
+
else:
|
|
2187
|
+
queue.append(PPcopy)
|
|
2188
|
+
|
|
2189
|
+
def plot(self, puzzles):
|
|
2190
|
+
r"""
|
|
2191
|
+
Return plot of puzzles.
|
|
2192
|
+
|
|
2193
|
+
INPUT:
|
|
2194
|
+
|
|
2195
|
+
- ``puzzles`` -- list of puzzles
|
|
2196
|
+
|
|
2197
|
+
EXAMPLES::
|
|
2198
|
+
|
|
2199
|
+
sage: from sage.combinat.knutson_tao_puzzles import KnutsonTaoPuzzleSolver
|
|
2200
|
+
sage: ps = KnutsonTaoPuzzleSolver('K')
|
|
2201
|
+
sage: solns = ps('0101', '0101')
|
|
2202
|
+
sage: ps.plot(solns) # not tested
|
|
2203
|
+
"""
|
|
2204
|
+
g = [p.plot() for p in puzzles]
|
|
2205
|
+
m = len([gg.axes(False) for gg in g])
|
|
2206
|
+
return graphics_array(g, (m + 3) / 4, 4)
|
|
2207
|
+
|
|
2208
|
+
def structure_constants(self, lamda, mu, nu=None):
|
|
2209
|
+
r"""
|
|
2210
|
+
Compute cohomology structure coefficients from puzzles.
|
|
2211
|
+
|
|
2212
|
+
INPUT:
|
|
2213
|
+
|
|
2214
|
+
- ``pieces`` -- puzzle pieces to be used
|
|
2215
|
+
- ``lambda``, ``mu`` -- edge labels of puzzle for northwest and north east side
|
|
2216
|
+
- ``nu`` -- (default: ``None``) if ``nu`` is not specified a dictionary is returned with
|
|
2217
|
+
the structure coefficients corresponding to all south labels; if ``nu`` is given, only
|
|
2218
|
+
the coefficients with the specified label is returned
|
|
2219
|
+
|
|
2220
|
+
OUTPUT: dictionary
|
|
2221
|
+
|
|
2222
|
+
EXAMPLES:
|
|
2223
|
+
|
|
2224
|
+
Note: In order to standardize the output of the following examples,
|
|
2225
|
+
we output a sorted list of items from the dictionary instead of the
|
|
2226
|
+
dictionary itself.
|
|
2227
|
+
|
|
2228
|
+
Grassmannian cohomology::
|
|
2229
|
+
|
|
2230
|
+
sage: ps = KnutsonTaoPuzzleSolver('H')
|
|
2231
|
+
sage: cp = ps.structure_constants('0101', '0101')
|
|
2232
|
+
sage: sorted(cp.items(), key=str)
|
|
2233
|
+
[(('0', '1', '1', '0'), 1), (('1', '0', '0', '1'), 1)]
|
|
2234
|
+
sage: ps.structure_constants('001001', '001010', '010100')
|
|
2235
|
+
1
|
|
2236
|
+
|
|
2237
|
+
Equivariant cohomology::
|
|
2238
|
+
|
|
2239
|
+
sage: ps = KnutsonTaoPuzzleSolver('HT')
|
|
2240
|
+
sage: cp = ps.structure_constants('0101', '0101')
|
|
2241
|
+
sage: sorted(cp.items(), key=str)
|
|
2242
|
+
[(('0', '1', '0', '1'), y2 - y3),
|
|
2243
|
+
(('0', '1', '1', '0'), 1),
|
|
2244
|
+
(('1', '0', '0', '1'), 1)]
|
|
2245
|
+
|
|
2246
|
+
K-theory::
|
|
2247
|
+
|
|
2248
|
+
sage: ps = KnutsonTaoPuzzleSolver('K')
|
|
2249
|
+
sage: cp = ps.structure_constants('0101', '0101')
|
|
2250
|
+
sage: sorted(cp.items(), key=str)
|
|
2251
|
+
[(('0', '1', '1', '0'), 1), (('1', '0', '0', '1'), 1), (('1', '0', '1', '0'), -1)]
|
|
2252
|
+
|
|
2253
|
+
Two-step::
|
|
2254
|
+
|
|
2255
|
+
sage: ps = KnutsonTaoPuzzleSolver('H2step')
|
|
2256
|
+
sage: cp = ps.structure_constants('01122', '01122')
|
|
2257
|
+
sage: sorted(cp.items(), key=str)
|
|
2258
|
+
[(('0', '1', '1', '2', '2'), 1)]
|
|
2259
|
+
sage: cp = ps.structure_constants('01201', '01021')
|
|
2260
|
+
sage: sorted(cp.items(), key=str)
|
|
2261
|
+
[(('0', '2', '1', '1', '0'), 1),
|
|
2262
|
+
(('1', '2', '0', '0', '1'), 1),
|
|
2263
|
+
(('2', '0', '1', '0', '1'), 1)]
|
|
2264
|
+
|
|
2265
|
+
Two-step equivariant::
|
|
2266
|
+
|
|
2267
|
+
sage: ps = KnutsonTaoPuzzleSolver('HT2step')
|
|
2268
|
+
sage: cp = ps.structure_constants('10212', '12012')
|
|
2269
|
+
sage: sorted(cp.items(), key=str)
|
|
2270
|
+
[(('1', '2', '0', '1', '2'), y1*y2 - y2*y3 - y1*y4 + y3*y4),
|
|
2271
|
+
(('1', '2', '0', '2', '1'), y1 - y3),
|
|
2272
|
+
(('1', '2', '1', '0', '2'), y2 - y4),
|
|
2273
|
+
(('1', '2', '1', '2', '0'), 1),
|
|
2274
|
+
(('1', '2', '2', '0', '1'), 1),
|
|
2275
|
+
(('2', '1', '0', '1', '2'), y1 - y3),
|
|
2276
|
+
(('2', '1', '1', '0', '2'), 1)]
|
|
2277
|
+
"""
|
|
2278
|
+
from collections import defaultdict
|
|
2279
|
+
R = PolynomialRing(Integers(), 'y', len(lamda) + 1)
|
|
2280
|
+
z = defaultdict(R.zero)
|
|
2281
|
+
for p in self(lamda, mu):
|
|
2282
|
+
z[p.south_labels()] += p.contribution()
|
|
2283
|
+
if nu is None:
|
|
2284
|
+
return dict(z)
|
|
2285
|
+
else:
|
|
2286
|
+
return z[tuple(nu)]
|