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,1698 @@
1
+ # sage_setup: distribution = sagemath-combinat
2
+ # sage.doctest: needs sage.combinat sage.modules
3
+ """
4
+ Free algebras
5
+
6
+ AUTHORS:
7
+
8
+ - David Kohel (2005-09)
9
+
10
+ - William Stein (2006-11-01): add all doctests; implemented many
11
+ things.
12
+
13
+ - Simon King (2011-04): Put free algebras into the category framework.
14
+ Reimplement free algebra constructor, using a
15
+ :class:`~sage.structure.factory.UniqueFactory` for handling
16
+ different implementations of free algebras. Allow degree weights
17
+ for free algebras in letterplace implementation.
18
+
19
+ EXAMPLES::
20
+
21
+ sage: F = FreeAlgebra(ZZ, 3, 'x,y,z')
22
+ sage: F.base_ring()
23
+ Integer Ring
24
+ sage: G = FreeAlgebra(F, 2, 'm,n'); G
25
+ Free Algebra on 2 generators (m, n) over
26
+ Free Algebra on 3 generators (x, y, z) over Integer Ring
27
+ sage: G.base_ring()
28
+ Free Algebra on 3 generators (x, y, z) over Integer Ring
29
+
30
+ The above free algebra is based on a generic implementation. By
31
+ :issue:`7797`, there is a different implementation
32
+ :class:`~sage.algebras.letterplace.free_algebra_letterplace.FreeAlgebra_letterplace`
33
+ based on Singular's letterplace rings. It is currently restricted to
34
+ weighted homogeneous elements and is therefore not the default. But the
35
+ arithmetic is much faster than in the generic implementation.
36
+ Moreover, we can compute Groebner bases with degree bound for its
37
+ two-sided ideals, and thus provide ideal containment tests::
38
+
39
+ sage: # needs sage.libs.singular
40
+ sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace'); F
41
+ Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field
42
+ sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F
43
+ sage: I.groebner_basis(degbound=4)
44
+ Twosided Ideal (x*y + y*z,
45
+ x*x - y*x - y*y - y*z,
46
+ y*y*y - y*y*z + y*z*y - y*z*z,
47
+ y*y*x + y*y*z + y*z*x + y*z*z,
48
+ y*y*z*y - y*y*z*z + y*z*z*y - y*z*z*z,
49
+ y*z*y*y - y*z*y*z + y*z*z*y - y*z*z*z,
50
+ y*y*z*x + y*y*z*z + y*z*z*x + y*z*z*z,
51
+ y*z*y*x + y*z*y*z + y*z*z*x + y*z*z*z) of Free Associative Unital
52
+ Algebra on 3 generators (x, y, z) over Rational Field
53
+ sage: y*z*y*y*z*z + 2*y*z*y*z*z*x + y*z*y*z*z*z - y*z*z*y*z*x + y*z*z*z*z*x in I
54
+ True
55
+
56
+ Positive integral degree weights for the letterplace implementation
57
+ was introduced in :issue:`7797`::
58
+
59
+ sage: # needs sage.libs.singular
60
+ sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3])
61
+ sage: x.degree()
62
+ 2
63
+ sage: y.degree()
64
+ 1
65
+ sage: z.degree()
66
+ 3
67
+ sage: I = F*[x*y-y*x, x^2+2*y*z, (x*y)^2-z^2]*F
68
+ sage: Q.<a,b,c> = F.quo(I)
69
+ sage: TestSuite(Q).run()
70
+ sage: a^2*b^2
71
+ c*c
72
+
73
+ TESTS::
74
+
75
+ sage: F = FreeAlgebra(GF(5),3,'x')
76
+ sage: TestSuite(F).run()
77
+ sage: F is loads(dumps(F))
78
+ True
79
+
80
+ sage: # needs sage.libs.singular
81
+ sage: F = FreeAlgebra(GF(5),3,'x', implementation='letterplace')
82
+ sage: TestSuite(F).run()
83
+ sage: F is loads(dumps(F))
84
+ True
85
+
86
+ ::
87
+
88
+ sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
89
+ sage: TestSuite(F).run()
90
+ sage: F is loads(dumps(F))
91
+ True
92
+
93
+ sage: # needs sage.libs.singular
94
+ sage: F.<x,y,z> = FreeAlgebra(GF(5),3, implementation='letterplace')
95
+ sage: TestSuite(F).run()
96
+ sage: F is loads(dumps(F))
97
+ True
98
+
99
+ ::
100
+
101
+ sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y'])
102
+ sage: TestSuite(F).run()
103
+ sage: F is loads(dumps(F))
104
+ True
105
+
106
+ sage: # needs sage.libs.singular
107
+ sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y'], implementation='letterplace')
108
+ sage: TestSuite(F).run()
109
+ sage: F is loads(dumps(F))
110
+ True
111
+
112
+ ::
113
+
114
+ sage: F = FreeAlgebra(GF(5),3, 'abc')
115
+ sage: TestSuite(F).run()
116
+ sage: F is loads(dumps(F))
117
+ True
118
+
119
+ sage: # needs sage.libs.singular
120
+ sage: F = FreeAlgebra(GF(5),3, 'abc', implementation='letterplace')
121
+ sage: TestSuite(F).run()
122
+ sage: F is loads(dumps(F))
123
+ True
124
+
125
+ ::
126
+
127
+ sage: F = FreeAlgebra(FreeAlgebra(ZZ,2,'ab'), 2, 'x')
128
+ sage: TestSuite(F).run()
129
+ sage: F is loads(dumps(F))
130
+ True
131
+
132
+ Note that the letterplace implementation can only be used if the corresponding
133
+ (multivariate) polynomial ring has an implementation in Singular::
134
+
135
+ sage: FreeAlgebra(FreeAlgebra(ZZ,2,'ab'), 2, 'x', implementation='letterplace') # needs sage.libs.singular
136
+ Traceback (most recent call last):
137
+ ...
138
+ NotImplementedError: polynomials over Free Algebra on 2 generators (a, b)
139
+ over Integer Ring are not supported in Singular
140
+
141
+ Some tests for the category::
142
+
143
+ sage: R.<x> = FreeAlgebra(QQ,1)
144
+ sage: R.is_commutative()
145
+ True
146
+ sage: R.<x,y> = FreeAlgebra(QQ,2)
147
+ sage: R.is_commutative()
148
+ False
149
+ """
150
+
151
+ # ***************************************************************************
152
+ # Copyright (C) 2005 David Kohel <kohel@maths.usyd.edu>
153
+ # Copyright (C) 2005,2006 William Stein <wstein@gmail.com>
154
+ # Copyright (C) 2011 Simon King <simon.king@uni-jena.de>
155
+ #
156
+ # This program is free software: you can redistribute it and/or modify
157
+ # it under the terms of the GNU General Public License as published by
158
+ # the Free Software Foundation, either version 2 of the License, or
159
+ # (at your option) any later version.
160
+ # https://www.gnu.org/licenses/
161
+ # ***************************************************************************
162
+
163
+
164
+ from sage.algebras.free_algebra_element import FreeAlgebraElement
165
+ from sage.categories.algebras_with_basis import AlgebrasWithBasis
166
+ from sage.categories.functor import Functor
167
+ from sage.categories.pushout import (ConstructionFunctor,
168
+ CompositeConstructionFunctor,
169
+ IdentityConstructionFunctor)
170
+ from sage.categories.rings import Rings
171
+ from sage.combinat.free_module import CombinatorialFreeModule
172
+ from sage.combinat.words.word import Word
173
+ from sage.misc.cachefunc import cached_method
174
+ from sage.misc.lazy_import import lazy_import
175
+ from sage.monoids.free_monoid import FreeMonoid
176
+ from sage.monoids.free_monoid_element import FreeMonoidElement
177
+ from sage.rings.integer_ring import ZZ
178
+ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
179
+ from sage.structure.category_object import normalize_names
180
+ from sage.structure.coerce_exceptions import CoercionException
181
+ from sage.structure.factory import UniqueFactory
182
+
183
+ lazy_import('sage.algebras.letterplace.free_algebra_letterplace', 'FreeAlgebra_letterplace')
184
+
185
+
186
+ class FreeAlgebraFactory(UniqueFactory):
187
+ """
188
+ A constructor of free algebras.
189
+
190
+ See :mod:`~sage.algebras.free_algebra` for examples and corner cases.
191
+
192
+ EXAMPLES::
193
+
194
+ sage: FreeAlgebra(GF(5),3,'x')
195
+ Free Algebra on 3 generators (x0, x1, x2) over Finite Field of size 5
196
+ sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
197
+ sage: (x+y+z)^2
198
+ x^2 + x*y + x*z + y*x + y^2 + y*z + z*x + z*y + z^2
199
+ sage: FreeAlgebra(GF(5),3, 'xx, zba, Y')
200
+ Free Algebra on 3 generators (xx, zba, Y) over Finite Field of size 5
201
+ sage: FreeAlgebra(GF(5),3, 'abc')
202
+ Free Algebra on 3 generators (a, b, c) over Finite Field of size 5
203
+ sage: FreeAlgebra(GF(5),1, 'z')
204
+ Free Algebra on 1 generator (z,) over Finite Field of size 5
205
+ sage: FreeAlgebra(GF(5),1, ['alpha'])
206
+ Free Algebra on 1 generator (alpha,) over Finite Field of size 5
207
+ sage: FreeAlgebra(FreeAlgebra(ZZ,1,'a'), 2, 'x')
208
+ Free Algebra on 2 generators (x0, x1) over
209
+ Free Algebra on 1 generator (a,) over Integer Ring
210
+
211
+ Free algebras are globally unique::
212
+
213
+ sage: F = FreeAlgebra(ZZ,3,'x,y,z')
214
+ sage: G = FreeAlgebra(ZZ,3,'x,y,z')
215
+ sage: F is G
216
+ True
217
+ sage: F.<x,y,z> = FreeAlgebra(GF(5),3) # indirect doctest
218
+ sage: F is loads(dumps(F))
219
+ True
220
+ sage: F is FreeAlgebra(GF(5),['x','y','z'])
221
+ True
222
+ sage: copy(F) is F is loads(dumps(F))
223
+ True
224
+ sage: TestSuite(F).run()
225
+
226
+ By :issue:`7797`, we provide a different implementation of free
227
+ algebras, based on Singular's "letterplace rings". Our letterplace
228
+ wrapper allows for choosing positive integral degree weights for the
229
+ generators of the free algebra. However, only (weighted) homogeneous
230
+ elements are supported. Of course, isomorphic algebras in different
231
+ implementations are not identical::
232
+
233
+ sage: # needs sage.libs.singular
234
+ sage: G = FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace')
235
+ sage: F == G
236
+ False
237
+ sage: G is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace')
238
+ True
239
+ sage: copy(G) is G is loads(dumps(G))
240
+ True
241
+ sage: TestSuite(G).run()
242
+
243
+ ::
244
+
245
+ sage: # needs sage.libs.singular
246
+ sage: H = FreeAlgebra(GF(5), ['x','y','z'], implementation='letterplace',
247
+ ....: degrees=[1,2,3])
248
+ sage: F != H != G
249
+ True
250
+ sage: H is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace',
251
+ ....: degrees=[1,2,3])
252
+ True
253
+ sage: copy(H) is H is loads(dumps(H))
254
+ True
255
+ sage: TestSuite(H).run()
256
+
257
+ Free algebras commute with their base ring.
258
+ ::
259
+
260
+ sage: K.<a,b> = FreeAlgebra(QQ,2)
261
+ sage: K.is_commutative()
262
+ False
263
+ sage: L.<c> = FreeAlgebra(K,1)
264
+ sage: L.is_commutative()
265
+ False
266
+ sage: s = a*b^2 * c^3; s
267
+ a*b^2*c^3
268
+ sage: parent(s)
269
+ Free Algebra on 1 generator (c,) over
270
+ Free Algebra on 2 generators (a, b) over Rational Field
271
+ sage: c^3 * a * b^2
272
+ a*b^2*c^3
273
+ """
274
+ def create_key(self, base_ring, arg1=None, arg2=None,
275
+ sparse=None, order=None,
276
+ names=None, name=None,
277
+ implementation=None, degrees=None):
278
+ """
279
+ Create the key under which a free algebra is stored.
280
+
281
+ TESTS::
282
+
283
+ sage: FreeAlgebra.create_key(GF(5),['x','y','z'])
284
+ (Finite Field of size 5, ('x', 'y', 'z'))
285
+ sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3)
286
+ (Finite Field of size 5, ('x', 'y', 'z'))
287
+ sage: FreeAlgebra.create_key(GF(5),3,'xyz')
288
+ (Finite Field of size 5, ('x', 'y', 'z'))
289
+
290
+ sage: # needs sage.libs.singular
291
+ sage: FreeAlgebra.create_key(GF(5),['x','y','z'],
292
+ ....: implementation='letterplace')
293
+ (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
294
+ sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3,
295
+ ....: implementation='letterplace')
296
+ (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
297
+ sage: FreeAlgebra.create_key(GF(5),3,'xyz',
298
+ ....: implementation='letterplace')
299
+ (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
300
+ sage: FreeAlgebra.create_key(GF(5),3,'xyz',
301
+ ....: implementation='letterplace', degrees=[1,2,3])
302
+ ((1, 2, 3), Multivariate Polynomial Ring in x, y, z, x_ over Finite Field of size 5)
303
+ """
304
+ if arg1 is None and arg2 is None and names is None:
305
+ # this is used for pickling
306
+ if degrees is None:
307
+ return (base_ring,)
308
+ return tuple(degrees), base_ring
309
+ # test if we can use libSingular/letterplace
310
+ if implementation == "letterplace":
311
+ if order is None:
312
+ order = 'degrevlex' if degrees is None else 'deglex'
313
+ args = [arg for arg in (arg1, arg2) if arg is not None]
314
+ kwds = {'sparse': sparse, 'order': order, 'implementation': "singular"}
315
+ if name is not None:
316
+ kwds["name"] = name
317
+ if names is not None:
318
+ kwds["names"] = names
319
+ PolRing = PolynomialRing(base_ring, *args, **kwds)
320
+ if degrees is None:
321
+ return (PolRing,)
322
+ from sage.rings.polynomial.term_order import TermOrder
323
+ T = TermOrder(PolRing.term_order(), PolRing.ngens() + 1)
324
+ varnames = list(PolRing.variable_names())
325
+ newname = 'x'
326
+ while newname in varnames:
327
+ newname += '_'
328
+ varnames.append(newname)
329
+ R = PolynomialRing(
330
+ PolRing.base(), varnames,
331
+ sparse=sparse, order=T)
332
+ return tuple(degrees), R
333
+ # normalise the generator names
334
+ from sage.rings.integer import Integer
335
+ if isinstance(arg1, (Integer, int)):
336
+ arg1, arg2 = arg2, arg1
337
+ if names is not None:
338
+ arg1 = names
339
+ elif name is not None:
340
+ arg1 = name
341
+ if arg2 is None:
342
+ arg2 = len(arg1)
343
+ names = normalize_names(arg2, arg1)
344
+ if degrees is None:
345
+ return base_ring, names
346
+ if degrees in ZZ:
347
+ return base_ring, names, (degrees,) * len(names)
348
+ return base_ring, names, tuple(degrees)
349
+
350
+ def create_object(self, version, key):
351
+ """
352
+ Construct the free algebra that belongs to a unique key.
353
+
354
+ NOTE:
355
+
356
+ Of course, that method should not be called directly,
357
+ since it does not use the cache of free algebras.
358
+
359
+ TESTS::
360
+
361
+ sage: FreeAlgebra.create_object('4.7.1', (QQ['x','y'],)) # needs sage.libs.singular
362
+ Free Associative Unital Algebra on 2 generators (x, y) over Rational Field
363
+ sage: FreeAlgebra.create_object('4.7.1', (QQ['x','y'],)) is FreeAlgebra(QQ,['x','y']) # needs sage.libs.singular
364
+ False
365
+ """
366
+ if len(key) == 1:
367
+ from sage.algebras.letterplace.free_algebra_letterplace import FreeAlgebra_letterplace
368
+ return FreeAlgebra_letterplace(key[0])
369
+ if isinstance(key[0], tuple):
370
+ from sage.algebras.letterplace.free_algebra_letterplace import FreeAlgebra_letterplace
371
+ return FreeAlgebra_letterplace(key[1], degrees=key[0])
372
+ if len(key) == 2:
373
+ return FreeAlgebra_generic(key[0], len(key[1]), key[1])
374
+ return FreeAlgebra_generic(key[0], len(key[1]), key[1], key[2])
375
+
376
+
377
+ FreeAlgebra = FreeAlgebraFactory('FreeAlgebra')
378
+
379
+
380
+ def is_FreeAlgebra(x) -> bool:
381
+ """
382
+ Return ``True`` if x is a free algebra; otherwise, return ``False``.
383
+
384
+ EXAMPLES::
385
+
386
+ sage: from sage.algebras.free_algebra import is_FreeAlgebra
387
+ sage: is_FreeAlgebra(5)
388
+ doctest:warning...
389
+ DeprecationWarning: the function is_FreeAlgebra is deprecated;
390
+ use 'isinstance(..., (FreeAlgebra_generic, FreeAlgebra_letterplace))' instead
391
+ See https://github.com/sagemath/sage/issues/37896 for details.
392
+ False
393
+ sage: is_FreeAlgebra(ZZ)
394
+ False
395
+ sage: is_FreeAlgebra(FreeAlgebra(ZZ,100,'x'))
396
+ True
397
+ sage: is_FreeAlgebra(FreeAlgebra(ZZ,10,'x',implementation='letterplace')) # needs sage.libs.singular
398
+ True
399
+ sage: is_FreeAlgebra(FreeAlgebra(ZZ,10,'x',implementation='letterplace', # needs sage.libs.singular
400
+ ....: degrees=list(range(1,11))))
401
+ True
402
+ """
403
+ from sage.misc.superseded import deprecation
404
+ deprecation(37896, "the function is_FreeAlgebra is deprecated; use 'isinstance(..., (FreeAlgebra_generic, FreeAlgebra_letterplace))' instead")
405
+ return isinstance(x, (FreeAlgebra_generic, FreeAlgebra_letterplace))
406
+
407
+
408
+ class FreeAlgebra_generic(CombinatorialFreeModule):
409
+ """
410
+ The free algebra on `n` generators over a base ring.
411
+
412
+ INPUT:
413
+
414
+ - ``R`` -- a ring
415
+ - ``n`` -- integer
416
+ - ``names`` -- the generator names
417
+ - ``degrees`` -- (optional) a tuple or list specifying the
418
+ degrees of all the generators, if omitted, the algebra is not
419
+ graded
420
+
421
+ EXAMPLES::
422
+
423
+ sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F
424
+ Free Algebra on 3 generators (x, y, z) over Rational Field
425
+ sage: mul(F.gens())
426
+ x*y*z
427
+ sage: mul([ F.gen(i%3) for i in range(12) ])
428
+ x*y*z*x*y*z*x*y*z*x*y*z
429
+ sage: mul([ F.gen(i%3) for i in range(12) ]) + mul([ F.gen(i%2) for i in range(12) ])
430
+ x*y*x*y*x*y*x*y*x*y*x*y + x*y*z*x*y*z*x*y*z*x*y*z
431
+ sage: (2 + x*z + x^2)^2 + (x - y)^2
432
+ 4 + 5*x^2 - x*y + 4*x*z - y*x + y^2 + x^4 + x^3*z + x*z*x^2 + x*z*x*z
433
+
434
+ TESTS:
435
+
436
+ Free algebras commute with their base ring::
437
+
438
+ sage: K.<a,b> = FreeAlgebra(QQ)
439
+ sage: K.is_commutative()
440
+ False
441
+ sage: L.<c,d> = FreeAlgebra(K)
442
+ sage: L.is_commutative()
443
+ False
444
+ sage: s = a*b^2 * c^3; s
445
+ a*b^2*c^3
446
+ sage: parent(s)
447
+ Free Algebra on 2 generators (c, d) over Free Algebra on 2 generators (a, b) over Rational Field
448
+ sage: c^3 * a * b^2
449
+ a*b^2*c^3
450
+
451
+ Two free algebras are considered the same if they have the same
452
+ base ring, number of generators and variable names, and the same
453
+ implementation::
454
+
455
+ sage: F = FreeAlgebra(QQ,3,'x')
456
+ sage: F == FreeAlgebra(QQ,3,'x')
457
+ True
458
+ sage: F is FreeAlgebra(QQ,3,'x')
459
+ True
460
+ sage: F == FreeAlgebra(ZZ,3,'x')
461
+ False
462
+ sage: F == FreeAlgebra(QQ,4,'x')
463
+ False
464
+ sage: F == FreeAlgebra(QQ,3,'y')
465
+ False
466
+
467
+ Note that since :issue:`7797` there is a different
468
+ implementation of free algebras. Two corresponding free
469
+ algebras in different implementations are not equal, but there
470
+ is a coercion.
471
+ """
472
+ Element = FreeAlgebraElement
473
+
474
+ def __init__(self, R, n, names, degrees=None):
475
+ """
476
+ The free algebra on `n` generators over a base ring.
477
+
478
+ EXAMPLES::
479
+
480
+ sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F # indirect doctest
481
+ Free Algebra on 3 generators (x, y, z) over Rational Field
482
+
483
+ TESTS:
484
+
485
+ Note that the following is *not* the recommended way to create
486
+ a free algebra::
487
+
488
+ sage: from sage.algebras.free_algebra import FreeAlgebra_generic
489
+ sage: FreeAlgebra_generic(ZZ, 3, 'abc')
490
+ Free Algebra on 3 generators (a, b, c) over Integer Ring
491
+ """
492
+ if R not in Rings():
493
+ raise TypeError("argument R must be a ring")
494
+ self.__ngens = n
495
+ indices = FreeMonoid(n, names=names)
496
+ cat = AlgebrasWithBasis(R)
497
+ if self.__ngens <= 1 and R.is_commutative():
498
+ cat = cat.Commutative()
499
+ if degrees is not None:
500
+ if len(degrees) != len(names) or not all(d in ZZ for d in degrees):
501
+ raise ValueError("argument degrees must specify an integer for each generator")
502
+ cat = cat.Graded()
503
+
504
+ CombinatorialFreeModule.__init__(self, R, indices, prefix='F',
505
+ category=cat)
506
+ self._assign_names(indices.variable_names())
507
+ if degrees is None:
508
+ self._degrees = None
509
+ else:
510
+ self._degrees = {g: ZZ(d) for g, d in zip(self.monoid().gens(), degrees)}
511
+
512
+ def construction(self):
513
+ """
514
+ Return the construction of ``self``.
515
+
516
+ EXAMPLES::
517
+
518
+ sage: F, R = algebras.Free(QQ,4,'x,y,z,t').construction(); F
519
+ Associative[x,y,z,t]
520
+ """
521
+ return AssociativeFunctor(self.variable_names(), self._degrees), self.base_ring()
522
+
523
+ def one_basis(self):
524
+ """
525
+ Return the index of the basis element `1`.
526
+
527
+ EXAMPLES::
528
+
529
+ sage: F = FreeAlgebra(QQ, 2, 'x,y')
530
+ sage: F.one_basis()
531
+ 1
532
+ sage: F.one_basis().parent()
533
+ Free monoid on 2 generators (x, y)
534
+ """
535
+ return self._indices.one()
536
+
537
+ def is_field(self, proof=True) -> bool:
538
+ """
539
+ Return ``True`` if this Free Algebra is a field.
540
+
541
+ This happens only if the
542
+ base ring is a field and there are no generators
543
+
544
+ EXAMPLES::
545
+
546
+ sage: A = FreeAlgebra(QQ,0,'')
547
+ sage: A.is_field()
548
+ True
549
+ sage: A = FreeAlgebra(QQ,1,'x')
550
+ sage: A.is_field()
551
+ False
552
+ """
553
+ if self.__ngens == 0:
554
+ return self.base_ring().is_field(proof)
555
+ return False
556
+
557
+ def _repr_(self) -> str:
558
+ """
559
+ Text representation of this free algebra.
560
+
561
+ EXAMPLES::
562
+
563
+ sage: F = FreeAlgebra(QQ, 3, 'x')
564
+ sage: F # indirect doctest
565
+ Free Algebra on 3 generators (x0, x1, x2) over Rational Field
566
+ sage: F.rename('QQ<<x0,x1,x2>>')
567
+ sage: F # indirect doctest
568
+ QQ<<x0,x1,x2>>
569
+ sage: FreeAlgebra(ZZ, 1, ['a'])
570
+ Free Algebra on 1 generator (a,) over Integer Ring
571
+
572
+ sage: FreeAlgebra(QQ, 2, ['x', 'y'], degrees=(2,1))
573
+ Free Algebra on 2 generators (x, y) with degrees (2, 1) over Rational Field
574
+ """
575
+ txt = "generator" if self.__ngens == 1 else "generators"
576
+ if self._degrees is None:
577
+ return "Free Algebra on {} {} {} over {}".format(
578
+ self.__ngens, txt, self.gens(), self.base_ring())
579
+ return "Free Algebra on {} {} {} with degrees {} over {}".format(
580
+ self.__ngens, txt, self.gens(), tuple(self._degrees.values()), self.base_ring())
581
+
582
+ def _latex_(self) -> str:
583
+ r"""
584
+ Return a latex representation of ``self``.
585
+
586
+ EXAMPLES::
587
+
588
+ sage: F = FreeAlgebra(QQ,3,'x')
589
+ sage: latex(F)
590
+ \Bold{Q}\langle x_{0}, x_{1}, x_{2}\rangle
591
+ sage: F = FreeAlgebra(ZZ['q'], 3, 'a,b,c')
592
+ sage: latex(F)
593
+ \Bold{Z}[q]\langle a, b, c\rangle
594
+ """
595
+ from sage.misc.latex import latex
596
+ return "{}\\langle {}\\rangle".format(latex(self.base_ring()),
597
+ ', '.join(self.latex_variable_names()))
598
+
599
+ def _element_constructor_(self, x):
600
+ """
601
+ Convert ``x`` into ``self``.
602
+
603
+ EXAMPLES::
604
+
605
+ sage: R.<x,y> = FreeAlgebra(QQ,2)
606
+ sage: R(3) # indirect doctest
607
+ 3
608
+
609
+ TESTS::
610
+
611
+ sage: # needs sage.libs.singular
612
+ sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
613
+ sage: L.<x,y,z> = FreeAlgebra(ZZ,3,implementation='letterplace')
614
+ sage: F(x) # indirect doctest
615
+ x
616
+ sage: F.1*L.2
617
+ y*z
618
+ sage: (F.1*L.2).parent() is F
619
+ True
620
+
621
+ ::
622
+
623
+ sage: # needs sage.libs.singular sage.rings.finite_rings
624
+ sage: K.<z> = GF(25)
625
+ sage: F.<a,b,c> = FreeAlgebra(K,3)
626
+ sage: L.<a,b,c> = FreeAlgebra(K,3, implementation='letterplace')
627
+ sage: F.1 + (z+1)*L.2
628
+ b + (z+1)*c
629
+
630
+ Check that :issue:`15169` is fixed::
631
+
632
+ sage: A.<x> = FreeAlgebra(CC)
633
+ sage: A(2)
634
+ 2.00000000000000
635
+
636
+ We check that the string coercions work correctly over
637
+ inexact fields::
638
+
639
+ sage: F.<x,y> = FreeAlgebra(CC)
640
+ sage: F('2')
641
+ 2.00000000000000
642
+ sage: F('x')
643
+ 1.00000000000000*x
644
+
645
+ Check that it also converts factorizations::
646
+
647
+ sage: f = Factorization([(x,2),(y,3)]); f
648
+ 1.00000000000000*x^2 * 1.00000000000000*y^3
649
+ sage: F(f)
650
+ 1.00000000000000*x^2*y^3
651
+
652
+ Check for extended coercion::
653
+
654
+ sage: A = algebras.Free(QQ,['x','y'])
655
+ sage: B = algebras.Free(QQ,['y'])
656
+ sage: y, = B.gens()
657
+ sage: A(4+y)
658
+ 4 + y
659
+ """
660
+ if isinstance(x, FreeAlgebraElement):
661
+ P = x.parent()
662
+ if P is self:
663
+ return x
664
+ # from another FreeAlgebra:
665
+ if x not in self.base_ring():
666
+ D = {self.monoid()(T): cf
667
+ for T, cf in x.monomial_coefficients().items()}
668
+ return self.element_class(self, D)
669
+ elif hasattr(x, 'letterplace_polynomial'):
670
+ P = x.parent()
671
+ if self.has_coerce_map_from(P): # letterplace versus generic
672
+ ngens = P.ngens()
673
+ M = self._indices
674
+
675
+ def exp_to_monomial(T):
676
+ return M([(i % ngens, Ti) for i, Ti in enumerate(T) if Ti])
677
+
678
+ return self.element_class(self, {exp_to_monomial(T): c
679
+ for T, c in x.letterplace_polynomial().monomial_coefficients().items()})
680
+ # ok, not a free algebra element (or should not be viewed as one).
681
+ if isinstance(x, str):
682
+ from sage.misc.sage_eval import sage_eval
683
+ G = self.gens()
684
+ d = {str(v): G[i] for i, v in enumerate(self.variable_names())}
685
+ return self(sage_eval(x, locals=d))
686
+ R = self.base_ring()
687
+ # coercion from free monoid
688
+ if isinstance(x, FreeMonoidElement) and x.parent() is self._indices:
689
+ return self.element_class(self, {x: R.one()})
690
+ # coercion from the PBW basis
691
+ if isinstance(x, PBWBasisOfFreeAlgebra.Element) \
692
+ and self.has_coerce_map_from(x.parent()._alg):
693
+ return self(x.parent().expansion(x))
694
+
695
+ # Check if it's a factorization
696
+ from sage.structure.factorization import Factorization
697
+ if isinstance(x, Factorization):
698
+ return self.prod(f**i for f, i in x)
699
+
700
+ # coercion via base ring
701
+ x = R(x)
702
+ if x == 0:
703
+ return self.element_class(self, {})
704
+ return self.element_class(self, {self.one_basis(): x})
705
+
706
+ def _coerce_map_from_(self, R) -> bool:
707
+ """
708
+ Return ``True`` if there is a coercion from ``R`` into ``self`` and
709
+ ``False`` otherwise.
710
+
711
+ The things that coerce into ``self`` are:
712
+
713
+ - This free algebra.
714
+
715
+ - The PBW basis of ``self``.
716
+
717
+ - Free algebras in some subset of variables
718
+ over a base with a coercion map into ``self.base_ring()``.
719
+
720
+ - The underlying monoid.
721
+
722
+ - Anything with a coercion into ``self.monoid()``.
723
+
724
+ - Anything with a coercion into ``self.base_ring()``.
725
+
726
+ TESTS::
727
+
728
+ sage: F = FreeAlgebra(ZZ, 3, 'x,y,z')
729
+ sage: G = FreeAlgebra(QQ, 3, 'x,y,z')
730
+ sage: H = FreeAlgebra(ZZ, 1, 'y')
731
+ sage: F._coerce_map_from_(G)
732
+ False
733
+ sage: G._coerce_map_from_(F)
734
+ True
735
+ sage: F._coerce_map_from_(H)
736
+ True
737
+ sage: F._coerce_map_from_(QQ)
738
+ False
739
+ sage: G._coerce_map_from_(QQ)
740
+ True
741
+ sage: F._coerce_map_from_(G.monoid())
742
+ True
743
+ sage: F._coerce_map_from_(F.pbw_basis())
744
+ True
745
+ sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z'))
746
+ False
747
+
748
+ sage: # needs sage.rings.finite_rings
749
+ sage: K.<z> = GF(25)
750
+ sage: F.<a,b,c> = FreeAlgebra(K,3)
751
+ sage: F._coerce_map_from_(ZZ)
752
+ True
753
+ sage: F._coerce_map_from_(QQ)
754
+ False
755
+ sage: F._coerce_map_from_(F.monoid())
756
+ True
757
+ sage: F._coerce_map_from_(F.pbw_basis())
758
+ True
759
+ sage: G = FreeAlgebra(ZZ, 3, 'a,b,c')
760
+ sage: F._coerce_map_from_(G)
761
+ True
762
+ sage: G._coerce_map_from_(F)
763
+ False
764
+ sage: L.<a,b,c> = FreeAlgebra(K,3, implementation='letterplace') # needs sage.libs.singular
765
+ sage: F.1 + (z+1) * L.2 # needs sage.libs.singular
766
+ b + (z+1)*c
767
+ """
768
+ if self._indices.has_coerce_map_from(R):
769
+ return True
770
+
771
+ # free algebras in the same variable over any base that coerces in:
772
+ if isinstance(R, (FreeAlgebra_generic, FreeAlgebra_letterplace)):
773
+ if all(x in self.variable_names() for x in R.variable_names()):
774
+ return self.base_ring().has_coerce_map_from(R.base_ring())
775
+ if isinstance(R, PBWBasisOfFreeAlgebra):
776
+ return self.has_coerce_map_from(R._alg)
777
+
778
+ return self.base_ring().has_coerce_map_from(R)
779
+
780
+ def _is_valid_homomorphism_(self, other, im_gens, base_map=None):
781
+ """
782
+ Check that the number of given images is correct.
783
+
784
+ EXAMPLES::
785
+
786
+ sage: ring = algebras.Free(QQ, ['a', 'b'])
787
+ sage: a, b = ring.gens()
788
+ sage: A = matrix(QQ, 2, 2, [1, 5, 1, 5])
789
+ sage: B = matrix(QQ, 2, 2, [1, 4, 9, 2])
790
+ sage: C = matrix(QQ, 2, 2, [1, 7, 8, 9])
791
+ sage: f = ring.hom([A, B])
792
+ sage: f(a*b+1)
793
+ [47 14]
794
+ [46 15]
795
+
796
+ sage: ring.hom([A, B, C])
797
+ Traceback (most recent call last):
798
+ ...
799
+ ValueError: number of images must equal number of generators
800
+ """
801
+ return len(im_gens) == self.__ngens
802
+
803
+ def gen(self, i):
804
+ """
805
+ The ``i``-th generator of the algebra.
806
+
807
+ EXAMPLES::
808
+
809
+ sage: F = FreeAlgebra(ZZ,3,'x,y,z')
810
+ sage: F.gen(0)
811
+ x
812
+ """
813
+ if i < 0 or not i < self.__ngens:
814
+ raise IndexError("argument i (= {}) must be between 0 and {}".format(i, self.__ngens - 1))
815
+ R = self.base_ring()
816
+ F = self._indices
817
+ return self.element_class(self, {F.gen(i): R.one()})
818
+
819
+ @cached_method
820
+ def algebra_generators(self):
821
+ """
822
+ Return the algebra generators of ``self``.
823
+
824
+ EXAMPLES::
825
+
826
+ sage: F = FreeAlgebra(ZZ,3,'x,y,z')
827
+ sage: F.algebra_generators()
828
+ Finite family {'x': x, 'y': y, 'z': z}
829
+ """
830
+ ret = {}
831
+ for i in range(self.__ngens):
832
+ x = self.gen(i)
833
+ ret[str(x)] = x
834
+ from sage.sets.family import Family
835
+ return Family(self.variable_names(), lambda i: ret[i])
836
+
837
+ @cached_method
838
+ def gens(self) -> tuple:
839
+ """
840
+ Return the generators of ``self``.
841
+
842
+ EXAMPLES::
843
+
844
+ sage: F = FreeAlgebra(ZZ,3,'x,y,z')
845
+ sage: F.gens()
846
+ (x, y, z)
847
+ """
848
+ return tuple(self.gen(i) for i in range(self.__ngens))
849
+
850
+ def degree_on_basis(self, m):
851
+ r"""
852
+ Return the degree of the basis element indexed by ``m``.
853
+
854
+ EXAMPLES::
855
+
856
+ sage: A.<a, b> = FreeAlgebra(QQ, degrees=(1, -1))
857
+ sage: m = A.basis().keys()[42]
858
+ sage: m
859
+ a*b*a*b^2
860
+ sage: A.degree_on_basis(m)
861
+ -1
862
+ sage: (a*b*a*b^2).degree()
863
+ -1
864
+ """
865
+ return ZZ.sum(self._degrees[g] * e for g, e in m)
866
+
867
+ def product_on_basis(self, x, y):
868
+ """
869
+ Return the product of the basis elements indexed by ``x`` and ``y``.
870
+
871
+ EXAMPLES::
872
+
873
+ sage: F = FreeAlgebra(ZZ,3,'x,y,z')
874
+ sage: I = F.basis().keys()
875
+ sage: x,y,z = I.gens()
876
+ sage: F.product_on_basis(x*y, z*y)
877
+ x*y*z*y
878
+ """
879
+ return self.monomial(x * y)
880
+
881
+ def quotient(self, mons, mats=None, names=None, **args):
882
+ """
883
+ Return a quotient algebra.
884
+
885
+ The quotient algebra is defined via the action of a free algebra
886
+ `A` on a (finitely generated) free module. The input for the quotient
887
+ algebra is a list of monomials (in the underlying monoid for `A`)
888
+ which form a free basis for the module of `A`, and a list of
889
+ matrices, which give the action of the free generators of `A` on this
890
+ monomial basis.
891
+
892
+ EXAMPLES:
893
+
894
+ Here is the quaternion algebra defined in terms of three generators::
895
+
896
+ sage: n = 3
897
+ sage: A = FreeAlgebra(QQ,n,'i')
898
+ sage: F = A.monoid()
899
+ sage: i, j, k = F.gens()
900
+ sage: mons = [ F(1), i, j, k ]
901
+ sage: M = MatrixSpace(QQ,4)
902
+ sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]),
903
+ ....: M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]),
904
+ ....: M([0,0,0,1, 0,0,-1,0, 0,1,0,0, -1,0,0,0]) ]
905
+ sage: H.<i,j,k> = A.quotient(mons, mats); H
906
+ Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4
907
+ over Rational Field
908
+ """
909
+ if mats is None:
910
+ return super().quotient(mons, names)
911
+ from . import free_algebra_quotient
912
+ return free_algebra_quotient.FreeAlgebraQuotient(self, mons, mats, names)
913
+
914
+ quo = quotient
915
+
916
+ def ngens(self):
917
+ """
918
+ The number of generators of the algebra.
919
+
920
+ EXAMPLES::
921
+
922
+ sage: F = FreeAlgebra(ZZ,3,'x,y,z')
923
+ sage: F.ngens()
924
+ 3
925
+ """
926
+ return self.__ngens
927
+
928
+ def monoid(self):
929
+ """
930
+ The free monoid of generators of the algebra.
931
+
932
+ EXAMPLES::
933
+
934
+ sage: F = FreeAlgebra(ZZ,3,'x,y,z')
935
+ sage: F.monoid()
936
+ Free monoid on 3 generators (x, y, z)
937
+ """
938
+ return self._indices
939
+
940
+ def g_algebra(self, relations, names=None, order='degrevlex', check=True):
941
+ """
942
+ The `G`-Algebra derived from this algebra by relations.
943
+
944
+ By default it is assumed that any two variables commute.
945
+
946
+ .. TODO::
947
+
948
+ - Coercion doesn't work yet, there is some cheating about assumptions
949
+ - The optional argument ``check`` controls checking the degeneracy
950
+ conditions. Furthermore, the default values interfere with
951
+ non-degeneracy conditions.
952
+
953
+ EXAMPLES::
954
+
955
+ sage: # needs sage.libs.singular
956
+ sage: A.<x,y,z> = FreeAlgebra(QQ,3)
957
+ sage: G = A.g_algebra({y*x: -x*y})
958
+ sage: (x,y,z) = G.gens()
959
+ sage: x*y
960
+ x*y
961
+ sage: y*x
962
+ -x*y
963
+ sage: z*x
964
+ x*z
965
+ sage: (x,y,z) = A.gens()
966
+ sage: G = A.g_algebra({y*x: -x*y + 1})
967
+ sage: (x,y,z) = G.gens()
968
+ sage: y*x
969
+ -x*y + 1
970
+ sage: (x,y,z) = A.gens()
971
+ sage: G = A.g_algebra({y*x: -x*y + z})
972
+ sage: (x,y,z) = G.gens()
973
+ sage: y*x
974
+ -x*y + z
975
+
976
+ TESTS::
977
+
978
+ sage: # needs sage.libs.singular
979
+ sage: S = FractionField(QQ['t'])
980
+ sage: t = S.gen()
981
+ sage: F.<x,y> = FreeAlgebra(S)
982
+ sage: K = F.g_algebra({y*x: -x*y + 1 + y})
983
+ sage: x,y = K.gens()
984
+ sage: 1 + t*y*x
985
+ (-t)*x*y + t*y + (t + 1)
986
+ """
987
+ from sage.matrix.constructor import Matrix
988
+ commutative = not relations
989
+
990
+ base_ring = self.base_ring()
991
+ polynomial_ring = PolynomialRing(base_ring, self.gens())
992
+ n = self.__ngens
993
+ cmat = Matrix(base_ring, n)
994
+ dmat = Matrix(polynomial_ring, n)
995
+ for i in range(n):
996
+ for j in range(i + 1, n):
997
+ cmat[i, j] = 1
998
+ for to_commute, commuted in relations.items():
999
+ # This is dirty, coercion is broken
1000
+ assert isinstance(to_commute, FreeAlgebraElement), to_commute
1001
+ assert isinstance(commuted, FreeAlgebraElement), commuted
1002
+ (v1, e1), (v2, e2) = next(iter(to_commute))[0]
1003
+ assert e1 == 1
1004
+ assert e2 == 1
1005
+ assert v1 > v2
1006
+ c_coef = None
1007
+ d_poly = None
1008
+ reverse_monomial = v2 * v1
1009
+ for m, c in commuted:
1010
+ if m == reverse_monomial:
1011
+ c_coef = c
1012
+ # buggy coercion workaround
1013
+ d_poly = commuted - c * self.monomial(m)
1014
+ break
1015
+ assert c_coef is not None, m
1016
+ v2_ind = self.gens().index(v2)
1017
+ v1_ind = self.gens().index(v1)
1018
+ cmat[v2_ind, v1_ind] = c_coef
1019
+ if d_poly:
1020
+ dmat[v2_ind, v1_ind] = polynomial_ring(d_poly)
1021
+ from sage.rings.polynomial.plural import g_Algebra
1022
+ return g_Algebra(base_ring, cmat, dmat,
1023
+ names=names or self.variable_names(),
1024
+ order=order, check=check, commutative=commutative)
1025
+
1026
+ def poincare_birkhoff_witt_basis(self):
1027
+ """
1028
+ Return the Poincaré-Birkhoff-Witt (PBW) basis of ``self``.
1029
+
1030
+ EXAMPLES::
1031
+
1032
+ sage: F.<x,y> = FreeAlgebra(QQ, 2)
1033
+ sage: F.poincare_birkhoff_witt_basis()
1034
+ The Poincare-Birkhoff-Witt basis of Free Algebra on 2 generators (x, y) over Rational Field
1035
+ """
1036
+ return PBWBasisOfFreeAlgebra(self)
1037
+
1038
+ pbw_basis = poincare_birkhoff_witt_basis
1039
+
1040
+ def pbw_element(self, elt):
1041
+ """
1042
+ Return the element ``elt`` in the Poincaré-Birkhoff-Witt basis.
1043
+
1044
+ EXAMPLES::
1045
+
1046
+ sage: F.<x,y> = FreeAlgebra(QQ, 2)
1047
+ sage: F.pbw_element(x*y - y*x + 2)
1048
+ 2*PBW[1] + PBW[x*y]
1049
+ sage: F.pbw_element(F.one())
1050
+ PBW[1]
1051
+ sage: F.pbw_element(x*y*x + x^3*y)
1052
+ PBW[x*y]*PBW[x] + PBW[y]*PBW[x]^2 + PBW[x^3*y]
1053
+ + 3*PBW[x^2*y]*PBW[x] + 3*PBW[x*y]*PBW[x]^2 + PBW[y]*PBW[x]^3
1054
+ """
1055
+ PBW = self.pbw_basis()
1056
+ if elt == self.zero():
1057
+ return PBW.zero()
1058
+
1059
+ l = {}
1060
+ while elt: # != 0
1061
+ lst = list(elt)
1062
+ support = [i[0].to_word() for i in lst]
1063
+ min_elt = support[0]
1064
+ for word in support[1:len(support) - 1]:
1065
+ if min_elt.lex_less(word):
1066
+ min_elt = word
1067
+ coeff = lst[support.index(min_elt)][1]
1068
+ min_elt = min_elt.to_monoid_element()
1069
+ l[min_elt] = l.get(min_elt, 0) + coeff
1070
+ elt = elt - coeff * self.lie_polynomial(min_elt)
1071
+ return PBW.sum_of_terms([(k, v) for k, v in l.items() if v != 0], distinct=True)
1072
+
1073
+ def lie_polynomial(self, w):
1074
+ """
1075
+ Return the Lie polynomial associated to the Lyndon word ``w``. If
1076
+ ``w`` is not Lyndon, then return the product of Lie polynomials of
1077
+ the Lyndon factorization of ``w``.
1078
+
1079
+ Given a Lyndon word `w`, the Lie polynomial `L_w` is defined
1080
+ recursively by `L_w = [L_u, L_v]`, where `w = uv` is the
1081
+ :meth:`standard factorization
1082
+ <sage.combinat.words.finite_word.FiniteWord_class.standard_factorization>`
1083
+ of `w`, and `L_w = w` when `w` is a single letter.
1084
+
1085
+ INPUT:
1086
+
1087
+ - ``w`` -- a word or an element of the free monoid
1088
+
1089
+ EXAMPLES::
1090
+
1091
+ sage: F = FreeAlgebra(QQ, 3, 'x,y,z')
1092
+ sage: M.<x,y,z> = FreeMonoid(3)
1093
+ sage: F.lie_polynomial(x*y)
1094
+ x*y - y*x
1095
+ sage: F.lie_polynomial(y*x)
1096
+ y*x
1097
+ sage: F.lie_polynomial(x^2*y*x)
1098
+ x^2*y*x - 2*x*y*x^2 + y*x^3
1099
+ sage: F.lie_polynomial(y*z*x*z*x*z)
1100
+ y*z*x*z*x*z - y*z*x*z^2*x - y*z^2*x^2*z + y*z^2*x*z*x
1101
+ - z*y*x*z*x*z + z*y*x*z^2*x + z*y*z*x^2*z - z*y*z*x*z*x
1102
+
1103
+ TESTS:
1104
+
1105
+ We test some corner cases and alternative inputs::
1106
+
1107
+ sage: F = FreeAlgebra(QQ, 3, 'x,y,z')
1108
+ sage: M.<x,y,z> = FreeMonoid(3)
1109
+ sage: F.lie_polynomial(Word('xy'))
1110
+ x*y - y*x
1111
+ sage: F.lie_polynomial('xy')
1112
+ x*y - y*x
1113
+ sage: F.lie_polynomial(M.one())
1114
+ 1
1115
+ sage: F.lie_polynomial(Word([]))
1116
+ 1
1117
+ sage: F.lie_polynomial('')
1118
+ 1
1119
+
1120
+ We check that :issue:`22251` is fixed::
1121
+
1122
+ sage: F.lie_polynomial(x*y*z)
1123
+ x*y*z - x*z*y - y*z*x + z*y*x
1124
+ """
1125
+ if not w:
1126
+ return self.one()
1127
+ M = self._indices
1128
+
1129
+ if len(w) == 1:
1130
+ return self(M(w))
1131
+
1132
+ ret = self.one()
1133
+ # We have to be careful about order here.
1134
+ # Since the Lyndon factors appear from left to right
1135
+ # we must multiply from left to right as well.
1136
+ for factor in Word(w).lyndon_factorization():
1137
+ if len(factor) == 1:
1138
+ ret = ret * self(M(factor))
1139
+ continue
1140
+ x, y = factor.standard_factorization()
1141
+ x = self.lie_polynomial(M(x))
1142
+ y = self.lie_polynomial(M(y))
1143
+ ret = ret * (x * y - y * x)
1144
+ return ret
1145
+
1146
+
1147
+ class PBWBasisOfFreeAlgebra(CombinatorialFreeModule):
1148
+ """
1149
+ The Poincaré-Birkhoff-Witt basis of the free algebra.
1150
+
1151
+ EXAMPLES::
1152
+
1153
+ sage: F.<x,y> = FreeAlgebra(QQ, 2)
1154
+ sage: PBW = F.pbw_basis()
1155
+ sage: px, py = PBW.gens()
1156
+ sage: px * py
1157
+ PBW[x*y] + PBW[y]*PBW[x]
1158
+ sage: py * px
1159
+ PBW[y]*PBW[x]
1160
+ sage: px * py^3 * px - 2*px * py
1161
+ -2*PBW[x*y] - 2*PBW[y]*PBW[x] + PBW[x*y^3]*PBW[x]
1162
+ + 3*PBW[y]*PBW[x*y^2]*PBW[x] + 3*PBW[y]^2*PBW[x*y]*PBW[x]
1163
+ + PBW[y]^3*PBW[x]^2
1164
+
1165
+ We can convert between the two bases::
1166
+
1167
+ sage: p = PBW(x*y - y*x + 2); p
1168
+ 2*PBW[1] + PBW[x*y]
1169
+ sage: F(p)
1170
+ 2 + x*y - y*x
1171
+ sage: f = F.pbw_element(x*y*x + x^3*y + x + 3)
1172
+ sage: F(PBW(f)) == f
1173
+ True
1174
+ sage: p = px*py + py^4*px^2
1175
+ sage: F(p)
1176
+ x*y + y^4*x^2
1177
+ sage: PBW(F(p)) == p
1178
+ True
1179
+
1180
+ Note that multiplication in the PBW basis agrees with multiplication
1181
+ as monomials::
1182
+
1183
+ sage: F(px * py^3 * px - 2*px * py) == x*y^3*x - 2*x*y
1184
+ True
1185
+
1186
+ We verify Examples 1 and 2 in [MR1989]_::
1187
+
1188
+ sage: F.<x,y,z> = FreeAlgebra(QQ)
1189
+ sage: PBW = F.pbw_basis()
1190
+ sage: PBW(x*y*z)
1191
+ PBW[x*y*z] + PBW[x*z*y] + PBW[y]*PBW[x*z] + PBW[y*z]*PBW[x]
1192
+ + PBW[z]*PBW[x*y] + PBW[z]*PBW[y]*PBW[x]
1193
+ sage: PBW(x*y*y*x)
1194
+ PBW[x*y^2]*PBW[x] + 2*PBW[y]*PBW[x*y]*PBW[x] + PBW[y]^2*PBW[x]^2
1195
+
1196
+ TESTS:
1197
+
1198
+ Check that going between the two bases is the identity::
1199
+
1200
+ sage: F = FreeAlgebra(QQ, 2, 'x,y')
1201
+ sage: PBW = F.pbw_basis()
1202
+ sage: M = F.monoid()
1203
+ sage: L = [j.to_monoid_element() for i in range(6) for j in Words('xy', i)]
1204
+ sage: all(PBW(F(PBW(m))) == PBW(m) for m in L)
1205
+ True
1206
+ sage: all(F(PBW(F(m))) == F(m) for m in L)
1207
+ True
1208
+ """
1209
+ @staticmethod
1210
+ def __classcall_private__(cls, R, n=None, names=None):
1211
+ """
1212
+ Normalize input to ensure a unique representation.
1213
+
1214
+ EXAMPLES::
1215
+
1216
+ sage: from sage.algebras.free_algebra import PBWBasisOfFreeAlgebra
1217
+ sage: PBW1 = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
1218
+ sage: PBW2.<x,y> = PBWBasisOfFreeAlgebra(QQ)
1219
+ sage: PBW3 = PBWBasisOfFreeAlgebra(QQ, 2, ['x','y'])
1220
+ sage: PBW1 is PBW2 and PBW2 is PBW3
1221
+ True
1222
+ """
1223
+ if n is None and names is None:
1224
+ if not isinstance(R, FreeAlgebra_generic):
1225
+ raise ValueError("{} is not a free algebra".format(R))
1226
+ alg = R
1227
+ else:
1228
+ if n is None:
1229
+ n = len(names)
1230
+ alg = FreeAlgebra(R, n, names)
1231
+ return super().__classcall__(cls, alg)
1232
+
1233
+ def __init__(self, alg):
1234
+ """
1235
+ Initialize ``self``.
1236
+
1237
+ EXAMPLES::
1238
+
1239
+ sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
1240
+ sage: TestSuite(PBW).run()
1241
+ """
1242
+ R = alg.base_ring()
1243
+ self._alg = alg
1244
+ category = AlgebrasWithBasis(R)
1245
+ CombinatorialFreeModule.__init__(self, R, alg.monoid(), prefix='PBW',
1246
+ category=category)
1247
+ self._assign_names(alg.variable_names())
1248
+
1249
+ def _repr_(self):
1250
+ """
1251
+ Return a string representation of ``self``.
1252
+
1253
+ EXAMPLES::
1254
+
1255
+ sage: FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
1256
+ The Poincare-Birkhoff-Witt basis of Free Algebra on 2 generators (x, y) over Rational Field
1257
+ """
1258
+ return "The Poincare-Birkhoff-Witt basis of {}".format(self._alg)
1259
+
1260
+ def _repr_term(self, w):
1261
+ """
1262
+ Return a representation of term indexed by ``w``.
1263
+
1264
+ EXAMPLES::
1265
+
1266
+ sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
1267
+ sage: x,y = PBW.gens()
1268
+ sage: x*y # indirect doctest
1269
+ PBW[x*y] + PBW[y]*PBW[x]
1270
+ sage: y*x
1271
+ PBW[y]*PBW[x]
1272
+ sage: x^3
1273
+ PBW[x]^3
1274
+ sage: PBW.one()
1275
+ PBW[1]
1276
+ sage: 3*PBW.one()
1277
+ 3*PBW[1]
1278
+ """
1279
+ if len(w) == 0:
1280
+ return super()._repr_term(w)
1281
+ ret = ''
1282
+ p = 1
1283
+ cur = None
1284
+ for x in w.to_word().lyndon_factorization():
1285
+ if x == cur:
1286
+ p += 1
1287
+ else:
1288
+ if len(ret) != 0:
1289
+ if p != 1:
1290
+ ret += "^{}".format(p)
1291
+ ret += "*"
1292
+ ret += super()._repr_term(x.to_monoid_element())
1293
+ cur = x
1294
+ p = 1
1295
+ if p != 1:
1296
+ ret += "^{}".format(p)
1297
+ return ret
1298
+
1299
+ def _element_constructor_(self, x):
1300
+ """
1301
+ Convert ``x`` into ``self``.
1302
+
1303
+ EXAMPLES::
1304
+
1305
+ sage: F.<x,y> = FreeAlgebra(QQ, 2)
1306
+ sage: R = F.pbw_basis()
1307
+ sage: R(3)
1308
+ 3*PBW[1]
1309
+ sage: R(x*y)
1310
+ PBW[x*y] + PBW[y]*PBW[x]
1311
+ """
1312
+ if isinstance(x, FreeAlgebraElement):
1313
+ return self._alg.pbw_element(self._alg(x))
1314
+ return CombinatorialFreeModule._element_constructor_(self, x)
1315
+
1316
+ def _coerce_map_from_(self, R):
1317
+ """
1318
+ Return ``True`` if there is a coercion from ``R`` into ``self`` and
1319
+ ``False`` otherwise. The things that coerce into ``self`` are:
1320
+
1321
+ - Anything that coerces into the associated free algebra of ``self``
1322
+
1323
+ TESTS::
1324
+
1325
+ sage: F = FreeAlgebra(ZZ, 3, 'x,y,z').pbw_basis()
1326
+ sage: G = FreeAlgebra(QQ, 3, 'x,y,z').pbw_basis()
1327
+ sage: H = FreeAlgebra(ZZ, 1, 'y').pbw_basis()
1328
+ sage: F._coerce_map_from_(G)
1329
+ False
1330
+ sage: G._coerce_map_from_(F)
1331
+ True
1332
+ sage: F._coerce_map_from_(H)
1333
+ True
1334
+ sage: F._coerce_map_from_(QQ)
1335
+ False
1336
+ sage: G._coerce_map_from_(QQ)
1337
+ True
1338
+ sage: F._coerce_map_from_(G._alg.monoid())
1339
+ True
1340
+ sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z'))
1341
+ False
1342
+ sage: F.has_coerce_map_from(FreeAlgebra(ZZ, 3, 'x,y,z'))
1343
+ True
1344
+ """
1345
+ return self._alg.has_coerce_map_from(R)
1346
+
1347
+ def one_basis(self):
1348
+ """
1349
+ Return the index of the basis element for `1`.
1350
+
1351
+ EXAMPLES::
1352
+
1353
+ sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
1354
+ sage: PBW.one_basis()
1355
+ 1
1356
+ sage: PBW.one_basis().parent()
1357
+ Free monoid on 2 generators (x, y)
1358
+ """
1359
+ return self._indices.one()
1360
+
1361
+ def algebra_generators(self):
1362
+ """
1363
+ Return the generators of ``self`` as an algebra.
1364
+
1365
+ EXAMPLES::
1366
+
1367
+ sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
1368
+ sage: gens = PBW.algebra_generators(); gens
1369
+ (PBW[x], PBW[y])
1370
+ sage: all(g.parent() is PBW for g in gens)
1371
+ True
1372
+ """
1373
+ return tuple(self.monomial(x) for x in self._indices.gens())
1374
+
1375
+ gens = algebra_generators
1376
+
1377
+ def gen(self, i):
1378
+ """
1379
+ Return the ``i``-th generator of ``self``.
1380
+
1381
+ EXAMPLES::
1382
+
1383
+ sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
1384
+ sage: PBW.gen(0)
1385
+ PBW[x]
1386
+ sage: PBW.gen(1)
1387
+ PBW[y]
1388
+ """
1389
+ return self.algebra_generators()[i]
1390
+
1391
+ def free_algebra(self):
1392
+ """
1393
+ Return the associated free algebra of ``self``.
1394
+
1395
+ EXAMPLES::
1396
+
1397
+ sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
1398
+ sage: PBW.free_algebra()
1399
+ Free Algebra on 2 generators (x, y) over Rational Field
1400
+ """
1401
+ return self._alg
1402
+
1403
+ def product(self, u, v):
1404
+ """
1405
+ Return the product of two elements ``u`` and ``v``.
1406
+
1407
+ EXAMPLES::
1408
+
1409
+ sage: F = FreeAlgebra(QQ, 2, 'x,y')
1410
+ sage: PBW = F.pbw_basis()
1411
+ sage: x, y = PBW.gens()
1412
+ sage: PBW.product(x, y)
1413
+ PBW[x*y] + PBW[y]*PBW[x]
1414
+ sage: PBW.product(y, x)
1415
+ PBW[y]*PBW[x]
1416
+ sage: PBW.product(y^2*x, x*y*x)
1417
+ PBW[y]^2*PBW[x^2*y]*PBW[x] + 2*PBW[y]^2*PBW[x*y]*PBW[x]^2 + PBW[y]^3*PBW[x]^3
1418
+
1419
+ TESTS:
1420
+
1421
+ Check that multiplication agrees with the multiplication in the
1422
+ free algebra::
1423
+
1424
+ sage: F = FreeAlgebra(QQ, 2, 'x,y')
1425
+ sage: PBW = F.pbw_basis()
1426
+ sage: x, y = PBW.gens()
1427
+ sage: F(x*y)
1428
+ x*y
1429
+ sage: F(x*y*x)
1430
+ x*y*x
1431
+ sage: PBW(F(x)*F(y)*F(x)) == x*y*x
1432
+ True
1433
+ """
1434
+ return self(self.expansion(u) * self.expansion(v))
1435
+
1436
+ def expansion(self, t):
1437
+ """
1438
+ Return the expansion of the element ``t`` of the Poincaré-Birkhoff-Witt
1439
+ basis in the monomials of the free algebra.
1440
+
1441
+ EXAMPLES::
1442
+
1443
+ sage: F = FreeAlgebra(QQ, 2, 'x,y')
1444
+ sage: PBW = F.pbw_basis()
1445
+ sage: x,y = F.monoid().gens()
1446
+ sage: PBW.expansion(PBW(x*y))
1447
+ x*y - y*x
1448
+ sage: PBW.expansion(PBW.one())
1449
+ 1
1450
+ sage: PBW.expansion(PBW(x*y*x) + 2*PBW(x) + 3)
1451
+ 3 + 2*x + x*y*x - y*x^2
1452
+
1453
+ TESTS:
1454
+
1455
+ Check that we have the correct parent::
1456
+
1457
+ sage: PBW.expansion(PBW(x*y)).parent() is F
1458
+ True
1459
+ sage: PBW.expansion(PBW.one()).parent() is F
1460
+ True
1461
+ """
1462
+ return sum([i[1] * self._alg.lie_polynomial(i[0]) for i in list(t)],
1463
+ self._alg.zero())
1464
+
1465
+ class Element(CombinatorialFreeModule.Element):
1466
+ def expand(self):
1467
+ """
1468
+ Expand ``self`` in the monomials of the free algebra.
1469
+
1470
+ EXAMPLES::
1471
+
1472
+ sage: F = FreeAlgebra(QQ, 2, 'x,y')
1473
+ sage: PBW = F.pbw_basis()
1474
+ sage: x,y = F.monoid().gens()
1475
+ sage: f = PBW(x^2*y) + PBW(x) + PBW(y^4*x)
1476
+ sage: f.expand()
1477
+ x + x^2*y - 2*x*y*x + y*x^2 + y^4*x
1478
+ """
1479
+ return self.parent().expansion(self)
1480
+
1481
+
1482
+ class AssociativeFunctor(ConstructionFunctor):
1483
+ """
1484
+ A constructor for free associative algebras.
1485
+
1486
+ EXAMPLES::
1487
+
1488
+ sage: P = algebras.Free(ZZ, 2, 'x,y')
1489
+ sage: x,y = P.gens()
1490
+ sage: F = P.construction()[0]; F
1491
+ Associative[x,y]
1492
+
1493
+ sage: A = GF(5)['a,b']
1494
+ sage: a, b = A.gens()
1495
+ sage: F(A)
1496
+ Free Algebra on 2 generators (x, y) over Multivariate Polynomial Ring in a, b over Finite Field of size 5
1497
+
1498
+ sage: f = A.hom([a+b,a-b],A)
1499
+ sage: F(f)
1500
+ Generic endomorphism of Free Algebra on 2 generators (x, y)
1501
+ over Multivariate Polynomial Ring in a, b over Finite Field of size 5
1502
+
1503
+ sage: F(f)(a * F(A)(x))
1504
+ (a+b)*x
1505
+ """
1506
+ rank = 9
1507
+
1508
+ def __init__(self, vars, degs=None):
1509
+ """
1510
+ EXAMPLES::
1511
+
1512
+ sage: from sage.algebras.free_algebra import AssociativeFunctor
1513
+ sage: F = AssociativeFunctor(['x','y'])
1514
+ sage: F
1515
+ Associative[x,y]
1516
+ sage: F(ZZ)
1517
+ Free Algebra on 2 generators (x, y) over Integer Ring
1518
+ """
1519
+ Functor.__init__(self, Rings(), Rings())
1520
+ if not isinstance(vars, (list, tuple)):
1521
+ raise TypeError("vars must be a list or tuple")
1522
+ if degs is not None and not isinstance(degs, (list, tuple, dict)):
1523
+ raise TypeError("degs must be a list, tuple or dict")
1524
+ self.vars = vars
1525
+ self.degs = degs
1526
+
1527
+ def _apply_functor(self, R):
1528
+ """
1529
+ Apply the functor to an object of ``self``'s domain.
1530
+
1531
+ EXAMPLES::
1532
+
1533
+ sage: R = algebras.Free(ZZ, 3, 'x,y,z')
1534
+ sage: F = R.construction()[0]; F
1535
+ Associative[x,y,z]
1536
+ sage: type(F)
1537
+ <class 'sage.algebras.free_algebra.AssociativeFunctor'>
1538
+ sage: F(ZZ) # indirect doctest
1539
+ Free Algebra on 3 generators (x, y, z) over Integer Ring
1540
+ """
1541
+ return FreeAlgebra(R, self.vars, self.degs)
1542
+
1543
+ def _apply_functor_to_morphism(self, f):
1544
+ """
1545
+ Apply the functor ``self`` to the ring morphism `f`.
1546
+
1547
+ TESTS::
1548
+
1549
+ sage: R = algebras.Free(ZZ, 'x').construction()[0]
1550
+ sage: R(ZZ.hom(GF(3))) # indirect doctest
1551
+ Generic morphism:
1552
+ From: Free Algebra on 1 generator (x,) over Integer Ring
1553
+ To: Free Algebra on 1 generator (x,) over Finite Field of size 3
1554
+ """
1555
+ dom = self(f.domain())
1556
+ codom = self(f.codomain())
1557
+
1558
+ def action(x):
1559
+ return codom._from_dict({a: f(b)
1560
+ for a, b in x.monomial_coefficients().items()})
1561
+ return dom.module_morphism(function=action, codomain=codom)
1562
+
1563
+ def __eq__(self, other):
1564
+ """
1565
+ EXAMPLES::
1566
+
1567
+ sage: F = algebras.Free(ZZ, 3, 'x,y,z').construction()[0]
1568
+ sage: G = algebras.Free(QQ, 3, 'x,y,z').construction()[0]
1569
+ sage: F == G
1570
+ True
1571
+ sage: G == loads(dumps(G))
1572
+ True
1573
+ sage: G = algebras.Free(QQ, 2, 'x,y').construction()[0]
1574
+ sage: F == G
1575
+ False
1576
+ """
1577
+ if not isinstance(other, AssociativeFunctor):
1578
+ return False
1579
+ return self.vars == other.vars and self.degs == other.degs
1580
+
1581
+ def __mul__(self, other):
1582
+ """
1583
+ If two Associative functors are given in a row, form a single Associative functor
1584
+ with all of the variables.
1585
+
1586
+ EXAMPLES::
1587
+
1588
+ sage: from sage.algebras.free_algebra import AssociativeFunctor
1589
+ sage: F = AssociativeFunctor(['x','y'])
1590
+ sage: G = AssociativeFunctor(['t'])
1591
+ sage: G * F
1592
+ Associative[x,y,t]
1593
+ """
1594
+ if isinstance(other, IdentityConstructionFunctor):
1595
+ return self
1596
+ if isinstance(other, AssociativeFunctor):
1597
+ if set(self.vars).intersection(other.vars):
1598
+ raise CoercionException("Overlapping variables (%s,%s)" %
1599
+ (self.vars, other.vars))
1600
+ return AssociativeFunctor(other.vars + self.vars)
1601
+ elif (isinstance(other, CompositeConstructionFunctor) and
1602
+ isinstance(other.all[-1], AssociativeFunctor)):
1603
+ return CompositeConstructionFunctor(other.all[:-1],
1604
+ self * other.all[-1])
1605
+ else:
1606
+ return CompositeConstructionFunctor(other, self)
1607
+
1608
+ def merge(self, other):
1609
+ """
1610
+ Merge ``self`` with another construction functor, or return ``None``.
1611
+
1612
+ EXAMPLES::
1613
+
1614
+ sage: from sage.algebras.free_algebra import AssociativeFunctor
1615
+ sage: F = AssociativeFunctor(['x','y'])
1616
+ sage: G = AssociativeFunctor(['t'])
1617
+ sage: F.merge(G)
1618
+ Associative[x,y,t]
1619
+ sage: F.merge(F)
1620
+ Associative[x,y]
1621
+
1622
+ With degrees::
1623
+
1624
+ sage: F = AssociativeFunctor(['x','y'], (2,3))
1625
+ sage: G = AssociativeFunctor(['t'], (4,))
1626
+ sage: H = AssociativeFunctor(['z','y'], (5,3))
1627
+ sage: F.merge(G)
1628
+ Associative[x,y,t] with degrees (2, 3, 4)
1629
+ sage: F.merge(H)
1630
+ Associative[x,y,z] with degrees (2, 3, 5)
1631
+
1632
+ Now some actual use cases::
1633
+
1634
+ sage: R = algebras.Free(ZZ, 3, 'x,y,z')
1635
+ sage: x,y,z = R.gens()
1636
+ sage: 1/2 * x
1637
+ 1/2*x
1638
+ sage: parent(1/2 * x)
1639
+ Free Algebra on 3 generators (x, y, z) over Rational Field
1640
+
1641
+ sage: S = algebras.Free(QQ, 2, 'z,t')
1642
+ sage: z,t = S.gens()
1643
+ sage: x + t
1644
+ t + x
1645
+ sage: parent(x + t)
1646
+ Free Algebra on 4 generators (z, t, x, y) over Rational Field
1647
+
1648
+ TESTS::
1649
+
1650
+ sage: F = AssociativeFunctor(['x','y'], (2,3))
1651
+ sage: H = AssociativeFunctor(['z','y'], (5,4))
1652
+ sage: F.merge(H)
1653
+ """
1654
+ if isinstance(other, AssociativeFunctor):
1655
+ if self.vars == other.vars and self.degs == other.degs:
1656
+ return self
1657
+
1658
+ ret = list(self.vars)
1659
+ self_vars = set(ret)
1660
+ ret.extend(v for v in other.vars if v not in self_vars)
1661
+
1662
+ # first case: no degrees
1663
+ if self.degs is None and other.degs is None:
1664
+ return AssociativeFunctor(tuple(ret))
1665
+
1666
+ # second case: merge the degrees
1667
+ if self.degs is None:
1668
+ deg = [1] * len(self.vars)
1669
+ else:
1670
+ deg = list(self.degs)
1671
+ if other.degs is None:
1672
+ o_degs = [1] * len(other.vars)
1673
+ else:
1674
+ o_degs = list(other.degs)
1675
+ self_table = dict(zip(self.vars, deg))
1676
+ for v, d in zip(other.vars, o_degs):
1677
+ if v not in self_vars:
1678
+ deg.append(d)
1679
+ elif d != self_table[v]:
1680
+ # incompatible degrees
1681
+ return None
1682
+ return AssociativeFunctor(tuple(ret), tuple(deg))
1683
+
1684
+ return None
1685
+
1686
+ def _repr_(self) -> str:
1687
+ """
1688
+ TESTS::
1689
+
1690
+ sage: algebras.Free(QQ,4,'x,y,z,t').construction()[0]
1691
+ Associative[x,y,z,t]
1692
+ sage: algebras.Free(QQ,4,'x,y,z,t',degrees=(1,2,3,4)).construction()[0]
1693
+ Associative[x,y,z,t] with degrees {x: 1, y: 2, z: 3, t: 4}
1694
+ """
1695
+ vars = ','.join(self.vars)
1696
+ if self.degs is None:
1697
+ return f"Associative[{vars}]"
1698
+ return f"Associative[{vars}] with degrees {self.degs}"