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,1523 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-combinat
|
|
2
|
+
# sage.doctest: needs sage.combinat sage.modules
|
|
3
|
+
r"""
|
|
4
|
+
Fully packed loops
|
|
5
|
+
|
|
6
|
+
AUTHORS:
|
|
7
|
+
|
|
8
|
+
- Vincent Knight, James Campbell, Kevin Dilks, Emily Gunawan (2015): Initial version
|
|
9
|
+
- Vincent Delecroix (2017): cleaning and enhanced plotting function
|
|
10
|
+
"""
|
|
11
|
+
# ****************************************************************************
|
|
12
|
+
# Copyright (C) 2015 Vincent Knight <vincent.knight@gmail.com>
|
|
13
|
+
# James Campbell <james.campbell@tanti.org.uk>
|
|
14
|
+
# Kevin Dilks <kdilks@gmail.com>
|
|
15
|
+
# Emily Gunawan <egunawan@umn.edu>
|
|
16
|
+
# 2017 Vincent Delecroix <20100.delecroix@gmail.com>
|
|
17
|
+
#
|
|
18
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
19
|
+
#
|
|
20
|
+
# This code is distributed in the hope that it will be useful, but
|
|
21
|
+
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
22
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
23
|
+
# General Public License for more details.
|
|
24
|
+
#
|
|
25
|
+
# The full text of the GPL is available at:
|
|
26
|
+
#
|
|
27
|
+
# https://www.gnu.org/licenses/
|
|
28
|
+
# ****************************************************************************
|
|
29
|
+
|
|
30
|
+
from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass
|
|
31
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
32
|
+
from sage.structure.parent import Parent
|
|
33
|
+
from sage.structure.element import parent, Element
|
|
34
|
+
|
|
35
|
+
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
|
|
36
|
+
from sage.combinat.six_vertex_model import (SquareIceModel,
|
|
37
|
+
SixVertexConfiguration,
|
|
38
|
+
SixVertexModel)
|
|
39
|
+
from sage.combinat.alternating_sign_matrix import AlternatingSignMatrix
|
|
40
|
+
|
|
41
|
+
from sage.misc.decorators import options
|
|
42
|
+
from sage.matrix.constructor import matrix
|
|
43
|
+
from sage.arith.misc import factorial
|
|
44
|
+
from sage.rings.integer import Integer
|
|
45
|
+
from sage.misc.misc_c import prod
|
|
46
|
+
|
|
47
|
+
# edges of a fpl in terms of the six vertex possible configurations
|
|
48
|
+
R = (1, 0)
|
|
49
|
+
L = (-1, 0)
|
|
50
|
+
U = (0, 1)
|
|
51
|
+
D = (0, -1)
|
|
52
|
+
|
|
53
|
+
FPL_edges = (
|
|
54
|
+
# 0 UD 1 RD, 2 UR, 3 LR, 4 LD 5 LU
|
|
55
|
+
((D, U), (L, D), (D, R), (R, L), (L, U), (R, U)), # even
|
|
56
|
+
((R, L), (R, U), (L, U), (D, U), (D, R), (L, D)) # odd
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
FPL_turns = (
|
|
60
|
+
# 0 UD 1 RD 2 UR 3 LR 4 LD 5 LU
|
|
61
|
+
({U: U, D: D}, {R: D, U: L}, {U: R, L: D}, {L: L, R: R}, {R: U, D: L}, {L: U, D: R}), # even
|
|
62
|
+
({L: L, R: R}, {L: U, D: R}, {R: U, D: L}, {U: U, D: D}, {U: R, L: D}, {R: D, U: L}) # odd
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _make_color_list(n, colors=None, color_map=None, randomize=False):
|
|
67
|
+
r"""
|
|
68
|
+
TESTS::
|
|
69
|
+
|
|
70
|
+
sage: # needs numpy
|
|
71
|
+
sage: import numpy as np
|
|
72
|
+
sage: if int(np.version.short_version[0]) > 1:
|
|
73
|
+
....: _ = np.set_printoptions(legacy="1.25")
|
|
74
|
+
sage: from sage.combinat.fully_packed_loop import _make_color_list
|
|
75
|
+
sage: _make_color_list(5)
|
|
76
|
+
sage: _make_color_list(5, ['blue', 'red'])
|
|
77
|
+
['blue', 'red', 'blue', 'red', 'blue']
|
|
78
|
+
sage: _make_color_list(5, color_map='summer')
|
|
79
|
+
[(0.0, 0.5, 0.4),
|
|
80
|
+
(0.25098039215686274, 0.6254901960784314, 0.4),
|
|
81
|
+
(0.5019607843137255, 0.7509803921568627, 0.4),
|
|
82
|
+
(0.7529411764705882, 0.8764705882352941, 0.4),
|
|
83
|
+
(1.0, 1.0, 0.4)]
|
|
84
|
+
sage: l = _make_color_list(8, ['blue', 'red'], randomize=True)
|
|
85
|
+
sage: len(l)
|
|
86
|
+
8
|
|
87
|
+
sage: l.count('blue')
|
|
88
|
+
4
|
|
89
|
+
sage: l.count('red')
|
|
90
|
+
4
|
|
91
|
+
"""
|
|
92
|
+
if colors:
|
|
93
|
+
dim = len(colors)
|
|
94
|
+
colors = [colors[i % dim] for i in range(n)]
|
|
95
|
+
|
|
96
|
+
elif color_map:
|
|
97
|
+
from matplotlib import cm
|
|
98
|
+
if color_map not in cm.datad:
|
|
99
|
+
raise ValueError('unknown color map %s' % color_map)
|
|
100
|
+
cmap = cm.__dict__[color_map]
|
|
101
|
+
colors = [cmap(i / float(n - 1))[:3] for i in range(n)]
|
|
102
|
+
|
|
103
|
+
if colors and randomize:
|
|
104
|
+
from sage.misc.prandom import shuffle
|
|
105
|
+
shuffle(colors)
|
|
106
|
+
|
|
107
|
+
return colors
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class FullyPackedLoop(Element, metaclass=InheritComparisonClasscallMetaclass):
|
|
111
|
+
r"""
|
|
112
|
+
A class for fully packed loops.
|
|
113
|
+
|
|
114
|
+
A fully packed loop is a collection of non-intersecting lattice paths on a square
|
|
115
|
+
grid such that every vertex is part of some path, and the paths are either closed
|
|
116
|
+
internal loops or have endpoints corresponding to alternate points on the
|
|
117
|
+
boundary [Pro2001]_. They are known to be in bijection with alternating sign
|
|
118
|
+
matrices.
|
|
119
|
+
|
|
120
|
+
.. SEEALSO::
|
|
121
|
+
|
|
122
|
+
:class:`AlternatingSignMatrix`
|
|
123
|
+
|
|
124
|
+
To each fully packed loop, we assign a link pattern, which is the non-crossing
|
|
125
|
+
matching attained by seeing which points on the boundary are connected
|
|
126
|
+
by open paths in the fully packed loop.
|
|
127
|
+
|
|
128
|
+
We can create a fully packed loop using the corresponding alternating sign
|
|
129
|
+
matrix and also extract the link pattern::
|
|
130
|
+
|
|
131
|
+
sage: A = AlternatingSignMatrix([[0, 0, 1], [0, 1, 0], [1, 0, 0]])
|
|
132
|
+
sage: fpl = FullyPackedLoop(A)
|
|
133
|
+
sage: fpl.link_pattern()
|
|
134
|
+
[(1, 4), (2, 3), (5, 6)]
|
|
135
|
+
sage: fpl
|
|
136
|
+
│ │
|
|
137
|
+
│ │
|
|
138
|
+
+ ── + +
|
|
139
|
+
│ │
|
|
140
|
+
│ │
|
|
141
|
+
── + + + ──
|
|
142
|
+
│ │
|
|
143
|
+
│ │
|
|
144
|
+
+ + ── +
|
|
145
|
+
│ │
|
|
146
|
+
│ │
|
|
147
|
+
sage: B = AlternatingSignMatrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
|
|
148
|
+
sage: fplb = FullyPackedLoop(B)
|
|
149
|
+
sage: fplb.link_pattern()
|
|
150
|
+
[(1, 6), (2, 5), (3, 4)]
|
|
151
|
+
sage: fplb
|
|
152
|
+
│ │
|
|
153
|
+
│ │
|
|
154
|
+
+ + ── +
|
|
155
|
+
│ │
|
|
156
|
+
│ │
|
|
157
|
+
── + + + ──
|
|
158
|
+
│ │
|
|
159
|
+
│ │
|
|
160
|
+
+ ── + +
|
|
161
|
+
│ │
|
|
162
|
+
│ │
|
|
163
|
+
|
|
164
|
+
The class also has a plot method::
|
|
165
|
+
|
|
166
|
+
sage: fpl.plot() # needs sage.plot
|
|
167
|
+
Graphics object consisting of 3 graphics primitives
|
|
168
|
+
|
|
169
|
+
which gives:
|
|
170
|
+
|
|
171
|
+
.. PLOT::
|
|
172
|
+
:width: 200 px
|
|
173
|
+
|
|
174
|
+
A = AlternatingSignMatrix([[0, 0, 1], [0, 1, 0], [1, 0, 0]])
|
|
175
|
+
fpl = FullyPackedLoop(A)
|
|
176
|
+
p = fpl.plot()
|
|
177
|
+
sphinx_plot(p)
|
|
178
|
+
|
|
179
|
+
Note that we can also create a fully packed loop from a six vertex model configuration::
|
|
180
|
+
|
|
181
|
+
sage: S = SixVertexModel(3, boundary_conditions='ice').from_alternating_sign_matrix(A)
|
|
182
|
+
sage: S
|
|
183
|
+
^ ^ ^
|
|
184
|
+
| | |
|
|
185
|
+
--> # -> # -> # <--
|
|
186
|
+
^ ^ |
|
|
187
|
+
| | V
|
|
188
|
+
--> # -> # <- # <--
|
|
189
|
+
^ | |
|
|
190
|
+
| V V
|
|
191
|
+
--> # <- # <- # <--
|
|
192
|
+
| | |
|
|
193
|
+
V V V
|
|
194
|
+
sage: fpl = FullyPackedLoop(S)
|
|
195
|
+
sage: fpl
|
|
196
|
+
│ │
|
|
197
|
+
│ │
|
|
198
|
+
+ ── + +
|
|
199
|
+
│ │
|
|
200
|
+
│ │
|
|
201
|
+
── + + + ──
|
|
202
|
+
│ │
|
|
203
|
+
│ │
|
|
204
|
+
+ + ── +
|
|
205
|
+
│ │
|
|
206
|
+
│ │
|
|
207
|
+
|
|
208
|
+
Once we have a fully packed loop we can obtain the corresponding alternating sign matrix::
|
|
209
|
+
|
|
210
|
+
sage: fpl.to_alternating_sign_matrix()
|
|
211
|
+
[0 0 1]
|
|
212
|
+
[0 1 0]
|
|
213
|
+
[1 0 0]
|
|
214
|
+
|
|
215
|
+
Here are some more examples using bigger ASMs::
|
|
216
|
+
|
|
217
|
+
sage: A = AlternatingSignMatrix([[0,1,0,0],[0,0,1,0],[1,-1,0,1],[0,1,0,0]])
|
|
218
|
+
sage: S = SixVertexModel(4, boundary_conditions='ice').from_alternating_sign_matrix(A)
|
|
219
|
+
sage: fpl = FullyPackedLoop(S)
|
|
220
|
+
sage: fpl.link_pattern()
|
|
221
|
+
[(1, 2), (3, 6), (4, 5), (7, 8)]
|
|
222
|
+
sage: fpl
|
|
223
|
+
│ │
|
|
224
|
+
│ │
|
|
225
|
+
+ ── + ── + + ──
|
|
226
|
+
│
|
|
227
|
+
│
|
|
228
|
+
── + + ── + ── +
|
|
229
|
+
│ │
|
|
230
|
+
│ │
|
|
231
|
+
+ + + ── + ──
|
|
232
|
+
│ │ │
|
|
233
|
+
│ │ │
|
|
234
|
+
── + + + ── +
|
|
235
|
+
│ │
|
|
236
|
+
│ │
|
|
237
|
+
|
|
238
|
+
sage: m = AlternatingSignMatrix([[0,0,1,0,0,0],
|
|
239
|
+
....: [1,0,-1,0,1,0],
|
|
240
|
+
....: [0,0,0,1,0,0],
|
|
241
|
+
....: [0,1,0,0,-1,1],
|
|
242
|
+
....: [0,0,0,0,1,0],
|
|
243
|
+
....: [0,0,1,0,0,0]])
|
|
244
|
+
sage: fpl = FullyPackedLoop(m)
|
|
245
|
+
sage: fpl.link_pattern()
|
|
246
|
+
[(1, 12), (2, 7), (3, 4), (5, 6), (8, 9), (10, 11)]
|
|
247
|
+
sage: fpl
|
|
248
|
+
│ │ │
|
|
249
|
+
│ │ │
|
|
250
|
+
+ ── + + + ── + + ──
|
|
251
|
+
│ │ │ │
|
|
252
|
+
│ │ │ │
|
|
253
|
+
── + ── + + + ── + ── +
|
|
254
|
+
│
|
|
255
|
+
│
|
|
256
|
+
+ ── + + ── + ── + + ──
|
|
257
|
+
│ │ │ │
|
|
258
|
+
│ │ │ │
|
|
259
|
+
── + + + ── + + +
|
|
260
|
+
│ │ │ │ │
|
|
261
|
+
│ │ │ │ │
|
|
262
|
+
+ ── + + ── + + + ──
|
|
263
|
+
│ │
|
|
264
|
+
│ │
|
|
265
|
+
── + + ── + ── + + ── +
|
|
266
|
+
│ │ │
|
|
267
|
+
│ │ │
|
|
268
|
+
|
|
269
|
+
sage: m = AlternatingSignMatrix([[0,1,0,0,0,0,0],
|
|
270
|
+
....: [1,-1,0,0,1,0,0],
|
|
271
|
+
....: [0,0,0,1,0,0,0],
|
|
272
|
+
....: [0,1,0,0,-1,1,0],
|
|
273
|
+
....: [0,0,0,0,1,0,0],
|
|
274
|
+
....: [0,0,1,0,-1,0,1],
|
|
275
|
+
....: [0,0,0,0,1,0,0]])
|
|
276
|
+
sage: fpl = FullyPackedLoop(m)
|
|
277
|
+
sage: fpl.link_pattern()
|
|
278
|
+
[(1, 2), (3, 4), (5, 6), (7, 8), (9, 14), (10, 11), (12, 13)]
|
|
279
|
+
sage: fpl
|
|
280
|
+
│ │ │ │
|
|
281
|
+
│ │ │ │
|
|
282
|
+
+ ── + ── + + ── + + ── +
|
|
283
|
+
│ │
|
|
284
|
+
│ │
|
|
285
|
+
── + ── + ── + + ── + ── + + ──
|
|
286
|
+
│ │
|
|
287
|
+
│ │
|
|
288
|
+
+ ── + + ── + ── + + ── +
|
|
289
|
+
│ │ │ │
|
|
290
|
+
│ │ │ │
|
|
291
|
+
── + + + ── + + + + ──
|
|
292
|
+
│ │ │ │ │ │
|
|
293
|
+
│ │ │ │ │ │
|
|
294
|
+
+ ── + + ── + + + ── +
|
|
295
|
+
│ │
|
|
296
|
+
│ │
|
|
297
|
+
── + + ── + ── + + + ── + ──
|
|
298
|
+
│ │ │ │
|
|
299
|
+
│ │ │ │
|
|
300
|
+
+ ── + + ── + + + ── +
|
|
301
|
+
│ │ │ │
|
|
302
|
+
│ │ │ │
|
|
303
|
+
|
|
304
|
+
Gyration on an alternating sign matrix/fully packed loop ``fpl``
|
|
305
|
+
of the link pattern corresponding to ``fpl``::
|
|
306
|
+
|
|
307
|
+
sage: ASMs = AlternatingSignMatrices(3).list()
|
|
308
|
+
sage: ncp = FullyPackedLoop(ASMs[1]).link_pattern() # fpl's gyration orbit size is 2
|
|
309
|
+
sage: rotated_ncp=[]
|
|
310
|
+
sage: for (a,b) in ncp:
|
|
311
|
+
....: for i in range(5):
|
|
312
|
+
....: a,b=a%6+1,b%6+1;
|
|
313
|
+
....: rotated_ncp.append((a,b))
|
|
314
|
+
sage: PerfectMatching(ASMs[1].gyration().to_fully_packed_loop().link_pattern()) ==\
|
|
315
|
+
....: PerfectMatching(rotated_ncp)
|
|
316
|
+
True
|
|
317
|
+
|
|
318
|
+
sage: fpl = FullyPackedLoop(ASMs[0])
|
|
319
|
+
sage: ncp = fpl.link_pattern() # fpl's gyration size is 3
|
|
320
|
+
sage: rotated_ncp=[]
|
|
321
|
+
sage: for (a,b) in ncp:
|
|
322
|
+
....: for i in range(5):
|
|
323
|
+
....: a,b=a%6+1,b%6+1;
|
|
324
|
+
....: rotated_ncp.append((a,b))
|
|
325
|
+
sage: PerfectMatching(ASMs[0].gyration().to_fully_packed_loop().link_pattern()) ==\
|
|
326
|
+
....: PerfectMatching(rotated_ncp)
|
|
327
|
+
True
|
|
328
|
+
|
|
329
|
+
sage: mat = AlternatingSignMatrix([[0,0,1,0,0,0,0],[1,0,-1,0,1,0,0],
|
|
330
|
+
....: [0,0,1,0,0,0,0],[0,1,-1,0,0,1,0],[0,0,1,0,0,0,0],[0,0,0,1,0,0,0],[0,0,0,0,0,0,1]])
|
|
331
|
+
sage: fpl = FullyPackedLoop(mat) # n=7
|
|
332
|
+
sage: ncp = fpl.link_pattern()
|
|
333
|
+
sage: rotated_ncp=[]
|
|
334
|
+
sage: for (a,b) in ncp:
|
|
335
|
+
....: for i in range(13):
|
|
336
|
+
....: a,b=a%14+1,b%14+1;
|
|
337
|
+
....: rotated_ncp.append((a,b))
|
|
338
|
+
sage: PerfectMatching(mat.gyration().to_fully_packed_loop().link_pattern()) ==\
|
|
339
|
+
....: PerfectMatching(rotated_ncp)
|
|
340
|
+
True
|
|
341
|
+
|
|
342
|
+
sage: mat = AlternatingSignMatrix([[0,0,0,1,0,0], [0,0,1,-1,1,0],
|
|
343
|
+
....: [0,1,0,0,-1,1], [1,0,-1,1,0,0], [0,0,1,0,0,0], [0,0,0,0,1,0]])
|
|
344
|
+
sage: fpl = FullyPackedLoop(mat) # n =6
|
|
345
|
+
sage: ncp = fpl.link_pattern()
|
|
346
|
+
sage: rotated_ncp=[]
|
|
347
|
+
sage: for (a,b) in ncp:
|
|
348
|
+
....: for i in range(11):
|
|
349
|
+
....: a,b=a%12+1,b%12+1;
|
|
350
|
+
....: rotated_ncp.append((a,b))
|
|
351
|
+
sage: PerfectMatching(mat.gyration().to_fully_packed_loop().link_pattern()) ==\
|
|
352
|
+
....: PerfectMatching(rotated_ncp)
|
|
353
|
+
True
|
|
354
|
+
|
|
355
|
+
More examples:
|
|
356
|
+
|
|
357
|
+
We can initiate a fully packed loop using an alternating sign matrix::
|
|
358
|
+
|
|
359
|
+
sage: A = AlternatingSignMatrix([[0, 0, 1], [0, 1, 0], [1, 0, 0]])
|
|
360
|
+
sage: fpl = FullyPackedLoop(A)
|
|
361
|
+
sage: fpl
|
|
362
|
+
│ │
|
|
363
|
+
│ │
|
|
364
|
+
+ ── + +
|
|
365
|
+
│ │
|
|
366
|
+
│ │
|
|
367
|
+
── + + + ──
|
|
368
|
+
│ │
|
|
369
|
+
│ │
|
|
370
|
+
+ + ── +
|
|
371
|
+
│ │
|
|
372
|
+
│ │
|
|
373
|
+
sage: FullyPackedLoops(3)(A) == fpl
|
|
374
|
+
True
|
|
375
|
+
|
|
376
|
+
We can also input a matrix::
|
|
377
|
+
|
|
378
|
+
sage: FullyPackedLoop([[0, 0, 1], [0, 1, 0], [1, 0, 0]])
|
|
379
|
+
│ │
|
|
380
|
+
│ │
|
|
381
|
+
+ ── + +
|
|
382
|
+
│ │
|
|
383
|
+
│ │
|
|
384
|
+
── + + + ──
|
|
385
|
+
│ │
|
|
386
|
+
│ │
|
|
387
|
+
+ + ── +
|
|
388
|
+
│ │
|
|
389
|
+
│ │
|
|
390
|
+
sage: FullyPackedLoop([[0, 0, 1], [0, 1, 0], [1, 0, 0]]) ==\
|
|
391
|
+
....: FullyPackedLoops(3)([[0, 0, 1], [0, 1, 0], [1, 0, 0]])
|
|
392
|
+
True
|
|
393
|
+
|
|
394
|
+
Otherwise we initiate a fully packed loop using a six vertex model::
|
|
395
|
+
|
|
396
|
+
sage: S = SixVertexModel(3, boundary_conditions='ice').from_alternating_sign_matrix(A)
|
|
397
|
+
sage: fpl = FullyPackedLoop(S)
|
|
398
|
+
sage: fpl
|
|
399
|
+
│ │
|
|
400
|
+
│ │
|
|
401
|
+
+ ── + +
|
|
402
|
+
│ │
|
|
403
|
+
│ │
|
|
404
|
+
── + + + ──
|
|
405
|
+
│ │
|
|
406
|
+
│ │
|
|
407
|
+
+ + ── +
|
|
408
|
+
│ │
|
|
409
|
+
│ │
|
|
410
|
+
|
|
411
|
+
sage: FullyPackedLoops(3)(S) == FullyPackedLoop(S)
|
|
412
|
+
True
|
|
413
|
+
|
|
414
|
+
sage: fpl.six_vertex_model().to_alternating_sign_matrix()
|
|
415
|
+
[0 0 1]
|
|
416
|
+
[0 1 0]
|
|
417
|
+
[1 0 0]
|
|
418
|
+
|
|
419
|
+
We can also input the matrix associated to a six vertex model::
|
|
420
|
+
|
|
421
|
+
sage: SixVertexModel(2)([[3,1],[5,3]])
|
|
422
|
+
^ ^
|
|
423
|
+
| |
|
|
424
|
+
--> # <- # <--
|
|
425
|
+
| ^
|
|
426
|
+
V |
|
|
427
|
+
--> # -> # <--
|
|
428
|
+
| |
|
|
429
|
+
V V
|
|
430
|
+
|
|
431
|
+
sage: FullyPackedLoop([[3,1],[5,3]])
|
|
432
|
+
│
|
|
433
|
+
│
|
|
434
|
+
+ + ──
|
|
435
|
+
│ │
|
|
436
|
+
│ │
|
|
437
|
+
── + +
|
|
438
|
+
│
|
|
439
|
+
│
|
|
440
|
+
|
|
441
|
+
sage: FullyPackedLoops(2)([[3,1],[5,3]]) == FullyPackedLoop([[3,1],[5,3]])
|
|
442
|
+
True
|
|
443
|
+
|
|
444
|
+
Note that the matrix corresponding to a six vertex model without
|
|
445
|
+
the ice boundary condition is not allowed::
|
|
446
|
+
|
|
447
|
+
sage: SixVertexModel(2)([[3,1],[5,5]])
|
|
448
|
+
^ ^
|
|
449
|
+
| |
|
|
450
|
+
--> # <- # <--
|
|
451
|
+
| ^
|
|
452
|
+
V V
|
|
453
|
+
--> # -> # -->
|
|
454
|
+
| |
|
|
455
|
+
V V
|
|
456
|
+
|
|
457
|
+
sage: FullyPackedLoop([[3,1],[5,5]])
|
|
458
|
+
Traceback (most recent call last):
|
|
459
|
+
...
|
|
460
|
+
ValueError: invalid alternating sign matrix
|
|
461
|
+
|
|
462
|
+
sage: FullyPackedLoops(2)([[3,1],[5,5]])
|
|
463
|
+
Traceback (most recent call last):
|
|
464
|
+
...
|
|
465
|
+
ValueError: invalid alternating sign matrix
|
|
466
|
+
|
|
467
|
+
Note that if anything else is used to generate the fully packed loop an error will occur::
|
|
468
|
+
|
|
469
|
+
sage: fpl = FullyPackedLoop(5)
|
|
470
|
+
Traceback (most recent call last):
|
|
471
|
+
...
|
|
472
|
+
ValueError: invalid alternating sign matrix
|
|
473
|
+
|
|
474
|
+
sage: fpl = FullyPackedLoop((1, 2, 3))
|
|
475
|
+
Traceback (most recent call last):
|
|
476
|
+
...
|
|
477
|
+
ValueError: the alternating sign matrices must be square
|
|
478
|
+
|
|
479
|
+
sage: SVM = SixVertexModel(3)[0]
|
|
480
|
+
sage: FullyPackedLoop(SVM)
|
|
481
|
+
Traceback (most recent call last):
|
|
482
|
+
...
|
|
483
|
+
ValueError: invalid alternating sign matrix
|
|
484
|
+
|
|
485
|
+
REFERENCES:
|
|
486
|
+
|
|
487
|
+
- [Pro2001]_
|
|
488
|
+
- [Str2015]_
|
|
489
|
+
"""
|
|
490
|
+
@staticmethod
|
|
491
|
+
def __classcall_private__(cls, generator):
|
|
492
|
+
"""
|
|
493
|
+
Create a FPL.
|
|
494
|
+
|
|
495
|
+
EXAMPLES::
|
|
496
|
+
|
|
497
|
+
sage: A = AlternatingSignMatrix([[1, 0, 0],[0, 1, 0],[0, 0, 1]])
|
|
498
|
+
sage: FullyPackedLoop(A)
|
|
499
|
+
│ │
|
|
500
|
+
│ │
|
|
501
|
+
+ + ── +
|
|
502
|
+
│ │
|
|
503
|
+
│ │
|
|
504
|
+
── + + + ──
|
|
505
|
+
│ │
|
|
506
|
+
│ │
|
|
507
|
+
+ ── + +
|
|
508
|
+
│ │
|
|
509
|
+
│ │
|
|
510
|
+
|
|
511
|
+
sage: SVM = SixVertexModel(4, boundary_conditions='ice')[0]
|
|
512
|
+
sage: FullyPackedLoop(SVM)
|
|
513
|
+
│ │
|
|
514
|
+
│ │
|
|
515
|
+
+ + ── + + ──
|
|
516
|
+
│ │ │
|
|
517
|
+
│ │ │
|
|
518
|
+
── + + + ── +
|
|
519
|
+
│ │
|
|
520
|
+
│ │
|
|
521
|
+
+ ── + + + ──
|
|
522
|
+
│ │ │
|
|
523
|
+
│ │ │
|
|
524
|
+
── + + ── + +
|
|
525
|
+
│ │
|
|
526
|
+
│ │
|
|
527
|
+
"""
|
|
528
|
+
if isinstance(generator, AlternatingSignMatrix):
|
|
529
|
+
SVM = generator.to_six_vertex_model()
|
|
530
|
+
elif isinstance(generator, SquareIceModel.Element):
|
|
531
|
+
SVM = generator
|
|
532
|
+
elif isinstance(generator, SixVertexConfiguration):
|
|
533
|
+
# Check that this is an ice square model
|
|
534
|
+
generator = SixVertexModel(generator.parent()._nrows,
|
|
535
|
+
boundary_conditions='ice')(generator)
|
|
536
|
+
M = generator.to_alternating_sign_matrix().to_matrix()
|
|
537
|
+
AlternatingSignMatrix(M)
|
|
538
|
+
SVM = generator
|
|
539
|
+
else: # Not ASM nor SVM
|
|
540
|
+
try:
|
|
541
|
+
SVM = AlternatingSignMatrix(generator).to_six_vertex_model()
|
|
542
|
+
except (TypeError, ValueError):
|
|
543
|
+
generator = matrix(generator)
|
|
544
|
+
generator = SixVertexModel(generator.nrows(), boundary_conditions='ice')(generator)
|
|
545
|
+
# Check that this is an ice square model
|
|
546
|
+
generator.to_alternating_sign_matrix()
|
|
547
|
+
SVM = generator
|
|
548
|
+
|
|
549
|
+
if not SVM:
|
|
550
|
+
raise TypeError('generator for FullyPackedLoop must either be an '
|
|
551
|
+
'AlternatingSignMatrix or a SquareIceModel.Element')
|
|
552
|
+
FPLs = FullyPackedLoops(len(SVM))
|
|
553
|
+
return FPLs(generator)
|
|
554
|
+
|
|
555
|
+
def __init__(self, parent, generator):
|
|
556
|
+
"""
|
|
557
|
+
Initialise object, can take ASM of FPL as generator.
|
|
558
|
+
|
|
559
|
+
TESTS::
|
|
560
|
+
|
|
561
|
+
sage: A = AlternatingSignMatrix([[0, 0, 1], [0, 1, 0], [1, 0, 0]])
|
|
562
|
+
sage: fpl = FullyPackedLoop(A)
|
|
563
|
+
sage: TestSuite(fpl).run()
|
|
564
|
+
"""
|
|
565
|
+
if isinstance(generator, AlternatingSignMatrix):
|
|
566
|
+
self._six_vertex_model = generator.to_six_vertex_model()
|
|
567
|
+
elif isinstance(generator, SquareIceModel.Element):
|
|
568
|
+
self._six_vertex_model = generator
|
|
569
|
+
|
|
570
|
+
Element.__init__(self, parent)
|
|
571
|
+
|
|
572
|
+
def _repr_(self):
|
|
573
|
+
"""
|
|
574
|
+
Return a string representation of ``self``.
|
|
575
|
+
|
|
576
|
+
EXAMPLES::
|
|
577
|
+
|
|
578
|
+
sage: A = AlternatingSignMatrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
|
|
579
|
+
sage: fpl = FullyPackedLoop(A)
|
|
580
|
+
sage: fpl
|
|
581
|
+
│ │
|
|
582
|
+
│ │
|
|
583
|
+
+ + ── +
|
|
584
|
+
│ │
|
|
585
|
+
│ │
|
|
586
|
+
── + + + ──
|
|
587
|
+
│ │
|
|
588
|
+
│ │
|
|
589
|
+
+ ── + +
|
|
590
|
+
│ │
|
|
591
|
+
│ │
|
|
592
|
+
|
|
593
|
+
sage: A = AlternatingSignMatrix([[0,1,0,0],[0,0,1,0],[1,-1,0,1],[0,1,0,0]])
|
|
594
|
+
sage: S = SixVertexModel(4, boundary_conditions='ice').from_alternating_sign_matrix(A)
|
|
595
|
+
sage: fpl = FullyPackedLoop(S)
|
|
596
|
+
sage: fpl
|
|
597
|
+
│ │
|
|
598
|
+
│ │
|
|
599
|
+
+ ── + ── + + ──
|
|
600
|
+
│
|
|
601
|
+
│
|
|
602
|
+
── + + ── + ── +
|
|
603
|
+
│ │
|
|
604
|
+
│ │
|
|
605
|
+
+ + + ── + ──
|
|
606
|
+
│ │ │
|
|
607
|
+
│ │ │
|
|
608
|
+
── + + + ── +
|
|
609
|
+
│ │
|
|
610
|
+
│ │
|
|
611
|
+
"""
|
|
612
|
+
# List are in the order of URDL
|
|
613
|
+
# One set of rules for how to draw around even vertex, one set of rules for odd vertex
|
|
614
|
+
n = len(self._six_vertex_model) - 1
|
|
615
|
+
ascii1 = [[r' ', ' ─', r' ', '─ '], # LR
|
|
616
|
+
[r' │ ', ' ', r' ', '─ '], # LU
|
|
617
|
+
[r' ', ' ', r' │ ', '─ '], # LD
|
|
618
|
+
[r' │ ', ' ', r' │ ', ' '], # UD
|
|
619
|
+
[r' │ ', ' ─', r' ', ' '], # UR
|
|
620
|
+
[r' ', ' ─', r' │ ', ' ']] # RD
|
|
621
|
+
|
|
622
|
+
ascii2 = [[r' │ ', ' ', r' │ ', ' '], # LR
|
|
623
|
+
[r' ', ' ─', r' │ ', ' '], # LU
|
|
624
|
+
[r' │ ', ' ─', r' ', ' '], # LD
|
|
625
|
+
[r' ', ' ─', r' ', '─ '], # UD
|
|
626
|
+
[r' ', ' ', r' │ ', '─ '], # UR
|
|
627
|
+
[r' │ ', ' ', r' ', '─ ']] # RD
|
|
628
|
+
ret = ' '
|
|
629
|
+
# Do the top line
|
|
630
|
+
for i, entry in enumerate(self._six_vertex_model[0]):
|
|
631
|
+
ret += ' ' if i % 2 else ' │ '
|
|
632
|
+
|
|
633
|
+
plus_sign = '+'
|
|
634
|
+
|
|
635
|
+
# Do the meat of the ascii art
|
|
636
|
+
for j, row in enumerate(self._six_vertex_model):
|
|
637
|
+
ret += '\n '
|
|
638
|
+
# Do the top row
|
|
639
|
+
for i, entry in enumerate(row):
|
|
640
|
+
if not (i + j) % 2:
|
|
641
|
+
ret += ascii1[entry][0]
|
|
642
|
+
else:
|
|
643
|
+
ret += ascii2[entry][0]
|
|
644
|
+
ret += '\n'
|
|
645
|
+
|
|
646
|
+
# Do the left-most entry
|
|
647
|
+
if not j % 2:
|
|
648
|
+
ret += ' '
|
|
649
|
+
else:
|
|
650
|
+
ret += ' ─'
|
|
651
|
+
|
|
652
|
+
# Do the middle row
|
|
653
|
+
for i, entry in enumerate(row):
|
|
654
|
+
if (i + j) % 2 == 0:
|
|
655
|
+
ret += ascii1[entry][3] + plus_sign + ascii1[entry][1]
|
|
656
|
+
else:
|
|
657
|
+
ret += ascii2[entry][3] + plus_sign + ascii2[entry][1]
|
|
658
|
+
|
|
659
|
+
# Do the right-most entry
|
|
660
|
+
if not (j + n) % 2:
|
|
661
|
+
ret += ' '
|
|
662
|
+
else:
|
|
663
|
+
ret += '─ '
|
|
664
|
+
|
|
665
|
+
# Do the bottom row
|
|
666
|
+
ret += '\n '
|
|
667
|
+
for i, entry in enumerate(row):
|
|
668
|
+
if not (i + j) % 2:
|
|
669
|
+
ret += ascii1[entry][2]
|
|
670
|
+
else:
|
|
671
|
+
ret += ascii2[entry][2]
|
|
672
|
+
|
|
673
|
+
# Do the bottom line
|
|
674
|
+
ret += '\n '
|
|
675
|
+
for i, entry in enumerate(self._six_vertex_model[-1]):
|
|
676
|
+
ret += ' │ ' if (i + n + 1) % 2 else ' '
|
|
677
|
+
|
|
678
|
+
return ret
|
|
679
|
+
|
|
680
|
+
def _richcmp_(self, other, op):
|
|
681
|
+
"""
|
|
682
|
+
Check equality or inequality.
|
|
683
|
+
|
|
684
|
+
EXAMPLES::
|
|
685
|
+
|
|
686
|
+
sage: A = AlternatingSignMatrices(3)
|
|
687
|
+
sage: M = A.random_element()
|
|
688
|
+
sage: FullyPackedLoop(M) == M.to_fully_packed_loop()
|
|
689
|
+
True
|
|
690
|
+
|
|
691
|
+
sage: FullyPackedLoop(A([[1, 0, 0],[0, 1, 0],[0, 0, 1]])) ==\
|
|
692
|
+
....: FullyPackedLoop(A([[1, 0, 0],[0, 0, 1],[0, 1, 0]]))
|
|
693
|
+
False
|
|
694
|
+
|
|
695
|
+
sage: FullyPackedLoop(M) == M
|
|
696
|
+
False
|
|
697
|
+
|
|
698
|
+
sage: M = A.random_element()
|
|
699
|
+
sage: FullyPackedLoop(M) != M.to_fully_packed_loop()
|
|
700
|
+
False
|
|
701
|
+
|
|
702
|
+
sage: f0 = FullyPackedLoop(A([[1, 0, 0],[0, 1, 0],[0, 0, 1]]))
|
|
703
|
+
sage: f1 = FullyPackedLoop(A([[1, 0, 0],[0, 0, 1],[0, 1, 0]]))
|
|
704
|
+
sage: f0 != f1
|
|
705
|
+
True
|
|
706
|
+
"""
|
|
707
|
+
return self._six_vertex_model._richcmp_(other._six_vertex_model, op)
|
|
708
|
+
|
|
709
|
+
def to_alternating_sign_matrix(self):
|
|
710
|
+
"""
|
|
711
|
+
Return the alternating sign matrix corresponding to this class.
|
|
712
|
+
|
|
713
|
+
.. SEEALSO::
|
|
714
|
+
|
|
715
|
+
:class:`AlternatingSignMatrix`
|
|
716
|
+
|
|
717
|
+
EXAMPLES::
|
|
718
|
+
|
|
719
|
+
sage: A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]])
|
|
720
|
+
sage: S = SixVertexModel(3, boundary_conditions='ice').from_alternating_sign_matrix(A)
|
|
721
|
+
sage: fpl = FullyPackedLoop(S)
|
|
722
|
+
sage: fpl.to_alternating_sign_matrix()
|
|
723
|
+
[ 0 1 0]
|
|
724
|
+
[ 1 -1 1]
|
|
725
|
+
[ 0 1 0]
|
|
726
|
+
sage: A = AlternatingSignMatrix([[0,1,0,0],[0,0,1,0],[1,-1,0,1],[0,1,0,0]])
|
|
727
|
+
sage: S = SixVertexModel(4, boundary_conditions='ice').from_alternating_sign_matrix(A)
|
|
728
|
+
sage: fpl = FullyPackedLoop(S)
|
|
729
|
+
sage: fpl.to_alternating_sign_matrix()
|
|
730
|
+
[ 0 1 0 0]
|
|
731
|
+
[ 0 0 1 0]
|
|
732
|
+
[ 1 -1 0 1]
|
|
733
|
+
[ 0 1 0 0]
|
|
734
|
+
"""
|
|
735
|
+
return self._six_vertex_model.to_alternating_sign_matrix()
|
|
736
|
+
|
|
737
|
+
@options(link=True, loop=True, loop_fill=False)
|
|
738
|
+
def plot(self, **options):
|
|
739
|
+
r"""
|
|
740
|
+
Return a graphical object of the Fully Packed Loop.
|
|
741
|
+
|
|
742
|
+
Each option can be specified separately for links (the curves that join
|
|
743
|
+
boundary points) and the loops. In order to do so, you need to prefix
|
|
744
|
+
its name with either ``'link_'`` or ``'loop_'``. As an example, setting
|
|
745
|
+
``color='red'`` will color both links and loops in red while setting
|
|
746
|
+
``link_color='red'`` will only apply the color option for the links.
|
|
747
|
+
|
|
748
|
+
INPUT:
|
|
749
|
+
|
|
750
|
+
- ``link``, ``loop`` -- boolean (default: ``True``); whether to plot the links
|
|
751
|
+
or the loops
|
|
752
|
+
|
|
753
|
+
- ``color``, ``link_color``, ``loop_color`` -- (optional) string or RGB triple
|
|
754
|
+
|
|
755
|
+
- ``colors``, ``link_colors``, ``loop_colors`` -- (optional) list of colors
|
|
756
|
+
|
|
757
|
+
- ``color_map``, ``link_color_map``, ``loop_color_map`` -- (string,
|
|
758
|
+
optional) a name of a matplotlib color map for the link or the loop
|
|
759
|
+
|
|
760
|
+
- ``link_color_randomize`` -- boolean (default: ``False``); when
|
|
761
|
+
``link_colors`` or ``link_color_map`` is specified it randomizes
|
|
762
|
+
its order. Setting this option to ``True`` makes it unlikely to
|
|
763
|
+
have two neighboring links with the same color.
|
|
764
|
+
|
|
765
|
+
- ``loop_fill`` -- (boolean, optional) whether to fill the interior of the loops
|
|
766
|
+
|
|
767
|
+
EXAMPLES:
|
|
768
|
+
|
|
769
|
+
To plot the fully packed loop associated to the following alternating sign
|
|
770
|
+
matrix
|
|
771
|
+
|
|
772
|
+
.. MATH::
|
|
773
|
+
|
|
774
|
+
\begin{pmatrix} 0&1&1 \\ 1&-1&1 \\ 0&1&0 \end{pmatrix}
|
|
775
|
+
|
|
776
|
+
simply do::
|
|
777
|
+
|
|
778
|
+
sage: A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]])
|
|
779
|
+
sage: fpl = FullyPackedLoop(A)
|
|
780
|
+
sage: fpl.plot() # needs sage.plot
|
|
781
|
+
Graphics object consisting of 3 graphics primitives
|
|
782
|
+
|
|
783
|
+
The resulting graphics is as follows
|
|
784
|
+
|
|
785
|
+
.. PLOT::
|
|
786
|
+
:width: 200 px
|
|
787
|
+
|
|
788
|
+
A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]])
|
|
789
|
+
fpl = FullyPackedLoop(A)
|
|
790
|
+
p = fpl.plot()
|
|
791
|
+
sphinx_plot(p)
|
|
792
|
+
|
|
793
|
+
You can also have the three links in different colors with::
|
|
794
|
+
|
|
795
|
+
sage: A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]])
|
|
796
|
+
sage: fpl = FullyPackedLoop(A)
|
|
797
|
+
sage: fpl.plot(link_color_map='rainbow') # needs sage.plot
|
|
798
|
+
Graphics object consisting of 3 graphics primitives
|
|
799
|
+
|
|
800
|
+
.. PLOT::
|
|
801
|
+
:width: 200 px
|
|
802
|
+
|
|
803
|
+
A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]])
|
|
804
|
+
fpl = FullyPackedLoop(A)
|
|
805
|
+
p = fpl.plot(link_color_map='rainbow')
|
|
806
|
+
sphinx_plot(p)
|
|
807
|
+
|
|
808
|
+
You can plot the 42 fully packed loops of size `4 \times 4` using::
|
|
809
|
+
|
|
810
|
+
sage: G = [fpl.plot(link_color_map='winter', loop_color='black') # needs sage.plot
|
|
811
|
+
....: for fpl in FullyPackedLoops(4)]
|
|
812
|
+
sage: graphics_array(G, 7, 6) # needs sage.plot
|
|
813
|
+
Graphics Array of size 7 x 6
|
|
814
|
+
|
|
815
|
+
.. PLOT::
|
|
816
|
+
:width: 600 px
|
|
817
|
+
|
|
818
|
+
G = [fpl.plot(link_color_map='winter', loop_color='black') for fpl in FullyPackedLoops(4)]
|
|
819
|
+
p = graphics_array(G, 7, 6)
|
|
820
|
+
sphinx_plot(p)
|
|
821
|
+
|
|
822
|
+
Here is an example of a `20 \times 20` fully packed loop::
|
|
823
|
+
|
|
824
|
+
sage: s = "00000000000+0000000000000000+00-0+00000000000+00-00+0-+00000\
|
|
825
|
+
....: 0000+-00+00-+00000000+00-0000+0000-+00000000+000-0+0-+0-+000\
|
|
826
|
+
....: 000+-000+-00+0000000+-+-000+00-+0-000+000+-000+-0+0000000-0+\
|
|
827
|
+
....: 0000+0-+0-+00000-+00000+-+0-0+-00+0000000000+-0000+0-00+0000\
|
|
828
|
+
....: 000000+0-000+000000000000000+0000-00+00000000+0000-000+00000\
|
|
829
|
+
....: 00+0-00+0000000000000000+-0000+000000-+000000+00-0000+-00+00\
|
|
830
|
+
....: 00000000+-0000+00000000000000+0000000000"
|
|
831
|
+
sage: a = matrix(20, [{'0':0, '+':1, '-': -1}[i] for i in s])
|
|
832
|
+
sage: fpl = FullyPackedLoop(a)
|
|
833
|
+
sage: fpl.plot(loop_fill=True, loop_color_map='rainbow') # needs sage.plot
|
|
834
|
+
Graphics object consisting of 27 graphics primitives
|
|
835
|
+
|
|
836
|
+
.. PLOT::
|
|
837
|
+
:width: 400 px
|
|
838
|
+
|
|
839
|
+
s = "00000000000+0000000000000000+00-0+00000000000+00-00+0-+00000\
|
|
840
|
+
0000+-00+00-+00000000+00-0000+0000-+00000000+000-0+0-+0-+000\
|
|
841
|
+
000+-000+-00+0000000+-+-000+00-+0-000+000+-000+-0+0000000-0+\
|
|
842
|
+
0000+0-+0-+00000-+00000+-+0-0+-00+0000000000+-0000+0-00+0000\
|
|
843
|
+
000000+0-000+000000000000000+0000-00+00000000+0000-000+00000\
|
|
844
|
+
00+0-00+0000000000000000+-0000+000000-+000000+00-0000+-00+00\
|
|
845
|
+
00000000+-0000+00000000000000+0000000000"
|
|
846
|
+
a = matrix(20, [{'0':0, '+':1, '-': -1}[i] for i in s])
|
|
847
|
+
p = FullyPackedLoop(a).plot(loop_fill=True, loop_color_map='rainbow')
|
|
848
|
+
sphinx_plot(p)
|
|
849
|
+
"""
|
|
850
|
+
from sage.plot.graphics import Graphics
|
|
851
|
+
from sage.plot.line import line2d
|
|
852
|
+
from sage.plot.polygon import polygon2d
|
|
853
|
+
|
|
854
|
+
link_options = {}
|
|
855
|
+
loop_options = {}
|
|
856
|
+
for k, v in options.items():
|
|
857
|
+
if k == 'link':
|
|
858
|
+
link = v
|
|
859
|
+
elif k == 'loop':
|
|
860
|
+
loop = v
|
|
861
|
+
elif k.startswith('link_'):
|
|
862
|
+
link_options[k[5:]] = v
|
|
863
|
+
elif k.startswith('loop_'):
|
|
864
|
+
loop_options[k[5:]] = v
|
|
865
|
+
else:
|
|
866
|
+
link_options[k] = v
|
|
867
|
+
loop_options[k] = v
|
|
868
|
+
|
|
869
|
+
sv = self._six_vertex_model
|
|
870
|
+
n = len(sv)
|
|
871
|
+
|
|
872
|
+
# LR boundaries => odd sum
|
|
873
|
+
# UD boundaries => even sum
|
|
874
|
+
rank = self.parent()._boundary_index
|
|
875
|
+
unrank = self.parent()._boundary
|
|
876
|
+
seen = [False] * (2*n)
|
|
877
|
+
|
|
878
|
+
squares = set((i, j) for i in range(n) for j in range(n))
|
|
879
|
+
|
|
880
|
+
colors = _make_color_list(2*n,
|
|
881
|
+
colors=link_options.pop('colors', None),
|
|
882
|
+
color_map=link_options.pop('color_map', None),
|
|
883
|
+
randomize=link_options.pop('color_randomize', False))
|
|
884
|
+
|
|
885
|
+
G = Graphics()
|
|
886
|
+
for i in range(2*n):
|
|
887
|
+
if seen[i]:
|
|
888
|
+
continue
|
|
889
|
+
orbit = self._link_or_loop_from(unrank(i))
|
|
890
|
+
j = rank(orbit[-1])
|
|
891
|
+
seen[i] = seen[j] = True
|
|
892
|
+
squares.difference_update(orbit)
|
|
893
|
+
|
|
894
|
+
if link:
|
|
895
|
+
if colors:
|
|
896
|
+
link_options['color'] = colors.pop()
|
|
897
|
+
|
|
898
|
+
# make it upside down
|
|
899
|
+
orbit = [(j, n - i - 1) for i, j in orbit]
|
|
900
|
+
G += line2d(orbit, **link_options)
|
|
901
|
+
|
|
902
|
+
loops = []
|
|
903
|
+
while squares:
|
|
904
|
+
orbit = self._link_or_loop_from(squares.pop())
|
|
905
|
+
loops.append(orbit)
|
|
906
|
+
squares.difference_update(orbit)
|
|
907
|
+
|
|
908
|
+
if loop:
|
|
909
|
+
colors = _make_color_list(len(loops),
|
|
910
|
+
colors=loop_options.pop('colors', None),
|
|
911
|
+
color_map=loop_options.pop('color_map', None),
|
|
912
|
+
randomize=loop_options.pop('color_randomize', False))
|
|
913
|
+
|
|
914
|
+
fill = loop_options.pop('fill')
|
|
915
|
+
|
|
916
|
+
for orbit in loops:
|
|
917
|
+
if colors:
|
|
918
|
+
loop_options['color'] = colors.pop()
|
|
919
|
+
|
|
920
|
+
# make it upside down
|
|
921
|
+
orbit = [(j, n - i - 1) for i, j in orbit]
|
|
922
|
+
|
|
923
|
+
if fill:
|
|
924
|
+
G += polygon2d(orbit, **loop_options)
|
|
925
|
+
else:
|
|
926
|
+
G += line2d(orbit, **loop_options)
|
|
927
|
+
|
|
928
|
+
G.axes(False)
|
|
929
|
+
G.set_aspect_ratio(1)
|
|
930
|
+
return G
|
|
931
|
+
|
|
932
|
+
def gyration(self):
|
|
933
|
+
r"""
|
|
934
|
+
Return the fully packed loop obtained by applying gyration
|
|
935
|
+
to the alternating sign matrix in bijection with ``self``.
|
|
936
|
+
|
|
937
|
+
Gyration was first defined in [Wie2000]_ as an action on
|
|
938
|
+
fully-packed loops.
|
|
939
|
+
|
|
940
|
+
EXAMPLES::
|
|
941
|
+
|
|
942
|
+
sage: A = AlternatingSignMatrix([[1, 0, 0],[0, 1, 0],[0, 0, 1]])
|
|
943
|
+
sage: fpl = FullyPackedLoop(A)
|
|
944
|
+
sage: fpl.gyration().to_alternating_sign_matrix()
|
|
945
|
+
[0 0 1]
|
|
946
|
+
[0 1 0]
|
|
947
|
+
[1 0 0]
|
|
948
|
+
sage: asm = AlternatingSignMatrix([[0, 0, 1],[1, 0, 0],[0, 1, 0]])
|
|
949
|
+
sage: f = FullyPackedLoop(asm)
|
|
950
|
+
sage: f.gyration().to_alternating_sign_matrix()
|
|
951
|
+
[0 1 0]
|
|
952
|
+
[0 0 1]
|
|
953
|
+
[1 0 0]
|
|
954
|
+
"""
|
|
955
|
+
return FullyPackedLoop(self.to_alternating_sign_matrix().gyration())
|
|
956
|
+
|
|
957
|
+
def _link_or_loop_from(self, pos, d0=None):
|
|
958
|
+
r"""
|
|
959
|
+
Return the coordinates of the line passing through ``pos``.
|
|
960
|
+
|
|
961
|
+
EXAMPLES:
|
|
962
|
+
|
|
963
|
+
A link::
|
|
964
|
+
|
|
965
|
+
sage: fpl = FullyPackedLoops(4).first()
|
|
966
|
+
sage: fpl._link_or_loop_from((2,2))
|
|
967
|
+
[(0, 4), (0, 3), (1, 3), (1, 2), (2, 2), (3, 2), (3, 1), (4, 1)]
|
|
968
|
+
sage: fpl._link_or_loop_from((-1, 0))
|
|
969
|
+
[(-1, 0), (0, 0), (1, 0), (1, -1)]
|
|
970
|
+
|
|
971
|
+
A loop::
|
|
972
|
+
|
|
973
|
+
sage: a = AlternatingSignMatrix([[0,1,0,0], [0,0,0,1], [1,0,0,0], [0,0,1,0]])
|
|
974
|
+
sage: fpl = FullyPackedLoop(a)
|
|
975
|
+
sage: fpl._link_or_loop_from((1,1))
|
|
976
|
+
[(1, 1), (2, 1), (2, 2), (1, 2), (1, 1)]
|
|
977
|
+
"""
|
|
978
|
+
global R, L, U, D, FPL_turns, FPL_edges
|
|
979
|
+
|
|
980
|
+
orbit = [pos]
|
|
981
|
+
sv = self._six_vertex_model
|
|
982
|
+
n = len(sv)
|
|
983
|
+
i, j = pos
|
|
984
|
+
|
|
985
|
+
# deal with boundary cases
|
|
986
|
+
if i < -1 or i > n or j < -1 or j > n:
|
|
987
|
+
raise ValueError('indices out of range')
|
|
988
|
+
if (i == -1 or i == n) and not (i + j) % 2:
|
|
989
|
+
raise ValueError('left and right boundary values must have odd sum')
|
|
990
|
+
if (j == -1 or j == n) and (i + j) % 2:
|
|
991
|
+
raise ValueError('up and down boundary values must have even sum')
|
|
992
|
+
|
|
993
|
+
if i == -1:
|
|
994
|
+
d = R
|
|
995
|
+
elif i == n:
|
|
996
|
+
d = L
|
|
997
|
+
elif j == -1:
|
|
998
|
+
d = U
|
|
999
|
+
elif j == n:
|
|
1000
|
+
d = D
|
|
1001
|
+
elif d0 is None:
|
|
1002
|
+
d = FPL_edges[(i + j) % 2][sv[i][j]][0]
|
|
1003
|
+
elif d0 in FPL_edges[(i + j) % 2][sv[i][j]]:
|
|
1004
|
+
d = d0
|
|
1005
|
+
else:
|
|
1006
|
+
raise ValueError('invalid direction')
|
|
1007
|
+
|
|
1008
|
+
# compute the link or loop
|
|
1009
|
+
while True:
|
|
1010
|
+
i += d[0]
|
|
1011
|
+
j += d[1]
|
|
1012
|
+
orbit.append((i, j))
|
|
1013
|
+
if (i, j) == orbit[0] or i == -1 or j == -1 or i == n or j == n:
|
|
1014
|
+
break
|
|
1015
|
+
|
|
1016
|
+
conf = sv[i][j]
|
|
1017
|
+
parity = (i + j) % 2
|
|
1018
|
+
|
|
1019
|
+
d = FPL_turns[parity][conf][d]
|
|
1020
|
+
if d is None:
|
|
1021
|
+
raise RuntimeError
|
|
1022
|
+
|
|
1023
|
+
if i == -1 or j == -1 or i == n or j == n:
|
|
1024
|
+
i0, j0 = orbit[0]
|
|
1025
|
+
if d0 is None and i0 != -1 and i0 != n and j0 != -1 and j0 != n:
|
|
1026
|
+
# only half of a link -> compute the other half
|
|
1027
|
+
i1, j1 = orbit[1]
|
|
1028
|
+
d = (i0-i1, j0-j1)
|
|
1029
|
+
orbit2 = self._link_or_loop_from(orbit[1], d)
|
|
1030
|
+
assert orbit2[0] == (i1, j1) and orbit2[1] == (i0, j0)
|
|
1031
|
+
return orbit2[:1:-1] + orbit
|
|
1032
|
+
return orbit
|
|
1033
|
+
else:
|
|
1034
|
+
return orbit
|
|
1035
|
+
|
|
1036
|
+
def link_pattern(self):
|
|
1037
|
+
r"""
|
|
1038
|
+
Return a link pattern corresponding to a fully packed loop.
|
|
1039
|
+
|
|
1040
|
+
Here we define a link pattern `LP` to be a partition of the list
|
|
1041
|
+
`[1, ..., 2k]` into 2-element sets (such a partition is also known as
|
|
1042
|
+
a perfect matching) such that the following non-crossing condition holds:
|
|
1043
|
+
Let the numbers `1, ..., 2k` be written on the perimeter of a circle.
|
|
1044
|
+
For every 2-element set `(a,b)` of the partition `LP`, draw an arc
|
|
1045
|
+
linking the two numbers `a` and `b`. We say that `LP` is non-crossing
|
|
1046
|
+
if every arc can be drawn so that no two arcs intersect.
|
|
1047
|
+
|
|
1048
|
+
Since every endpoint of a fully packed loop `fpl` is connected to a different
|
|
1049
|
+
endpoint, there is a natural surjection from the fully packed loops on an
|
|
1050
|
+
nxn grid onto the link patterns on the list `[1, \dots, 2n]`.
|
|
1051
|
+
The pairs of connected endpoints of a fully packed loop `fpl` correspond to
|
|
1052
|
+
the 2-element tuples of the corresponding link pattern.
|
|
1053
|
+
|
|
1054
|
+
.. SEEALSO::
|
|
1055
|
+
|
|
1056
|
+
:class:`PerfectMatching`
|
|
1057
|
+
|
|
1058
|
+
.. NOTE::
|
|
1059
|
+
|
|
1060
|
+
by convention, we choose the top left vertex to be even.
|
|
1061
|
+
See [Pro2001]_ and [Str2015]_.
|
|
1062
|
+
|
|
1063
|
+
EXAMPLES:
|
|
1064
|
+
|
|
1065
|
+
We can extract the underlying link pattern (a non-crossing
|
|
1066
|
+
partition) from a fully packed loop::
|
|
1067
|
+
|
|
1068
|
+
sage: A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]])
|
|
1069
|
+
sage: fpl = FullyPackedLoop(A)
|
|
1070
|
+
sage: fpl.link_pattern()
|
|
1071
|
+
[(1, 2), (3, 6), (4, 5)]
|
|
1072
|
+
|
|
1073
|
+
sage: B = AlternatingSignMatrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
|
|
1074
|
+
sage: fpl = FullyPackedLoop(B)
|
|
1075
|
+
sage: fpl.link_pattern()
|
|
1076
|
+
[(1, 6), (2, 5), (3, 4)]
|
|
1077
|
+
|
|
1078
|
+
Gyration on an alternating sign matrix/fully packed loop ``fpl``
|
|
1079
|
+
corresponds to a rotation (i.e. a becomes a-1 mod 2n)
|
|
1080
|
+
of the link pattern corresponding to ``fpl``::
|
|
1081
|
+
|
|
1082
|
+
sage: ASMs = AlternatingSignMatrices(3).list()
|
|
1083
|
+
sage: ncp = FullyPackedLoop(ASMs[1]).link_pattern()
|
|
1084
|
+
sage: rotated_ncp=[]
|
|
1085
|
+
sage: for (a,b) in ncp:
|
|
1086
|
+
....: for i in range(5):
|
|
1087
|
+
....: a,b=a%6+1,b%6+1;
|
|
1088
|
+
....: rotated_ncp.append((a,b))
|
|
1089
|
+
sage: PerfectMatching(ASMs[1].gyration().to_fully_packed_loop().link_pattern()) ==\
|
|
1090
|
+
....: PerfectMatching(rotated_ncp)
|
|
1091
|
+
True
|
|
1092
|
+
|
|
1093
|
+
sage: fpl = FullyPackedLoop(ASMs[0])
|
|
1094
|
+
sage: ncp = fpl.link_pattern()
|
|
1095
|
+
sage: rotated_ncp=[]
|
|
1096
|
+
sage: for (a,b) in ncp:
|
|
1097
|
+
....: for i in range(5):
|
|
1098
|
+
....: a,b=a%6+1,b%6+1;
|
|
1099
|
+
....: rotated_ncp.append((a,b))
|
|
1100
|
+
sage: PerfectMatching(ASMs[0].gyration().to_fully_packed_loop().link_pattern()) ==\
|
|
1101
|
+
....: PerfectMatching(rotated_ncp)
|
|
1102
|
+
True
|
|
1103
|
+
|
|
1104
|
+
sage: mat = AlternatingSignMatrix([[0,0,1,0,0,0,0],[1,0,-1,0,1,0,0],[0,0,1,0,0,0,0],
|
|
1105
|
+
....: [0,1,-1,0,0,1,0],[0,0,1,0,0,0,0],[0,0,0,1,0,0,0],[0,0,0,0,0,0,1]])
|
|
1106
|
+
sage: fpl = FullyPackedLoop(mat) # n=7
|
|
1107
|
+
sage: ncp = fpl.link_pattern()
|
|
1108
|
+
sage: rotated_ncp=[]
|
|
1109
|
+
sage: for (a,b) in ncp:
|
|
1110
|
+
....: for i in range(13):
|
|
1111
|
+
....: a,b=a%14+1,b%14+1;
|
|
1112
|
+
....: rotated_ncp.append((a,b))
|
|
1113
|
+
sage: PerfectMatching(mat.gyration().to_fully_packed_loop().link_pattern()) ==\
|
|
1114
|
+
....: PerfectMatching(rotated_ncp)
|
|
1115
|
+
True
|
|
1116
|
+
|
|
1117
|
+
sage: mat = AlternatingSignMatrix([[0,0,0,1,0,0], [0,0,1,-1,1,0], [0,1,0,0,-1,1], [1,0,-1,1,0,0],
|
|
1118
|
+
....: [0,0,1,0,0,0], [0,0,0,0,1,0]])
|
|
1119
|
+
sage: fpl = FullyPackedLoop(mat)
|
|
1120
|
+
sage: ncp = fpl.link_pattern()
|
|
1121
|
+
sage: rotated_ncp=[]
|
|
1122
|
+
sage: for (a,b) in ncp:
|
|
1123
|
+
....: for i in range(11):
|
|
1124
|
+
....: a,b=a%12+1,b%12+1;
|
|
1125
|
+
....: rotated_ncp.append((a,b))
|
|
1126
|
+
sage: PerfectMatching(mat.gyration().to_fully_packed_loop().link_pattern()) ==\
|
|
1127
|
+
....: PerfectMatching(rotated_ncp)
|
|
1128
|
+
True
|
|
1129
|
+
|
|
1130
|
+
TESTS:
|
|
1131
|
+
|
|
1132
|
+
We test previous two bugs which showed up when this method is called twice::
|
|
1133
|
+
|
|
1134
|
+
sage: A = AlternatingSignMatrices(6)
|
|
1135
|
+
sage: B = A.random_element()
|
|
1136
|
+
sage: C = FullyPackedLoop(B)
|
|
1137
|
+
sage: D = C.link_pattern()
|
|
1138
|
+
sage: E = C.link_pattern()
|
|
1139
|
+
sage: D == E
|
|
1140
|
+
True
|
|
1141
|
+
"""
|
|
1142
|
+
global L, R, U, D, FPL_turns
|
|
1143
|
+
|
|
1144
|
+
link_pattern = []
|
|
1145
|
+
n = len(self._six_vertex_model)
|
|
1146
|
+
seen = [False] * (2*n)
|
|
1147
|
+
unrank = self.parent()._boundary
|
|
1148
|
+
rank = self.parent()._boundary_index
|
|
1149
|
+
sv = self._six_vertex_model
|
|
1150
|
+
|
|
1151
|
+
for k in range(2*n):
|
|
1152
|
+
if seen[k]:
|
|
1153
|
+
continue
|
|
1154
|
+
|
|
1155
|
+
i, j = unrank(k)
|
|
1156
|
+
|
|
1157
|
+
# initial direction
|
|
1158
|
+
if i == -1:
|
|
1159
|
+
d = R
|
|
1160
|
+
elif i == n:
|
|
1161
|
+
d = L
|
|
1162
|
+
elif j == -1:
|
|
1163
|
+
d = U
|
|
1164
|
+
elif j == n:
|
|
1165
|
+
d = D
|
|
1166
|
+
|
|
1167
|
+
# go through the link
|
|
1168
|
+
while True:
|
|
1169
|
+
i += d[0]
|
|
1170
|
+
j += d[1]
|
|
1171
|
+
if i == -1 or j == -1 or i == n or j == n:
|
|
1172
|
+
break
|
|
1173
|
+
|
|
1174
|
+
conf = sv[i][j]
|
|
1175
|
+
parity = (i + j) % 2
|
|
1176
|
+
d = FPL_turns[parity][conf][d]
|
|
1177
|
+
|
|
1178
|
+
# update seen and link_pattern
|
|
1179
|
+
l = rank((i, j))
|
|
1180
|
+
seen[k] = seen[l] = True
|
|
1181
|
+
link_pattern.append((k+1, l+1))
|
|
1182
|
+
|
|
1183
|
+
return link_pattern
|
|
1184
|
+
|
|
1185
|
+
def six_vertex_model(self):
|
|
1186
|
+
"""
|
|
1187
|
+
Return the underlying six vertex model configuration.
|
|
1188
|
+
|
|
1189
|
+
EXAMPLES::
|
|
1190
|
+
|
|
1191
|
+
sage: B = AlternatingSignMatrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
|
|
1192
|
+
sage: fpl = FullyPackedLoop(B)
|
|
1193
|
+
sage: fpl
|
|
1194
|
+
│ │
|
|
1195
|
+
│ │
|
|
1196
|
+
+ + ── +
|
|
1197
|
+
│ │
|
|
1198
|
+
│ │
|
|
1199
|
+
── + + + ──
|
|
1200
|
+
│ │
|
|
1201
|
+
│ │
|
|
1202
|
+
+ ── + +
|
|
1203
|
+
│ │
|
|
1204
|
+
│ │
|
|
1205
|
+
sage: fpl.six_vertex_model()
|
|
1206
|
+
^ ^ ^
|
|
1207
|
+
| | |
|
|
1208
|
+
--> # <- # <- # <--
|
|
1209
|
+
| ^ ^
|
|
1210
|
+
V | |
|
|
1211
|
+
--> # -> # <- # <--
|
|
1212
|
+
| | ^
|
|
1213
|
+
V V |
|
|
1214
|
+
--> # -> # -> # <--
|
|
1215
|
+
| | |
|
|
1216
|
+
V V V
|
|
1217
|
+
"""
|
|
1218
|
+
return self._six_vertex_model
|
|
1219
|
+
|
|
1220
|
+
|
|
1221
|
+
class FullyPackedLoops(Parent, UniqueRepresentation):
|
|
1222
|
+
r"""
|
|
1223
|
+
Class of all fully packed loops on an `n \times n` grid.
|
|
1224
|
+
|
|
1225
|
+
They are known to be in bijection with alternating sign matrices.
|
|
1226
|
+
|
|
1227
|
+
.. SEEALSO::
|
|
1228
|
+
|
|
1229
|
+
:class:`AlternatingSignMatrices`
|
|
1230
|
+
|
|
1231
|
+
INPUT:
|
|
1232
|
+
|
|
1233
|
+
- ``n`` -- the number of row (and column) or grid
|
|
1234
|
+
|
|
1235
|
+
EXAMPLES:
|
|
1236
|
+
|
|
1237
|
+
This will create an instance to manipulate the fully packed loops of size 3::
|
|
1238
|
+
|
|
1239
|
+
sage: FPLs = FullyPackedLoops(3)
|
|
1240
|
+
sage: FPLs
|
|
1241
|
+
Fully packed loops on a 3x3 grid
|
|
1242
|
+
sage: FPLs.cardinality()
|
|
1243
|
+
7
|
|
1244
|
+
|
|
1245
|
+
When using the square ice model, it is known that the number of
|
|
1246
|
+
configurations is equal to the number of alternating sign matrices::
|
|
1247
|
+
|
|
1248
|
+
sage: M = FullyPackedLoops(1)
|
|
1249
|
+
sage: len(M)
|
|
1250
|
+
1
|
|
1251
|
+
sage: M = FullyPackedLoops(4)
|
|
1252
|
+
sage: len(M)
|
|
1253
|
+
42
|
|
1254
|
+
sage: all(len(SixVertexModel(n, boundary_conditions='ice'))
|
|
1255
|
+
....: == FullyPackedLoops(n).cardinality() for n in range(1, 7))
|
|
1256
|
+
True
|
|
1257
|
+
"""
|
|
1258
|
+
|
|
1259
|
+
def __init__(self, n):
|
|
1260
|
+
r"""
|
|
1261
|
+
Initialize ``self``.
|
|
1262
|
+
|
|
1263
|
+
TESTS::
|
|
1264
|
+
|
|
1265
|
+
sage: FPLs = FullyPackedLoops(3)
|
|
1266
|
+
sage: TestSuite(FPLs).run()
|
|
1267
|
+
"""
|
|
1268
|
+
self._n = n
|
|
1269
|
+
Parent.__init__(self, category=FiniteEnumeratedSets())
|
|
1270
|
+
|
|
1271
|
+
def __iter__(self):
|
|
1272
|
+
"""
|
|
1273
|
+
Iterate through ``self``.
|
|
1274
|
+
|
|
1275
|
+
EXAMPLES::
|
|
1276
|
+
|
|
1277
|
+
sage: FPLs = FullyPackedLoops(2)
|
|
1278
|
+
sage: len(FPLs)
|
|
1279
|
+
2
|
|
1280
|
+
"""
|
|
1281
|
+
for X in SixVertexModel(self._n, boundary_conditions='ice'):
|
|
1282
|
+
yield self.element_class(self, X)
|
|
1283
|
+
|
|
1284
|
+
def _repr_(self):
|
|
1285
|
+
r"""
|
|
1286
|
+
Return a string representation of ``self``.
|
|
1287
|
+
|
|
1288
|
+
TESTS::
|
|
1289
|
+
|
|
1290
|
+
sage: FPLs = FullyPackedLoops(4); FPLs
|
|
1291
|
+
Fully packed loops on a 4x4 grid
|
|
1292
|
+
"""
|
|
1293
|
+
return "Fully packed loops on a %sx%s grid" % (self._n, self._n)
|
|
1294
|
+
|
|
1295
|
+
def __contains__(self, fpl):
|
|
1296
|
+
"""
|
|
1297
|
+
Check if ``fpl`` is in ``self``.
|
|
1298
|
+
|
|
1299
|
+
TESTS::
|
|
1300
|
+
|
|
1301
|
+
sage: FPLs = FullyPackedLoops(3)
|
|
1302
|
+
sage: FullyPackedLoop(AlternatingSignMatrix([[0,1,0],[1,0,0],[0,0,1]])) in FPLs
|
|
1303
|
+
True
|
|
1304
|
+
sage: FullyPackedLoop(AlternatingSignMatrix([[0,1,0],[1,-1,1],[0,1,0]])) in FPLs
|
|
1305
|
+
True
|
|
1306
|
+
sage: FullyPackedLoop(AlternatingSignMatrix([[0, 1],[1,0]])) in FPLs
|
|
1307
|
+
False
|
|
1308
|
+
sage: FullyPackedLoop(AlternatingSignMatrix([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]])) in FPLs
|
|
1309
|
+
False
|
|
1310
|
+
sage: [1,2,3] in FPLs
|
|
1311
|
+
False
|
|
1312
|
+
"""
|
|
1313
|
+
return parent(fpl) is self
|
|
1314
|
+
|
|
1315
|
+
def _element_constructor_(self, generator):
|
|
1316
|
+
"""
|
|
1317
|
+
Construct an element of ``self``.
|
|
1318
|
+
|
|
1319
|
+
EXAMPLES::
|
|
1320
|
+
|
|
1321
|
+
sage: FPLs = FullyPackedLoops(4)
|
|
1322
|
+
sage: M = [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]
|
|
1323
|
+
sage: A = AlternatingSignMatrix(M)
|
|
1324
|
+
sage: elt = FullyPackedLoop(A)
|
|
1325
|
+
sage: FPL = FPLs(elt); FPL
|
|
1326
|
+
│ │
|
|
1327
|
+
│ │
|
|
1328
|
+
+ + ── + + ──
|
|
1329
|
+
│ │ │
|
|
1330
|
+
│ │ │
|
|
1331
|
+
── + + + ── +
|
|
1332
|
+
│ │
|
|
1333
|
+
│ │
|
|
1334
|
+
+ ── + + + ──
|
|
1335
|
+
│ │ │
|
|
1336
|
+
│ │ │
|
|
1337
|
+
── + + ── + +
|
|
1338
|
+
│ │
|
|
1339
|
+
│ │
|
|
1340
|
+
|
|
1341
|
+
sage: FPLs(A) == FPL
|
|
1342
|
+
True
|
|
1343
|
+
|
|
1344
|
+
sage: FPLs(M) == FPL
|
|
1345
|
+
True
|
|
1346
|
+
|
|
1347
|
+
sage: FPLs(FPL._six_vertex_model) == FPL
|
|
1348
|
+
True
|
|
1349
|
+
|
|
1350
|
+
sage: FPL.parent() is FPLs
|
|
1351
|
+
True
|
|
1352
|
+
|
|
1353
|
+
sage: FPL = FullyPackedLoops(2)
|
|
1354
|
+
sage: FPL([[3,1],[5,3]])
|
|
1355
|
+
│
|
|
1356
|
+
│
|
|
1357
|
+
+ + ──
|
|
1358
|
+
│ │
|
|
1359
|
+
│ │
|
|
1360
|
+
── + +
|
|
1361
|
+
│
|
|
1362
|
+
│
|
|
1363
|
+
"""
|
|
1364
|
+
if isinstance(generator, AlternatingSignMatrix):
|
|
1365
|
+
SVM = generator.to_six_vertex_model()
|
|
1366
|
+
elif isinstance(generator, (SquareIceModel.Element,
|
|
1367
|
+
SixVertexConfiguration)):
|
|
1368
|
+
SVM = generator
|
|
1369
|
+
else: # Not ASM nor SVM
|
|
1370
|
+
try:
|
|
1371
|
+
SVM = AlternatingSignMatrix(generator).to_six_vertex_model()
|
|
1372
|
+
except (TypeError, ValueError):
|
|
1373
|
+
SVM = SixVertexModel(self._n, boundary_conditions='ice')(generator)
|
|
1374
|
+
SVM.to_alternating_sign_matrix()
|
|
1375
|
+
if len(SVM) != self._n:
|
|
1376
|
+
raise ValueError("invalid size")
|
|
1377
|
+
return self.element_class(self, SVM)
|
|
1378
|
+
|
|
1379
|
+
Element = FullyPackedLoop
|
|
1380
|
+
|
|
1381
|
+
def size(self):
|
|
1382
|
+
r"""
|
|
1383
|
+
Return the size of the matrices in ``self``.
|
|
1384
|
+
|
|
1385
|
+
TESTS::
|
|
1386
|
+
|
|
1387
|
+
sage: FPLs = FullyPackedLoops(4)
|
|
1388
|
+
sage: FPLs.size()
|
|
1389
|
+
4
|
|
1390
|
+
"""
|
|
1391
|
+
return self._n
|
|
1392
|
+
|
|
1393
|
+
def cardinality(self):
|
|
1394
|
+
r"""
|
|
1395
|
+
Return the cardinality of ``self``.
|
|
1396
|
+
|
|
1397
|
+
The number of fully packed loops on `n \times n` grid
|
|
1398
|
+
|
|
1399
|
+
.. MATH::
|
|
1400
|
+
|
|
1401
|
+
\prod_{k=0}^{n-1} \frac{(3k+1)!}{(n+k)!} = \frac{1! 4! 7! 10!
|
|
1402
|
+
\cdots (3n-2)!}{n! (n+1)! (n+2)! (n+3)! \cdots (2n-1)!}.
|
|
1403
|
+
|
|
1404
|
+
EXAMPLES::
|
|
1405
|
+
|
|
1406
|
+
sage: [AlternatingSignMatrices(n).cardinality() for n in range(10)]
|
|
1407
|
+
[1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460]
|
|
1408
|
+
"""
|
|
1409
|
+
return Integer(prod(factorial(3 * k + 1) / factorial(self._n + k)
|
|
1410
|
+
for k in range(self._n)))
|
|
1411
|
+
|
|
1412
|
+
def _an_element_(self):
|
|
1413
|
+
"""
|
|
1414
|
+
Return an element of ``self``.
|
|
1415
|
+
|
|
1416
|
+
EXAMPLES::
|
|
1417
|
+
|
|
1418
|
+
sage: FPLs = FullyPackedLoops(3)
|
|
1419
|
+
sage: FPLs.an_element()
|
|
1420
|
+
│ │
|
|
1421
|
+
│ │
|
|
1422
|
+
+ + ── +
|
|
1423
|
+
│ │
|
|
1424
|
+
│ │
|
|
1425
|
+
── + + + ──
|
|
1426
|
+
│ │
|
|
1427
|
+
│ │
|
|
1428
|
+
+ ── + +
|
|
1429
|
+
│ │
|
|
1430
|
+
│ │
|
|
1431
|
+
"""
|
|
1432
|
+
# ASM = AlternatingSignMatrix(matrix.identity(self._n))
|
|
1433
|
+
# SVM = ASM.to_six_vertex_model()
|
|
1434
|
+
SVM = SixVertexModel(self._n, boundary_conditions='ice').an_element()
|
|
1435
|
+
return self.element_class(self, SVM)
|
|
1436
|
+
|
|
1437
|
+
def _boundary(self, k):
|
|
1438
|
+
r"""
|
|
1439
|
+
Return the coordinates of the ``k``-th boundary.
|
|
1440
|
+
|
|
1441
|
+
TESTS::
|
|
1442
|
+
|
|
1443
|
+
sage: F = FullyPackedLoops(5)
|
|
1444
|
+
sage: [F._boundary(k) for k in range(10)] == F._boundaries()
|
|
1445
|
+
True
|
|
1446
|
+
sage: all(F._boundary_index(F._boundary(k)) == k for k in range(10))
|
|
1447
|
+
True
|
|
1448
|
+
|
|
1449
|
+
sage: F = FullyPackedLoops(6)
|
|
1450
|
+
sage: [F._boundary(k) for k in range(12)] == F._boundaries()
|
|
1451
|
+
True
|
|
1452
|
+
sage: all(F._boundary_index(F._boundary(k)) == k for k in range(12))
|
|
1453
|
+
True
|
|
1454
|
+
"""
|
|
1455
|
+
n = self._n
|
|
1456
|
+
n_LR = n//2 if n % 2 == 0 else (n+1) // 2
|
|
1457
|
+
n_TB = n//2 if n % 2 == 0 else (n-1) // 2
|
|
1458
|
+
if k < n_LR:
|
|
1459
|
+
return (-1, 2*k)
|
|
1460
|
+
k -= n_LR
|
|
1461
|
+
if k < n_TB:
|
|
1462
|
+
return (n % 2 + 2*k, n)
|
|
1463
|
+
k -= n_TB
|
|
1464
|
+
if k < n_LR:
|
|
1465
|
+
return (n, n - 1 - 2*k)
|
|
1466
|
+
k -= n_LR
|
|
1467
|
+
if k < n_TB:
|
|
1468
|
+
return (n - 1 - n % 2 - 2*k, -1)
|
|
1469
|
+
|
|
1470
|
+
def _boundary_index(self, pos):
|
|
1471
|
+
r"""
|
|
1472
|
+
Return the index of the boundary at position ``pos``.
|
|
1473
|
+
|
|
1474
|
+
TESTS::
|
|
1475
|
+
|
|
1476
|
+
sage: F = FullyPackedLoops(5)
|
|
1477
|
+
sage: [F._boundary_index(b) for b in F._boundaries()]
|
|
1478
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
1479
|
+
sage: all(F._boundary(F._boundary_index(b)) == b for b in F._boundaries())
|
|
1480
|
+
True
|
|
1481
|
+
|
|
1482
|
+
sage: F = FullyPackedLoops(6)
|
|
1483
|
+
sage: [F._boundary_index(b) for b in F._boundaries()]
|
|
1484
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
|
|
1485
|
+
sage: all(F._boundary(F._boundary_index(b)) == b for b in F._boundaries())
|
|
1486
|
+
True
|
|
1487
|
+
"""
|
|
1488
|
+
n = self._n
|
|
1489
|
+
i, j = pos
|
|
1490
|
+
if i == -1:
|
|
1491
|
+
return j//2
|
|
1492
|
+
elif j == n:
|
|
1493
|
+
return (n + 1) // 2 + i // 2
|
|
1494
|
+
elif i == n:
|
|
1495
|
+
return n + (n - j) // 2
|
|
1496
|
+
elif j == -1:
|
|
1497
|
+
return 3 * n // 2 + (n - i) // 2
|
|
1498
|
+
|
|
1499
|
+
def _boundaries(self):
|
|
1500
|
+
r"""
|
|
1501
|
+
Return the list of coordinates for the link in the boundaries.
|
|
1502
|
+
|
|
1503
|
+
TESTS::
|
|
1504
|
+
|
|
1505
|
+
sage: FullyPackedLoops(5)._boundaries()
|
|
1506
|
+
[(-1, 0), (-1, 2), (-1, 4), (1, 5), (3, 5),
|
|
1507
|
+
(5, 4), (5, 2), (5, 0), (3, -1), (1, -1)]
|
|
1508
|
+
|
|
1509
|
+
sage: FullyPackedLoops(6)._boundaries()
|
|
1510
|
+
[(-1, 0), (-1, 2), (-1, 4), (0, 6), (2, 6), (4, 6),
|
|
1511
|
+
(6, 5), (6, 3), (6, 1), (5, -1), (3, -1), (1, -1)]
|
|
1512
|
+
"""
|
|
1513
|
+
n = self._n
|
|
1514
|
+
boundaries = []
|
|
1515
|
+
# left side: j = 0 mod 2
|
|
1516
|
+
boundaries.extend((-1, j) for j in range(0, n, 2))
|
|
1517
|
+
# top side: i = n mod 2
|
|
1518
|
+
boundaries.extend((i, n) for i in range(n % 2, n, 2))
|
|
1519
|
+
# right side: j = n+1 mod 2
|
|
1520
|
+
boundaries.extend((n, j) for j in range(n - 1, -1, -2))
|
|
1521
|
+
# bottom side: i = 1 mod 2
|
|
1522
|
+
boundaries.extend((i, -1) for i in range(n - 1 - n % 2, -1, -2))
|
|
1523
|
+
return boundaries
|