passagemath-combinat 10.6.42__cp314-cp314-musllinux_1_2_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (400) hide show
  1. passagemath_combinat/__init__.py +3 -0
  2. passagemath_combinat-10.6.42.dist-info/METADATA +160 -0
  3. passagemath_combinat-10.6.42.dist-info/RECORD +400 -0
  4. passagemath_combinat-10.6.42.dist-info/WHEEL +5 -0
  5. passagemath_combinat-10.6.42.dist-info/top_level.txt +3 -0
  6. passagemath_combinat.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
  7. passagemath_combinat.libs/libsymmetrica-81fe8739.so.3.0.0 +0 -0
  8. sage/algebras/affine_nil_temperley_lieb.py +263 -0
  9. sage/algebras/all.py +24 -0
  10. sage/algebras/all__sagemath_combinat.py +35 -0
  11. sage/algebras/askey_wilson.py +935 -0
  12. sage/algebras/associated_graded.py +345 -0
  13. sage/algebras/cellular_basis.py +350 -0
  14. sage/algebras/cluster_algebra.py +2766 -0
  15. sage/algebras/down_up_algebra.py +860 -0
  16. sage/algebras/free_algebra.py +1698 -0
  17. sage/algebras/free_algebra_element.py +345 -0
  18. sage/algebras/free_algebra_quotient.py +405 -0
  19. sage/algebras/free_algebra_quotient_element.py +295 -0
  20. sage/algebras/free_zinbiel_algebra.py +885 -0
  21. sage/algebras/hall_algebra.py +783 -0
  22. sage/algebras/hecke_algebras/all.py +4 -0
  23. sage/algebras/hecke_algebras/ariki_koike_algebra.py +1796 -0
  24. sage/algebras/hecke_algebras/ariki_koike_specht_modules.py +475 -0
  25. sage/algebras/hecke_algebras/cubic_hecke_algebra.py +3520 -0
  26. sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +1473 -0
  27. sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +1079 -0
  28. sage/algebras/iwahori_hecke_algebra.py +3095 -0
  29. sage/algebras/jordan_algebra.py +1773 -0
  30. sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py +113 -0
  31. sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py +156 -0
  32. sage/algebras/lie_conformal_algebras/all.py +18 -0
  33. sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +134 -0
  34. sage/algebras/lie_conformal_algebras/examples.py +43 -0
  35. sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py +131 -0
  36. sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py +139 -0
  37. sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py +174 -0
  38. sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py +167 -0
  39. sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py +107 -0
  40. sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py +135 -0
  41. sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py +353 -0
  42. sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py +236 -0
  43. sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py +78 -0
  44. sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py +328 -0
  45. sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py +117 -0
  46. sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py +86 -0
  47. sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py +82 -0
  48. sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +205 -0
  49. sage/algebras/nil_coxeter_algebra.py +191 -0
  50. sage/algebras/q_commuting_polynomials.py +673 -0
  51. sage/algebras/q_system.py +608 -0
  52. sage/algebras/quantum_clifford.py +959 -0
  53. sage/algebras/quantum_groups/ace_quantum_onsager.py +693 -0
  54. sage/algebras/quantum_groups/all.py +9 -0
  55. sage/algebras/quantum_groups/fock_space.py +2219 -0
  56. sage/algebras/quantum_groups/q_numbers.py +207 -0
  57. sage/algebras/quantum_groups/quantum_group_gap.py +2695 -0
  58. sage/algebras/quantum_groups/representations.py +591 -0
  59. sage/algebras/quantum_matrix_coordinate_algebra.py +1006 -0
  60. sage/algebras/quantum_oscillator.py +623 -0
  61. sage/algebras/quaternion_algebra.py +20 -0
  62. sage/algebras/quaternion_algebra_element.py +55 -0
  63. sage/algebras/rational_cherednik_algebra.py +525 -0
  64. sage/algebras/schur_algebra.py +670 -0
  65. sage/algebras/shuffle_algebra.py +1011 -0
  66. sage/algebras/splitting_algebra.py +779 -0
  67. sage/algebras/tensor_algebra.py +709 -0
  68. sage/algebras/yangian.py +1082 -0
  69. sage/algebras/yokonuma_hecke_algebra.py +1018 -0
  70. sage/all__sagemath_combinat.py +35 -0
  71. sage/combinat/SJT.py +255 -0
  72. sage/combinat/affine_permutation.py +2405 -0
  73. sage/combinat/algebraic_combinatorics.py +55 -0
  74. sage/combinat/all.py +53 -0
  75. sage/combinat/all__sagemath_combinat.py +195 -0
  76. sage/combinat/alternating_sign_matrix.py +2063 -0
  77. sage/combinat/baxter_permutations.py +346 -0
  78. sage/combinat/bijectionist.py +3220 -0
  79. sage/combinat/binary_recurrence_sequences.py +1180 -0
  80. sage/combinat/blob_algebra.py +685 -0
  81. sage/combinat/catalog_partitions.py +27 -0
  82. sage/combinat/chas/all.py +23 -0
  83. sage/combinat/chas/fsym.py +1180 -0
  84. sage/combinat/chas/wqsym.py +2601 -0
  85. sage/combinat/cluster_complex.py +326 -0
  86. sage/combinat/colored_permutations.py +2039 -0
  87. sage/combinat/colored_permutations_representations.py +964 -0
  88. sage/combinat/composition_signed.py +142 -0
  89. sage/combinat/composition_tableau.py +855 -0
  90. sage/combinat/constellation.py +1729 -0
  91. sage/combinat/core.py +751 -0
  92. sage/combinat/counting.py +12 -0
  93. sage/combinat/crystals/affine.py +742 -0
  94. sage/combinat/crystals/affine_factorization.py +518 -0
  95. sage/combinat/crystals/affinization.py +331 -0
  96. sage/combinat/crystals/alcove_path.py +2013 -0
  97. sage/combinat/crystals/all.py +22 -0
  98. sage/combinat/crystals/bkk_crystals.py +141 -0
  99. sage/combinat/crystals/catalog.py +115 -0
  100. sage/combinat/crystals/catalog_elementary_crystals.py +18 -0
  101. sage/combinat/crystals/catalog_infinity_crystals.py +33 -0
  102. sage/combinat/crystals/catalog_kirillov_reshetikhin.py +18 -0
  103. sage/combinat/crystals/crystals.py +257 -0
  104. sage/combinat/crystals/direct_sum.py +260 -0
  105. sage/combinat/crystals/elementary_crystals.py +1251 -0
  106. sage/combinat/crystals/fast_crystals.py +441 -0
  107. sage/combinat/crystals/fully_commutative_stable_grothendieck.py +1205 -0
  108. sage/combinat/crystals/generalized_young_walls.py +1076 -0
  109. sage/combinat/crystals/highest_weight_crystals.py +436 -0
  110. sage/combinat/crystals/induced_structure.py +695 -0
  111. sage/combinat/crystals/infinity_crystals.py +730 -0
  112. sage/combinat/crystals/kac_modules.py +863 -0
  113. sage/combinat/crystals/kirillov_reshetikhin.py +4196 -0
  114. sage/combinat/crystals/kyoto_path_model.py +497 -0
  115. sage/combinat/crystals/letters.cpython-314-x86_64-linux-musl.so +0 -0
  116. sage/combinat/crystals/letters.pxd +79 -0
  117. sage/combinat/crystals/letters.pyx +3056 -0
  118. sage/combinat/crystals/littelmann_path.py +1518 -0
  119. sage/combinat/crystals/monomial_crystals.py +1262 -0
  120. sage/combinat/crystals/multisegments.py +462 -0
  121. sage/combinat/crystals/mv_polytopes.py +467 -0
  122. sage/combinat/crystals/pbw_crystal.py +511 -0
  123. sage/combinat/crystals/pbw_datum.cpython-314-x86_64-linux-musl.so +0 -0
  124. sage/combinat/crystals/pbw_datum.pxd +4 -0
  125. sage/combinat/crystals/pbw_datum.pyx +487 -0
  126. sage/combinat/crystals/polyhedral_realization.py +372 -0
  127. sage/combinat/crystals/spins.cpython-314-x86_64-linux-musl.so +0 -0
  128. sage/combinat/crystals/spins.pxd +21 -0
  129. sage/combinat/crystals/spins.pyx +756 -0
  130. sage/combinat/crystals/star_crystal.py +290 -0
  131. sage/combinat/crystals/subcrystal.py +464 -0
  132. sage/combinat/crystals/tensor_product.py +1177 -0
  133. sage/combinat/crystals/tensor_product_element.cpython-314-x86_64-linux-musl.so +0 -0
  134. sage/combinat/crystals/tensor_product_element.pxd +35 -0
  135. sage/combinat/crystals/tensor_product_element.pyx +1870 -0
  136. sage/combinat/crystals/virtual_crystal.py +420 -0
  137. sage/combinat/cyclic_sieving_phenomenon.py +204 -0
  138. sage/combinat/debruijn_sequence.cpython-314-x86_64-linux-musl.so +0 -0
  139. sage/combinat/debruijn_sequence.pyx +355 -0
  140. sage/combinat/decorated_permutation.py +270 -0
  141. sage/combinat/degree_sequences.cpython-314-x86_64-linux-musl.so +0 -0
  142. sage/combinat/degree_sequences.pyx +588 -0
  143. sage/combinat/derangements.py +527 -0
  144. sage/combinat/descent_algebra.py +1008 -0
  145. sage/combinat/diagram.py +1551 -0
  146. sage/combinat/diagram_algebras.py +5886 -0
  147. sage/combinat/dyck_word.py +4349 -0
  148. sage/combinat/e_one_star.py +1623 -0
  149. sage/combinat/enumerated_sets.py +123 -0
  150. sage/combinat/expnums.cpython-314-x86_64-linux-musl.so +0 -0
  151. sage/combinat/expnums.pyx +148 -0
  152. sage/combinat/fast_vector_partitions.cpython-314-x86_64-linux-musl.so +0 -0
  153. sage/combinat/fast_vector_partitions.pyx +346 -0
  154. sage/combinat/fqsym.py +1977 -0
  155. sage/combinat/free_dendriform_algebra.py +954 -0
  156. sage/combinat/free_prelie_algebra.py +1141 -0
  157. sage/combinat/fully_commutative_elements.py +1077 -0
  158. sage/combinat/fully_packed_loop.py +1523 -0
  159. sage/combinat/gelfand_tsetlin_patterns.py +1409 -0
  160. sage/combinat/gray_codes.py +311 -0
  161. sage/combinat/grossman_larson_algebras.py +667 -0
  162. sage/combinat/growth.py +4352 -0
  163. sage/combinat/hall_polynomial.py +188 -0
  164. sage/combinat/hillman_grassl.py +866 -0
  165. sage/combinat/integer_matrices.py +329 -0
  166. sage/combinat/integer_vectors_mod_permgroup.py +1238 -0
  167. sage/combinat/k_tableau.py +4564 -0
  168. sage/combinat/kazhdan_lusztig.py +215 -0
  169. sage/combinat/key_polynomial.py +885 -0
  170. sage/combinat/knutson_tao_puzzles.py +2286 -0
  171. sage/combinat/lr_tableau.py +311 -0
  172. sage/combinat/matrices/all.py +24 -0
  173. sage/combinat/matrices/hadamard_matrix.py +3790 -0
  174. sage/combinat/matrices/latin.py +2912 -0
  175. sage/combinat/misc.py +401 -0
  176. sage/combinat/multiset_partition_into_sets_ordered.py +3541 -0
  177. sage/combinat/ncsf_qsym/all.py +21 -0
  178. sage/combinat/ncsf_qsym/combinatorics.py +317 -0
  179. sage/combinat/ncsf_qsym/generic_basis_code.py +1427 -0
  180. sage/combinat/ncsf_qsym/ncsf.py +5637 -0
  181. sage/combinat/ncsf_qsym/qsym.py +4053 -0
  182. sage/combinat/ncsf_qsym/tutorial.py +447 -0
  183. sage/combinat/ncsym/all.py +21 -0
  184. sage/combinat/ncsym/bases.py +855 -0
  185. sage/combinat/ncsym/dual.py +593 -0
  186. sage/combinat/ncsym/ncsym.py +2076 -0
  187. sage/combinat/necklace.py +551 -0
  188. sage/combinat/non_decreasing_parking_function.py +634 -0
  189. sage/combinat/nu_dyck_word.py +1474 -0
  190. sage/combinat/output.py +861 -0
  191. sage/combinat/parallelogram_polyomino.py +4326 -0
  192. sage/combinat/parking_functions.py +1602 -0
  193. sage/combinat/partition_algebra.py +1998 -0
  194. sage/combinat/partition_kleshchev.py +1982 -0
  195. sage/combinat/partition_shifting_algebras.py +584 -0
  196. sage/combinat/partition_tuple.py +3114 -0
  197. sage/combinat/path_tableaux/all.py +13 -0
  198. sage/combinat/path_tableaux/catalog.py +29 -0
  199. sage/combinat/path_tableaux/dyck_path.py +380 -0
  200. sage/combinat/path_tableaux/frieze.py +476 -0
  201. sage/combinat/path_tableaux/path_tableau.py +728 -0
  202. sage/combinat/path_tableaux/semistandard.py +510 -0
  203. sage/combinat/perfect_matching.py +779 -0
  204. sage/combinat/plane_partition.py +3300 -0
  205. sage/combinat/q_bernoulli.cpython-314-x86_64-linux-musl.so +0 -0
  206. sage/combinat/q_bernoulli.pyx +128 -0
  207. sage/combinat/quickref.py +81 -0
  208. sage/combinat/recognizable_series.py +2051 -0
  209. sage/combinat/regular_sequence.py +4316 -0
  210. sage/combinat/regular_sequence_bounded.py +543 -0
  211. sage/combinat/restricted_growth.py +81 -0
  212. sage/combinat/ribbon.py +20 -0
  213. sage/combinat/ribbon_shaped_tableau.py +489 -0
  214. sage/combinat/ribbon_tableau.py +1180 -0
  215. sage/combinat/rigged_configurations/all.py +46 -0
  216. sage/combinat/rigged_configurations/bij_abstract_class.py +548 -0
  217. sage/combinat/rigged_configurations/bij_infinity.py +370 -0
  218. sage/combinat/rigged_configurations/bij_type_A.py +163 -0
  219. sage/combinat/rigged_configurations/bij_type_A2_dual.py +338 -0
  220. sage/combinat/rigged_configurations/bij_type_A2_even.py +218 -0
  221. sage/combinat/rigged_configurations/bij_type_A2_odd.py +199 -0
  222. sage/combinat/rigged_configurations/bij_type_B.py +900 -0
  223. sage/combinat/rigged_configurations/bij_type_C.py +267 -0
  224. sage/combinat/rigged_configurations/bij_type_D.py +771 -0
  225. sage/combinat/rigged_configurations/bij_type_D_tri.py +392 -0
  226. sage/combinat/rigged_configurations/bij_type_D_twisted.py +576 -0
  227. sage/combinat/rigged_configurations/bij_type_E67.py +402 -0
  228. sage/combinat/rigged_configurations/bijection.py +143 -0
  229. sage/combinat/rigged_configurations/kleber_tree.py +1475 -0
  230. sage/combinat/rigged_configurations/kr_tableaux.py +1898 -0
  231. sage/combinat/rigged_configurations/rc_crystal.py +461 -0
  232. sage/combinat/rigged_configurations/rc_infinity.py +540 -0
  233. sage/combinat/rigged_configurations/rigged_configuration_element.py +2403 -0
  234. sage/combinat/rigged_configurations/rigged_configurations.py +1918 -0
  235. sage/combinat/rigged_configurations/rigged_partition.cpython-314-x86_64-linux-musl.so +0 -0
  236. sage/combinat/rigged_configurations/rigged_partition.pxd +15 -0
  237. sage/combinat/rigged_configurations/rigged_partition.pyx +680 -0
  238. sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py +499 -0
  239. sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element.py +428 -0
  240. sage/combinat/rsk.py +3438 -0
  241. sage/combinat/schubert_polynomial.py +508 -0
  242. sage/combinat/set_partition.py +3318 -0
  243. sage/combinat/set_partition_iterator.cpython-314-x86_64-linux-musl.so +0 -0
  244. sage/combinat/set_partition_iterator.pyx +136 -0
  245. sage/combinat/set_partition_ordered.py +1590 -0
  246. sage/combinat/sf/abreu_nigro.py +346 -0
  247. sage/combinat/sf/all.py +52 -0
  248. sage/combinat/sf/character.py +576 -0
  249. sage/combinat/sf/classical.py +319 -0
  250. sage/combinat/sf/dual.py +996 -0
  251. sage/combinat/sf/elementary.py +549 -0
  252. sage/combinat/sf/hall_littlewood.py +1028 -0
  253. sage/combinat/sf/hecke.py +336 -0
  254. sage/combinat/sf/homogeneous.py +464 -0
  255. sage/combinat/sf/jack.py +1428 -0
  256. sage/combinat/sf/k_dual.py +1458 -0
  257. sage/combinat/sf/kfpoly.py +447 -0
  258. sage/combinat/sf/llt.py +789 -0
  259. sage/combinat/sf/macdonald.py +2019 -0
  260. sage/combinat/sf/monomial.py +525 -0
  261. sage/combinat/sf/multiplicative.py +113 -0
  262. sage/combinat/sf/new_kschur.py +1786 -0
  263. sage/combinat/sf/ns_macdonald.py +964 -0
  264. sage/combinat/sf/orthogonal.py +246 -0
  265. sage/combinat/sf/orthotriang.py +355 -0
  266. sage/combinat/sf/powersum.py +963 -0
  267. sage/combinat/sf/schur.py +880 -0
  268. sage/combinat/sf/sf.py +1653 -0
  269. sage/combinat/sf/sfa.py +7053 -0
  270. sage/combinat/sf/symplectic.py +253 -0
  271. sage/combinat/sf/witt.py +721 -0
  272. sage/combinat/shifted_primed_tableau.py +2735 -0
  273. sage/combinat/shuffle.py +830 -0
  274. sage/combinat/sidon_sets.py +146 -0
  275. sage/combinat/similarity_class_type.py +1721 -0
  276. sage/combinat/sine_gordon.py +618 -0
  277. sage/combinat/six_vertex_model.py +784 -0
  278. sage/combinat/skew_partition.py +2053 -0
  279. sage/combinat/skew_tableau.py +2989 -0
  280. sage/combinat/sloane_functions.py +8935 -0
  281. sage/combinat/specht_module.py +1403 -0
  282. sage/combinat/species/all.py +48 -0
  283. sage/combinat/species/characteristic_species.py +321 -0
  284. sage/combinat/species/composition_species.py +273 -0
  285. sage/combinat/species/cycle_species.py +284 -0
  286. sage/combinat/species/empty_species.py +155 -0
  287. sage/combinat/species/functorial_composition_species.py +148 -0
  288. sage/combinat/species/generating_series.py +673 -0
  289. sage/combinat/species/library.py +148 -0
  290. sage/combinat/species/linear_order_species.py +169 -0
  291. sage/combinat/species/misc.py +83 -0
  292. sage/combinat/species/partition_species.py +290 -0
  293. sage/combinat/species/permutation_species.py +268 -0
  294. sage/combinat/species/product_species.py +423 -0
  295. sage/combinat/species/recursive_species.py +476 -0
  296. sage/combinat/species/set_species.py +192 -0
  297. sage/combinat/species/species.py +820 -0
  298. sage/combinat/species/structure.py +539 -0
  299. sage/combinat/species/subset_species.py +243 -0
  300. sage/combinat/species/sum_species.py +225 -0
  301. sage/combinat/subword.py +564 -0
  302. sage/combinat/subword_complex.py +2122 -0
  303. sage/combinat/subword_complex_c.cpython-314-x86_64-linux-musl.so +0 -0
  304. sage/combinat/subword_complex_c.pyx +119 -0
  305. sage/combinat/super_tableau.py +821 -0
  306. sage/combinat/superpartition.py +1154 -0
  307. sage/combinat/symmetric_group_algebra.py +3774 -0
  308. sage/combinat/symmetric_group_representations.py +1830 -0
  309. sage/combinat/t_sequences.py +877 -0
  310. sage/combinat/tableau.py +9506 -0
  311. sage/combinat/tableau_residues.py +860 -0
  312. sage/combinat/tableau_tuple.py +5353 -0
  313. sage/combinat/tiling.py +2432 -0
  314. sage/combinat/triangles_FHM.py +777 -0
  315. sage/combinat/tutorial.py +1857 -0
  316. sage/combinat/vector_partition.py +337 -0
  317. sage/combinat/words/abstract_word.py +1722 -0
  318. sage/combinat/words/all.py +59 -0
  319. sage/combinat/words/alphabet.py +268 -0
  320. sage/combinat/words/finite_word.py +7201 -0
  321. sage/combinat/words/infinite_word.py +113 -0
  322. sage/combinat/words/lyndon_word.py +652 -0
  323. sage/combinat/words/morphic.py +351 -0
  324. sage/combinat/words/morphism.py +3878 -0
  325. sage/combinat/words/paths.py +2932 -0
  326. sage/combinat/words/shuffle_product.py +278 -0
  327. sage/combinat/words/suffix_trees.py +1873 -0
  328. sage/combinat/words/word.py +769 -0
  329. sage/combinat/words/word_char.cpython-314-x86_64-linux-musl.so +0 -0
  330. sage/combinat/words/word_char.pyx +847 -0
  331. sage/combinat/words/word_datatypes.cpython-314-x86_64-linux-musl.so +0 -0
  332. sage/combinat/words/word_datatypes.pxd +4 -0
  333. sage/combinat/words/word_datatypes.pyx +1067 -0
  334. sage/combinat/words/word_generators.py +2026 -0
  335. sage/combinat/words/word_infinite_datatypes.py +1218 -0
  336. sage/combinat/words/word_options.py +99 -0
  337. sage/combinat/words/words.py +2396 -0
  338. sage/data_structures/all__sagemath_combinat.py +1 -0
  339. sage/databases/all__sagemath_combinat.py +13 -0
  340. sage/databases/findstat.py +4897 -0
  341. sage/databases/oeis.py +2058 -0
  342. sage/databases/sloane.py +393 -0
  343. sage/dynamics/all__sagemath_combinat.py +14 -0
  344. sage/dynamics/cellular_automata/all.py +7 -0
  345. sage/dynamics/cellular_automata/catalog.py +34 -0
  346. sage/dynamics/cellular_automata/elementary.py +612 -0
  347. sage/dynamics/cellular_automata/glca.py +477 -0
  348. sage/dynamics/cellular_automata/solitons.py +1463 -0
  349. sage/dynamics/finite_dynamical_system.py +1249 -0
  350. sage/dynamics/finite_dynamical_system_catalog.py +382 -0
  351. sage/games/all.py +7 -0
  352. sage/games/hexad.py +704 -0
  353. sage/games/quantumino.py +591 -0
  354. sage/games/sudoku.py +889 -0
  355. sage/games/sudoku_backtrack.cpython-314-x86_64-linux-musl.so +0 -0
  356. sage/games/sudoku_backtrack.pyx +189 -0
  357. sage/groups/all__sagemath_combinat.py +1 -0
  358. sage/groups/indexed_free_group.py +489 -0
  359. sage/libs/all__sagemath_combinat.py +6 -0
  360. sage/libs/lrcalc/__init__.py +1 -0
  361. sage/libs/lrcalc/lrcalc.py +525 -0
  362. sage/libs/symmetrica/__init__.py +7 -0
  363. sage/libs/symmetrica/all.py +101 -0
  364. sage/libs/symmetrica/kostka.pxi +168 -0
  365. sage/libs/symmetrica/part.pxi +193 -0
  366. sage/libs/symmetrica/plet.pxi +42 -0
  367. sage/libs/symmetrica/sab.pxi +196 -0
  368. sage/libs/symmetrica/sb.pxi +332 -0
  369. sage/libs/symmetrica/sc.pxi +192 -0
  370. sage/libs/symmetrica/schur.pxi +956 -0
  371. sage/libs/symmetrica/symmetrica.cpython-314-x86_64-linux-musl.so +0 -0
  372. sage/libs/symmetrica/symmetrica.pxi +1172 -0
  373. sage/libs/symmetrica/symmetrica.pyx +39 -0
  374. sage/monoids/all.py +13 -0
  375. sage/monoids/automatic_semigroup.py +1054 -0
  376. sage/monoids/free_abelian_monoid.py +315 -0
  377. sage/monoids/free_abelian_monoid_element.cpython-314-x86_64-linux-musl.so +0 -0
  378. sage/monoids/free_abelian_monoid_element.pxd +16 -0
  379. sage/monoids/free_abelian_monoid_element.pyx +397 -0
  380. sage/monoids/free_monoid.py +335 -0
  381. sage/monoids/free_monoid_element.py +431 -0
  382. sage/monoids/hecke_monoid.py +65 -0
  383. sage/monoids/string_monoid.py +817 -0
  384. sage/monoids/string_monoid_element.py +547 -0
  385. sage/monoids/string_ops.py +143 -0
  386. sage/monoids/trace_monoid.py +972 -0
  387. sage/rings/all__sagemath_combinat.py +2 -0
  388. sage/sat/all.py +4 -0
  389. sage/sat/boolean_polynomials.py +405 -0
  390. sage/sat/converters/__init__.py +6 -0
  391. sage/sat/converters/anf2cnf.py +14 -0
  392. sage/sat/converters/polybori.py +611 -0
  393. sage/sat/solvers/__init__.py +5 -0
  394. sage/sat/solvers/cryptominisat.py +287 -0
  395. sage/sat/solvers/dimacs.py +783 -0
  396. sage/sat/solvers/picosat.py +228 -0
  397. sage/sat/solvers/sat_lp.py +156 -0
  398. sage/sat/solvers/satsolver.cpython-314-x86_64-linux-musl.so +0 -0
  399. sage/sat/solvers/satsolver.pxd +3 -0
  400. 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