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,2122 @@
1
+ # sage_setup: distribution = sagemath-combinat
2
+ # sage.doctest: needs sage.combinat sage.graphs sage.modules
3
+ r"""
4
+ Subword complex
5
+
6
+ Fix a Coxeter system `(W,S)`. The subword complex `\mathcal{SC}(Q,w)`
7
+ associated to a word `Q \in S^*` and an element `w \in W` is the
8
+ simplicial complex whose ground set is the set of positions in `Q` and whose
9
+ facets are complements of sets of positions defining a reduced
10
+ expression for `w`.
11
+
12
+ A subword complex is a shellable sphere if and only if the Demazure
13
+ product of `Q` equals `w`, otherwise it is a shellable ball.
14
+
15
+ The code is optimized to be used with :class:`ReflectionGroup`, it works as well
16
+ with :class:`CoxeterGroup`, but many methods fail for :class:`WeylGroup`.
17
+
18
+ EXAMPLES::
19
+
20
+ sage: W = ReflectionGroup(['A',3]); I = list(W.index_set()) # optional - gap3
21
+ sage: Q = I + W.w0.coxeter_sorting_word(I); Q # optional - gap3
22
+ [1, 2, 3, 1, 2, 3, 1, 2, 1]
23
+
24
+ sage: S = SubwordComplex(Q,W.w0) # optional - gap3
25
+ sage: for F in S: print("{} {}".format(F, F.root_configuration())) # optional - gap3
26
+ (0, 1, 2) [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
27
+ (0, 1, 8) [(1, 0, 0), (0, 1, 0), (0, 0, -1)]
28
+ (0, 2, 6) [(1, 0, 0), (0, 1, 1), (0, -1, 0)]
29
+ (0, 6, 7) [(1, 0, 0), (0, 0, 1), (0, -1, -1)]
30
+ (0, 7, 8) [(1, 0, 0), (0, -1, 0), (0, 0, -1)]
31
+ (1, 2, 3) [(1, 1, 0), (0, 0, 1), (-1, 0, 0)]
32
+ (1, 3, 8) [(1, 1, 0), (-1, 0, 0), (0, 0, -1)]
33
+ (2, 3, 4) [(1, 1, 1), (0, 1, 0), (-1, -1, 0)]
34
+ (2, 4, 6) [(1, 1, 1), (-1, 0, 0), (0, -1, 0)]
35
+ (3, 4, 5) [(0, 1, 0), (0, 0, 1), (-1, -1, -1)]
36
+ (3, 5, 8) [(0, 1, 0), (-1, -1, 0), (0, 0, -1)]
37
+ (4, 5, 6) [(0, 1, 1), (-1, -1, -1), (0, -1, 0)]
38
+ (5, 6, 7) [(-1, 0, 0), (0, 0, 1), (0, -1, -1)]
39
+ (5, 7, 8) [(-1, 0, 0), (0, -1, 0), (0, 0, -1)]
40
+
41
+ Testing that the implementation also works with CoxeterGroup::
42
+
43
+ sage: W = CoxeterGroup(['A',3]); I = list(W.index_set())
44
+ sage: Q = I + W.w0.coxeter_sorting_word(I); Q
45
+ [1, 2, 3, 1, 2, 3, 1, 2, 1]
46
+ sage: S = SubwordComplex(Q,W.w0); S
47
+ Subword complex of type ['A', 3] for Q = (1, 2, 3, 1, 2, 3, 1, 2, 1) and pi = [1, 2, 3, 1, 2, 1]
48
+ sage: P = S.increasing_flip_poset(); P; len(P.cover_relations())
49
+ Finite poset containing 14 elements
50
+ 21
51
+
52
+ The root configuration works::
53
+
54
+ sage: for F in S: print("{} {}".format(F, F.root_configuration()))
55
+ (0, 1, 2) [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
56
+ (0, 1, 8) [(1, 0, 0), (0, 1, 0), (0, 0, -1)]
57
+ (0, 2, 6) [(1, 0, 0), (0, 1, 1), (0, -1, 0)]
58
+ (0, 6, 7) [(1, 0, 0), (0, 0, 1), (0, -1, -1)]
59
+ (0, 7, 8) [(1, 0, 0), (0, -1, 0), (0, 0, -1)]
60
+ (1, 2, 3) [(1, 1, 0), (0, 0, 1), (-1, 0, 0)]
61
+ (1, 3, 8) [(1, 1, 0), (-1, 0, 0), (0, 0, -1)]
62
+ (2, 3, 4) [(1, 1, 1), (0, 1, 0), (-1, -1, 0)]
63
+ (2, 4, 6) [(1, 1, 1), (-1, 0, 0), (0, -1, 0)]
64
+ (3, 4, 5) [(0, 1, 0), (0, 0, 1), (-1, -1, -1)]
65
+ (3, 5, 8) [(0, 1, 0), (-1, -1, 0), (0, 0, -1)]
66
+ (4, 5, 6) [(0, 1, 1), (-1, -1, -1), (0, -1, 0)]
67
+ (5, 6, 7) [(-1, 0, 0), (0, 0, 1), (0, -1, -1)]
68
+ (5, 7, 8) [(-1, 0, 0), (0, -1, 0), (0, 0, -1)]
69
+
70
+ And the weight configuration also works::
71
+
72
+ sage: W = CoxeterGroup(['A',2])
73
+ sage: w = W.from_reduced_word([1,2,1])
74
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
75
+ sage: F = SC([1,2])
76
+ sage: F.extended_weight_configuration()
77
+ [(4/3, 2/3), (2/3, 4/3), (-2/3, 2/3), (2/3, 4/3), (-2/3, 2/3)]
78
+ sage: F.extended_weight_configuration(coefficients=(1,2))
79
+ [(4/3, 2/3), (4/3, 8/3), (-2/3, 2/3), (4/3, 8/3), (-2/3, 2/3)]
80
+
81
+ One finally can compute the brick polytope, using all functionality
82
+ on weight configurations, though it does not realize to live in
83
+ real space::
84
+
85
+ sage: W = CoxeterGroup(['A',3]); I = list(W.index_set())
86
+ sage: Q = I + W.w0.coxeter_sorting_word(I)
87
+ sage: S = SubwordComplex(Q,W.w0)
88
+ sage: S.brick_polytope() # needs sage.geometry.polyhedron
89
+ A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 14 vertices
90
+
91
+ sage: W = CoxeterGroup(['H',3]); I = list(W.index_set())
92
+ sage: Q = I + W.w0.coxeter_sorting_word(I)
93
+ sage: S = SubwordComplex(Q,W.w0)
94
+ sage: S.brick_polytope() # needs sage.geometry.polyhedron
95
+ doctest:...: RuntimeWarning: the polytope is built with rational vertices
96
+ A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 32 vertices
97
+
98
+ AUTHORS:
99
+
100
+ - Christian Stump: initial version
101
+ - Vincent Pilaud: greedy flip algorithm, minor improvements, documentation
102
+
103
+ REFERENCES:
104
+
105
+ .. [KnuMil] Knutson and Miller. *Subword complexes in Coxeter groups*. Adv. Math., 184(1):161-176, 2004.
106
+ .. [PilStu] Pilaud and Stump. *Brick polytopes of spherical subword complexes and generalized associahedra*. Adv. Math. 276:1-61, 2015.
107
+ """
108
+ # ****************************************************************************
109
+ # Copyright (C) 2015 Christian Stump <christian.stump@gmail.com>
110
+ #
111
+ # Distributed under the terms of the GNU General Public License (GPL)
112
+ # The full text of the GPL is available at:
113
+ #
114
+ # https://www.gnu.org/licenses/
115
+ # ****************************************************************************
116
+ from itertools import repeat
117
+ from copy import copy
118
+ from sage.misc.cachefunc import cached_method
119
+ from sage.misc.lazy_import import lazy_import
120
+ from sage.structure.element import Element
121
+ from sage.structure.unique_representation import UniqueRepresentation
122
+ from sage.topology.simplicial_complex import SimplicialComplex, Simplex
123
+ from sage.categories.simplicial_complexes import SimplicialComplexes
124
+ from sage.combinat.subword_complex_c import _flip_c, _construct_facets_c
125
+
126
+ lazy_import('sage.geometry.polyhedron.constructor', 'Polyhedron')
127
+ lazy_import('sage.geometry.cone', 'Cone')
128
+
129
+
130
+ class SubwordComplexFacet(Simplex, Element):
131
+ r"""
132
+ A facet of a subword complex.
133
+
134
+ Facets of the subword complex `\mathcal{SC}(Q,w)` are complements
135
+ of sets of positions in `Q` defining a reduced expression for `w`.
136
+
137
+ EXAMPLES::
138
+
139
+ sage: # optional - gap3
140
+ sage: W = ReflectionGroup(['A',2])
141
+ sage: w = W.from_reduced_word([1,2,1])
142
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
143
+ sage: F = SC[0]; F
144
+ (0, 1)
145
+
146
+ sage: W = CoxeterGroup(['A',2])
147
+ sage: w = W.from_reduced_word([1,2,1])
148
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
149
+ sage: F = SC[0]; F
150
+ (0, 1)
151
+
152
+ TESTS::
153
+
154
+ sage: type(F) # optional - gap3
155
+ <class 'sage.combinat.subword_complex.SubwordComplex_with_category.element_class'>
156
+ """
157
+
158
+ # standard functions
159
+
160
+ def __init__(self, parent, positions, facet_test=True):
161
+ r"""
162
+ Initialize a facet of the subword complex ``parent``.
163
+
164
+ EXAMPLES::
165
+
166
+ sage: W = ReflectionGroup(['A',2]) # optional - gap3
167
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0) # optional - gap3
168
+ sage: F = SC([1,2]); F # optional - gap3
169
+ (1, 2)
170
+
171
+ sage: W = CoxeterGroup(['A',2])
172
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0)
173
+ sage: F = SC([1,2]); F
174
+ (1, 2)
175
+
176
+ TESTS::
177
+
178
+ sage: W = ReflectionGroup(['A',2]) # optional - gap3
179
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0) # optional - gap3
180
+ sage: SC([1,3]) # optional - gap3
181
+ Traceback (most recent call last):
182
+ ...
183
+ ValueError: the given iterable [1, 3] is not a facet of the Subword complex of type ['A', 2] for Q = (1, 2, 1, 2, 1) and pi = [1, 2, 1]
184
+
185
+ sage: W = ReflectionGroup(['A',2]) # optional - gap3
186
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0) # optional - gap3
187
+ sage: TestSuite(SC).run() # optional - gap3
188
+ """
189
+ if facet_test and positions not in parent:
190
+ raise ValueError("the given iterable %s is not a facet of the %s" % (positions, parent))
191
+ Simplex.__init__(self, sorted(positions))
192
+ Element.__init__(self, parent)
193
+ self._extended_root_conf_indices = None
194
+ self._extended_weight_conf = None
195
+
196
+ # roots
197
+
198
+ def _extended_root_configuration_indices(self):
199
+ r"""
200
+ Return the indices of the roots in ``self.group().roots()`` of
201
+ the extended root configuration of ``self``.
202
+
203
+ Let `Q = q_1 \dots q_m \in S^*` and `w \in W`. The extended
204
+ root configuration of a facet `I` of `\mathcal{SC}(Q,w)` is
205
+ the sequence `\mathsf{r}(I, 1), \dots, \mathsf{r}(I, m)` of
206
+ roots defined by `\mathsf{r}(I, k) = \Pi Q_{[k-1]
207
+ \smallsetminus I} (\alpha_{q_k})`, where `\Pi Q_{[k-1]
208
+ \smallsetminus I}` is the product of the simple reflections
209
+ `q_i` for `i \in [k-1] \smallsetminus I` in this order.
210
+
211
+ .. SEEALSO::
212
+
213
+ :meth:`extended_root_configuration`
214
+
215
+ EXAMPLES::
216
+
217
+ sage: # optional - gap3
218
+ sage: W = ReflectionGroup(['A',2])
219
+ sage: w = W.from_reduced_word([1,2,1])
220
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
221
+ sage: F = SC([1,2]); F
222
+ (1, 2)
223
+ sage: F._extended_root_configuration_indices()
224
+ [0, 2, 3, 2, 1]
225
+
226
+ sage: W = CoxeterGroup(['A',2])
227
+ sage: w = W.from_reduced_word([1,2,1])
228
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
229
+ sage: F = SC([1,2]); F
230
+ (1, 2)
231
+ sage: F._extended_root_configuration_indices()
232
+ [0, 1, 3, 1, 2]
233
+ """
234
+ if self._extended_root_conf_indices is None:
235
+ self._extended_root_conf_indices = _extended_root_configuration_indices(self.parent().group(), self.parent().word(), self)
236
+ return self._extended_root_conf_indices
237
+
238
+ def _root_configuration_indices(self):
239
+ r"""
240
+ Return the indices of the roots in ``self.group().roots()`` of
241
+ the root configuration of ``self``.
242
+
243
+ Let `Q = q_1 \dots q_m \in S^*` and `w \in W`. The root
244
+ configuration of a facet `I = [i_1, \dots, i_n]` of
245
+ `\mathcal{SC}(Q,w)` is the sequence `\mathsf{r}(I, i_1),
246
+ \dots, \mathsf{r}(I, i_n)` of roots defined by `\mathsf{r}(I,
247
+ k) = \Pi Q_{[k-1] \smallsetminus I} (\alpha_{q_k})`, where
248
+ `\Pi Q_{[k-1] \smallsetminus I}` is the product of the simple
249
+ reflections `q_i` for `i \in [k-1] \smallsetminus I` in this
250
+ order.
251
+
252
+ .. SEEALSO::
253
+
254
+ :meth:`root_configuration`
255
+
256
+ EXAMPLES::
257
+
258
+ sage: # optional - gap3
259
+ sage: W = ReflectionGroup(['A',2])
260
+ sage: w = W.from_reduced_word([1,2,1])
261
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
262
+ sage: F = SC([1,2]); F
263
+ (1, 2)
264
+ sage: F._root_configuration_indices()
265
+ [2, 3]
266
+
267
+ sage: W = CoxeterGroup(['A',2])
268
+ sage: w = W.from_reduced_word([1,2,1])
269
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
270
+ sage: F = SC([1,2]); F
271
+ (1, 2)
272
+ sage: F._root_configuration_indices() # optional - gap3
273
+ [1, 3]
274
+ """
275
+ indices = self._extended_root_configuration_indices()
276
+ return [indices[i] for i in self]
277
+
278
+ def extended_root_configuration(self):
279
+ r"""
280
+ Return the extended root configuration of ``self``.
281
+
282
+ Let `Q = q_1 \dots q_m \in S^*` and `w \in W`. The extended
283
+ root configuration of a facet `I` of `\mathcal{SC}(Q,w)` is
284
+ the sequence `\mathsf{r}(I, 1), \dots, \mathsf{r}(I, m)` of
285
+ roots defined by `\mathsf{r}(I, k) = \Pi Q_{[k-1]
286
+ \smallsetminus I} (\alpha_{q_k})`, where `\Pi Q_{[k-1]
287
+ \smallsetminus I}` is the product of the simple reflections
288
+ `q_i` for `i \in [k-1] \smallsetminus I` in this order.
289
+
290
+ The extended root configuration is used to perform flips efficiently.
291
+
292
+ .. SEEALSO::
293
+
294
+ :meth:`flip`
295
+
296
+ EXAMPLES::
297
+
298
+ sage: # optional - gap3
299
+ sage: W = ReflectionGroup(['A',2])
300
+ sage: w = W.from_reduced_word([1,2,1])
301
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
302
+ sage: F = SC([1,2]); F
303
+ (1, 2)
304
+ sage: F.extended_root_configuration()
305
+ [(1, 0), (1, 1), (-1, 0), (1, 1), (0, 1)]
306
+
307
+ sage: W = CoxeterGroup(['A',2])
308
+ sage: w = W.from_reduced_word([1,2,1])
309
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
310
+ sage: F = SC([1,2]); F
311
+ (1, 2)
312
+ sage: F.extended_root_configuration()
313
+ [(1, 0), (1, 1), (-1, 0), (1, 1), (0, 1)]
314
+ """
315
+ Phi = self.parent().group().roots()
316
+ return [Phi[i] for i in self._extended_root_configuration_indices()]
317
+
318
+ def root_configuration(self):
319
+ r"""
320
+ Return the root configuration of ``self``.
321
+
322
+ Let `Q = q_1 \dots q_m \in S^*` and `w \in W`. The root
323
+ configuration of a facet `I = [i_1, \dots, i_n]` of
324
+ `\mathcal{SC}(Q,w)` is the sequence `\mathsf{r}(I, i_1),
325
+ \dots, \mathsf{r}(I, i_n)` of roots defined by `\mathsf{r}(I,
326
+ k) = \Pi Q_{[k-1] \smallsetminus I} (\alpha_{q_k})`, where
327
+ `\Pi Q_{[k-1] \smallsetminus I}` is the product of the simple
328
+ reflections `q_i` for `i \in [k-1] \smallsetminus I` in this
329
+ order.
330
+
331
+ EXAMPLES::
332
+
333
+ sage: # optional - gap3
334
+ sage: W = ReflectionGroup(['A',2])
335
+ sage: w = W.from_reduced_word([1,2,1])
336
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
337
+ sage: F = SC([1,2]); F
338
+ (1, 2)
339
+ sage: F.root_configuration()
340
+ [(1, 1), (-1, 0)]
341
+
342
+ sage: W = CoxeterGroup(['A',2])
343
+ sage: w = W.from_reduced_word([1,2,1])
344
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
345
+ sage: F = SC([1,2]); F
346
+ (1, 2)
347
+ sage: F.root_configuration() # optional - gap3
348
+ [(1, 1), (-1, 0)]
349
+ """
350
+ Phi = self.parent().group().roots()
351
+ return [Phi[i] for i in self._root_configuration_indices()]
352
+
353
+ def kappa_preimage(self):
354
+ r"""
355
+ Return the fiber of ``self`` under the `\kappa` map.
356
+
357
+ The `\kappa` map sends an element `w \in W` to the unique
358
+ facet of `I \in \mathcal{SC}(Q,w)` such that the root
359
+ configuration of `I` is contained in `w(\Phi^+)`.
360
+ In other words, `w` is in the preimage of ``self`` under
361
+ `\kappa` if and only if `w^{-1}` sends every root in the
362
+ root configuration to a positive root.
363
+
364
+ EXAMPLES::
365
+
366
+ sage: W = ReflectionGroup(['A',2]) # optional - gap3
367
+ sage: w = W.from_reduced_word([1,2,1]) # optional - gap3
368
+ sage: SC = SubwordComplex([1,2,1,2,1],w) # optional - gap3
369
+
370
+ sage: F = SC([1,2]); F # optional - gap3
371
+ (1, 2)
372
+ sage: F.kappa_preimage() # optional - gap3
373
+ [(1,4)(2,3)(5,6)]
374
+
375
+ sage: F = SC([0,4]); F # optional - gap3
376
+ (0, 4)
377
+ sage: F.kappa_preimage() # optional - gap3
378
+ [(1,3)(2,5)(4,6), (1,2,6)(3,4,5)]
379
+
380
+ sage: W = CoxeterGroup(['A',2])
381
+ sage: w = W.from_reduced_word([1,2,1])
382
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
383
+
384
+ sage: F = SC([1,2]); F
385
+ (1, 2)
386
+ sage: F.kappa_preimage()
387
+ [
388
+ [-1 1]
389
+ [ 0 1]
390
+ ]
391
+
392
+ sage: F = SC([0,4]); F
393
+ (0, 4)
394
+ sage: F.kappa_preimage()
395
+ [
396
+ [ 1 0] [-1 1]
397
+ [ 1 -1], [-1 0]
398
+ ]
399
+ """
400
+ W = self.parent().group()
401
+ N = len(W.long_element(as_word=True))
402
+ root_conf = self._root_configuration_indices()
403
+ return [~w for w in W
404
+ if all(w.action_on_root_indices(i, side='left') < N
405
+ for i in root_conf)]
406
+
407
+ def is_vertex(self):
408
+ r"""
409
+ Return ``True`` if ``self`` is a vertex of the brick polytope
410
+ of ``self.parent``.
411
+
412
+ A facet is a vertex of the brick polytope if its root cone is
413
+ pointed. Note that this property is always satisfied for
414
+ root-independent subword complexes.
415
+
416
+ .. SEEALSO::
417
+
418
+ :meth:`root_cone`
419
+
420
+ EXAMPLES::
421
+
422
+ sage: # optional - gap3
423
+ sage: W = ReflectionGroup(['A',1])
424
+ sage: w = W.from_reduced_word([1])
425
+ sage: SC = SubwordComplex([1,1,1],w)
426
+ sage: F = SC([0,1]); F.is_vertex()
427
+ True
428
+ sage: F = SC([0,2]); F.is_vertex()
429
+ False
430
+
431
+ sage: # optional - gap3
432
+ sage: W = ReflectionGroup(['A',2])
433
+ sage: w = W.from_reduced_word([1,2,1])
434
+ sage: SC = SubwordComplex([1,2,1,2,1,2,1],w)
435
+ sage: F = SC([0,1,2,3]); F.is_vertex()
436
+ True
437
+ sage: F = SC([0,1,2,6]); F.is_vertex()
438
+ False
439
+
440
+ sage: W = CoxeterGroup(['A',2])
441
+ sage: w = W.from_reduced_word([1,2,1])
442
+ sage: SC = SubwordComplex([1,2,1,2,1,2,1],w)
443
+ sage: F = SC([0,1,2,3]); F.is_vertex()
444
+ True
445
+ sage: F = SC([0,1,2,6]); F.is_vertex()
446
+ False
447
+ """
448
+ S = self.parent()
449
+ if S.is_root_independent():
450
+ return True
451
+ return self.root_cone().is_strictly_convex()
452
+
453
+ @cached_method
454
+ def root_cone(self):
455
+ r"""
456
+ Return the polyhedral cone generated by the root configuration
457
+ of ``self``.
458
+
459
+ .. SEEALSO::
460
+
461
+ :meth:`root_configuration`
462
+
463
+ EXAMPLES::
464
+
465
+ sage: # optional - gap3
466
+ sage: W = ReflectionGroup(['A',1])
467
+ sage: w = W.from_reduced_word([1])
468
+ sage: SC = SubwordComplex([1,1,1],w)
469
+ sage: F = SC([0,2]); F.root_cone()
470
+ 1-d cone in 1-d lattice N
471
+
472
+ sage: W = CoxeterGroup(['A',1])
473
+ sage: w = W.from_reduced_word([1])
474
+ sage: SC = SubwordComplex([1,1,1],w)
475
+ sage: F = SC([0,2]); F.root_cone()
476
+ 1-d cone in 1-d lattice N
477
+ """
478
+ return Cone(self.root_configuration())
479
+
480
+ def upper_root_configuration(self):
481
+ r"""
482
+ Return the positive roots of the root configuration of ``self``.
483
+
484
+ EXAMPLES::
485
+
486
+ sage: # optional - gap3
487
+ sage: W = ReflectionGroup(['A',2])
488
+ sage: w = W.from_reduced_word([1,2,1])
489
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
490
+ sage: F = SC([1,2]); F
491
+ (1, 2)
492
+ sage: F.root_configuration()
493
+ [(1, 1), (-1, 0)]
494
+ sage: F.upper_root_configuration()
495
+ [(1, 0)]
496
+
497
+ sage: W = CoxeterGroup(['A',2])
498
+ sage: w = W.from_reduced_word([1,2,1])
499
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
500
+ sage: F = SC([1,2]); F
501
+ (1, 2)
502
+ sage: F.upper_root_configuration()
503
+ [(1, 0)]
504
+ """
505
+ conf = self._root_configuration_indices()
506
+ W = self.parent().group()
507
+ Phi = W.roots()
508
+ N = len(Phi) // 2
509
+ return [Phi[i - N] for i in conf if i >= N]
510
+
511
+ # weights
512
+
513
+ def extended_weight_configuration(self, coefficients=None):
514
+ r"""
515
+ Return the extended weight configuration of ``self``.
516
+
517
+ Let `Q = q_1 \dots q_m \in S^*` and `w \in W`. The extended
518
+ weight configuration of a facet `I` of `\mathcal{SC}(Q,w)` is
519
+ the sequence `\mathsf{w}(I, 1), \dots, \mathsf{w}(I, m)` of
520
+ weights defined by `\mathsf{w}(I, k) = \Pi Q_{[k-1]
521
+ \smallsetminus I} (\omega_{q_k})`, where `\Pi Q_{[k-1]
522
+ \smallsetminus I}` is the product of the simple reflections
523
+ `q_i` for `i \in [k-1] \smallsetminus I` in this order.
524
+
525
+ The extended weight configuration is used to compute the brick vector.
526
+
527
+ INPUT:
528
+
529
+ - ``coefficients`` -- (optional) a list of coefficients used to
530
+ scale the fundamental weights
531
+
532
+ .. SEEALSO::
533
+
534
+ :meth:`brick_vector`
535
+
536
+ EXAMPLES::
537
+
538
+ sage: # optional - gap3
539
+ sage: W = ReflectionGroup(['A',2])
540
+ sage: w = W.from_reduced_word([1,2,1])
541
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
542
+ sage: F = SC([1,2])
543
+ sage: F.extended_weight_configuration()
544
+ [(2/3, 1/3), (1/3, 2/3), (-1/3, 1/3), (1/3, 2/3), (-1/3, 1/3)]
545
+ sage: F.extended_weight_configuration(coefficients=(1,2))
546
+ [(2/3, 1/3), (2/3, 4/3), (-1/3, 1/3), (2/3, 4/3), (-1/3, 1/3)]
547
+
548
+ sage: W = CoxeterGroup(['A',2])
549
+ sage: w = W.from_reduced_word([1,2,1])
550
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
551
+ sage: F = SC([1,2])
552
+ sage: F.extended_weight_configuration()
553
+ [(4/3, 2/3), (2/3, 4/3), (-2/3, 2/3), (2/3, 4/3), (-2/3, 2/3)]
554
+ sage: F.extended_weight_configuration(coefficients=(1,2))
555
+ [(4/3, 2/3), (4/3, 8/3), (-2/3, 2/3), (4/3, 8/3), (-2/3, 2/3)]
556
+ """
557
+ if coefficients is not None or self._extended_weight_conf is None:
558
+ W = self.parent().group()
559
+ I = W.index_set()
560
+ Lambda = W.fundamental_weights()
561
+ if coefficients is not None:
562
+ coeff = {I[i]: coefficients[i]
563
+ for i in range(len(coefficients))}
564
+ Lambda = {li: coeff[li] * Lambda[li] for li in Lambda.keys()}
565
+ Q = self.parent().word()
566
+ V_weights = []
567
+ pi = W.one()
568
+ for i, wi in enumerate(Q):
569
+ fund_weight = Lambda[wi]
570
+ V_weights.append(pi * fund_weight)
571
+ if i not in self:
572
+ pi = pi.apply_simple_reflection_right(wi)
573
+ if self._extended_weight_conf is None:
574
+ self._extended_weight_conf = V_weights
575
+ return V_weights
576
+ else:
577
+ return self._extended_weight_conf
578
+
579
+ def weight_configuration(self):
580
+ r"""
581
+ Return the weight configuration of ``self``.
582
+
583
+ Let `Q = q_1 \dots q_m \in S^*` and `w \in W`. The weight
584
+ configuration of a facet `I = [i_1, \dots, i_n]` of
585
+ `\mathcal{SC}(Q,w)` is the sequence `\mathsf{w}(I, i_1),
586
+ \dots, \mathsf{w}(I, i_n)` of weights defined by
587
+ `\mathsf{w}(I, k) = \Pi Q_{[k-1] \smallsetminus I}
588
+ (\omega_{q_k})`, where `\Pi Q_{[k-1] \smallsetminus I}` is the
589
+ product of the simple reflections `q_i` for `i \in [k-1]
590
+ \smallsetminus I` in this order.
591
+
592
+ EXAMPLES::
593
+
594
+ sage: # optional - gap3
595
+ sage: W = ReflectionGroup(['A',2])
596
+ sage: w = W.from_reduced_word([1,2,1])
597
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
598
+ sage: F = SC([1,2]); F
599
+ (1, 2)
600
+ sage: F.weight_configuration()
601
+ [(1/3, 2/3), (-1/3, 1/3)]
602
+
603
+ sage: W = CoxeterGroup(['A',2])
604
+ sage: w = W.from_reduced_word([1,2,1])
605
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
606
+ sage: F = SC([1,2]); F
607
+ (1, 2)
608
+ sage: F.weight_configuration()
609
+ [(2/3, 4/3), (-2/3, 2/3)]
610
+ """
611
+ extended_configuration = self.extended_weight_configuration()
612
+ return [extended_configuration[i] for i in self]
613
+
614
+ @cached_method
615
+ def weight_cone(self):
616
+ r"""
617
+ Return the polyhedral cone generated by the weight
618
+ configuration of ``self``.
619
+
620
+ .. SEEALSO::
621
+
622
+ :meth:`weight_configuration`
623
+
624
+ EXAMPLES::
625
+
626
+ sage: # optional - gap3
627
+ sage: W = ReflectionGroup(['A',2])
628
+ sage: w = W.from_reduced_word([1,2,1])
629
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
630
+ sage: F = SC([1,2]); F
631
+ (1, 2)
632
+ sage: WC = F.weight_cone(); WC
633
+ 2-d cone in 2-d lattice N
634
+ sage: WC.rays()
635
+ N( 1, 2),
636
+ N(-1, 1)
637
+ in 2-d lattice N
638
+
639
+ sage: W = CoxeterGroup(['A',2])
640
+ sage: w = W.from_reduced_word([1,2,1])
641
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
642
+ sage: F = SC([1,2]); F
643
+ (1, 2)
644
+ sage: WC = F.weight_cone(); WC
645
+ 2-d cone in 2-d lattice N
646
+ """
647
+ return Cone(self.weight_configuration())
648
+
649
+ def brick_vector(self, coefficients=None):
650
+ r"""
651
+ Return the brick vector of ``self``.
652
+
653
+ This is the sum of the weight vectors in the extended weight
654
+ configuration.
655
+
656
+ INPUT:
657
+
658
+ - ``coefficients`` -- (optional) a list of coefficients used to
659
+ scale the fundamental weights
660
+
661
+ .. SEEALSO::
662
+
663
+ :meth:`extended_weight_configuration`
664
+
665
+ EXAMPLES::
666
+
667
+ sage: # optional - gap3
668
+ sage: W = ReflectionGroup(['A',2])
669
+ sage: w = W.from_reduced_word([1,2,1])
670
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
671
+ sage: F = SC([1,2]); F
672
+ (1, 2)
673
+ sage: F.extended_weight_configuration()
674
+ [(2/3, 1/3), (1/3, 2/3), (-1/3, 1/3), (1/3, 2/3), (-1/3, 1/3)]
675
+ sage: F.brick_vector()
676
+ (2/3, 7/3)
677
+ sage: F.brick_vector(coefficients=[1,2])
678
+ (4/3, 11/3)
679
+
680
+ sage: W = CoxeterGroup(['A',2])
681
+ sage: w = W.from_reduced_word([1,2,1])
682
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
683
+ sage: F = SC([1,2])
684
+ sage: F.brick_vector()
685
+ (4/3, 14/3)
686
+ sage: F.brick_vector(coefficients=[1,2])
687
+ (8/3, 22/3)
688
+ """
689
+ return sum(self.extended_weight_configuration(coefficients=coefficients))
690
+
691
+ # flip
692
+
693
+ def flip(self, i, return_position=False):
694
+ r"""
695
+ Return the facet obtained after flipping position ``i`` in ``self``.
696
+
697
+ INPUT:
698
+
699
+ - ``i`` -- integer; position in the word `Q`
700
+ - ``return_position`` -- boolean (default: ``False``); tells
701
+ whether the new position should be returned as well
702
+
703
+ OUTPUT:
704
+
705
+ - The new subword complex facet.
706
+ - The new position if ``return_position`` is ``True``.
707
+
708
+ EXAMPLES::
709
+
710
+ sage: # optional - gap3
711
+ sage: W = ReflectionGroup(['A',2])
712
+ sage: w = W.from_reduced_word([1,2,1])
713
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
714
+ sage: F = SC([1,2]); F
715
+ (1, 2)
716
+ sage: F.flip(1)
717
+ (2, 3)
718
+ sage: F.flip(1, return_position=True)
719
+ ((2, 3), 3)
720
+
721
+ sage: W = CoxeterGroup(['A',2])
722
+ sage: w = W.from_reduced_word([1,2,1])
723
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
724
+ sage: F = SC([1,2]); F
725
+ (1, 2)
726
+ sage: F.flip(1)
727
+ (2, 3)
728
+ sage: F.flip(1, return_position=True)
729
+ ((2, 3), 3)
730
+ """
731
+ S = self.parent()
732
+ F = set(self)
733
+ R = list(self._extended_root_configuration_indices())
734
+ j = _flip_c(self.parent().group(), F, R, i) # F and R are changed here
735
+ new_facet = S.element_class(self.parent(), F)
736
+ new_facet._extended_root_conf_indices = tuple(R)
737
+ if return_position:
738
+ return new_facet, j
739
+ else:
740
+ return new_facet
741
+
742
+ # plot and show
743
+
744
+ def plot(self, list_colors=None, labels=[], thickness=3, fontsize=14,
745
+ shift=(0, 0), compact=False, roots=True, **args):
746
+ r"""
747
+ In type `A` or `B`, plot a pseudoline arrangement representing
748
+ the facet ``self``.
749
+
750
+ Pseudoline arrangements are graphical representations of
751
+ facets of types A or B subword complexes.
752
+
753
+ INPUT:
754
+
755
+ - ``list_colors`` -- list (default: ``[]``); to change the colors
756
+ of the pseudolines
757
+ - ``labels`` -- list (default: ``[]``); to change the labels
758
+ of the pseudolines
759
+ - ``thickness`` -- integer (default: 3); for the thickness
760
+ of the pseudolines
761
+ - ``fontsize`` -- integer (default: 14); for the size
762
+ of the font used for labels
763
+ - ``shift`` -- couple of coordinates (default: ``(0,0)``)
764
+ to change the origin
765
+ - ``compact`` -- boolean (default: ``False``); to require
766
+ a more compact representation
767
+ - ``roots`` -- boolean (default: ``True``); whether to print
768
+ the extended root configuration
769
+
770
+ EXAMPLES::
771
+
772
+ sage: # optional - gap3
773
+ sage: W = ReflectionGroup(['A',2])
774
+ sage: w = W.from_reduced_word([1,2,1])
775
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
776
+ sage: F = SC([1,2]); F.plot() # needs sage.plot
777
+ Graphics object consisting of 26 graphics primitives
778
+
779
+ sage: W = CoxeterGroup(['A',2])
780
+ sage: w = W.from_reduced_word([1,2,1])
781
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
782
+ sage: F = SC([1,2]); F.plot() # needs sage.plot
783
+ Graphics object consisting of 26 graphics primitives
784
+
785
+ sage: # optional - gap3
786
+ sage: W = ReflectionGroup(['B',3])
787
+ sage: c = W.from_reduced_word([1,2,3])
788
+ sage: Q = c.reduced_word()*2 + W.w0.coxeter_sorting_word(c)
789
+ sage: SC = SubwordComplex(Q, W.w0)
790
+ sage: F = SC[15]; F.plot() # needs sage.plot
791
+ Graphics object consisting of 53 graphics primitives
792
+
793
+ TESTS::
794
+
795
+ sage: # optional - gap3
796
+ sage: W = ReflectionGroup(['D',4])
797
+ sage: c = W.from_reduced_word([1,2,3,4])
798
+ sage: Q = c.reduced_word() + W.w0.coxeter_sorting_word(c)
799
+ sage: SC = SubwordComplex(Q, W.w0)
800
+ sage: F = SC[1]; F.plot() # needs sage.plot
801
+ Traceback (most recent call last):
802
+ ...
803
+ ValueError: plotting is currently only implemented for irreducibles types A, B, and C.
804
+
805
+ sage: W = CoxeterGroup(CoxeterMatrix((['A',2],['A',2])))
806
+ sage: c = W.from_reduced_word([1,2,3,4])
807
+ sage: Q = c.reduced_word() + W.w0.coxeter_sorting_word(c)
808
+ sage: SC = SubwordComplex(Q, W.w0)
809
+ sage: F = SC[1]; F.plot() # needs sage.plot
810
+ Traceback (most recent call last):
811
+ ...
812
+ ValueError: plotting is currently only implemented for irreducibles types A, B, and C.
813
+
814
+ REFERENCES: [PilStu]_
815
+ """
816
+ # check that the type is A or B
817
+ # TODO in a better way
818
+ S = self.parent()
819
+ Q = S.word()
820
+ W = S.group()
821
+ n = W.rank()
822
+
823
+ error_msg = "plotting is currently only implemented for irreducibles types A, B, and C."
824
+ if S._cartan_type is not None:
825
+ cartan_type = S._cartan_type
826
+ type = cartan_type.type()
827
+ G = cartan_type.coxeter_matrix().coxeter_graph()
828
+ else:
829
+ type = None
830
+
831
+ if type not in ['A', 'B', 'C'] or not G.is_connected():
832
+ raise ValueError(error_msg)
833
+
834
+ # organization of the indexing
835
+ # TODO: this might be better done in CoxeterType directly.
836
+ index_set = None
837
+ for a in G.vertex_iterator():
838
+ if G.degree(a) == 1:
839
+ b = G.neighbors(a)[0]
840
+ if type == "A" or G.edge_label(a, b) == 4:
841
+ index_set = [a, b]
842
+ break
843
+ assert index_set is not None, "Bug in the plot method"
844
+ while G.degree(b) == 2:
845
+ for c in G.neighbors(b):
846
+ # picking the other neighbors of b
847
+ if c != a:
848
+ index_set.append(c)
849
+ a = b
850
+ b = c
851
+ break
852
+
853
+ # import plot facilities
854
+ from sage.plot.line import line
855
+ from sage.plot.text import text
856
+ from sage.plot.colors import colors
857
+ from sage.combinat.permutation import Permutation
858
+
859
+ # get properties
860
+ if type == 'A':
861
+ last = n
862
+ else:
863
+ last = n - 1
864
+ permutation = Permutation(range(1, last + 2))
865
+ x_max = .5
866
+
867
+ # list the pseudolines to be drawn
868
+ pseudolines = [[(shift[0], shift[1] + i), .5] for i in range(last + 1)]
869
+ pseudolines_type_B = [[] for _ in repeat(None, last + 1)]
870
+ contact_points = []
871
+ root_labels = []
872
+ pseudoline_labels = []
873
+ if labels is not False:
874
+ pseudoline_labels += [(pseudoline,
875
+ (shift[0] - .1, shift[1] + pseudoline),
876
+ "center") for pseudoline in range(last + 1)]
877
+ if roots:
878
+ extended_root_conf = self.extended_root_configuration()
879
+ for position in range(len(Q)):
880
+ y = index_set.index(Q[position])
881
+ if type in ['B', 'C'] and y == 0:
882
+ pseudoline = permutation(1) - 1
883
+ x = pseudolines[pseudoline].pop()
884
+ if compact:
885
+ x_max = max(x + 1, x_max)
886
+ else:
887
+ x = x_max
888
+ x_max += 1
889
+ if position in self:
890
+ pseudolines[pseudoline] += [(shift[0] + x + 1,
891
+ shift[1]), x + 1]
892
+ contact_points += [[(shift[0] + x + .5, shift[1] - .2),
893
+ (shift[0] + x + .5, shift[1])]]
894
+ else:
895
+ pseudolines_type_B[pseudoline] = pseudolines[pseudoline] + [(shift[0] + x + .5, shift[1]), (shift[0] + x + .5, shift[1] - .2)]
896
+ pseudolines[pseudoline] = [(shift[0] + x + .6, shift[1] - .2), (shift[0] + x + .6, shift[1]), .5]
897
+ if roots:
898
+ root_labels.append((extended_root_conf[position],
899
+ (shift[0] + x + .25, shift[1] - .2)))
900
+ else:
901
+ if type in ['B', 'C']:
902
+ y -= 1
903
+ pseudoline1 = permutation(y + 1) - 1
904
+ pseudoline2 = permutation(y + 2) - 1
905
+ x = max(pseudolines[pseudoline1].pop(),
906
+ pseudolines[pseudoline2].pop())
907
+ if compact:
908
+ x_max = max(x + 1, x_max)
909
+ else:
910
+ x = x_max
911
+ x_max += 1
912
+ if position in self:
913
+ pseudolines[pseudoline1] += [(shift[0] + x + 1,
914
+ shift[1] + y), x + 1]
915
+ pseudolines[pseudoline2] += [(shift[0] + x + 1,
916
+ shift[1] + y + 1), x + 1]
917
+ contact_points += [[(shift[0] + x + .5, shift[1] + y),
918
+ (shift[0] + x + .5, shift[1] + y + 1)]]
919
+ else:
920
+ pseudolines[pseudoline1] += [(shift[0] + x + .6,
921
+ shift[1] + y),
922
+ (shift[0] + x + .6,
923
+ shift[1] + y + 1), x + 1]
924
+ pseudolines[pseudoline2] += [(shift[0] + x + .5,
925
+ shift[1] + y + 1),
926
+ (shift[0] + x + .5,
927
+ shift[1] + y), x + 1]
928
+ permutation = permutation._left_to_right_multiply_on_left(Permutation((y + 1, y + 2)))
929
+ if roots:
930
+ root_labels.append((extended_root_conf[position],
931
+ (shift[0] + x + .35,
932
+ shift[1] + y + .5)))
933
+ if labels is not False:
934
+ pseudoline_labels += [(pseudoline1, (shift[0] + x + .35,
935
+ shift[1] + y + .05),
936
+ "bottom"),
937
+ (pseudoline2, (shift[0] + x + .35,
938
+ shift[1] + y + .95),
939
+ "top")]
940
+
941
+ # transform list to real lines
942
+ if list_colors is None:
943
+ list_colors = []
944
+ list_colors += ['red', 'blue', 'green', 'orange', 'yellow', 'purple']
945
+ list_colors += list(colors)
946
+ thickness = max(thickness, 2)
947
+ L = line([(1, 1)])
948
+ for contact_point in contact_points:
949
+ L += line(contact_point, rgbcolor=[0, 0, 0],
950
+ thickness=thickness - 1)
951
+ for pseudoline in range(last + 1):
952
+ pseudolines[pseudoline].pop()
953
+ pseudolines[pseudoline].append((shift[0] + x_max,
954
+ shift[1] + permutation.inverse()(pseudoline + 1) - 1))
955
+ L += line(pseudolines[pseudoline], color=list_colors[pseudoline],
956
+ thickness=thickness)
957
+ if type in ['B', 'C']:
958
+ L += line(pseudolines_type_B[pseudoline],
959
+ color=list_colors[pseudoline],
960
+ thickness=thickness, linestyle='--')
961
+ for root_label in root_labels:
962
+ L += text(root_label[0], root_label[1], rgbcolor=[0, 0, 0],
963
+ fontsize=fontsize, vertical_alignment='center',
964
+ horizontal_alignment='right')
965
+ if len(labels) < last + 1:
966
+ labels = list(range(1, last + 2))
967
+ for pseudoline_label in pseudoline_labels:
968
+ L += text(labels[pseudoline_label[0]], pseudoline_label[1],
969
+ color=list_colors[pseudoline_label[0]],
970
+ fontsize=fontsize,
971
+ vertical_alignment=pseudoline_label[2],
972
+ horizontal_alignment='right')
973
+ if labels is not False:
974
+ for pseudoline in range(last):
975
+ L += text(labels[pseudoline],
976
+ (shift[0] + x_max + .1,
977
+ shift[1] + permutation.inverse()(pseudoline + 1) - 1),
978
+ color=list_colors[pseudoline], fontsize=fontsize,
979
+ vertical_alignment='center',
980
+ horizontal_alignment='left')
981
+ L.axes(False)
982
+ return L
983
+
984
+ def show(self, *kwds, **args):
985
+ """
986
+ Show the facet ``self``.
987
+
988
+ .. SEEALSO::
989
+
990
+ :meth:`plot`
991
+
992
+ EXAMPLES::
993
+
994
+ sage: # optional - gap3
995
+ sage: W = ReflectionGroup(['A',2])
996
+ sage: w = W.from_reduced_word([1,2,1])
997
+ sage: SC = SubwordComplex([1,2,1,2,1],w)
998
+ sage: F = SC([1,2]); F.show()
999
+ <BLANKLINE>
1000
+ """
1001
+ return self.plot().show(*kwds, **args)
1002
+
1003
+
1004
+ class SubwordComplex(UniqueRepresentation, SimplicialComplex):
1005
+ r"""
1006
+ Fix a Coxeter system `(W,S)`. The subword complex
1007
+ `\mathcal{SC}(Q,w)` associated to a word `Q \in S^*` and an
1008
+ element `w \in W` is the simplicial complex whose ground set is the set of
1009
+ positions in `Q` and whose facets are complements of sets of
1010
+ positions defining a reduced expression for `w`.
1011
+
1012
+ A subword complex is a shellable sphere if and only if the
1013
+ Demazure product of `Q` equals `w`, otherwise it is a shellable
1014
+ ball.
1015
+
1016
+ .. WARNING::
1017
+
1018
+ This implementation only works for groups build using ``CoxeterGroup``,
1019
+ and does not work with groups build using ``WeylGroup``.
1020
+
1021
+ EXAMPLES:
1022
+
1023
+ As an example, dual associahedra are subword complexes in type
1024
+ `A_{n-1}` given by the word `[1, \dots, n, 1, \dots, n, 1, \dots,
1025
+ n-1, \dots, 1, 2, 1]` and the permutation `w_0`.
1026
+
1027
+ ::
1028
+
1029
+ sage: # optional - gap3
1030
+ sage: W = ReflectionGroup(['A',2])
1031
+ sage: w = W.from_reduced_word([1,2,1])
1032
+ sage: SC = SubwordComplex([1,2,1,2,1], w); SC
1033
+ Subword complex of type ['A', 2] for Q = (1, 2, 1, 2, 1) and pi = [1, 2, 1]
1034
+ sage: SC.facets()
1035
+ [(0, 1), (0, 4), (1, 2), (2, 3), (3, 4)]
1036
+
1037
+ sage: W = CoxeterGroup(['A',2])
1038
+ sage: w = W.from_reduced_word([1,2,1])
1039
+ sage: SC = SubwordComplex([1,2,1,2,1], w); SC
1040
+ Subword complex of type ['A', 2] for Q = (1, 2, 1, 2, 1) and pi = [1, 2, 1]
1041
+ sage: SC.facets()
1042
+ [(0, 1), (0, 4), (1, 2), (2, 3), (3, 4)]
1043
+
1044
+ REFERENCES: [KnuMil]_, [PilStu]_
1045
+
1046
+ TESTS::
1047
+
1048
+ sage: # optional - gap3
1049
+ sage: W = ReflectionGroup(['A',2])
1050
+ sage: w = W.from_reduced_word([1,2,1])
1051
+ sage: SC1 = SubwordComplex([1,2,1,2,1], w)
1052
+ sage: SC2 = SubwordComplex([1,2,1,2,1], w)
1053
+ sage: SC1 == SC2
1054
+ True
1055
+
1056
+ sage: W = CoxeterGroup(['A',2])
1057
+ sage: w = W.from_reduced_word([1,2,1])
1058
+ sage: SC1 = SubwordComplex([1,2,1,2,1], w)
1059
+ sage: SC2 = SubwordComplex([1,2,1,2,1], w)
1060
+ sage: SC1 == SC2
1061
+ True
1062
+ """
1063
+
1064
+ # standard functions
1065
+
1066
+ @staticmethod
1067
+ def __classcall__(cls, Q, w, algorithm='inductive'):
1068
+ r"""
1069
+ Making the input hashable.
1070
+
1071
+ TESTS::
1072
+
1073
+ sage: # optional - gap3
1074
+ sage: W = ReflectionGroup(['B',2])
1075
+ sage: S = SubwordComplex((1,2)*3,W.w0)
1076
+ sage: T = SubwordComplex([1,2]*3,W.w0)
1077
+ sage: S is T
1078
+ True
1079
+
1080
+ sage: W = CoxeterGroup(['B',2])
1081
+ sage: S = SubwordComplex((1,2)*3,W.w0)
1082
+ sage: T = SubwordComplex([1,2]*3,W.w0)
1083
+ sage: S is T
1084
+ True
1085
+ """
1086
+ Q = tuple(Q)
1087
+ return super().__classcall__(cls, Q, w, algorithm=algorithm)
1088
+
1089
+ def __init__(self, Q, w, algorithm='inductive'):
1090
+ r"""
1091
+ Initialize the subword complex `\mathcal{SC}(Q,w)`.
1092
+
1093
+ INPUT:
1094
+
1095
+ - ``Q`` -- word on the simple generators of the Coxeter group
1096
+ - ``w`` -- element of the Coxeter group
1097
+ - ``algorithm`` -- (default: ``'inductive'``) choice of the
1098
+ algorithm to generate the subword complex. Options are
1099
+ ``'inductive'`` or ``'greedy'``. The second option is
1100
+ recommended when `|Q|` is closed to `\ell(w) + \mathrm{rank}(W)`.
1101
+
1102
+ EXAMPLES::
1103
+
1104
+ sage: # optional - gap3
1105
+ sage: W = ReflectionGroup(['A',3])
1106
+ sage: w = W.from_reduced_word([1,2,3,1,2,1])
1107
+ sage: SC = SubwordComplex([1,2,3,1,2,3,1,2,1], w); SC
1108
+ Subword complex of type ['A', 3] for Q = (1, 2, 3, 1, 2, 3, 1, 2, 1) and pi = [1, 2, 1, 3, 2, 1]
1109
+ sage: len(SC)
1110
+ 14
1111
+
1112
+ sage: W = CoxeterGroup(['A',3])
1113
+ sage: w = W.from_reduced_word([1,2,3,1,2,1])
1114
+ sage: SC = SubwordComplex([1,2,3,1,2,3,1,2,1], w); SC
1115
+ Subword complex of type ['A', 3] for Q = (1, 2, 3, 1, 2, 3, 1, 2, 1) and pi = [1, 2, 3, 1, 2, 1]
1116
+ sage: len(SC)
1117
+ 14
1118
+
1119
+ TESTS:
1120
+
1121
+ Check for methods from the enumerated sets category::
1122
+
1123
+ sage: # optional - gap3
1124
+ sage: W = ReflectionGroup(['A',2])
1125
+ sage: w = W.from_reduced_word([1,2,1])
1126
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1127
+ sage: list(SC)
1128
+ [(0, 1), (0, 4), (1, 2), (2, 3), (3, 4)]
1129
+
1130
+ sage: W = CoxeterGroup(['A',2])
1131
+ sage: w = W.from_reduced_word([1,2,1])
1132
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1133
+ sage: list(SC)
1134
+ [(0, 1), (0, 4), (1, 2), (2, 3), (3, 4)]
1135
+
1136
+ sage: W = CoxeterGroup(['A',2])
1137
+ sage: w = W.from_reduced_word([1,1,1])
1138
+ sage: SC = SubwordComplex([1,2,2,2,1], w)
1139
+ sage: len(SC)
1140
+ 2
1141
+ """
1142
+ W = w.parent()
1143
+ I = W.index_set()
1144
+ if not all(i in I for i in Q):
1145
+ raise ValueError("all elements in Q = %s must be contained in the index set %s" % (Q, I))
1146
+ self._Q = Q
1147
+ self._pi = w
1148
+ if algorithm == "inductive":
1149
+ Fs = _construct_facets_c(Q, w)
1150
+ elif algorithm == "greedy":
1151
+ Fs, Rs = _greedy_flip_algorithm(Q, w)
1152
+ else:
1153
+ raise ValueError("the optional argument algorithm can be "
1154
+ "either inductive or greedy")
1155
+ if not Fs:
1156
+ raise ValueError("the word %s does not contain a reduced expression for %s" % (Q, w.reduced_word()))
1157
+ cat = SimplicialComplexes().Finite().Enumerated()
1158
+ SimplicialComplex.__init__(self, maximal_faces=Fs,
1159
+ maximality_check=False,
1160
+ category=cat)
1161
+ self._W = W
1162
+ try:
1163
+ T = W.coxeter_matrix().coxeter_type()
1164
+ self._cartan_type = T.cartan_type()
1165
+ except AttributeError:
1166
+ self._cartan_type = None
1167
+ self._facets_dict = None
1168
+ if algorithm == "greedy":
1169
+ _facets_dict = {}
1170
+ for i in range(len(Fs)):
1171
+ X = self(Fs[i], facet_test=False)
1172
+ X._extended_root_conf_indices = Rs[i]
1173
+ _facets_dict[tuple(sorted(Fs[i]))] = X
1174
+ self._facets_dict = _facets_dict
1175
+ else:
1176
+ self._facets_dict = {}
1177
+
1178
+ def _repr_(self):
1179
+ r"""
1180
+ Return a string representation of ``self``.
1181
+
1182
+ EXAMPLES::
1183
+
1184
+ sage: W = ReflectionGroup(['A',2]) # optional - gap3
1185
+ sage: w = W.from_reduced_word([1,2,1]) # optional - gap3
1186
+ sage: SubwordComplex([1,2,1,2,1], w) # optional - gap3
1187
+ Subword complex of type ['A', 2] for Q = (1, 2, 1, 2, 1) and pi = [1, 2, 1]
1188
+
1189
+ sage: W = CoxeterGroup(['A',2])
1190
+ sage: w = W.from_reduced_word([1,2,1])
1191
+ sage: SubwordComplex([1,2,1,2,1], w)
1192
+ Subword complex of type ['A', 2] for Q = (1, 2, 1, 2, 1) and pi = [1, 2, 1]
1193
+ """
1194
+ if self._cartan_type is None:
1195
+ return "Subword complex of unknown type for Q = {} and pi = {}".format(self._Q, self._pi.reduced_word())
1196
+ else:
1197
+ return 'Subword complex of type {} for Q = {} and pi = {}'.format(self.cartan_type(), self._Q, self._pi.reduced_word())
1198
+
1199
+ def __call__(self, F, facet_test=True):
1200
+ r"""
1201
+ Create a facet of ``self``.
1202
+
1203
+ INPUT:
1204
+
1205
+ - ``F`` -- an iterable of positions
1206
+ - ``facet_test`` -- boolean (default: ``True``); whether or
1207
+ not the facet ``F`` should be tested before creation
1208
+
1209
+ OUTPUT: the facet of ``self`` at positions given by ``F``
1210
+
1211
+ EXAMPLES::
1212
+
1213
+ sage: W = ReflectionGroup(['A',2]) # optional - gap3
1214
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0) # optional - gap3
1215
+ sage: F = SC([1,2]); F # optional - gap3
1216
+ (1, 2)
1217
+
1218
+ sage: W = CoxeterGroup(['A',2])
1219
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0)
1220
+ sage: F = SC([1,2]); F
1221
+ (1, 2)
1222
+ """
1223
+ if hasattr(F, "parent") and F.parent() is self:
1224
+ return F
1225
+ return self.element_class(self, F, facet_test=facet_test)
1226
+
1227
+ Element = SubwordComplexFacet
1228
+
1229
+ def __contains__(self, F):
1230
+ r"""
1231
+ Test if ``self`` contains a given iterable ``F``.
1232
+
1233
+ EXAMPLES::
1234
+
1235
+ sage: # optional - gap3
1236
+ sage: W = ReflectionGroup(['A',2])
1237
+ sage: w = W.from_reduced_word([1,2,1])
1238
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1239
+ sage: SC.facets()
1240
+ [(0, 1), (0, 4), (1, 2), (2, 3), (3, 4)]
1241
+ sage: [0,1] in SC
1242
+ True
1243
+ sage: [0,2] in SC
1244
+ False
1245
+ sage: [0,1,5] in SC
1246
+ False
1247
+ sage: [0] in SC
1248
+ False
1249
+ sage: ['a','b'] in SC
1250
+ False
1251
+
1252
+ sage: W = CoxeterGroup(['A',2])
1253
+ sage: w = W.from_reduced_word([1,2,1])
1254
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1255
+ sage: SC.facets()
1256
+ [(0, 1), (0, 4), (1, 2), (2, 3), (3, 4)]
1257
+ sage: [0,1] in SC
1258
+ True
1259
+ sage: [0,2] in SC
1260
+ False
1261
+ sage: [0,1,5] in SC
1262
+ False
1263
+ sage: [0] in SC
1264
+ False
1265
+ sage: ['a','b'] in SC
1266
+ False
1267
+ """
1268
+ W = self.group()
1269
+ Q = self.word()
1270
+ r = range(len(Q))
1271
+ if not all(i in r for i in F):
1272
+ return False
1273
+ return W.from_reduced_word(Qi for i, Qi in enumerate(Q) if i not in F) == self.pi()
1274
+
1275
+ # getting the stored properties
1276
+
1277
+ def group(self):
1278
+ r"""
1279
+ Return the group associated to ``self``.
1280
+
1281
+ EXAMPLES::
1282
+
1283
+ sage: # optional - gap3
1284
+ sage: W = ReflectionGroup(['A',2])
1285
+ sage: w = W.from_reduced_word([1,2,1])
1286
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1287
+ sage: SC.group()
1288
+ Irreducible real reflection group of rank 2 and type A2
1289
+
1290
+ sage: W = CoxeterGroup(['A',2])
1291
+ sage: w = W.from_reduced_word([1,2,1])
1292
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1293
+ sage: SC.group()
1294
+ Finite Coxeter group over Integer Ring with Coxeter matrix:
1295
+ [1 3]
1296
+ [3 1]
1297
+ """
1298
+ return self._W
1299
+
1300
+ def cartan_type(self):
1301
+ r"""
1302
+ Return the Cartan type of ``self``.
1303
+
1304
+ EXAMPLES::
1305
+
1306
+ sage: # optional - gap3
1307
+ sage: W = ReflectionGroup(['A',2])
1308
+ sage: w = W.from_reduced_word([1,2,1])
1309
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1310
+ sage: SC.cartan_type()
1311
+ ['A', 2]
1312
+
1313
+ sage: W = CoxeterGroup(['A',2])
1314
+ sage: w = W.from_reduced_word([1,2,1])
1315
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1316
+ sage: SC.cartan_type()
1317
+ ['A', 2]
1318
+ """
1319
+ if self._cartan_type is None:
1320
+ raise ValueError("no Cartan type defined for {}".format(self._W))
1321
+ else:
1322
+ return self._cartan_type
1323
+
1324
+ def word(self):
1325
+ r"""
1326
+ Return the word in the simple generators associated to ``self``.
1327
+
1328
+ EXAMPLES::
1329
+
1330
+ sage: # optional - gap3
1331
+ sage: W = ReflectionGroup(['A',2])
1332
+ sage: w = W.from_reduced_word([1,2,1])
1333
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1334
+ sage: SC.word()
1335
+ (1, 2, 1, 2, 1)
1336
+
1337
+ sage: W = CoxeterGroup(['A',2])
1338
+ sage: w = W.from_reduced_word([1,2,1])
1339
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1340
+ sage: SC.word()
1341
+ (1, 2, 1, 2, 1)
1342
+ """
1343
+ return copy(self._Q)
1344
+
1345
+ def pi(self):
1346
+ r"""
1347
+ Return the element in the Coxeter group associated to ``self``.
1348
+
1349
+ EXAMPLES::
1350
+
1351
+ sage: # optional - gap3
1352
+ sage: W = ReflectionGroup(['A',2])
1353
+ sage: w = W.from_reduced_word([1,2,1])
1354
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1355
+ sage: SC.pi().reduced_word()
1356
+ [1, 2, 1]
1357
+
1358
+ sage: W = CoxeterGroup(['A',2])
1359
+ sage: w = W.from_reduced_word([1,2,1])
1360
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1361
+ sage: SC.pi().reduced_word()
1362
+ [1, 2, 1]
1363
+ """
1364
+ return self._pi
1365
+
1366
+ def facets(self):
1367
+ r"""
1368
+ Return all facets of ``self``.
1369
+
1370
+ EXAMPLES::
1371
+
1372
+ sage: # optional - gap3
1373
+ sage: W = ReflectionGroup(['A',2])
1374
+ sage: w = W.from_reduced_word([1,2,1])
1375
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1376
+ sage: SC.facets()
1377
+ [(0, 1), (0, 4), (1, 2), (2, 3), (3, 4)]
1378
+
1379
+ sage: W = CoxeterGroup(['A',2])
1380
+ sage: w = W.from_reduced_word([1,2,1])
1381
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1382
+ sage: SC.facets()
1383
+ [(0, 1), (0, 4), (1, 2), (2, 3), (3, 4)]
1384
+ """
1385
+ if self._facets_dict:
1386
+ return [self._facets_dict[tuple(F)] for F in self._facets]
1387
+ else:
1388
+ return [self(F, facet_test=False) for F in self._facets]
1389
+
1390
+ def __iter__(self):
1391
+ r"""
1392
+ Return an iterator on the facets of ``self``.
1393
+
1394
+ EXAMPLES::
1395
+
1396
+ sage: # optional - gap3
1397
+ sage: W = ReflectionGroup(['A',2])
1398
+ sage: w = W.from_reduced_word([1,2,1])
1399
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1400
+ sage: for I in SC: print(I)
1401
+ (0, 1)
1402
+ (0, 4)
1403
+ (1, 2)
1404
+ (2, 3)
1405
+ (3, 4)
1406
+
1407
+ sage: W = CoxeterGroup(['A',2])
1408
+ sage: w = W.from_reduced_word([1,2,1])
1409
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1410
+ sage: for I in SC: print(I)
1411
+ (0, 1)
1412
+ (0, 4)
1413
+ (1, 2)
1414
+ (2, 3)
1415
+ (3, 4)
1416
+ """
1417
+ return iter(self.facets())
1418
+
1419
+ def greedy_facet(self, side='positive'):
1420
+ r"""
1421
+ Return the negative (or positive) greedy facet of ``self``.
1422
+
1423
+ This is the lexicographically last (or first) facet of ``self``.
1424
+
1425
+ EXAMPLES::
1426
+
1427
+ sage: # optional - gap3
1428
+ sage: W = ReflectionGroup(['A',2])
1429
+ sage: w = W.from_reduced_word([1,2,1])
1430
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1431
+ sage: SC.greedy_facet(side='positive')
1432
+ (0, 1)
1433
+ sage: SC.greedy_facet(side='negative')
1434
+ (3, 4)
1435
+
1436
+ sage: W = CoxeterGroup(['A',2])
1437
+ sage: w = W.from_reduced_word([1,2,1])
1438
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1439
+ sage: SC.greedy_facet(side='positive')
1440
+ (0, 1)
1441
+ sage: SC.greedy_facet(side='negative')
1442
+ (3, 4)
1443
+ """
1444
+ return self.element_class(self, _greedy_facet(self.word(),
1445
+ self.pi(), side=side))
1446
+
1447
+ # topological properties
1448
+
1449
+ def is_sphere(self):
1450
+ r"""
1451
+ Return ``True`` if the subword complex ``self`` is a sphere.
1452
+
1453
+ EXAMPLES::
1454
+
1455
+ sage: # optional - gap3
1456
+ sage: W = ReflectionGroup(['A',3])
1457
+ sage: w = W.from_reduced_word([2,3,2])
1458
+ sage: SC = SubwordComplex([3,2,3,2,3], w)
1459
+ sage: SC.is_sphere()
1460
+ True
1461
+
1462
+ sage: SC = SubwordComplex([3,2,1,3,2,3], w) # optional - gap3
1463
+ sage: SC.is_sphere() # optional - gap3
1464
+ False
1465
+
1466
+ sage: W = CoxeterGroup(['A',3])
1467
+ sage: w = W.from_reduced_word([2,3,2])
1468
+ sage: SC = SubwordComplex([3,2,3,2,3], w)
1469
+ sage: SC.is_sphere()
1470
+ True
1471
+ """
1472
+ W = self._pi.parent()
1473
+ w = W.demazure_product(self._Q)
1474
+ return w == self._pi
1475
+
1476
+ def is_ball(self):
1477
+ r"""
1478
+ Return ``True`` if the subword complex ``self`` is a ball.
1479
+
1480
+ This is the case if and only if it is not a sphere.
1481
+
1482
+ EXAMPLES::
1483
+
1484
+ sage: # optional - gap3
1485
+ sage: W = ReflectionGroup(['A',3])
1486
+ sage: w = W.from_reduced_word([2,3,2])
1487
+ sage: SC = SubwordComplex([3,2,3,2,3], w)
1488
+ sage: SC.is_ball()
1489
+ False
1490
+
1491
+ sage: SC = SubwordComplex([3,2,1,3,2,3], w) # optional - gap3
1492
+ sage: SC.is_ball() # optional - gap3
1493
+ True
1494
+
1495
+ sage: W = CoxeterGroup(['A',3])
1496
+ sage: w = W.from_reduced_word([2,3,2])
1497
+ sage: SC = SubwordComplex([3,2,3,2,3], w)
1498
+ sage: SC.is_ball()
1499
+ False
1500
+ """
1501
+ return not self.is_sphere()
1502
+
1503
+ def is_pure(self):
1504
+ r"""
1505
+ Return ``True`` since all subword complexes are pure.
1506
+
1507
+ EXAMPLES::
1508
+
1509
+ sage: # optional - gap3
1510
+ sage: W = ReflectionGroup(['A',3])
1511
+ sage: w = W.from_reduced_word([2,3,2])
1512
+ sage: SC = SubwordComplex([3,2,3,2,3], w)
1513
+ sage: SC.is_pure()
1514
+ True
1515
+
1516
+ sage: W = CoxeterGroup(['A',3])
1517
+ sage: w = W.from_reduced_word([2,3,2])
1518
+ sage: SC = SubwordComplex([3,2,3,2,3], w)
1519
+ sage: SC.is_pure()
1520
+ True
1521
+ """
1522
+ return True
1523
+
1524
+ def dimension(self):
1525
+ r"""
1526
+ Return the dimension of ``self``.
1527
+
1528
+ EXAMPLES::
1529
+
1530
+ sage: W = ReflectionGroup(['A',2]) # optional - gap3
1531
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0) # optional - gap3
1532
+ sage: SC.dimension() # optional - gap3
1533
+ 1
1534
+
1535
+ sage: W = CoxeterGroup(['A',2])
1536
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0)
1537
+ sage: SC.dimension()
1538
+ 1
1539
+ """
1540
+ return self._facets[0].dimension()
1541
+
1542
+ # root and weight
1543
+
1544
+ @cached_method
1545
+ def is_root_independent(self):
1546
+ r"""
1547
+ Return ``True`` if ``self`` is root-independent.
1548
+
1549
+ This means that the root configuration
1550
+ of any (or equivalently all) facets is linearly independent.
1551
+
1552
+ EXAMPLES::
1553
+
1554
+ sage: W = ReflectionGroup(['A',2]) # optional - gap3
1555
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0) # optional - gap3
1556
+ sage: SC.is_root_independent() # optional - gap3
1557
+ True
1558
+
1559
+ sage: SC = SubwordComplex([1,2,1,2,1,2], W.w0) # optional - gap3
1560
+ sage: SC.is_root_independent() # optional - gap3
1561
+ False
1562
+
1563
+ sage: W = CoxeterGroup(['A',2])
1564
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0)
1565
+ sage: SC.is_root_independent()
1566
+ True
1567
+ """
1568
+ from sage.matrix.constructor import matrix
1569
+ M = matrix(self.greedy_facet(side='negative').root_configuration())
1570
+ return M.rank() == max(M.ncols(), M.nrows())
1571
+
1572
+ @cached_method
1573
+ def is_double_root_free(self):
1574
+ r"""
1575
+ Return ``True`` if ``self`` is double-root-free.
1576
+
1577
+ This means that the root configurations
1578
+ of all facets do not contain a root twice.
1579
+
1580
+ EXAMPLES::
1581
+
1582
+ sage: # optional - gap3
1583
+ sage: W = ReflectionGroup(['A',2])
1584
+ sage: w = W.from_reduced_word([1,2,1])
1585
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1586
+ sage: SC.is_double_root_free()
1587
+ True
1588
+
1589
+ sage: SC = SubwordComplex([1,1,2,2,1,1], w) # optional - gap3
1590
+ sage: SC.is_double_root_free() # optional - gap3
1591
+ True
1592
+
1593
+ sage: SC = SubwordComplex([1,2,1,2,1,2], w) # optional - gap3
1594
+ sage: SC.is_double_root_free() # optional - gap3
1595
+ False
1596
+
1597
+ sage: W = CoxeterGroup(['A',2])
1598
+ sage: w = W.from_reduced_word([1,2,1])
1599
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1600
+ sage: SC.is_double_root_free()
1601
+ True
1602
+ """
1603
+ if not self.is_root_independent():
1604
+ size = self.dimension() + 1
1605
+ for F in self:
1606
+ conf = F._root_configuration_indices()
1607
+ if len(set(conf)) < size:
1608
+ return False
1609
+ return True
1610
+
1611
+ def kappa_preimages(self):
1612
+ """
1613
+ Return a dictionary containing facets of ``self`` as keys,
1614
+ and list of elements of ``self.group()`` as values.
1615
+
1616
+ .. SEEALSO::
1617
+
1618
+ :meth:`kappa_preimage <sage.combinat.subword_complex.SubwordComplexFacet.kappa_preimage>`
1619
+
1620
+ EXAMPLES::
1621
+
1622
+ sage: # optional - gap3
1623
+ sage: W = ReflectionGroup(['A',2])
1624
+ sage: w = W.from_reduced_word([1,2,1])
1625
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1626
+ sage: kappa = SC.kappa_preimages()
1627
+ sage: for F in SC: print("{} {}".format(F, [w.reduced_word() for w in kappa[F]]))
1628
+ (0, 1) [[]]
1629
+ (0, 4) [[2], [2, 1]]
1630
+ (1, 2) [[1]]
1631
+ (2, 3) [[1, 2]]
1632
+ (3, 4) [[1, 2, 1]]
1633
+
1634
+ sage: W = CoxeterGroup(['A',2])
1635
+ sage: w = W.from_reduced_word([1,2,1])
1636
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1637
+ sage: kappa = SC.kappa_preimages()
1638
+ sage: for F in SC: print("{} {}".format(F, [w.reduced_word() for w in kappa[F]]))
1639
+ (0, 1) [[]]
1640
+ (0, 4) [[2], [2, 1]]
1641
+ (1, 2) [[1]]
1642
+ (2, 3) [[1, 2]]
1643
+ (3, 4) [[1, 2, 1]]
1644
+ """
1645
+ return {F: F.kappa_preimage() for F in self}
1646
+
1647
+ def brick_fan(self):
1648
+ r"""
1649
+ Return the brick fan of ``self``.
1650
+
1651
+ It is the normal fan of the brick polytope of ``self``. It is
1652
+ formed by the cones generated by the weight configurations of
1653
+ the facets of ``self``.
1654
+
1655
+ .. SEEALSO::
1656
+
1657
+ :func:`weight_cone <sage.combinat.subword_complex.SubwordComplexFacet.weight_cone>`
1658
+
1659
+ EXAMPLES::
1660
+
1661
+ sage: # optional - gap3
1662
+ sage: W = ReflectionGroup(['A',2])
1663
+ sage: w = W.from_reduced_word([1,2,1])
1664
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1665
+ sage: SC.brick_fan()
1666
+ Rational polyhedral fan in 2-d lattice N
1667
+
1668
+ sage: W = CoxeterGroup(['A',2])
1669
+ sage: w = W.from_reduced_word([1,2,1])
1670
+ sage: SC = SubwordComplex([1,2,1,2,1], w)
1671
+ sage: SC.brick_fan()
1672
+ Rational polyhedral fan in 2-d lattice N
1673
+ """
1674
+ from sage.geometry.fan import Fan
1675
+ return Fan([F.weight_cone() for F in self])
1676
+
1677
+ # brick polytope
1678
+
1679
+ def brick_vectors(self, coefficients=None):
1680
+ r"""
1681
+ Return the list of all brick vectors of facets of ``self``.
1682
+
1683
+ INPUT:
1684
+
1685
+ - ``coefficients`` -- (optional) a list of coefficients used to
1686
+ scale the fundamental weights
1687
+
1688
+ .. SEEALSO::
1689
+
1690
+ :func:`brick_vector <sage.combinat.subword_complex.SubwordComplexFacet.brick_vector>`
1691
+
1692
+ EXAMPLES::
1693
+
1694
+ sage: # optional - gap3
1695
+ sage: W = ReflectionGroup(['A',2])
1696
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0)
1697
+ sage: SC.brick_vectors()
1698
+ [(5/3, 7/3), (5/3, 1/3), (2/3, 7/3), (-1/3, 4/3), (-1/3, 1/3)]
1699
+ sage: SC.brick_vectors(coefficients=(1,2))
1700
+ [(7/3, 11/3), (7/3, 2/3), (4/3, 11/3), (-2/3, 5/3), (-2/3, 2/3)]
1701
+
1702
+ sage: W = CoxeterGroup(['A',2])
1703
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0)
1704
+ sage: SC.brick_vectors()
1705
+ [(10/3, 14/3), (10/3, 2/3), (4/3, 14/3), (-2/3, 8/3), (-2/3, 2/3)]
1706
+ sage: SC.brick_vectors(coefficients=(1,2))
1707
+ [(14/3, 22/3), (14/3, 4/3), (8/3, 22/3), (-4/3, 10/3), (-4/3, 4/3)]
1708
+ """
1709
+ return [F.brick_vector(coefficients=coefficients) for F in self]
1710
+
1711
+ def minkowski_summand(self, i):
1712
+ r"""
1713
+ Return the `i` th Minkowski summand of ``self``.
1714
+
1715
+ INPUT:
1716
+
1717
+ - ``i`` -- an integer defining a position in the word `Q`
1718
+
1719
+ EXAMPLES::
1720
+
1721
+ sage: W = ReflectionGroup(['A',2]) # optional - gap3
1722
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0) # optional - gap3
1723
+ sage: SC.minkowski_summand(1) # optional - gap3
1724
+ A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex
1725
+
1726
+ sage: W = CoxeterGroup(['A',2])
1727
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0)
1728
+ sage: SC.minkowski_summand(1)
1729
+ A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex
1730
+ """
1731
+ G = self.group()
1732
+ from sage.rings.rational_field import QQ
1733
+ if G.coxeter_matrix().is_crystallographic():
1734
+ min_sum = [[QQ(v) for v in F.extended_weight_configuration()[i]] for F in self]
1735
+ else:
1736
+ from sage.rings.cc import CC
1737
+ from warnings import warn
1738
+ warn("the polytope is built with rational vertices", RuntimeWarning)
1739
+ min_sum = [[QQ(CC(v)) for v in F.extended_weight_configuration()[i]] for F in self]
1740
+ return Polyhedron(min_sum)
1741
+
1742
+ def brick_polytope(self, coefficients=None):
1743
+ r"""
1744
+ Return the brick polytope of ``self``.
1745
+
1746
+ This polytope is the convex hull of the brick vectors of ``self``.
1747
+
1748
+ INPUT:
1749
+
1750
+ - ``coefficients`` -- (optional) a list of coefficients used to
1751
+ scale the fundamental weights
1752
+
1753
+ .. SEEALSO::
1754
+
1755
+ :meth:`brick_vectors`
1756
+
1757
+ EXAMPLES::
1758
+
1759
+ sage: W = ReflectionGroup(['A',2]) # optional - gap3
1760
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0) # optional - gap3
1761
+ sage: X = SC.brick_polytope(); X # optional - gap3
1762
+ A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices
1763
+
1764
+ sage: Y = SC.brick_polytope(coefficients=[1,2]); Y # optional - gap3
1765
+ A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices
1766
+
1767
+ sage: X == Y # optional - gap3
1768
+ False
1769
+
1770
+ sage: W = CoxeterGroup(['A',2])
1771
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0)
1772
+ sage: X = SC.brick_polytope(); X
1773
+ A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices
1774
+
1775
+ sage: # optional - gap3
1776
+ sage: W = ReflectionGroup(['H',3])
1777
+ sage: c = W.index_set(); Q = c + tuple(W.w0.coxeter_sorting_word(c))
1778
+ sage: SC = SubwordComplex(Q,W.w0)
1779
+ sage: SC.brick_polytope()
1780
+ doctest:...:
1781
+ RuntimeWarning: the polytope is built with rational vertices
1782
+ A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 32 vertices
1783
+ """
1784
+ BV = self.brick_vectors(coefficients=coefficients)
1785
+ G = self.group()
1786
+ from sage.rings.rational_field import QQ
1787
+ if G.coxeter_matrix().is_crystallographic():
1788
+ BV = [[QQ(v) for v in V] for V in BV]
1789
+ else:
1790
+ from sage.rings.cc import CC
1791
+ from warnings import warn
1792
+ warn("the polytope is built with rational vertices", RuntimeWarning)
1793
+ BV = [[QQ(CC(v).real()) for v in V] for V in BV]
1794
+ return Polyhedron(BV)
1795
+
1796
+ def barycenter(self):
1797
+ """
1798
+ Return the barycenter of the brick polytope of ``self``.
1799
+
1800
+ .. SEEALSO::
1801
+
1802
+ :meth:`brick_polytope`
1803
+
1804
+ EXAMPLES::
1805
+
1806
+ sage: W = ReflectionGroup(['A',2]) # optional - gap3
1807
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0) # optional - gap3
1808
+ sage: SC.barycenter() # optional - gap3
1809
+ (2/3, 4/3)
1810
+
1811
+ sage: W = CoxeterGroup(['A',2])
1812
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0)
1813
+ sage: SC.barycenter()
1814
+ (4/3, 8/3)
1815
+ """
1816
+ facets = self.facets()
1817
+ if not self.is_root_independent():
1818
+ facets = [F for F in facets if F.is_vertex()]
1819
+ return sum(F.brick_vector() for F in facets) / len(facets)
1820
+
1821
+ # cambrian constructions
1822
+
1823
+ def cover_relations(self, label=False):
1824
+ """
1825
+ Return the set of cover relations in the associated poset.
1826
+
1827
+ INPUT:
1828
+
1829
+ - ``label`` -- boolean (default: ``False``); whether or not to label
1830
+ the cover relations by the position of flip
1831
+
1832
+ OUTPUT: list of pairs of facets
1833
+
1834
+ EXAMPLES::
1835
+
1836
+ sage: W = ReflectionGroup(['A',2]) # optional - gap3
1837
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0) # optional - gap3
1838
+ sage: sorted(SC.cover_relations()) # optional - gap3
1839
+ [((0, 1), (0, 4)),
1840
+ ((0, 1), (1, 2)),
1841
+ ((0, 4), (3, 4)),
1842
+ ((1, 2), (2, 3)),
1843
+ ((2, 3), (3, 4))]
1844
+
1845
+ sage: W = CoxeterGroup(['A',2])
1846
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0)
1847
+ sage: sorted(SC.cover_relations())
1848
+ [((0, 1), (0, 4)),
1849
+ ((0, 1), (1, 2)),
1850
+ ((0, 4), (3, 4)),
1851
+ ((1, 2), (2, 3)),
1852
+ ((2, 3), (3, 4))]
1853
+ """
1854
+ N = len(self.group().long_element(as_word=True))
1855
+ F = self.greedy_facet(side='positive')
1856
+ Fs = {F}
1857
+ seen = {F}
1858
+ covers = []
1859
+ while Fs:
1860
+ F = Fs.pop()
1861
+ seen.add(F)
1862
+ conf = F._extended_root_configuration_indices()
1863
+ for i in F:
1864
+ if conf[i] < N:
1865
+ G = F.flip(i)
1866
+ if label:
1867
+ covers.append((F, G, i))
1868
+ else:
1869
+ covers.append((F, G))
1870
+ if G not in seen:
1871
+ Fs.add(G)
1872
+ return covers
1873
+
1874
+ def increasing_flip_graph(self, label=True):
1875
+ """
1876
+ Return the increasing flip graph of the subword complex.
1877
+
1878
+ OUTPUT: a directed graph
1879
+
1880
+ EXAMPLES::
1881
+
1882
+ sage: W = ReflectionGroup(['A',2]) # optional - gap3
1883
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0) # optional - gap3
1884
+ sage: SC.increasing_flip_graph() # optional - gap3
1885
+ Digraph on 5 vertices
1886
+
1887
+ sage: W = CoxeterGroup(['A',2])
1888
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0)
1889
+ sage: SC.increasing_flip_graph()
1890
+ Digraph on 5 vertices
1891
+ """
1892
+ from sage.graphs.digraph import DiGraph
1893
+ return DiGraph(self.cover_relations(label=label))
1894
+
1895
+ def interval(self, I, J) -> set:
1896
+ """
1897
+ Return the interval [I,J] in the increasing flip graph subword complex.
1898
+
1899
+ INPUT:
1900
+
1901
+ - I, J -- two facets
1902
+
1903
+ OUTPUT: a set of facets
1904
+
1905
+ EXAMPLES::
1906
+
1907
+ sage: # optional - gap3
1908
+ sage: W = ReflectionGroup(['A',2])
1909
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0)
1910
+ sage: F = SC([1,2])
1911
+ sage: SC.interval(F, F)
1912
+ {(1, 2)}
1913
+
1914
+ sage: W = CoxeterGroup(['A',2])
1915
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0)
1916
+ sage: F = SC([1,2])
1917
+ sage: SC.interval(F, F)
1918
+ {(1, 2)}
1919
+ """
1920
+ G = self.increasing_flip_graph()
1921
+ paths = G.all_paths(I, J)
1922
+ return {K for path in paths for K in path}
1923
+
1924
+ def increasing_flip_poset(self):
1925
+ """
1926
+ Return the increasing flip poset of the subword complex.
1927
+
1928
+ OUTPUT: a poset
1929
+
1930
+ EXAMPLES::
1931
+
1932
+ sage: W = ReflectionGroup(['A',2]) # optional - gap3
1933
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0) # optional - gap3
1934
+ sage: SC.increasing_flip_poset() # optional - gap3
1935
+ Finite poset containing 5 elements
1936
+
1937
+ sage: W = CoxeterGroup(['A',2])
1938
+ sage: SC = SubwordComplex([1,2,1,2,1], W.w0)
1939
+ sage: SC.increasing_flip_poset()
1940
+ Finite poset containing 5 elements
1941
+ """
1942
+ from sage.combinat.posets.posets import Poset
1943
+ cov = self.cover_relations()
1944
+ if not self.is_root_independent():
1945
+ Fs = [F for F in self if F.is_vertex()]
1946
+ cov = [(a, b) for a, b in cov if a in Fs and b in Fs]
1947
+ return Poset(((), cov), facade=True)
1948
+
1949
+
1950
+ def _greedy_facet(Q, w, side='negative', n=None, pos=0, l=None, elems=[]):
1951
+ r"""
1952
+ Return the (positive or negative) *greedy facet* of the subword
1953
+ complex `SC(Q, w)`.
1954
+
1955
+ INPUT:
1956
+
1957
+ - ``Q`` -- a word
1958
+ - ``w`` -- an element in the Coxeter group
1959
+ - ``side`` -- string; either ``'negative'`` (default) or ``'positive'``
1960
+ - ``n`` -- integer (default: the length of `Q`)
1961
+ - ``pos`` -- integer (default: 0)
1962
+ - ``l`` -- integer (default: the length of `w`)
1963
+ - ``elems`` -- list (optional)
1964
+
1965
+ OUTPUT: a set
1966
+
1967
+ EXAMPLES::
1968
+
1969
+ sage: from sage.combinat.subword_complex import _greedy_facet
1970
+
1971
+ sage: # optional - gap3
1972
+ sage: W = ReflectionGroup(['A',2])
1973
+ sage: Q = [1,2,1,2,1]
1974
+ sage: w = W.from_reduced_word([1, 2, 1])
1975
+ sage: _greedy_facet(Q, w)
1976
+ {3, 4}
1977
+
1978
+ sage: W = CoxeterGroup(['A',2])
1979
+ sage: Q = [1,2,1,2,1]
1980
+ sage: w = W.from_reduced_word([1, 2, 1])
1981
+ sage: _greedy_facet(Q, w)
1982
+ {3, 4}
1983
+ """
1984
+ if side == "negative":
1985
+ pass
1986
+ elif side == "positive":
1987
+ Q = Q[::-1]
1988
+ w = w.inverse()
1989
+ else:
1990
+ raise ValueError("the optional argument side is not positive "
1991
+ "or negative")
1992
+
1993
+ if n is None:
1994
+ n = len(Q)
1995
+ if l is None:
1996
+ l = w.length()
1997
+
1998
+ if l == 0:
1999
+ return elems + list(range(pos, n))
2000
+ elif n < l:
2001
+ return []
2002
+
2003
+ s = Q[pos]
2004
+
2005
+ if w.has_left_descent(s):
2006
+ X = _greedy_facet(Q, w.apply_simple_reflection_left(s),
2007
+ n=n, pos=pos + 1, l=l - 1, elems=elems)
2008
+ else:
2009
+ X = []
2010
+
2011
+ if not X:
2012
+ X = _greedy_facet(Q, w, n=n, pos=pos + 1, l=l, elems=elems + [pos])
2013
+
2014
+ if side == "positive":
2015
+ X = [n - 1 - i for i in X]
2016
+
2017
+ return set(X)
2018
+
2019
+
2020
+ def _extended_root_configuration_indices(W, Q, F):
2021
+ """
2022
+ Return the extended root configuration indices of the facet `F`.
2023
+
2024
+ INPUT:
2025
+
2026
+ - ``W`` -- a Coxeter group
2027
+ - ``Q`` -- a word representing an element of `W`
2028
+ - ``F`` -- a facet of the subword complex
2029
+
2030
+ OUTPUT: list of root indices
2031
+
2032
+ EXAMPLES::
2033
+
2034
+ sage: from sage.combinat.subword_complex import _extended_root_configuration_indices
2035
+
2036
+ sage: # optional - gap3
2037
+ sage: W = ReflectionGroup(['A',2])
2038
+ sage: w = W.from_reduced_word([1,2,1])
2039
+ sage: Q = [1,2,1,2,1]
2040
+ sage: SC = SubwordComplex(Q, w)
2041
+ sage: F = SC([1,2])
2042
+ sage: _extended_root_configuration_indices(W, Q, F)
2043
+ [0, 2, 3, 2, 1]
2044
+
2045
+ sage: W = CoxeterGroup(['A',2])
2046
+ sage: w = W.from_reduced_word([1,2,1])
2047
+ sage: Q = [1,2,1,2,1]
2048
+ sage: SC = SubwordComplex(Q, w)
2049
+ sage: F = SC([1,2])
2050
+ sage: _extended_root_configuration_indices(W, Q, F)
2051
+ [0, 1, 3, 1, 2]
2052
+ """
2053
+ V_roots = []
2054
+ pi = W.one()
2055
+ for i, wi in enumerate(Q):
2056
+ V_roots.append(pi.action_on_root_indices(W.simple_root_index(wi),
2057
+ side='left'))
2058
+ if i not in F:
2059
+ pi = pi.apply_simple_reflection_right(wi)
2060
+ return V_roots
2061
+
2062
+
2063
+ def _greedy_flip_algorithm(Q, w):
2064
+ """
2065
+ INPUT:
2066
+
2067
+ - ``Q`` -- a word in a Coxeter group `W`
2068
+ - ``w`` -- an element of `W`
2069
+
2070
+ OUTPUT: a pair: the list of facets and the list of extended root conf. indices
2071
+
2072
+ EXAMPLES::
2073
+
2074
+ sage: from sage.combinat.subword_complex import _greedy_flip_algorithm
2075
+
2076
+ sage: # optional - gap3
2077
+ sage: W = ReflectionGroup(['A',2])
2078
+ sage: Q = [1,2,1,2,1]
2079
+ sage: w = W.from_reduced_word([1,2,1])
2080
+ sage: _greedy_flip_algorithm(Q, w)
2081
+ ([{0, 1}, [1, 2], [2, 3], [3, 4], [0, 4]],
2082
+ [[0, 1, 0, 2, 1],
2083
+ [0, 2, 3, 2, 1],
2084
+ [0, 2, 1, 5, 1],
2085
+ [0, 2, 1, 3, 4],
2086
+ [0, 1, 2, 0, 4]])
2087
+
2088
+ sage: W = CoxeterGroup(['A',2])
2089
+ sage: Q = [1,2,1,2,1]
2090
+ sage: w = W.from_reduced_word([1,2,1])
2091
+ sage: _greedy_flip_algorithm(Q, w)
2092
+ ([{0, 1}, [1, 2], [2, 3], [3, 4], [0, 4]],
2093
+ [[0, 2, 0, 1, 2],
2094
+ [0, 1, 3, 1, 2],
2095
+ [0, 1, 2, 4, 2],
2096
+ [0, 1, 2, 3, 5],
2097
+ [0, 2, 1, 0, 5]])
2098
+ """
2099
+ W = w.parent()
2100
+ F = _greedy_facet(Q, w, side='positive')
2101
+ R = _extended_root_configuration_indices(W, Q, F)
2102
+ facet_list = [F]
2103
+ extended_root_conf_indices_list = [R]
2104
+ flip_to_ancestors = [-1]
2105
+ next_index = 0
2106
+ while flip_to_ancestors:
2107
+ has_new_child = False
2108
+ for i in sorted(F):
2109
+ if (not has_new_child) and (i >= next_index):
2110
+ j = _flip_c(W, F, R, i, side='positive')
2111
+ if j != i:
2112
+ flip_to_ancestors.append(j)
2113
+ next_index = i + 1
2114
+ has_new_child = True
2115
+ facet_list.append(list(F))
2116
+ extended_root_conf_indices_list.append(list(R))
2117
+ if not has_new_child:
2118
+ i = flip_to_ancestors.pop()
2119
+ if i != -1:
2120
+ j = _flip_c(W, F, R, i, side='negative')
2121
+ next_index = j + 1
2122
+ return facet_list, extended_root_conf_indices_list