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.
Files changed (401) hide show
  1. passagemath_combinat/__init__.py +3 -0
  2. passagemath_combinat-10.6.42.dist-info/DELVEWHEEL +2 -0
  3. passagemath_combinat-10.6.42.dist-info/METADATA +160 -0
  4. passagemath_combinat-10.6.42.dist-info/RECORD +401 -0
  5. passagemath_combinat-10.6.42.dist-info/WHEEL +5 -0
  6. passagemath_combinat-10.6.42.dist-info/top_level.txt +3 -0
  7. passagemath_combinat.libs/libgmp-10-3a5f019e2510aeaad918cab2b57a689d.dll +0 -0
  8. passagemath_combinat.libs/libsymmetrica-3-7dcf900932804d0df5fd0919b4668720.dll +0 -0
  9. sage/algebras/affine_nil_temperley_lieb.py +263 -0
  10. sage/algebras/all.py +24 -0
  11. sage/algebras/all__sagemath_combinat.py +35 -0
  12. sage/algebras/askey_wilson.py +935 -0
  13. sage/algebras/associated_graded.py +345 -0
  14. sage/algebras/cellular_basis.py +350 -0
  15. sage/algebras/cluster_algebra.py +2766 -0
  16. sage/algebras/down_up_algebra.py +860 -0
  17. sage/algebras/free_algebra.py +1698 -0
  18. sage/algebras/free_algebra_element.py +345 -0
  19. sage/algebras/free_algebra_quotient.py +405 -0
  20. sage/algebras/free_algebra_quotient_element.py +295 -0
  21. sage/algebras/free_zinbiel_algebra.py +885 -0
  22. sage/algebras/hall_algebra.py +783 -0
  23. sage/algebras/hecke_algebras/all.py +4 -0
  24. sage/algebras/hecke_algebras/ariki_koike_algebra.py +1796 -0
  25. sage/algebras/hecke_algebras/ariki_koike_specht_modules.py +475 -0
  26. sage/algebras/hecke_algebras/cubic_hecke_algebra.py +3520 -0
  27. sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +1473 -0
  28. sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +1079 -0
  29. sage/algebras/iwahori_hecke_algebra.py +3095 -0
  30. sage/algebras/jordan_algebra.py +1773 -0
  31. sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py +113 -0
  32. sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py +156 -0
  33. sage/algebras/lie_conformal_algebras/all.py +18 -0
  34. sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +134 -0
  35. sage/algebras/lie_conformal_algebras/examples.py +43 -0
  36. sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py +131 -0
  37. sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py +139 -0
  38. sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py +174 -0
  39. sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py +167 -0
  40. sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py +107 -0
  41. sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py +135 -0
  42. sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py +353 -0
  43. sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py +236 -0
  44. sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py +78 -0
  45. sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py +328 -0
  46. sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py +117 -0
  47. sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py +86 -0
  48. sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py +82 -0
  49. sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +205 -0
  50. sage/algebras/nil_coxeter_algebra.py +191 -0
  51. sage/algebras/q_commuting_polynomials.py +673 -0
  52. sage/algebras/q_system.py +608 -0
  53. sage/algebras/quantum_clifford.py +959 -0
  54. sage/algebras/quantum_groups/ace_quantum_onsager.py +693 -0
  55. sage/algebras/quantum_groups/all.py +9 -0
  56. sage/algebras/quantum_groups/fock_space.py +2219 -0
  57. sage/algebras/quantum_groups/q_numbers.py +207 -0
  58. sage/algebras/quantum_groups/quantum_group_gap.py +2695 -0
  59. sage/algebras/quantum_groups/representations.py +591 -0
  60. sage/algebras/quantum_matrix_coordinate_algebra.py +1006 -0
  61. sage/algebras/quantum_oscillator.py +623 -0
  62. sage/algebras/quaternion_algebra.py +20 -0
  63. sage/algebras/quaternion_algebra_element.py +55 -0
  64. sage/algebras/rational_cherednik_algebra.py +525 -0
  65. sage/algebras/schur_algebra.py +670 -0
  66. sage/algebras/shuffle_algebra.py +1011 -0
  67. sage/algebras/splitting_algebra.py +779 -0
  68. sage/algebras/tensor_algebra.py +709 -0
  69. sage/algebras/yangian.py +1082 -0
  70. sage/algebras/yokonuma_hecke_algebra.py +1018 -0
  71. sage/all__sagemath_combinat.py +44 -0
  72. sage/combinat/SJT.py +255 -0
  73. sage/combinat/affine_permutation.py +2405 -0
  74. sage/combinat/algebraic_combinatorics.py +55 -0
  75. sage/combinat/all.py +53 -0
  76. sage/combinat/all__sagemath_combinat.py +195 -0
  77. sage/combinat/alternating_sign_matrix.py +2063 -0
  78. sage/combinat/baxter_permutations.py +346 -0
  79. sage/combinat/bijectionist.py +3220 -0
  80. sage/combinat/binary_recurrence_sequences.py +1180 -0
  81. sage/combinat/blob_algebra.py +685 -0
  82. sage/combinat/catalog_partitions.py +27 -0
  83. sage/combinat/chas/all.py +23 -0
  84. sage/combinat/chas/fsym.py +1180 -0
  85. sage/combinat/chas/wqsym.py +2601 -0
  86. sage/combinat/cluster_complex.py +326 -0
  87. sage/combinat/colored_permutations.py +2039 -0
  88. sage/combinat/colored_permutations_representations.py +964 -0
  89. sage/combinat/composition_signed.py +142 -0
  90. sage/combinat/composition_tableau.py +855 -0
  91. sage/combinat/constellation.py +1729 -0
  92. sage/combinat/core.py +751 -0
  93. sage/combinat/counting.py +12 -0
  94. sage/combinat/crystals/affine.py +742 -0
  95. sage/combinat/crystals/affine_factorization.py +518 -0
  96. sage/combinat/crystals/affinization.py +331 -0
  97. sage/combinat/crystals/alcove_path.py +2013 -0
  98. sage/combinat/crystals/all.py +22 -0
  99. sage/combinat/crystals/bkk_crystals.py +141 -0
  100. sage/combinat/crystals/catalog.py +115 -0
  101. sage/combinat/crystals/catalog_elementary_crystals.py +18 -0
  102. sage/combinat/crystals/catalog_infinity_crystals.py +33 -0
  103. sage/combinat/crystals/catalog_kirillov_reshetikhin.py +18 -0
  104. sage/combinat/crystals/crystals.py +257 -0
  105. sage/combinat/crystals/direct_sum.py +260 -0
  106. sage/combinat/crystals/elementary_crystals.py +1251 -0
  107. sage/combinat/crystals/fast_crystals.py +441 -0
  108. sage/combinat/crystals/fully_commutative_stable_grothendieck.py +1205 -0
  109. sage/combinat/crystals/generalized_young_walls.py +1076 -0
  110. sage/combinat/crystals/highest_weight_crystals.py +436 -0
  111. sage/combinat/crystals/induced_structure.py +695 -0
  112. sage/combinat/crystals/infinity_crystals.py +730 -0
  113. sage/combinat/crystals/kac_modules.py +863 -0
  114. sage/combinat/crystals/kirillov_reshetikhin.py +4196 -0
  115. sage/combinat/crystals/kyoto_path_model.py +497 -0
  116. sage/combinat/crystals/letters.cp314t-win_amd64.pyd +0 -0
  117. sage/combinat/crystals/letters.pxd +79 -0
  118. sage/combinat/crystals/letters.pyx +3056 -0
  119. sage/combinat/crystals/littelmann_path.py +1518 -0
  120. sage/combinat/crystals/monomial_crystals.py +1262 -0
  121. sage/combinat/crystals/multisegments.py +462 -0
  122. sage/combinat/crystals/mv_polytopes.py +467 -0
  123. sage/combinat/crystals/pbw_crystal.py +511 -0
  124. sage/combinat/crystals/pbw_datum.cp314t-win_amd64.pyd +0 -0
  125. sage/combinat/crystals/pbw_datum.pxd +4 -0
  126. sage/combinat/crystals/pbw_datum.pyx +487 -0
  127. sage/combinat/crystals/polyhedral_realization.py +372 -0
  128. sage/combinat/crystals/spins.cp314t-win_amd64.pyd +0 -0
  129. sage/combinat/crystals/spins.pxd +21 -0
  130. sage/combinat/crystals/spins.pyx +756 -0
  131. sage/combinat/crystals/star_crystal.py +290 -0
  132. sage/combinat/crystals/subcrystal.py +464 -0
  133. sage/combinat/crystals/tensor_product.py +1177 -0
  134. sage/combinat/crystals/tensor_product_element.cp314t-win_amd64.pyd +0 -0
  135. sage/combinat/crystals/tensor_product_element.pxd +35 -0
  136. sage/combinat/crystals/tensor_product_element.pyx +1870 -0
  137. sage/combinat/crystals/virtual_crystal.py +420 -0
  138. sage/combinat/cyclic_sieving_phenomenon.py +204 -0
  139. sage/combinat/debruijn_sequence.cp314t-win_amd64.pyd +0 -0
  140. sage/combinat/debruijn_sequence.pyx +355 -0
  141. sage/combinat/decorated_permutation.py +270 -0
  142. sage/combinat/degree_sequences.cp314t-win_amd64.pyd +0 -0
  143. sage/combinat/degree_sequences.pyx +588 -0
  144. sage/combinat/derangements.py +527 -0
  145. sage/combinat/descent_algebra.py +1008 -0
  146. sage/combinat/diagram.py +1551 -0
  147. sage/combinat/diagram_algebras.py +5886 -0
  148. sage/combinat/dyck_word.py +4349 -0
  149. sage/combinat/e_one_star.py +1623 -0
  150. sage/combinat/enumerated_sets.py +123 -0
  151. sage/combinat/expnums.cp314t-win_amd64.pyd +0 -0
  152. sage/combinat/expnums.pyx +148 -0
  153. sage/combinat/fast_vector_partitions.cp314t-win_amd64.pyd +0 -0
  154. sage/combinat/fast_vector_partitions.pyx +346 -0
  155. sage/combinat/fqsym.py +1977 -0
  156. sage/combinat/free_dendriform_algebra.py +954 -0
  157. sage/combinat/free_prelie_algebra.py +1141 -0
  158. sage/combinat/fully_commutative_elements.py +1077 -0
  159. sage/combinat/fully_packed_loop.py +1523 -0
  160. sage/combinat/gelfand_tsetlin_patterns.py +1409 -0
  161. sage/combinat/gray_codes.py +311 -0
  162. sage/combinat/grossman_larson_algebras.py +667 -0
  163. sage/combinat/growth.py +4352 -0
  164. sage/combinat/hall_polynomial.py +188 -0
  165. sage/combinat/hillman_grassl.py +866 -0
  166. sage/combinat/integer_matrices.py +329 -0
  167. sage/combinat/integer_vectors_mod_permgroup.py +1238 -0
  168. sage/combinat/k_tableau.py +4564 -0
  169. sage/combinat/kazhdan_lusztig.py +215 -0
  170. sage/combinat/key_polynomial.py +885 -0
  171. sage/combinat/knutson_tao_puzzles.py +2286 -0
  172. sage/combinat/lr_tableau.py +311 -0
  173. sage/combinat/matrices/all.py +24 -0
  174. sage/combinat/matrices/hadamard_matrix.py +3790 -0
  175. sage/combinat/matrices/latin.py +2912 -0
  176. sage/combinat/misc.py +401 -0
  177. sage/combinat/multiset_partition_into_sets_ordered.py +3541 -0
  178. sage/combinat/ncsf_qsym/all.py +21 -0
  179. sage/combinat/ncsf_qsym/combinatorics.py +317 -0
  180. sage/combinat/ncsf_qsym/generic_basis_code.py +1427 -0
  181. sage/combinat/ncsf_qsym/ncsf.py +5637 -0
  182. sage/combinat/ncsf_qsym/qsym.py +4053 -0
  183. sage/combinat/ncsf_qsym/tutorial.py +447 -0
  184. sage/combinat/ncsym/all.py +21 -0
  185. sage/combinat/ncsym/bases.py +855 -0
  186. sage/combinat/ncsym/dual.py +593 -0
  187. sage/combinat/ncsym/ncsym.py +2076 -0
  188. sage/combinat/necklace.py +551 -0
  189. sage/combinat/non_decreasing_parking_function.py +634 -0
  190. sage/combinat/nu_dyck_word.py +1474 -0
  191. sage/combinat/output.py +861 -0
  192. sage/combinat/parallelogram_polyomino.py +4326 -0
  193. sage/combinat/parking_functions.py +1602 -0
  194. sage/combinat/partition_algebra.py +1998 -0
  195. sage/combinat/partition_kleshchev.py +1982 -0
  196. sage/combinat/partition_shifting_algebras.py +584 -0
  197. sage/combinat/partition_tuple.py +3114 -0
  198. sage/combinat/path_tableaux/all.py +13 -0
  199. sage/combinat/path_tableaux/catalog.py +29 -0
  200. sage/combinat/path_tableaux/dyck_path.py +380 -0
  201. sage/combinat/path_tableaux/frieze.py +476 -0
  202. sage/combinat/path_tableaux/path_tableau.py +728 -0
  203. sage/combinat/path_tableaux/semistandard.py +510 -0
  204. sage/combinat/perfect_matching.py +779 -0
  205. sage/combinat/plane_partition.py +3300 -0
  206. sage/combinat/q_bernoulli.cp314t-win_amd64.pyd +0 -0
  207. sage/combinat/q_bernoulli.pyx +128 -0
  208. sage/combinat/quickref.py +81 -0
  209. sage/combinat/recognizable_series.py +2051 -0
  210. sage/combinat/regular_sequence.py +4316 -0
  211. sage/combinat/regular_sequence_bounded.py +543 -0
  212. sage/combinat/restricted_growth.py +81 -0
  213. sage/combinat/ribbon.py +20 -0
  214. sage/combinat/ribbon_shaped_tableau.py +489 -0
  215. sage/combinat/ribbon_tableau.py +1180 -0
  216. sage/combinat/rigged_configurations/all.py +46 -0
  217. sage/combinat/rigged_configurations/bij_abstract_class.py +548 -0
  218. sage/combinat/rigged_configurations/bij_infinity.py +370 -0
  219. sage/combinat/rigged_configurations/bij_type_A.py +163 -0
  220. sage/combinat/rigged_configurations/bij_type_A2_dual.py +338 -0
  221. sage/combinat/rigged_configurations/bij_type_A2_even.py +218 -0
  222. sage/combinat/rigged_configurations/bij_type_A2_odd.py +199 -0
  223. sage/combinat/rigged_configurations/bij_type_B.py +900 -0
  224. sage/combinat/rigged_configurations/bij_type_C.py +267 -0
  225. sage/combinat/rigged_configurations/bij_type_D.py +771 -0
  226. sage/combinat/rigged_configurations/bij_type_D_tri.py +392 -0
  227. sage/combinat/rigged_configurations/bij_type_D_twisted.py +576 -0
  228. sage/combinat/rigged_configurations/bij_type_E67.py +402 -0
  229. sage/combinat/rigged_configurations/bijection.py +143 -0
  230. sage/combinat/rigged_configurations/kleber_tree.py +1475 -0
  231. sage/combinat/rigged_configurations/kr_tableaux.py +1898 -0
  232. sage/combinat/rigged_configurations/rc_crystal.py +461 -0
  233. sage/combinat/rigged_configurations/rc_infinity.py +540 -0
  234. sage/combinat/rigged_configurations/rigged_configuration_element.py +2403 -0
  235. sage/combinat/rigged_configurations/rigged_configurations.py +1918 -0
  236. sage/combinat/rigged_configurations/rigged_partition.cp314t-win_amd64.pyd +0 -0
  237. sage/combinat/rigged_configurations/rigged_partition.pxd +15 -0
  238. sage/combinat/rigged_configurations/rigged_partition.pyx +680 -0
  239. sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py +499 -0
  240. sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element.py +428 -0
  241. sage/combinat/rsk.py +3438 -0
  242. sage/combinat/schubert_polynomial.py +508 -0
  243. sage/combinat/set_partition.py +3318 -0
  244. sage/combinat/set_partition_iterator.cp314t-win_amd64.pyd +0 -0
  245. sage/combinat/set_partition_iterator.pyx +136 -0
  246. sage/combinat/set_partition_ordered.py +1590 -0
  247. sage/combinat/sf/abreu_nigro.py +346 -0
  248. sage/combinat/sf/all.py +52 -0
  249. sage/combinat/sf/character.py +576 -0
  250. sage/combinat/sf/classical.py +319 -0
  251. sage/combinat/sf/dual.py +996 -0
  252. sage/combinat/sf/elementary.py +549 -0
  253. sage/combinat/sf/hall_littlewood.py +1028 -0
  254. sage/combinat/sf/hecke.py +336 -0
  255. sage/combinat/sf/homogeneous.py +464 -0
  256. sage/combinat/sf/jack.py +1428 -0
  257. sage/combinat/sf/k_dual.py +1458 -0
  258. sage/combinat/sf/kfpoly.py +447 -0
  259. sage/combinat/sf/llt.py +789 -0
  260. sage/combinat/sf/macdonald.py +2019 -0
  261. sage/combinat/sf/monomial.py +525 -0
  262. sage/combinat/sf/multiplicative.py +113 -0
  263. sage/combinat/sf/new_kschur.py +1786 -0
  264. sage/combinat/sf/ns_macdonald.py +964 -0
  265. sage/combinat/sf/orthogonal.py +246 -0
  266. sage/combinat/sf/orthotriang.py +355 -0
  267. sage/combinat/sf/powersum.py +963 -0
  268. sage/combinat/sf/schur.py +880 -0
  269. sage/combinat/sf/sf.py +1653 -0
  270. sage/combinat/sf/sfa.py +7053 -0
  271. sage/combinat/sf/symplectic.py +253 -0
  272. sage/combinat/sf/witt.py +721 -0
  273. sage/combinat/shifted_primed_tableau.py +2735 -0
  274. sage/combinat/shuffle.py +830 -0
  275. sage/combinat/sidon_sets.py +146 -0
  276. sage/combinat/similarity_class_type.py +1721 -0
  277. sage/combinat/sine_gordon.py +618 -0
  278. sage/combinat/six_vertex_model.py +784 -0
  279. sage/combinat/skew_partition.py +2053 -0
  280. sage/combinat/skew_tableau.py +2989 -0
  281. sage/combinat/sloane_functions.py +8935 -0
  282. sage/combinat/specht_module.py +1403 -0
  283. sage/combinat/species/all.py +48 -0
  284. sage/combinat/species/characteristic_species.py +321 -0
  285. sage/combinat/species/composition_species.py +273 -0
  286. sage/combinat/species/cycle_species.py +284 -0
  287. sage/combinat/species/empty_species.py +155 -0
  288. sage/combinat/species/functorial_composition_species.py +148 -0
  289. sage/combinat/species/generating_series.py +673 -0
  290. sage/combinat/species/library.py +148 -0
  291. sage/combinat/species/linear_order_species.py +169 -0
  292. sage/combinat/species/misc.py +83 -0
  293. sage/combinat/species/partition_species.py +290 -0
  294. sage/combinat/species/permutation_species.py +268 -0
  295. sage/combinat/species/product_species.py +423 -0
  296. sage/combinat/species/recursive_species.py +476 -0
  297. sage/combinat/species/set_species.py +192 -0
  298. sage/combinat/species/species.py +820 -0
  299. sage/combinat/species/structure.py +539 -0
  300. sage/combinat/species/subset_species.py +243 -0
  301. sage/combinat/species/sum_species.py +225 -0
  302. sage/combinat/subword.py +564 -0
  303. sage/combinat/subword_complex.py +2122 -0
  304. sage/combinat/subword_complex_c.cp314t-win_amd64.pyd +0 -0
  305. sage/combinat/subword_complex_c.pyx +119 -0
  306. sage/combinat/super_tableau.py +821 -0
  307. sage/combinat/superpartition.py +1154 -0
  308. sage/combinat/symmetric_group_algebra.py +3774 -0
  309. sage/combinat/symmetric_group_representations.py +1830 -0
  310. sage/combinat/t_sequences.py +877 -0
  311. sage/combinat/tableau.py +9506 -0
  312. sage/combinat/tableau_residues.py +860 -0
  313. sage/combinat/tableau_tuple.py +5353 -0
  314. sage/combinat/tiling.py +2432 -0
  315. sage/combinat/triangles_FHM.py +777 -0
  316. sage/combinat/tutorial.py +1857 -0
  317. sage/combinat/vector_partition.py +337 -0
  318. sage/combinat/words/abstract_word.py +1722 -0
  319. sage/combinat/words/all.py +59 -0
  320. sage/combinat/words/alphabet.py +268 -0
  321. sage/combinat/words/finite_word.py +7201 -0
  322. sage/combinat/words/infinite_word.py +113 -0
  323. sage/combinat/words/lyndon_word.py +652 -0
  324. sage/combinat/words/morphic.py +351 -0
  325. sage/combinat/words/morphism.py +3878 -0
  326. sage/combinat/words/paths.py +2932 -0
  327. sage/combinat/words/shuffle_product.py +278 -0
  328. sage/combinat/words/suffix_trees.py +1873 -0
  329. sage/combinat/words/word.py +769 -0
  330. sage/combinat/words/word_char.cp314t-win_amd64.pyd +0 -0
  331. sage/combinat/words/word_char.pyx +847 -0
  332. sage/combinat/words/word_datatypes.cp314t-win_amd64.pyd +0 -0
  333. sage/combinat/words/word_datatypes.pxd +4 -0
  334. sage/combinat/words/word_datatypes.pyx +1067 -0
  335. sage/combinat/words/word_generators.py +2026 -0
  336. sage/combinat/words/word_infinite_datatypes.py +1218 -0
  337. sage/combinat/words/word_options.py +99 -0
  338. sage/combinat/words/words.py +2396 -0
  339. sage/data_structures/all__sagemath_combinat.py +1 -0
  340. sage/databases/all__sagemath_combinat.py +13 -0
  341. sage/databases/findstat.py +4897 -0
  342. sage/databases/oeis.py +2058 -0
  343. sage/databases/sloane.py +393 -0
  344. sage/dynamics/all__sagemath_combinat.py +14 -0
  345. sage/dynamics/cellular_automata/all.py +7 -0
  346. sage/dynamics/cellular_automata/catalog.py +34 -0
  347. sage/dynamics/cellular_automata/elementary.py +612 -0
  348. sage/dynamics/cellular_automata/glca.py +477 -0
  349. sage/dynamics/cellular_automata/solitons.py +1463 -0
  350. sage/dynamics/finite_dynamical_system.py +1249 -0
  351. sage/dynamics/finite_dynamical_system_catalog.py +382 -0
  352. sage/games/all.py +7 -0
  353. sage/games/hexad.py +704 -0
  354. sage/games/quantumino.py +591 -0
  355. sage/games/sudoku.py +889 -0
  356. sage/games/sudoku_backtrack.cp314t-win_amd64.pyd +0 -0
  357. sage/games/sudoku_backtrack.pyx +189 -0
  358. sage/groups/all__sagemath_combinat.py +1 -0
  359. sage/groups/indexed_free_group.py +489 -0
  360. sage/libs/all__sagemath_combinat.py +6 -0
  361. sage/libs/lrcalc/__init__.py +1 -0
  362. sage/libs/lrcalc/lrcalc.py +525 -0
  363. sage/libs/symmetrica/__init__.py +7 -0
  364. sage/libs/symmetrica/all.py +101 -0
  365. sage/libs/symmetrica/kostka.pxi +168 -0
  366. sage/libs/symmetrica/part.pxi +193 -0
  367. sage/libs/symmetrica/plet.pxi +42 -0
  368. sage/libs/symmetrica/sab.pxi +196 -0
  369. sage/libs/symmetrica/sb.pxi +332 -0
  370. sage/libs/symmetrica/sc.pxi +192 -0
  371. sage/libs/symmetrica/schur.pxi +956 -0
  372. sage/libs/symmetrica/symmetrica.cp314t-win_amd64.pyd +0 -0
  373. sage/libs/symmetrica/symmetrica.pxi +1172 -0
  374. sage/libs/symmetrica/symmetrica.pyx +39 -0
  375. sage/monoids/all.py +13 -0
  376. sage/monoids/automatic_semigroup.py +1054 -0
  377. sage/monoids/free_abelian_monoid.py +315 -0
  378. sage/monoids/free_abelian_monoid_element.cp314t-win_amd64.pyd +0 -0
  379. sage/monoids/free_abelian_monoid_element.pxd +16 -0
  380. sage/monoids/free_abelian_monoid_element.pyx +397 -0
  381. sage/monoids/free_monoid.py +335 -0
  382. sage/monoids/free_monoid_element.py +431 -0
  383. sage/monoids/hecke_monoid.py +65 -0
  384. sage/monoids/string_monoid.py +817 -0
  385. sage/monoids/string_monoid_element.py +547 -0
  386. sage/monoids/string_ops.py +143 -0
  387. sage/monoids/trace_monoid.py +972 -0
  388. sage/rings/all__sagemath_combinat.py +2 -0
  389. sage/sat/all.py +4 -0
  390. sage/sat/boolean_polynomials.py +405 -0
  391. sage/sat/converters/__init__.py +6 -0
  392. sage/sat/converters/anf2cnf.py +14 -0
  393. sage/sat/converters/polybori.py +611 -0
  394. sage/sat/solvers/__init__.py +5 -0
  395. sage/sat/solvers/cryptominisat.py +287 -0
  396. sage/sat/solvers/dimacs.py +783 -0
  397. sage/sat/solvers/picosat.py +228 -0
  398. sage/sat/solvers/sat_lp.py +156 -0
  399. sage/sat/solvers/satsolver.cp314t-win_amd64.pyd +0 -0
  400. sage/sat/solvers/satsolver.pxd +3 -0
  401. sage/sat/solvers/satsolver.pyx +405 -0
@@ -0,0 +1,1998 @@
1
+ # sage_setup: distribution = sagemath-combinat
2
+ # sage.doctest: needs sage.combinat sage.modules
3
+ r"""
4
+ Partition/diagram algebras
5
+ """
6
+ # ****************************************************************************
7
+ # Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>,
8
+ #
9
+ # Distributed under the terms of the GNU General Public License (GPL)
10
+ #
11
+ # This code is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ # General Public License for more details.
15
+ #
16
+ # The full text of the GPL is available at:
17
+ #
18
+ # https://www.gnu.org/licenses/
19
+ # ****************************************************************************
20
+ from sage.arith.misc import binomial, factorial, integer_ceil as ceil
21
+ from sage.categories.algebras_with_basis import AlgebrasWithBasis
22
+ from sage.combinat.combinat import catalan_number
23
+ from sage.combinat.free_module import CombinatorialFreeModule
24
+ from sage.combinat.permutation import Permutations
25
+ from sage.combinat.set_partition import SetPartition, SetPartitions, SetPartitions_set
26
+ from sage.combinat.subset import Subsets
27
+ from sage.misc.lazy_import import lazy_import
28
+ from sage.rings.integer_ring import ZZ
29
+ from sage.rings.rational_field import QQ
30
+ from sage.sets.set import Set, Set_generic
31
+
32
+ lazy_import('sage.graphs.graph', 'Graph')
33
+
34
+
35
+ def _int_or_half_int(k):
36
+ r"""
37
+ Check if ``k`` is an integer or half integer.
38
+
39
+ OUTPUT:
40
+
41
+ If ``k`` is not in `1/2 \ZZ`, then this raises a :exc:`ValueError`.
42
+ Otherwise, we return the pair:
43
+
44
+ - boolean; ``True`` if ``k`` is an integer and ``False`` if a half integer
45
+ - integer; the floor of ``k``
46
+
47
+ TESTS::
48
+
49
+ sage: from sage.combinat.partition_algebra import _int_or_half_int
50
+ sage: _int_or_half_int(2)
51
+ (True, 2)
52
+ sage: _int_or_half_int(3/2)
53
+ (False, 1)
54
+ sage: _int_or_half_int(1.5)
55
+ (False, 1)
56
+ sage: _int_or_half_int(2.)
57
+ (True, 2)
58
+ sage: _int_or_half_int(2.1)
59
+ Traceback (most recent call last):
60
+ ...
61
+ ValueError: k must be an integer or an integer + 1/2
62
+ """
63
+ if k in ZZ:
64
+ return True, ZZ(k)
65
+ # Try to see if it is a half integer
66
+ try:
67
+ k = QQ(k)
68
+ if k.denominator() == 2:
69
+ return False, k.floor()
70
+ except (ValueError, TypeError):
71
+ pass
72
+
73
+ raise ValueError("k must be an integer or an integer + 1/2")
74
+
75
+
76
+ class SetPartitionsXkElement(SetPartition):
77
+ """
78
+ An element for the classes of ``SetPartitionXk`` where ``X`` is some
79
+ letter.
80
+ """
81
+
82
+ def check(self):
83
+ """
84
+ Check to make sure this is a set partition.
85
+
86
+ EXAMPLES::
87
+
88
+ sage: A2p5 = SetPartitionsAk(2.5)
89
+ sage: x = A2p5.first(); x
90
+ {{-3, -2, -1, 1, 2, 3}}
91
+ sage: x.check()
92
+ sage: y = A2p5.next(x); y
93
+ {{-3, 3}, {-2, -1, 1, 2}}
94
+ sage: y.check()
95
+ """
96
+ # Check to make sure each element of x is a set
97
+ for s in self:
98
+ assert isinstance(s, (set, frozenset, Set_generic))
99
+
100
+
101
+ #######
102
+ # A_k #
103
+ #######
104
+
105
+ def SetPartitionsAk(k):
106
+ r"""
107
+ Return the combinatorial class of set partitions of type `A_k`.
108
+
109
+ EXAMPLES::
110
+
111
+ sage: A3 = SetPartitionsAk(3); A3
112
+ Set partitions of {1, ..., 3, -1, ..., -3}
113
+
114
+ sage: A3.first() #random
115
+ {{1, 2, 3, -1, -3, -2}}
116
+ sage: A3.last() #random
117
+ {{-1}, {-2}, {3}, {1}, {-3}, {2}}
118
+ sage: A3.random_element() #random # needs sage.symbolic
119
+ {{1, 3, -3, -1}, {2, -2}}
120
+
121
+ sage: A3.cardinality() # needs sage.libs.flint
122
+ 203
123
+
124
+ sage: A2p5 = SetPartitionsAk(2.5); A2p5
125
+ Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block
126
+ sage: A2p5.cardinality()
127
+ 52
128
+
129
+ sage: A2p5.first() #random
130
+ {{1, 2, 3, -1, -3, -2}}
131
+ sage: A2p5.last() #random
132
+ {{-1}, {-2}, {2}, {3, -3}, {1}}
133
+ sage: A2p5.random_element() #random # needs sage.symbolic
134
+ {{-1}, {-2}, {3, -3}, {1, 2}}
135
+ """
136
+ is_int, k = _int_or_half_int(k)
137
+ if not is_int:
138
+ return SetPartitionsAkhalf_k(k)
139
+ return SetPartitionsAk_k(k)
140
+
141
+
142
+ class SetPartitionsAk_k(SetPartitions_set):
143
+ def __init__(self, k):
144
+ """
145
+ TESTS::
146
+
147
+ sage: A3 = SetPartitionsAk(3); A3
148
+ Set partitions of {1, ..., 3, -1, ..., -3}
149
+ sage: A3 == loads(dumps(A3))
150
+ True
151
+ """
152
+ self.k = k
153
+ set_k = frozenset(list(range(1, k + 1)) +
154
+ [-x for x in range(1, k + 1)])
155
+ SetPartitions_set.__init__(self, set_k)
156
+
157
+ Element = SetPartitionsXkElement
158
+
159
+ def _repr_(self):
160
+ """
161
+ TESTS::
162
+
163
+ sage: SetPartitionsAk(3)
164
+ Set partitions of {1, ..., 3, -1, ..., -3}
165
+ """
166
+ return "Set partitions of {1, ..., %s, -1, ..., -%s}" % (self.k, self.k)
167
+
168
+
169
+ class SetPartitionsAkhalf_k(SetPartitions_set):
170
+ def __init__(self, k):
171
+ """
172
+ TESTS::
173
+
174
+ sage: A2p5 = SetPartitionsAk(2.5); A2p5
175
+ Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block
176
+ sage: A2p5 == loads(dumps(A2p5))
177
+ True
178
+ """
179
+ self.k = k
180
+ set_k = frozenset(list(range(1, k + 2)) + [-x for x in range(1, k + 1)])
181
+ SetPartitions_set.__init__(self, set_k)
182
+
183
+ Element = SetPartitionsXkElement
184
+
185
+ def _repr_(self):
186
+ """
187
+ TESTS::
188
+
189
+ sage: SetPartitionsAk(2.5)
190
+ Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block
191
+ """
192
+ s = self.k + 1
193
+ return "Set partitions of {1, ..., %s, -1, ..., -%s} with %s and -%s in the same block" % (s, s, s, s)
194
+
195
+ def __contains__(self, x):
196
+ """
197
+ TESTS::
198
+
199
+ sage: A2p5 = SetPartitionsAk(2.5)
200
+ sage: all(sp in A2p5 for sp in A2p5)
201
+ True
202
+ sage: A3 = SetPartitionsAk(3)
203
+ sage: len([x for x in A3 if x in A2p5])
204
+ 52
205
+ sage: A2p5.cardinality()
206
+ 52
207
+ """
208
+ if x not in SetPartitionsAk_k(self.k + 1):
209
+ return False
210
+
211
+ for part in x:
212
+ if self.k + 1 in part and -self.k - 1 not in part:
213
+ return False
214
+
215
+ return True
216
+
217
+ def __iter__(self):
218
+ """
219
+ TESTS::
220
+
221
+ sage: SetPartitionsAk(1.5).list() #random
222
+ [{{1, 2, -2, -1}},
223
+ {{2, -2, -1}, {1}},
224
+ {{2, -2}, {1, -1}},
225
+ {{-1}, {1, 2, -2}},
226
+ {{-1}, {2, -2}, {1}}]
227
+
228
+ ::
229
+
230
+ sage: ks = [ 1.5, 2.5, 3.5 ]
231
+ sage: aks = map(SetPartitionsAk, ks)
232
+ sage: all(ak.cardinality() == len(ak.list()) for ak in aks)
233
+ True
234
+ """
235
+ kp = frozenset([-self.k - 1])
236
+ for sp in SetPartitions_set.__iter__(self):
237
+ res = []
238
+ for part in sp:
239
+ if self.k + 1 in part:
240
+ res.append(part.union(kp))
241
+ else:
242
+ res.append(part)
243
+ yield self.element_class(self, res)
244
+
245
+
246
+ #######
247
+ # S_k #
248
+ #######
249
+
250
+ def SetPartitionsSk(k):
251
+ r"""
252
+ Return the combinatorial class of set partitions of type `S_k`.
253
+
254
+ There is a bijection between these set partitions and the
255
+ permutations of `1, \ldots, k`.
256
+
257
+ EXAMPLES::
258
+
259
+ sage: S3 = SetPartitionsSk(3); S3
260
+ Set partitions of {1, ..., 3, -1, ..., -3} with propagating number 3
261
+ sage: S3.cardinality()
262
+ 6
263
+
264
+ sage: S3.list() #random
265
+ [{{2, -2}, {3, -3}, {1, -1}},
266
+ {{1, -1}, {2, -3}, {3, -2}},
267
+ {{2, -1}, {3, -3}, {1, -2}},
268
+ {{1, -2}, {2, -3}, {3, -1}},
269
+ {{1, -3}, {2, -1}, {3, -2}},
270
+ {{1, -3}, {2, -2}, {3, -1}}]
271
+ sage: S3.first() #random
272
+ {{2, -2}, {3, -3}, {1, -1}}
273
+ sage: S3.last() #random
274
+ {{1, -3}, {2, -2}, {3, -1}}
275
+ sage: S3.random_element() #random # needs sage.symbolic
276
+ {{1, -3}, {2, -1}, {3, -2}}
277
+
278
+ sage: S3p5 = SetPartitionsSk(3.5); S3p5
279
+ Set partitions of {1, ..., 4, -1, ..., -4} with 4 and -4 in the same block and propagating number 4
280
+ sage: S3p5.cardinality()
281
+ 6
282
+
283
+ sage: S3p5.list() #random
284
+ [{{2, -2}, {3, -3}, {1, -1}, {4, -4}},
285
+ {{2, -3}, {1, -1}, {4, -4}, {3, -2}},
286
+ {{2, -1}, {3, -3}, {1, -2}, {4, -4}},
287
+ {{2, -3}, {1, -2}, {4, -4}, {3, -1}},
288
+ {{1, -3}, {2, -1}, {4, -4}, {3, -2}},
289
+ {{1, -3}, {2, -2}, {4, -4}, {3, -1}}]
290
+ sage: S3p5.first() #random
291
+ {{2, -2}, {3, -3}, {1, -1}, {4, -4}}
292
+ sage: S3p5.last() #random
293
+ {{1, -3}, {2, -2}, {4, -4}, {3, -1}}
294
+ sage: S3p5.random_element() #random # needs sage.symbolic
295
+ {{1, -3}, {2, -2}, {4, -4}, {3, -1}}
296
+ """
297
+ is_int, k = _int_or_half_int(k)
298
+ if not is_int:
299
+ return SetPartitionsSkhalf_k(k)
300
+ return SetPartitionsSk_k(k)
301
+
302
+
303
+ class SetPartitionsSk_k(SetPartitionsAk_k):
304
+ def _repr_(self):
305
+ """
306
+ TESTS::
307
+
308
+ sage: SetPartitionsSk(3)
309
+ Set partitions of {1, ..., 3, -1, ..., -3} with propagating number 3
310
+ """
311
+ return SetPartitionsAk_k._repr_(self) + " with propagating number %s" % self.k
312
+
313
+ def __contains__(self, x):
314
+ """
315
+ TESTS::
316
+
317
+ sage: A3 = SetPartitionsAk(3)
318
+ sage: S3 = SetPartitionsSk(3)
319
+ sage: all(sp in S3 for sp in S3)
320
+ True
321
+ sage: S3.cardinality()
322
+ 6
323
+ sage: len([x for x in A3 if x in S3])
324
+ 6
325
+ """
326
+ if not SetPartitionsAk_k.__contains__(self, x):
327
+ return False
328
+
329
+ if propagating_number(x) != self.k:
330
+ return False
331
+
332
+ return True
333
+
334
+ def cardinality(self):
335
+ """
336
+ Return k!.
337
+
338
+ TESTS::
339
+
340
+ sage: SetPartitionsSk(2).cardinality()
341
+ 2
342
+ sage: SetPartitionsSk(3).cardinality()
343
+ 6
344
+ sage: SetPartitionsSk(4).cardinality()
345
+ 24
346
+ sage: SetPartitionsSk(5).cardinality()
347
+ 120
348
+ """
349
+ return factorial(self.k)
350
+
351
+ def __iter__(self):
352
+ """
353
+ TESTS::
354
+
355
+ sage: SetPartitionsSk(3).list() #random
356
+ [{{2, -2}, {3, -3}, {1, -1}},
357
+ {{1, -1}, {2, -3}, {3, -2}},
358
+ {{2, -1}, {3, -3}, {1, -2}},
359
+ {{1, -2}, {2, -3}, {3, -1}},
360
+ {{1, -3}, {2, -1}, {3, -2}},
361
+ {{1, -3}, {2, -2}, {3, -1}}]
362
+ sage: ks = list(range(1, 6))
363
+ sage: sks = map(SetPartitionsSk, ks)
364
+ sage: all(sk.cardinality() == len(sk.list()) for sk in sks)
365
+ True
366
+ """
367
+ for p in Permutations(self.k):
368
+ res = [Set([i, -pi]) for i, pi in enumerate(p, start=1)]
369
+ yield self.element_class(self, res)
370
+
371
+
372
+ class SetPartitionsSkhalf_k(SetPartitionsAkhalf_k):
373
+ def __contains__(self, x):
374
+ """
375
+ TESTS::
376
+
377
+ sage: S2p5 = SetPartitionsSk(2.5)
378
+ sage: A3 = SetPartitionsAk(3)
379
+ sage: all(sp in S2p5 for sp in S2p5)
380
+ True
381
+ sage: len([x for x in A3 if x in S2p5])
382
+ 2
383
+ sage: S2p5.cardinality()
384
+ 2
385
+ """
386
+ if not SetPartitionsAkhalf_k.__contains__(self, x):
387
+ return False
388
+ if propagating_number(x) != self.k + 1:
389
+ return False
390
+ return True
391
+
392
+ def _repr_(self):
393
+ """
394
+ TESTS::
395
+
396
+ sage: SetPartitionsSk(2.5)
397
+ Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and propagating number 3
398
+ """
399
+ s = self.k + 1
400
+ return SetPartitionsAkhalf_k._repr_(self) + " and propagating number %s" % s
401
+
402
+ def cardinality(self):
403
+ """
404
+ TESTS::
405
+
406
+ sage: SetPartitionsSk(2.5).cardinality()
407
+ 2
408
+ sage: SetPartitionsSk(3.5).cardinality()
409
+ 6
410
+ sage: SetPartitionsSk(4.5).cardinality()
411
+ 24
412
+
413
+ ::
414
+
415
+ sage: ks = [2.5, 3.5, 4.5, 5.5]
416
+ sage: sks = [SetPartitionsSk(k) for k in ks]
417
+ sage: all(sk.cardinality() == len(sk.list()) for sk in sks)
418
+ True
419
+ """
420
+ return factorial(self.k)
421
+
422
+ def __iter__(self):
423
+ """
424
+ TESTS::
425
+
426
+ sage: SetPartitionsSk(3.5).list() #random indirect test
427
+ [{{2, -2}, {3, -3}, {1, -1}, {4, -4}},
428
+ {{2, -3}, {1, -1}, {4, -4}, {3, -2}},
429
+ {{2, -1}, {3, -3}, {1, -2}, {4, -4}},
430
+ {{2, -3}, {1, -2}, {4, -4}, {3, -1}},
431
+ {{1, -3}, {2, -1}, {4, -4}, {3, -2}},
432
+ {{1, -3}, {2, -2}, {4, -4}, {3, -1}}]
433
+ """
434
+ for p in Permutations(self.k):
435
+ res = [Set([i, -pi]) for i, pi in enumerate(p, start=1)]
436
+ res.append(Set([self.k + 1, -self.k - 1]))
437
+ yield self.element_class(self, res)
438
+
439
+
440
+ #######
441
+ # I_k #
442
+ #######
443
+
444
+ def SetPartitionsIk(k):
445
+ r"""
446
+ Return the combinatorial class of set partitions of type `I_k`.
447
+
448
+ These are set partitions with a propagating number of less than `k`.
449
+ Note that the identity set partition `\{\{1, -1\}, \ldots, \{k, -k\}\}`
450
+ is not in `I_k`.
451
+
452
+ EXAMPLES::
453
+
454
+ sage: I3 = SetPartitionsIk(3); I3
455
+ Set partitions of {1, ..., 3, -1, ..., -3} with propagating number < 3
456
+ sage: I3.cardinality()
457
+ 197
458
+
459
+ sage: I3.first() #random
460
+ {{1, 2, 3, -1, -3, -2}}
461
+ sage: I3.last() #random
462
+ {{-1}, {-2}, {3}, {1}, {-3}, {2}}
463
+ sage: I3.random_element() #random # needs sage.symbolic
464
+ {{-1}, {-3, -2}, {2, 3}, {1}}
465
+
466
+ sage: I2p5 = SetPartitionsIk(2.5); I2p5
467
+ Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and propagating number < 3
468
+ sage: I2p5.cardinality()
469
+ 50
470
+
471
+ sage: I2p5.first() #random
472
+ {{1, 2, 3, -1, -3, -2}}
473
+ sage: I2p5.last() #random
474
+ {{-1}, {-2}, {2}, {3, -3}, {1}}
475
+ sage: I2p5.random_element() #random # needs sage.symbolic
476
+ {{-1}, {-2}, {1, 3, -3}, {2}}
477
+ """
478
+ is_int, k = _int_or_half_int(k)
479
+ if not is_int:
480
+ return SetPartitionsIkhalf_k(k)
481
+ return SetPartitionsIk_k(k)
482
+
483
+
484
+ class SetPartitionsIk_k(SetPartitionsAk_k):
485
+ def _repr_(self):
486
+ """
487
+ TESTS::
488
+
489
+ sage: SetPartitionsIk(3)
490
+ Set partitions of {1, ..., 3, -1, ..., -3} with propagating number < 3
491
+ """
492
+ return SetPartitionsAk_k._repr_(self) + " with propagating number < %s" % self.k
493
+
494
+ def __contains__(self, x):
495
+ """
496
+ TESTS::
497
+
498
+ sage: I3 = SetPartitionsIk(3)
499
+ sage: A3 = SetPartitionsAk(3)
500
+ sage: all(sp in I3 for sp in I3)
501
+ True
502
+ sage: len([x for x in A3 if x in I3])
503
+ 197
504
+ sage: I3.cardinality()
505
+ 197
506
+ """
507
+ if not SetPartitionsAk_k.__contains__(self, x):
508
+ return False
509
+ if propagating_number(x) >= self.k:
510
+ return False
511
+ return True
512
+
513
+ def cardinality(self):
514
+ """
515
+ TESTS::
516
+
517
+ sage: SetPartitionsIk(2).cardinality()
518
+ 13
519
+ """
520
+ return len(self.list())
521
+
522
+ def __iter__(self):
523
+ """
524
+ TESTS::
525
+
526
+ sage: SetPartitionsIk(2).list() #random indirect test
527
+ [{{1, 2, -1, -2}},
528
+ {{2, -1, -2}, {1}},
529
+ {{2}, {1, -1, -2}},
530
+ {{-1}, {1, 2, -2}},
531
+ {{-2}, {1, 2, -1}},
532
+ {{1, 2}, {-1, -2}},
533
+ {{2}, {-1, -2}, {1}},
534
+ {{-1}, {2, -2}, {1}},
535
+ {{-2}, {2, -1}, {1}},
536
+ {{-1}, {2}, {1, -2}},
537
+ {{-2}, {2}, {1, -1}},
538
+ {{-1}, {-2}, {1, 2}},
539
+ {{-1}, {-2}, {2}, {1}}]
540
+ """
541
+ for sp in SetPartitionsAk_k.__iter__(self):
542
+ if propagating_number(sp) < self.k:
543
+ yield sp
544
+
545
+
546
+ class SetPartitionsIkhalf_k(SetPartitionsAkhalf_k):
547
+ def __contains__(self, x):
548
+ """
549
+ TESTS::
550
+
551
+ sage: I2p5 = SetPartitionsIk(2.5)
552
+ sage: A3 = SetPartitionsAk(3)
553
+ sage: all(sp in I2p5 for sp in I2p5)
554
+ True
555
+ sage: len([x for x in A3 if x in I2p5])
556
+ 50
557
+ sage: I2p5.cardinality()
558
+ 50
559
+ """
560
+ if not SetPartitionsAkhalf_k.__contains__(self, x):
561
+ return False
562
+ if propagating_number(x) >= self.k + 1:
563
+ return False
564
+ return True
565
+
566
+ def _repr_(self):
567
+ """
568
+ TESTS::
569
+
570
+ sage: SetPartitionsIk(2.5)
571
+ Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and propagating number < 3
572
+ """
573
+ return SetPartitionsAkhalf_k._repr_(self) + " and propagating number < %s" % (self.k + 1)
574
+
575
+ def cardinality(self):
576
+ """
577
+ TESTS::
578
+
579
+ sage: SetPartitionsIk(1.5).cardinality()
580
+ 4
581
+ sage: SetPartitionsIk(2.5).cardinality()
582
+ 50
583
+ sage: SetPartitionsIk(3.5).cardinality()
584
+ 871
585
+ """
586
+ return len(self.list())
587
+
588
+ def __iter__(self):
589
+ """
590
+ TESTS::
591
+
592
+ sage: SetPartitionsIk(1.5).list() #random
593
+ [{{1, 2, -2, -1}},
594
+ {{2, -2, -1}, {1}},
595
+ {{-1}, {1, 2, -2}},
596
+ {{-1}, {2, -2}, {1}}]
597
+ """
598
+
599
+ for sp in SetPartitionsAkhalf_k.__iter__(self):
600
+ if propagating_number(sp) < self.k + 1:
601
+ yield sp
602
+
603
+
604
+ #######
605
+ # B_k #
606
+ #######
607
+
608
+ def SetPartitionsBk(k):
609
+ r"""
610
+ Return the combinatorial class of set partitions of type `B_k`.
611
+
612
+ These are the set partitions where every block has size 2.
613
+
614
+ EXAMPLES::
615
+
616
+ sage: B3 = SetPartitionsBk(3); B3
617
+ Set partitions of {1, ..., 3, -1, ..., -3} with block size 2
618
+
619
+ sage: # needs sage.graphs
620
+ sage: B3.first() #random
621
+ {{2, -2}, {1, -3}, {3, -1}}
622
+ sage: B3.last() #random
623
+ {{1, 2}, {3, -2}, {-3, -1}}
624
+ sage: B3.random_element() #random # needs sage.symbolic
625
+ {{2, -1}, {1, -3}, {3, -2}}
626
+
627
+ sage: B3.cardinality()
628
+ 15
629
+
630
+ sage: B2p5 = SetPartitionsBk(2.5); B2p5
631
+ Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and with block size 2
632
+
633
+ sage: # needs sage.graphs
634
+ sage: B2p5.first() #random
635
+ {{2, -1}, {3, -3}, {1, -2}}
636
+ sage: B2p5.last() #random
637
+ {{1, 2}, {3, -3}, {-1, -2}}
638
+ sage: B2p5.random_element() #random # needs sage.symbolic
639
+ {{2, -2}, {3, -3}, {1, -1}}
640
+
641
+ sage: B2p5.cardinality()
642
+ 3
643
+ """
644
+ is_int, k = _int_or_half_int(k)
645
+ if not is_int:
646
+ return SetPartitionsBkhalf_k(k)
647
+ return SetPartitionsBk_k(k)
648
+
649
+
650
+ class SetPartitionsBk_k(SetPartitionsAk_k):
651
+ def _repr_(self):
652
+ """
653
+ TESTS::
654
+
655
+ sage: SetPartitionsBk(2.5)
656
+ Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and with block size 2
657
+ """
658
+ return SetPartitionsAk_k._repr_(self) + " with block size 2"
659
+
660
+ def __contains__(self, x):
661
+ """
662
+ TESTS::
663
+
664
+ sage: B3 = SetPartitionsBk(3)
665
+ sage: A3 = SetPartitionsAk(3)
666
+ sage: len([x for x in A3 if x in B3])
667
+ 15
668
+ sage: B3.cardinality()
669
+ 15
670
+ """
671
+ if not SetPartitionsAk_k.__contains__(self, x):
672
+ return False
673
+
674
+ for part in x:
675
+ if len(part) != 2:
676
+ return False
677
+
678
+ return True
679
+
680
+ def cardinality(self):
681
+ r"""
682
+ Return the number of set partitions in `B_k` where `k` is an integer.
683
+
684
+ This is given by (2k)!! = (2k-1)\*(2k-3)\*...\*5\*3\*1.
685
+
686
+ EXAMPLES::
687
+
688
+ sage: SetPartitionsBk(3).cardinality()
689
+ 15
690
+ sage: SetPartitionsBk(2).cardinality()
691
+ 3
692
+ sage: SetPartitionsBk(1).cardinality()
693
+ 1
694
+ sage: SetPartitionsBk(4).cardinality()
695
+ 105
696
+ sage: SetPartitionsBk(5).cardinality()
697
+ 945
698
+ """
699
+ c = 1
700
+ for i in range(1, 2 * self.k, 2):
701
+ c *= i
702
+ return c
703
+
704
+ def __iter__(self):
705
+ """
706
+ TESTS::
707
+
708
+ sage: SetPartitionsBk(1).list() # needs sage.graphs
709
+ [{{-1, 1}}]
710
+
711
+ ::
712
+
713
+ sage: SetPartitionsBk(2).list() #random # needs sage.graphs
714
+ [{{2, -1}, {1, -2}}, {{2, -2}, {1, -1}}, {{1, 2}, {-1, -2}}]
715
+ sage: SetPartitionsBk(3).list() #random # needs sage.graphs
716
+ [{{2, -2}, {1, -3}, {3, -1}},
717
+ {{2, -1}, {1, -3}, {3, -2}},
718
+ {{1, -3}, {2, 3}, {-1, -2}},
719
+ {{3, -1}, {1, -2}, {2, -3}},
720
+ {{3, -2}, {1, -1}, {2, -3}},
721
+ {{1, 3}, {2, -3}, {-1, -2}},
722
+ {{2, -1}, {3, -3}, {1, -2}},
723
+ {{2, -2}, {3, -3}, {1, -1}},
724
+ {{1, 2}, {3, -3}, {-1, -2}},
725
+ {{-3, -2}, {2, 3}, {1, -1}},
726
+ {{1, 3}, {-3, -2}, {2, -1}},
727
+ {{1, 2}, {3, -1}, {-3, -2}},
728
+ {{-3, -1}, {2, 3}, {1, -2}},
729
+ {{1, 3}, {-3, -1}, {2, -2}},
730
+ {{1, 2}, {3, -2}, {-3, -1}}]
731
+
732
+ Check to make sure that the number of elements generated is the
733
+ same as what is given by cardinality()
734
+
735
+ ::
736
+
737
+ sage: bks = [SetPartitionsBk(i) for i in range(1, 6)]
738
+ sage: all(bk.cardinality() == len(bk.list()) for bk in bks) # needs sage.graphs
739
+ True
740
+ """
741
+ for sp in SetPartitions(self._set, [2] * (len(self._set) // 2)):
742
+ yield self.element_class(self, sp)
743
+
744
+
745
+ class SetPartitionsBkhalf_k(SetPartitionsAkhalf_k):
746
+ def _repr_(self):
747
+ """
748
+ TESTS::
749
+
750
+ sage: SetPartitionsBk(2.5)
751
+ Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and with block size 2
752
+ """
753
+ return SetPartitionsAkhalf_k._repr_(self) + " and with block size 2"
754
+
755
+ def __contains__(self, x):
756
+ """
757
+ TESTS::
758
+
759
+ sage: A3 = SetPartitionsAk(3)
760
+ sage: B2p5 = SetPartitionsBk(2.5)
761
+ sage: all(sp in B2p5 for sp in B2p5)
762
+ True
763
+ sage: len([x for x in A3 if x in B2p5])
764
+ 3
765
+ sage: B2p5.cardinality()
766
+ 3
767
+ """
768
+ if not SetPartitionsAkhalf_k.__contains__(self, x):
769
+ return False
770
+ for part in x:
771
+ if len(part) != 2:
772
+ return False
773
+ return True
774
+
775
+ def cardinality(self):
776
+ """
777
+ TESTS::
778
+
779
+ sage: B3p5 = SetPartitionsBk(3.5)
780
+ sage: B3p5.cardinality()
781
+ 15
782
+ """
783
+ return len(self.list())
784
+
785
+ def __iter__(self):
786
+ """
787
+ TESTS::
788
+
789
+ sage: B3p5 = SetPartitionsBk(3.5)
790
+ sage: B3p5.cardinality()
791
+ 15
792
+
793
+ ::
794
+
795
+ sage: B3p5.list() #random
796
+ [{{2, -2}, {1, -3}, {4, -4}, {3, -1}},
797
+ {{2, -1}, {1, -3}, {4, -4}, {3, -2}},
798
+ {{1, -3}, {2, 3}, {4, -4}, {-1, -2}},
799
+ {{2, -3}, {1, -2}, {4, -4}, {3, -1}},
800
+ {{2, -3}, {1, -1}, {4, -4}, {3, -2}},
801
+ {{1, 3}, {4, -4}, {2, -3}, {-1, -2}},
802
+ {{2, -1}, {3, -3}, {1, -2}, {4, -4}},
803
+ {{2, -2}, {3, -3}, {1, -1}, {4, -4}},
804
+ {{1, 2}, {3, -3}, {4, -4}, {-1, -2}},
805
+ {{-3, -2}, {2, 3}, {1, -1}, {4, -4}},
806
+ {{1, 3}, {-3, -2}, {2, -1}, {4, -4}},
807
+ {{1, 2}, {-3, -2}, {4, -4}, {3, -1}},
808
+ {{-3, -1}, {2, 3}, {1, -2}, {4, -4}},
809
+ {{1, 3}, {-3, -1}, {2, -2}, {4, -4}},
810
+ {{1, 2}, {-3, -1}, {4, -4}, {3, -2}}]
811
+ """
812
+ set = list(range(1, self.k + 1)) + [-x for x in range(1, self.k + 1)]
813
+ for sp in SetPartitions(set, [2] * (len(set) // 2)):
814
+ yield self.element_class(self, Set(list(sp)) + Set([Set([self.k + 1, -self.k - 1])]))
815
+
816
+
817
+ #######
818
+ # P_k #
819
+ #######
820
+
821
+ def SetPartitionsPk(k):
822
+ r"""
823
+ Return the combinatorial class of set partitions of type `P_k`.
824
+
825
+ These are the planar set partitions.
826
+
827
+ EXAMPLES::
828
+
829
+ sage: P3 = SetPartitionsPk(3); P3
830
+ Set partitions of {1, ..., 3, -1, ..., -3} that are planar
831
+ sage: P3.cardinality()
832
+ 132
833
+
834
+ sage: P3.first() #random
835
+ {{1, 2, 3, -1, -3, -2}}
836
+ sage: P3.last() #random
837
+ {{-1}, {-2}, {3}, {1}, {-3}, {2}}
838
+ sage: P3.random_element() #random # needs sage.symbolic
839
+ {{1, 2, -1}, {-3}, {3, -2}}
840
+
841
+ sage: P2p5 = SetPartitionsPk(2.5); P2p5
842
+ Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and that are planar
843
+ sage: P2p5.cardinality()
844
+ 42
845
+
846
+ sage: P2p5.first() #random
847
+ {{1, 2, 3, -1, -3, -2}}
848
+ sage: P2p5.last() #random
849
+ {{-1}, {-2}, {2}, {3, -3}, {1}}
850
+ sage: P2p5.random_element() #random # needs sage.symbolic
851
+ {{1, 2, 3, -3}, {-1, -2}}
852
+ """
853
+ is_int, k = _int_or_half_int(k)
854
+ if not is_int:
855
+ return SetPartitionsPkhalf_k(k)
856
+ return SetPartitionsPk_k(k)
857
+
858
+
859
+ class SetPartitionsPk_k(SetPartitionsAk_k):
860
+ def _repr_(self):
861
+ """
862
+ TESTS::
863
+
864
+ sage: SetPartitionsPk(3)
865
+ Set partitions of {1, ..., 3, -1, ..., -3} that are planar
866
+ """
867
+ return SetPartitionsAk_k._repr_(self) + " that are planar"
868
+
869
+ def __contains__(self, x):
870
+ """
871
+ TESTS::
872
+
873
+ sage: P3 = SetPartitionsPk(3)
874
+ sage: A3 = SetPartitionsAk(3)
875
+ sage: len([x for x in A3 if x in P3])
876
+ 132
877
+ sage: P3.cardinality()
878
+ 132
879
+ sage: all(sp in P3 for sp in P3)
880
+ True
881
+ """
882
+ if not SetPartitionsAk_k.__contains__(self, x):
883
+ return False
884
+
885
+ if not is_planar(x):
886
+ return False
887
+
888
+ return True
889
+
890
+ def cardinality(self):
891
+ """
892
+ TESTS::
893
+
894
+ sage: SetPartitionsPk(2).cardinality()
895
+ 14
896
+ sage: SetPartitionsPk(3).cardinality()
897
+ 132
898
+ sage: SetPartitionsPk(4).cardinality()
899
+ 1430
900
+ """
901
+ return catalan_number(2 * self.k)
902
+
903
+ def __iter__(self):
904
+ """
905
+ TESTS::
906
+
907
+ sage: SetPartitionsPk(2).list() #random indirect test
908
+ [{{1, 2, -1, -2}},
909
+ {{2, -1, -2}, {1}},
910
+ {{2}, {1, -1, -2}},
911
+ {{-1}, {1, 2, -2}},
912
+ {{-2}, {1, 2, -1}},
913
+ {{2, -2}, {1, -1}},
914
+ {{1, 2}, {-1, -2}},
915
+ {{2}, {-1, -2}, {1}},
916
+ {{-1}, {2, -2}, {1}},
917
+ {{-2}, {2, -1}, {1}},
918
+ {{-1}, {2}, {1, -2}},
919
+ {{-2}, {2}, {1, -1}},
920
+ {{-1}, {-2}, {1, 2}},
921
+ {{-1}, {-2}, {2}, {1}}]
922
+ """
923
+ for sp in SetPartitionsAk_k.__iter__(self):
924
+ if is_planar(sp):
925
+ yield self.element_class(self, sp)
926
+
927
+
928
+ class SetPartitionsPkhalf_k(SetPartitionsAkhalf_k):
929
+ def __contains__(self, x):
930
+ """
931
+ TESTS::
932
+
933
+ sage: A3 = SetPartitionsAk(3)
934
+ sage: P2p5 = SetPartitionsPk(2.5)
935
+ sage: all(sp in P2p5 for sp in P2p5)
936
+ True
937
+ sage: len([x for x in A3 if x in P2p5])
938
+ 42
939
+ sage: P2p5.cardinality()
940
+ 42
941
+ """
942
+ if not SetPartitionsAkhalf_k.__contains__(self, x):
943
+ return False
944
+ if not is_planar(x):
945
+ return False
946
+
947
+ return True
948
+
949
+ def _repr_(self):
950
+ """
951
+ TESTS::
952
+
953
+ sage: repr( SetPartitionsPk(2.5) )
954
+ 'Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and that are planar'
955
+ """
956
+ return SetPartitionsAkhalf_k._repr_(self) + " and that are planar"
957
+
958
+ def cardinality(self):
959
+ """
960
+ TESTS::
961
+
962
+ sage: SetPartitionsPk(2.5).cardinality()
963
+ 42
964
+ sage: SetPartitionsPk(1.5).cardinality()
965
+ 5
966
+ """
967
+ return len(self.list())
968
+
969
+ def __iter__(self):
970
+ """
971
+ TESTS::
972
+
973
+ sage: SetPartitionsPk(1.5).list() #random
974
+ [{{1, 2, -2, -1}},
975
+ {{2, -2, -1}, {1}},
976
+ {{2, -2}, {1, -1}},
977
+ {{-1}, {1, 2, -2}},
978
+ {{-1}, {2, -2}, {1}}]
979
+ """
980
+ for sp in SetPartitionsAkhalf_k.__iter__(self):
981
+ if is_planar(sp):
982
+ yield self.element_class(self, sp)
983
+
984
+
985
+ #######
986
+ # T_k #
987
+ #######
988
+
989
+ def SetPartitionsTk(k):
990
+ r"""
991
+ Return the combinatorial class of set partitions of type `T_k`.
992
+
993
+ These are planar set partitions where every block is of size 2.
994
+
995
+ EXAMPLES::
996
+
997
+ sage: T3 = SetPartitionsTk(3); T3
998
+ Set partitions of {1, ..., 3, -1, ..., -3} with block size 2 and that are planar
999
+ sage: T3.cardinality()
1000
+ 5
1001
+
1002
+ sage: # needs sage.graphs
1003
+ sage: T3.first() # random
1004
+ {{1, -3}, {2, 3}, {-1, -2}}
1005
+ sage: T3.last() # random
1006
+ {{1, 2}, {3, -1}, {-3, -2}}
1007
+ sage: T3.random_element() # random # needs sage.symbolic
1008
+ {{1, -3}, {2, 3}, {-1, -2}}
1009
+
1010
+ sage: T2p5 = SetPartitionsTk(2.5); T2p5
1011
+ Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and with block size 2 and that are planar
1012
+ sage: T2p5.cardinality()
1013
+ 2
1014
+
1015
+ sage: # needs sage.graphs
1016
+ sage: T2p5.first() # random
1017
+ {{2, -2}, {3, -3}, {1, -1}}
1018
+ sage: T2p5.last() # random
1019
+ {{1, 2}, {3, -3}, {-1, -2}}
1020
+ """
1021
+ is_int, k = _int_or_half_int(k)
1022
+ if not is_int:
1023
+ return SetPartitionsTkhalf_k(k)
1024
+ return SetPartitionsTk_k(k)
1025
+
1026
+
1027
+ class SetPartitionsTk_k(SetPartitionsBk_k):
1028
+ def _repr_(self):
1029
+ """
1030
+ TESTS::
1031
+
1032
+ sage: SetPartitionsTk(3)
1033
+ Set partitions of {1, ..., 3, -1, ..., -3} with block size 2 and that are planar
1034
+ """
1035
+ return SetPartitionsBk_k._repr_(self) + " and that are planar"
1036
+
1037
+ def __contains__(self, x):
1038
+ """
1039
+ TESTS::
1040
+
1041
+ sage: # needs sage.graphs
1042
+ sage: T3 = SetPartitionsTk(3)
1043
+ sage: A3 = SetPartitionsAk(3)
1044
+ sage: all(sp in T3 for sp in T3)
1045
+ True
1046
+ sage: len([x for x in A3 if x in T3])
1047
+ 5
1048
+ sage: T3.cardinality()
1049
+ 5
1050
+ """
1051
+ if not SetPartitionsBk_k.__contains__(self, x):
1052
+ return False
1053
+
1054
+ if not is_planar(x):
1055
+ return False
1056
+
1057
+ return True
1058
+
1059
+ def cardinality(self):
1060
+ """
1061
+ TESTS::
1062
+
1063
+ sage: SetPartitionsTk(2).cardinality()
1064
+ 2
1065
+ sage: SetPartitionsTk(3).cardinality()
1066
+ 5
1067
+ sage: SetPartitionsTk(4).cardinality()
1068
+ 14
1069
+ sage: SetPartitionsTk(5).cardinality()
1070
+ 42
1071
+ """
1072
+ return catalan_number(self.k)
1073
+
1074
+ def __iter__(self):
1075
+ """
1076
+ TESTS::
1077
+
1078
+ sage: # needs sage.graphs
1079
+ sage: SetPartitionsTk(3).list() # random
1080
+ [{{1, -3}, {2, 3}, {-1, -2}},
1081
+ {{2, -2}, {3, -3}, {1, -1}},
1082
+ {{1, 2}, {3, -3}, {-1, -2}},
1083
+ {{-3, -2}, {2, 3}, {1, -1}},
1084
+ {{1, 2}, {3, -1}, {-3, -2}}]
1085
+ """
1086
+ for sp in SetPartitionsBk_k.__iter__(self):
1087
+ if is_planar(sp):
1088
+ yield self.element_class(self, sp)
1089
+
1090
+
1091
+ class SetPartitionsTkhalf_k(SetPartitionsBkhalf_k):
1092
+ def __contains__(self, x):
1093
+ """
1094
+ TESTS::
1095
+
1096
+ sage: A3 = SetPartitionsAk(3)
1097
+ sage: T2p5 = SetPartitionsTk(2.5)
1098
+ sage: all(sp in T2p5 for sp in T2p5)
1099
+ True
1100
+ sage: len([x for x in A3 if x in T2p5])
1101
+ 2
1102
+ sage: T2p5.cardinality()
1103
+ 2
1104
+ """
1105
+ if not SetPartitionsBkhalf_k.__contains__(self, x):
1106
+ return False
1107
+ if not is_planar(x):
1108
+ return False
1109
+
1110
+ return True
1111
+
1112
+ def _repr_(self):
1113
+ """
1114
+ TESTS::
1115
+
1116
+ sage: SetPartitionsTk(2.5)
1117
+ Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and with block size 2 and that are planar
1118
+ """
1119
+ return SetPartitionsBkhalf_k._repr_(self) + " and that are planar"
1120
+
1121
+ def cardinality(self):
1122
+ """
1123
+ TESTS::
1124
+
1125
+ sage: SetPartitionsTk(2.5).cardinality()
1126
+ 2
1127
+ sage: SetPartitionsTk(3.5).cardinality()
1128
+ 5
1129
+ sage: SetPartitionsTk(4.5).cardinality()
1130
+ 14
1131
+ """
1132
+ return catalan_number(self.k)
1133
+
1134
+ def __iter__(self):
1135
+ """
1136
+ TESTS::
1137
+
1138
+ sage: SetPartitionsTk(3.5).list() #random
1139
+ [{{1, -3}, {2, 3}, {4, -4}, {-1, -2}},
1140
+ {{2, -2}, {3, -3}, {1, -1}, {4, -4}},
1141
+ {{1, 2}, {3, -3}, {4, -4}, {-1, -2}},
1142
+ {{-3, -2}, {2, 3}, {1, -1}, {4, -4}},
1143
+ {{1, 2}, {-3, -2}, {4, -4}, {3, -1}}]
1144
+ """
1145
+ for sp in SetPartitionsBkhalf_k.__iter__(self):
1146
+ if is_planar(sp):
1147
+ yield self.element_class(self, sp)
1148
+
1149
+
1150
+ def SetPartitionsRk(k):
1151
+ r"""
1152
+ Return the combinatorial class of set partitions of type `R_k`.
1153
+
1154
+ EXAMPLES::
1155
+
1156
+ sage: SetPartitionsRk(3)
1157
+ Set partitions of {1, ..., 3, -1, ..., -3} with at most 1 positive
1158
+ and negative entry in each block
1159
+ """
1160
+ is_int, k = _int_or_half_int(k)
1161
+ if not is_int:
1162
+ return SetPartitionsRkhalf_k(k)
1163
+ return SetPartitionsRk_k(k)
1164
+
1165
+
1166
+ class SetPartitionsRk_k(SetPartitionsAk_k):
1167
+ def __init__(self, k):
1168
+ """
1169
+ TESTS::
1170
+
1171
+ sage: R3 = SetPartitionsRk(3); R3
1172
+ Set partitions of {1, ..., 3, -1, ..., -3} with at most 1 positive and negative entry in each block
1173
+ sage: R3 == loads(dumps(R3))
1174
+ True
1175
+ """
1176
+ self.k = k
1177
+ SetPartitionsAk_k.__init__(self, k)
1178
+
1179
+ def _repr_(self):
1180
+ """
1181
+ TESTS::
1182
+
1183
+ sage: SetPartitionsRk(3)
1184
+ Set partitions of {1, ..., 3, -1, ..., -3} with at most 1 positive and negative entry in each block
1185
+ """
1186
+ return SetPartitionsAk_k._repr_(self) + " with at most 1 positive and negative entry in each block"
1187
+
1188
+ def __contains__(self, x):
1189
+ """
1190
+ TESTS::
1191
+
1192
+ sage: R3 = SetPartitionsRk(3)
1193
+ sage: A3 = SetPartitionsAk(3)
1194
+ sage: all(sp in R3 for sp in R3)
1195
+ True
1196
+ sage: len([x for x in A3 if x in R3])
1197
+ 34
1198
+ sage: R3.cardinality()
1199
+ 34
1200
+ """
1201
+ if not SetPartitionsAk_k.__contains__(self, x):
1202
+ return False
1203
+
1204
+ for block in x:
1205
+ if len(block) > 2:
1206
+ return False
1207
+
1208
+ negatives = 0
1209
+ positives = 0
1210
+ for i in block:
1211
+ if i < 0:
1212
+ negatives += 1
1213
+ else:
1214
+ positives += 1
1215
+
1216
+ if negatives > 1 or positives > 1:
1217
+ return False
1218
+
1219
+ return True
1220
+
1221
+ def cardinality(self):
1222
+ """
1223
+ TESTS::
1224
+
1225
+ sage: SetPartitionsRk(2).cardinality()
1226
+ 7
1227
+ sage: SetPartitionsRk(3).cardinality()
1228
+ 34
1229
+ sage: SetPartitionsRk(4).cardinality()
1230
+ 209
1231
+ sage: SetPartitionsRk(5).cardinality()
1232
+ 1546
1233
+ """
1234
+ return sum(binomial(self.k, l)**2 * factorial(l)
1235
+ for l in range(self.k + 1))
1236
+
1237
+ def __iter__(self):
1238
+ """
1239
+ TESTS::
1240
+
1241
+ sage: len(SetPartitionsRk(3).list() ) == SetPartitionsRk(3).cardinality()
1242
+ True
1243
+ """
1244
+ # The number of blocks with at most two things
1245
+ positives = Set(range(1, self.k + 1))
1246
+ negatives = Set(-i for i in positives)
1247
+
1248
+ yield self.element_class(self, to_set_partition([], self.k))
1249
+ for n in range(1, self.k + 1):
1250
+ for top in Subsets(positives, n):
1251
+ t = list(top)
1252
+ for bottom in Subsets(negatives, n):
1253
+ b = list(bottom)
1254
+ for permutation in Permutations(n):
1255
+ l = [[t[i], b[permutation[i] - 1]] for i in range(n)]
1256
+ yield self.element_class(self, to_set_partition(l, k=self.k))
1257
+
1258
+
1259
+ class SetPartitionsRkhalf_k(SetPartitionsAkhalf_k):
1260
+ def __contains__(self, x):
1261
+ """
1262
+ TESTS::
1263
+
1264
+ sage: A3 = SetPartitionsAk(3)
1265
+ sage: R2p5 = SetPartitionsRk(2.5)
1266
+ sage: all(sp in R2p5 for sp in R2p5)
1267
+ True
1268
+ sage: len([x for x in A3 if x in R2p5])
1269
+ 7
1270
+ sage: R2p5.cardinality()
1271
+ 7
1272
+ """
1273
+ if not SetPartitionsAkhalf_k.__contains__(self, x):
1274
+ return False
1275
+
1276
+ for block in x:
1277
+ if len(block) > 2:
1278
+ return False
1279
+
1280
+ negatives = 0
1281
+ positives = 0
1282
+ for i in block:
1283
+ if i < 0:
1284
+ negatives += 1
1285
+ else:
1286
+ positives += 1
1287
+
1288
+ if negatives > 1 or positives > 1:
1289
+ return False
1290
+
1291
+ return True
1292
+
1293
+ def _repr_(self):
1294
+ """
1295
+ TESTS::
1296
+
1297
+ sage: SetPartitionsRk(2.5)
1298
+ Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and with at most 1 positive and negative entry in each block
1299
+ """
1300
+ return SetPartitionsAkhalf_k._repr_(self) + " and with at most 1 positive and negative entry in each block"
1301
+
1302
+ def cardinality(self):
1303
+ """
1304
+ TESTS::
1305
+
1306
+ sage: SetPartitionsRk(2.5).cardinality()
1307
+ 7
1308
+ sage: SetPartitionsRk(3.5).cardinality()
1309
+ 34
1310
+ sage: SetPartitionsRk(4.5).cardinality()
1311
+ 209
1312
+ """
1313
+ return sum(binomial(self.k, l)**2 * factorial(l)
1314
+ for l in range(self.k + 1))
1315
+
1316
+ def __iter__(self):
1317
+ """
1318
+ TESTS::
1319
+
1320
+ sage: R2p5 = SetPartitionsRk(2.5)
1321
+ sage: L = list(R2p5); L #random due to sets
1322
+ [{{-2}, {-1}, {3, -3}, {2}, {1}},
1323
+ {{-2}, {3, -3}, {2}, {1, -1}},
1324
+ {{-1}, {3, -3}, {2}, {1, -2}},
1325
+ {{-2}, {2, -1}, {3, -3}, {1}},
1326
+ {{-1}, {2, -2}, {3, -3}, {1}},
1327
+ {{2, -2}, {3, -3}, {1, -1}},
1328
+ {{2, -1}, {3, -3}, {1, -2}}]
1329
+ sage: len(L)
1330
+ 7
1331
+ """
1332
+ positives = Set(range(1, self.k + 1))
1333
+ negatives = Set(-i for i in positives)
1334
+
1335
+ yield self.element_class(self, to_set_partition([[self.k + 1, -self.k - 1]], self.k + 1))
1336
+ for n in range(1, self.k + 1):
1337
+ for top in Subsets(positives, n):
1338
+ t = list(top)
1339
+ for bottom in Subsets(negatives, n):
1340
+ b = list(bottom)
1341
+ for permutation in Permutations(n):
1342
+ l = [[t[i], b[permutation[i] - 1]] for i in range(n)] + [[self.k + 1, -self.k - 1]]
1343
+ yield self.element_class(self, to_set_partition(l, k=self.k + 1))
1344
+
1345
+
1346
+ def SetPartitionsPRk(k):
1347
+ r"""
1348
+ Return the combinatorial class of set partitions of type `PR_k`.
1349
+
1350
+ EXAMPLES::
1351
+
1352
+ sage: SetPartitionsPRk(3)
1353
+ Set partitions of {1, ..., 3, -1, ..., -3} with at most 1 positive
1354
+ and negative entry in each block and that are planar
1355
+ """
1356
+ is_int, k = _int_or_half_int(k)
1357
+ if not is_int:
1358
+ return SetPartitionsPRkhalf_k(k)
1359
+ return SetPartitionsPRk_k(k)
1360
+
1361
+
1362
+ class SetPartitionsPRk_k(SetPartitionsRk_k):
1363
+ def __init__(self, k):
1364
+ """
1365
+ TESTS::
1366
+
1367
+ sage: PR3 = SetPartitionsPRk(3); PR3
1368
+ Set partitions of {1, ..., 3, -1, ..., -3} with at most 1 positive and negative entry in each block and that are planar
1369
+ sage: PR3 == loads(dumps(PR3))
1370
+ True
1371
+ """
1372
+ self.k = k
1373
+ SetPartitionsRk_k.__init__(self, k)
1374
+
1375
+ def _repr_(self):
1376
+ """
1377
+ TESTS::
1378
+
1379
+ sage: SetPartitionsPRk(3)
1380
+ Set partitions of {1, ..., 3, -1, ..., -3} with at most 1 positive and negative entry in each block and that are planar
1381
+ """
1382
+ return SetPartitionsRk_k._repr_(self) + " and that are planar"
1383
+
1384
+ def __contains__(self, x):
1385
+ """
1386
+ TESTS::
1387
+
1388
+ sage: PR3 = SetPartitionsPRk(3)
1389
+ sage: A3 = SetPartitionsAk(3)
1390
+ sage: all(sp in PR3 for sp in PR3)
1391
+ True
1392
+ sage: len([x for x in A3 if x in PR3])
1393
+ 20
1394
+ sage: PR3.cardinality()
1395
+ 20
1396
+ """
1397
+ if not SetPartitionsRk_k.__contains__(self, x):
1398
+ return False
1399
+
1400
+ if not is_planar(x):
1401
+ return False
1402
+
1403
+ return True
1404
+
1405
+ def cardinality(self):
1406
+ """
1407
+ TESTS::
1408
+
1409
+ sage: SetPartitionsPRk(2).cardinality()
1410
+ 6
1411
+ sage: SetPartitionsPRk(3).cardinality()
1412
+ 20
1413
+ sage: SetPartitionsPRk(4).cardinality()
1414
+ 70
1415
+ sage: SetPartitionsPRk(5).cardinality()
1416
+ 252
1417
+ """
1418
+ return binomial(2 * self.k, self.k)
1419
+
1420
+ def __iter__(self):
1421
+ """
1422
+ TESTS::
1423
+
1424
+ sage: len(SetPartitionsPRk(3).list() ) == SetPartitionsPRk(3).cardinality()
1425
+ True
1426
+ """
1427
+ # The number of blocks with at most two things
1428
+ positives = Set(range(1, self.k + 1))
1429
+ negatives = Set(-i for i in positives)
1430
+
1431
+ yield self.element_class(self, to_set_partition([], self.k))
1432
+ for n in range(1, self.k + 1):
1433
+ for top in Subsets(positives, n):
1434
+ t = sorted(top)
1435
+ for bottom in Subsets(negatives, n):
1436
+ b = list(bottom)
1437
+ b.sort(reverse=True)
1438
+ l = [[t[i], b[i]] for i in range(n)]
1439
+ yield self.element_class(self, to_set_partition(l, k=self.k))
1440
+
1441
+
1442
+ class SetPartitionsPRkhalf_k(SetPartitionsRkhalf_k):
1443
+ def __contains__(self, x):
1444
+ """
1445
+ TESTS::
1446
+
1447
+ sage: A3 = SetPartitionsAk(3)
1448
+ sage: PR2p5 = SetPartitionsPRk(2.5)
1449
+ sage: all(sp in PR2p5 for sp in PR2p5)
1450
+ True
1451
+ sage: len([x for x in A3 if x in PR2p5])
1452
+ 6
1453
+ sage: PR2p5.cardinality()
1454
+ 6
1455
+ """
1456
+ if not SetPartitionsRkhalf_k.__contains__(self, x):
1457
+ return False
1458
+
1459
+ if not is_planar(x):
1460
+ return False
1461
+
1462
+ return True
1463
+
1464
+ def _repr_(self):
1465
+ """
1466
+ TESTS::
1467
+
1468
+ sage: SetPartitionsPRk(2.5)
1469
+ Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and with at most 1 positive and negative entry in each block and that are planar
1470
+ """
1471
+ return SetPartitionsRkhalf_k._repr_(self) + " and that are planar"
1472
+
1473
+ def cardinality(self):
1474
+ """
1475
+ TESTS::
1476
+
1477
+ sage: SetPartitionsPRk(2.5).cardinality()
1478
+ 6
1479
+ sage: SetPartitionsPRk(3.5).cardinality()
1480
+ 20
1481
+ sage: SetPartitionsPRk(4.5).cardinality()
1482
+ 70
1483
+ """
1484
+ return binomial(2 * self.k, self.k)
1485
+
1486
+ def __iter__(self):
1487
+ """
1488
+ TESTS::
1489
+
1490
+ sage: next(iter(SetPartitionsPRk(2.5)))
1491
+ {{-3, 3}, {-2}, {-1}, {1}, {2}}
1492
+ sage: len(list(SetPartitionsPRk(2.5)))
1493
+ 6
1494
+ """
1495
+ positives = Set(range(1, self.k + 1))
1496
+ negatives = Set(-i for i in positives)
1497
+
1498
+ yield self.element_class(self,
1499
+ to_set_partition([[self.k + 1, -self.k - 1]],
1500
+ k=self.k + 1))
1501
+ for n in range(1, self.k + 1):
1502
+ for top in Subsets(positives, n):
1503
+ t = sorted(top)
1504
+ for bottom in Subsets(negatives, n):
1505
+ b = list(bottom)
1506
+ b.sort(reverse=True)
1507
+ l = [[t[i], b[i]] for i in range(n)] + [[self.k + 1, -self.k - 1]]
1508
+ yield self.element_class(self,
1509
+ to_set_partition(l, k=self.k + 1))
1510
+
1511
+
1512
+ #########################################################
1513
+ # Algebras
1514
+
1515
+ class PartitionAlgebra_generic(CombinatorialFreeModule):
1516
+ def __init__(self, R, cclass, n, k, name=None, prefix=None):
1517
+ """
1518
+ EXAMPLES::
1519
+
1520
+ sage: from sage.combinat.partition_algebra import *
1521
+ sage: s = PartitionAlgebra_sk(QQ, 3, 1)
1522
+ sage: TestSuite(s).run() # needs sage.graphs
1523
+ sage: s == loads(dumps(s))
1524
+ True
1525
+ """
1526
+ self.k = k
1527
+ self.n = n
1528
+ self._indices = cclass
1529
+ self._name = "Generic partition algebra with k = %s and n = %s and basis %s" % (self.k, self.n, cclass) if name is None else name
1530
+ self._prefix = "" if prefix is None else prefix
1531
+ CombinatorialFreeModule.__init__(self, R, cclass, category=AlgebrasWithBasis(R))
1532
+
1533
+ def one_basis(self):
1534
+ """
1535
+ Return the basis index for the unit of the algebra.
1536
+
1537
+ EXAMPLES::
1538
+
1539
+ sage: from sage.combinat.partition_algebra import *
1540
+ sage: s = PartitionAlgebra_sk(ZZ, 3, 1)
1541
+ sage: len(s.one().support()) # indirect doctest
1542
+ 1
1543
+ """
1544
+ return self.basis().keys()(identity(ceil(self.k)))
1545
+
1546
+ def product_on_basis(self, left, right):
1547
+ """
1548
+ EXAMPLES::
1549
+
1550
+ sage: from sage.combinat.partition_algebra import *
1551
+ sage: s = PartitionAlgebra_sk(QQ, 3, 1)
1552
+ sage: t12 = s(Set([Set([1,-2]),Set([2,-1]),Set([3,-3])]))
1553
+ sage: t12^2 == s(1) # indirect doctest # needs sage.graphs
1554
+ True
1555
+ """
1556
+ sp, l = set_partition_composition(left, right)
1557
+ sp = self.basis().keys()(sp)
1558
+ return self.term(sp, self.n**l)
1559
+
1560
+
1561
+ class PartitionAlgebraElement_generic(CombinatorialFreeModule.Element):
1562
+ pass
1563
+
1564
+
1565
+ class PartitionAlgebraElement_ak(PartitionAlgebraElement_generic):
1566
+ pass
1567
+
1568
+
1569
+ class PartitionAlgebra_ak(PartitionAlgebra_generic):
1570
+ def __init__(self, R, k, n, name=None):
1571
+ """
1572
+ EXAMPLES::
1573
+
1574
+ sage: from sage.combinat.partition_algebra import *
1575
+ sage: p = PartitionAlgebra_ak(QQ, 3, 1)
1576
+ sage: p == loads(dumps(p))
1577
+ True
1578
+ """
1579
+ if name is None:
1580
+ name = "Partition algebra A_%s(%s)" % (k, n)
1581
+ cclass = SetPartitionsAk(k)
1582
+ self._element_class = PartitionAlgebraElement_ak
1583
+ PartitionAlgebra_generic.__init__(self, R, cclass, n, k, name=name, prefix='A')
1584
+
1585
+
1586
+ class PartitionAlgebraElement_bk(PartitionAlgebraElement_generic):
1587
+ pass
1588
+
1589
+
1590
+ class PartitionAlgebra_bk(PartitionAlgebra_generic):
1591
+ def __init__(self, R, k, n, name=None):
1592
+ """
1593
+ EXAMPLES::
1594
+
1595
+ sage: from sage.combinat.partition_algebra import *
1596
+ sage: p = PartitionAlgebra_bk(QQ, 3, 1)
1597
+ sage: p == loads(dumps(p))
1598
+ True
1599
+ """
1600
+ if name is None:
1601
+ name = "Partition algebra B_%s(%s)" % (k, n)
1602
+ cclass = SetPartitionsBk(k)
1603
+ self._element_class = PartitionAlgebraElement_bk
1604
+ PartitionAlgebra_generic.__init__(self, R, cclass, n, k, name=name, prefix='B')
1605
+
1606
+
1607
+ class PartitionAlgebraElement_sk(PartitionAlgebraElement_generic):
1608
+ pass
1609
+
1610
+
1611
+ class PartitionAlgebra_sk(PartitionAlgebra_generic):
1612
+ def __init__(self, R, k, n, name=None):
1613
+ """
1614
+ EXAMPLES::
1615
+
1616
+ sage: from sage.combinat.partition_algebra import *
1617
+ sage: p = PartitionAlgebra_sk(QQ, 3, 1)
1618
+ sage: p == loads(dumps(p))
1619
+ True
1620
+ """
1621
+ if name is None:
1622
+ name = "Partition algebra S_%s(%s)" % (k, n)
1623
+ cclass = SetPartitionsSk(k)
1624
+ self._element_class = PartitionAlgebraElement_sk
1625
+ PartitionAlgebra_generic.__init__(self, R, cclass, n, k, name=name, prefix='S')
1626
+
1627
+
1628
+ class PartitionAlgebraElement_pk(PartitionAlgebraElement_generic):
1629
+ pass
1630
+
1631
+
1632
+ class PartitionAlgebra_pk(PartitionAlgebra_generic):
1633
+ def __init__(self, R, k, n, name=None):
1634
+ """
1635
+ EXAMPLES::
1636
+
1637
+ sage: from sage.combinat.partition_algebra import *
1638
+ sage: p = PartitionAlgebra_pk(QQ, 3, 1)
1639
+ sage: p == loads(dumps(p))
1640
+ True
1641
+ """
1642
+ if name is None:
1643
+ name = "Partition algebra P_%s(%s)" % (k, n)
1644
+ cclass = SetPartitionsPk(k)
1645
+ self._element_class = PartitionAlgebraElement_pk
1646
+ PartitionAlgebra_generic.__init__(self, R, cclass, n, k, name=name, prefix='P')
1647
+
1648
+
1649
+ class PartitionAlgebraElement_tk(PartitionAlgebraElement_generic):
1650
+ pass
1651
+
1652
+
1653
+ class PartitionAlgebra_tk(PartitionAlgebra_generic):
1654
+ def __init__(self, R, k, n, name=None):
1655
+ """
1656
+ EXAMPLES::
1657
+
1658
+ sage: from sage.combinat.partition_algebra import *
1659
+ sage: p = PartitionAlgebra_tk(QQ, 3, 1)
1660
+ sage: p == loads(dumps(p))
1661
+ True
1662
+ """
1663
+ if name is None:
1664
+ name = "Partition algebra T_%s(%s)" % (k, n)
1665
+ cclass = SetPartitionsTk(k)
1666
+ self._element_class = PartitionAlgebraElement_tk
1667
+ PartitionAlgebra_generic.__init__(self, R, cclass, n, k, name=name, prefix='T')
1668
+
1669
+
1670
+ class PartitionAlgebraElement_rk(PartitionAlgebraElement_generic):
1671
+ pass
1672
+
1673
+
1674
+ class PartitionAlgebra_rk(PartitionAlgebra_generic):
1675
+ def __init__(self, R, k, n, name=None):
1676
+ """
1677
+ EXAMPLES::
1678
+
1679
+ sage: from sage.combinat.partition_algebra import *
1680
+ sage: p = PartitionAlgebra_rk(QQ, 3, 1)
1681
+ sage: p == loads(dumps(p))
1682
+ True
1683
+ """
1684
+ if name is None:
1685
+ name = "Partition algebra R_%s(%s)" % (k, n)
1686
+ cclass = SetPartitionsRk(k)
1687
+ self._element_class = PartitionAlgebraElement_rk
1688
+ PartitionAlgebra_generic.__init__(self, R, cclass, n, k, name=name, prefix='R')
1689
+
1690
+
1691
+ class PartitionAlgebraElement_prk(PartitionAlgebraElement_generic):
1692
+ pass
1693
+
1694
+
1695
+ class PartitionAlgebra_prk(PartitionAlgebra_generic):
1696
+ def __init__(self, R, k, n, name=None):
1697
+ """
1698
+ EXAMPLES::
1699
+
1700
+ sage: from sage.combinat.partition_algebra import *
1701
+ sage: p = PartitionAlgebra_prk(QQ, 3, 1)
1702
+ sage: p == loads(dumps(p))
1703
+ True
1704
+ """
1705
+ if name is None:
1706
+ name = "Partition algebra PR_%s(%s)" % (k, n)
1707
+ cclass = SetPartitionsPRk(k)
1708
+ self._element_class = PartitionAlgebraElement_prk
1709
+ PartitionAlgebra_generic.__init__(self, R, cclass, n, k, name=name, prefix='PR')
1710
+
1711
+
1712
+ ##########################################################
1713
+
1714
+ def is_planar(sp):
1715
+ """
1716
+ Return ``True`` if the diagram corresponding to the set partition is
1717
+ planar; otherwise, it returns ``False``.
1718
+
1719
+ EXAMPLES::
1720
+
1721
+ sage: import sage.combinat.partition_algebra as pa
1722
+ sage: pa.is_planar( pa.to_set_partition([[1,-2],[2,-1]]))
1723
+ False
1724
+ sage: pa.is_planar( pa.to_set_partition([[1,-1],[2,-2]]))
1725
+ True
1726
+ """
1727
+ # Singletons don't affect planarity
1728
+ to_consider = [x for x in map(list, sp) if len(x) > 1]
1729
+ n = len(to_consider)
1730
+
1731
+ for i in range(n):
1732
+ # Get the positive and negative entries of this
1733
+ # part
1734
+ ap = [x for x in to_consider[i] if x > 0]
1735
+ an = [-x for x in to_consider[i] if x < 0]
1736
+
1737
+ # Check if a includes numbers in both the top and bottom rows
1738
+ if ap and an:
1739
+ for j in range(n):
1740
+ if i == j:
1741
+ continue
1742
+ # Get the positive and negative entries of this part
1743
+ bp = [x for x in to_consider[j] if x > 0]
1744
+ bn = [-x for x in to_consider[j] if x < 0]
1745
+
1746
+ # Skip the ones that don't involve numbers in both
1747
+ # the bottom and top rows
1748
+ if not bn or not bp:
1749
+ continue
1750
+
1751
+ # Make sure that if min(bp) > max(ap)
1752
+ # then min(bn) > max(an)
1753
+ if max(bp) > max(ap):
1754
+ if min(bn) < min(an):
1755
+ return False
1756
+
1757
+ # Go through the bottom and top rows
1758
+ for row in [ap, an]:
1759
+ if len(row) > 1:
1760
+ row.sort()
1761
+ for s in range(len(row) - 1):
1762
+ if row[s] + 1 == row[s + 1]:
1763
+ # No gap, continue on
1764
+ continue
1765
+ else:
1766
+ rng = list(range(row[s] + 1, row[s + 1]))
1767
+
1768
+ # Go through and make sure any parts that
1769
+ # contain numbers in this range are completely
1770
+ # contained in this range
1771
+ for j in range(n):
1772
+ if i == j:
1773
+ continue
1774
+
1775
+ # Make sure we make the numbers negative again
1776
+ # if we are in the bottom row
1777
+ if row is ap:
1778
+ sr = Set(rng)
1779
+ else:
1780
+ sr = Set(-x for x in rng)
1781
+
1782
+ sj = Set(to_consider[j])
1783
+ intersection = sr.intersection(sj)
1784
+ if intersection:
1785
+ if sj != intersection:
1786
+ return False
1787
+
1788
+ return True
1789
+
1790
+
1791
+ def to_graph(sp):
1792
+ """
1793
+ Return a graph representing the set partition ``sp``.
1794
+
1795
+ EXAMPLES::
1796
+
1797
+ sage: # needs sage.graphs
1798
+ sage: import sage.combinat.partition_algebra as pa
1799
+ sage: g = pa.to_graph(pa.to_set_partition([[1,-2], [2,-1]])); g
1800
+ Graph on 4 vertices
1801
+ sage: g.vertices(sort=False) # random
1802
+ [1, 2, -2, -1]
1803
+ sage: g.edges(sort=False) # random
1804
+ [(1, -2, None), (2, -1, None)]
1805
+ """
1806
+ g = Graph()
1807
+ for part in sp:
1808
+ part_list = list(part)
1809
+ if part_list:
1810
+ g.add_vertex(part_list[0])
1811
+ for i in range(1, len(part_list)):
1812
+ g.add_vertex(part_list[i])
1813
+ g.add_edge(part_list[i - 1], part_list[i])
1814
+ return g
1815
+
1816
+
1817
+ def pair_to_graph(sp1, sp2):
1818
+ """
1819
+ Return a graph consisting of the disjoint union of the graphs of set
1820
+ partitions ``sp1`` and ``sp2`` along with edges joining the bottom
1821
+ row (negative numbers) of ``sp1`` to the top row (positive numbers)
1822
+ of ``sp2``.
1823
+
1824
+ The vertices of the graph ``sp1`` appear in the result as pairs
1825
+ ``(k, 1)``, whereas the vertices of the graph ``sp2`` appear as
1826
+ pairs ``(k, 2)``.
1827
+
1828
+ EXAMPLES::
1829
+
1830
+ sage: # needs sage.graphs
1831
+ sage: import sage.combinat.partition_algebra as pa
1832
+ sage: sp1 = pa.to_set_partition([[1,-2],[2,-1]])
1833
+ sage: sp2 = pa.to_set_partition([[1,-2],[2,-1]])
1834
+ sage: g = pa.pair_to_graph( sp1, sp2 ); g
1835
+ Graph on 8 vertices
1836
+
1837
+ ::
1838
+
1839
+ sage: # needs sage.graphs
1840
+ sage: g.vertices(sort=False) #random
1841
+ [(1, 2), (-1, 1), (-2, 2), (-1, 2), (-2, 1), (2, 1), (2, 2), (1, 1)]
1842
+ sage: g.edges(sort=False) #random
1843
+ [((1, 2), (-1, 1), None),
1844
+ ((1, 2), (-2, 2), None),
1845
+ ((-1, 1), (2, 1), None),
1846
+ ((-1, 2), (2, 2), None),
1847
+ ((-2, 1), (1, 1), None),
1848
+ ((-2, 1), (2, 2), None)]
1849
+
1850
+ Another example which used to be wrong until :issue:`15958`::
1851
+
1852
+ sage: # needs sage.graphs
1853
+ sage: sp3 = pa.to_set_partition([[1, -1], [2], [-2]])
1854
+ sage: sp4 = pa.to_set_partition([[1], [-1], [2], [-2]])
1855
+ sage: g = pa.pair_to_graph( sp3, sp4 ); g
1856
+ Graph on 8 vertices
1857
+ sage: g.vertices(sort=True)
1858
+ [(-2, 1), (-2, 2), (-1, 1), (-1, 2), (1, 1), (1, 2), (2, 1), (2, 2)]
1859
+ sage: g.edges(sort=True)
1860
+ [((-2, 1), (2, 2), None), ((-1, 1), (1, 1), None),
1861
+ ((-1, 1), (1, 2), None)]
1862
+ """
1863
+ g = Graph()
1864
+
1865
+ # Add the first set partition to the graph
1866
+ for part in sp1:
1867
+ part_list = list(part)
1868
+ if part_list:
1869
+ g.add_vertex((part_list[0], 1))
1870
+
1871
+ # Add the edge to the second part of the graph
1872
+ if part_list[0] < 0:
1873
+ g.add_edge((part_list[0], 1), (-part_list[0], 2))
1874
+
1875
+ for i in range(1, len(part_list)):
1876
+ g.add_vertex((part_list[i], 1))
1877
+
1878
+ # Add the edge to the second part of the graph
1879
+ if part_list[i] < 0:
1880
+ g.add_edge((part_list[i], 1), (-part_list[i], 2))
1881
+
1882
+ # Add the edge between adjacent elements of a part
1883
+ g.add_edge((part_list[i - 1], 1), (part_list[i], 1))
1884
+
1885
+ # Add the second set partition to the graph
1886
+ for part in sp2:
1887
+ part_list = list(part)
1888
+ if part_list:
1889
+ g.add_vertex((part_list[0], 2))
1890
+ for i in range(1, len(part_list)):
1891
+ g.add_vertex((part_list[i], 2))
1892
+ g.add_edge((part_list[i - 1], 2), (part_list[i], 2))
1893
+
1894
+ return g
1895
+
1896
+
1897
+ def propagating_number(sp):
1898
+ """
1899
+ Return the propagating number of the set partition ``sp``.
1900
+
1901
+ The propagating number is the number of blocks with both a
1902
+ positive and negative number.
1903
+
1904
+ EXAMPLES::
1905
+
1906
+ sage: import sage.combinat.partition_algebra as pa
1907
+ sage: sp1 = pa.to_set_partition([[1,-2],[2,-1]])
1908
+ sage: sp2 = pa.to_set_partition([[1,2],[-2,-1]])
1909
+ sage: pa.propagating_number(sp1)
1910
+ 2
1911
+ sage: pa.propagating_number(sp2)
1912
+ 0
1913
+ """
1914
+ return sum(1 for part in sp if min(part) < 0 < max(part))
1915
+
1916
+
1917
+ def to_set_partition(l, k=None):
1918
+ """
1919
+ Convert a list of a list of numbers to a set partitions.
1920
+
1921
+ Each list of numbers in the outer list specifies the numbers
1922
+ contained in one of the blocks in the set partition.
1923
+
1924
+ If k is specified, then the set partition will be a set partition
1925
+ of 1, ..., k, -1, ..., -k. Otherwise, k will default to the minimum
1926
+ number needed to contain all of the specified numbers.
1927
+
1928
+ EXAMPLES::
1929
+
1930
+ sage: import sage.combinat.partition_algebra as pa
1931
+ sage: pa.to_set_partition([[1,-1],[2,-2]]) == pa.identity(2)
1932
+ True
1933
+ """
1934
+ if k is None:
1935
+ if not l:
1936
+ return Set([])
1937
+ else:
1938
+ k = max(max(map(abs, x)) for x in l)
1939
+
1940
+ to_be_added = Set(list(range(1, k + 1)) + [-x for x in range(1, k + 1)])
1941
+
1942
+ sp = []
1943
+ for part in l:
1944
+ spart = Set(part)
1945
+ to_be_added -= spart
1946
+ sp.append(spart)
1947
+
1948
+ sp.extend(Set([singleton])
1949
+ for singleton in to_be_added)
1950
+
1951
+ return Set(sp)
1952
+
1953
+
1954
+ def identity(k):
1955
+ r"""
1956
+ Return the identity set partition `1, -1, \ldots, k, -k`.
1957
+
1958
+ EXAMPLES::
1959
+
1960
+ sage: import sage.combinat.partition_algebra as pa
1961
+ sage: pa.identity(2)
1962
+ {{2, -2}, {1, -1}}
1963
+ """
1964
+ return Set(Set([i, -i]) for i in range(1, k + 1))
1965
+
1966
+
1967
+ def set_partition_composition(sp1, sp2):
1968
+ """
1969
+ Return a tuple consisting of the composition of the set partitions
1970
+ sp1 and sp2 and the number of components removed from the middle
1971
+ rows of the graph.
1972
+
1973
+ EXAMPLES::
1974
+
1975
+ sage: # needs sage.graphs
1976
+ sage: import sage.combinat.partition_algebra as pa
1977
+ sage: sp1 = pa.to_set_partition([[1,-2],[2,-1]])
1978
+ sage: sp2 = pa.to_set_partition([[1,-2],[2,-1]])
1979
+ sage: pa.set_partition_composition(sp1, sp2) == (pa.identity(2), 0)
1980
+ True
1981
+ """
1982
+ g = pair_to_graph(sp1, sp2)
1983
+ connected_components = g.connected_components(sort=False)
1984
+
1985
+ res = []
1986
+ total_removed = 0
1987
+ for cc in connected_components:
1988
+ # Remove the vertices that live in the middle two rows
1989
+ new_cc = [x for x in cc if not ((x[0] < 0 and x[1] == 1) or
1990
+ (x[0] > 0 and x[1] == 2))]
1991
+
1992
+ if not new_cc:
1993
+ if len(cc) > 1:
1994
+ total_removed += 1
1995
+ else:
1996
+ res.append(Set(x[0] for x in new_cc))
1997
+
1998
+ return (Set(res), total_removed)