passagemath-combinat 10.6.42__cp314-cp314-musllinux_1_2_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (400) hide show
  1. passagemath_combinat/__init__.py +3 -0
  2. passagemath_combinat-10.6.42.dist-info/METADATA +160 -0
  3. passagemath_combinat-10.6.42.dist-info/RECORD +400 -0
  4. passagemath_combinat-10.6.42.dist-info/WHEEL +5 -0
  5. passagemath_combinat-10.6.42.dist-info/top_level.txt +3 -0
  6. passagemath_combinat.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
  7. passagemath_combinat.libs/libsymmetrica-81fe8739.so.3.0.0 +0 -0
  8. sage/algebras/affine_nil_temperley_lieb.py +263 -0
  9. sage/algebras/all.py +24 -0
  10. sage/algebras/all__sagemath_combinat.py +35 -0
  11. sage/algebras/askey_wilson.py +935 -0
  12. sage/algebras/associated_graded.py +345 -0
  13. sage/algebras/cellular_basis.py +350 -0
  14. sage/algebras/cluster_algebra.py +2766 -0
  15. sage/algebras/down_up_algebra.py +860 -0
  16. sage/algebras/free_algebra.py +1698 -0
  17. sage/algebras/free_algebra_element.py +345 -0
  18. sage/algebras/free_algebra_quotient.py +405 -0
  19. sage/algebras/free_algebra_quotient_element.py +295 -0
  20. sage/algebras/free_zinbiel_algebra.py +885 -0
  21. sage/algebras/hall_algebra.py +783 -0
  22. sage/algebras/hecke_algebras/all.py +4 -0
  23. sage/algebras/hecke_algebras/ariki_koike_algebra.py +1796 -0
  24. sage/algebras/hecke_algebras/ariki_koike_specht_modules.py +475 -0
  25. sage/algebras/hecke_algebras/cubic_hecke_algebra.py +3520 -0
  26. sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +1473 -0
  27. sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +1079 -0
  28. sage/algebras/iwahori_hecke_algebra.py +3095 -0
  29. sage/algebras/jordan_algebra.py +1773 -0
  30. sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py +113 -0
  31. sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py +156 -0
  32. sage/algebras/lie_conformal_algebras/all.py +18 -0
  33. sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +134 -0
  34. sage/algebras/lie_conformal_algebras/examples.py +43 -0
  35. sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py +131 -0
  36. sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py +139 -0
  37. sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py +174 -0
  38. sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py +167 -0
  39. sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py +107 -0
  40. sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py +135 -0
  41. sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py +353 -0
  42. sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py +236 -0
  43. sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py +78 -0
  44. sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py +328 -0
  45. sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py +117 -0
  46. sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py +86 -0
  47. sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py +82 -0
  48. sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +205 -0
  49. sage/algebras/nil_coxeter_algebra.py +191 -0
  50. sage/algebras/q_commuting_polynomials.py +673 -0
  51. sage/algebras/q_system.py +608 -0
  52. sage/algebras/quantum_clifford.py +959 -0
  53. sage/algebras/quantum_groups/ace_quantum_onsager.py +693 -0
  54. sage/algebras/quantum_groups/all.py +9 -0
  55. sage/algebras/quantum_groups/fock_space.py +2219 -0
  56. sage/algebras/quantum_groups/q_numbers.py +207 -0
  57. sage/algebras/quantum_groups/quantum_group_gap.py +2695 -0
  58. sage/algebras/quantum_groups/representations.py +591 -0
  59. sage/algebras/quantum_matrix_coordinate_algebra.py +1006 -0
  60. sage/algebras/quantum_oscillator.py +623 -0
  61. sage/algebras/quaternion_algebra.py +20 -0
  62. sage/algebras/quaternion_algebra_element.py +55 -0
  63. sage/algebras/rational_cherednik_algebra.py +525 -0
  64. sage/algebras/schur_algebra.py +670 -0
  65. sage/algebras/shuffle_algebra.py +1011 -0
  66. sage/algebras/splitting_algebra.py +779 -0
  67. sage/algebras/tensor_algebra.py +709 -0
  68. sage/algebras/yangian.py +1082 -0
  69. sage/algebras/yokonuma_hecke_algebra.py +1018 -0
  70. sage/all__sagemath_combinat.py +35 -0
  71. sage/combinat/SJT.py +255 -0
  72. sage/combinat/affine_permutation.py +2405 -0
  73. sage/combinat/algebraic_combinatorics.py +55 -0
  74. sage/combinat/all.py +53 -0
  75. sage/combinat/all__sagemath_combinat.py +195 -0
  76. sage/combinat/alternating_sign_matrix.py +2063 -0
  77. sage/combinat/baxter_permutations.py +346 -0
  78. sage/combinat/bijectionist.py +3220 -0
  79. sage/combinat/binary_recurrence_sequences.py +1180 -0
  80. sage/combinat/blob_algebra.py +685 -0
  81. sage/combinat/catalog_partitions.py +27 -0
  82. sage/combinat/chas/all.py +23 -0
  83. sage/combinat/chas/fsym.py +1180 -0
  84. sage/combinat/chas/wqsym.py +2601 -0
  85. sage/combinat/cluster_complex.py +326 -0
  86. sage/combinat/colored_permutations.py +2039 -0
  87. sage/combinat/colored_permutations_representations.py +964 -0
  88. sage/combinat/composition_signed.py +142 -0
  89. sage/combinat/composition_tableau.py +855 -0
  90. sage/combinat/constellation.py +1729 -0
  91. sage/combinat/core.py +751 -0
  92. sage/combinat/counting.py +12 -0
  93. sage/combinat/crystals/affine.py +742 -0
  94. sage/combinat/crystals/affine_factorization.py +518 -0
  95. sage/combinat/crystals/affinization.py +331 -0
  96. sage/combinat/crystals/alcove_path.py +2013 -0
  97. sage/combinat/crystals/all.py +22 -0
  98. sage/combinat/crystals/bkk_crystals.py +141 -0
  99. sage/combinat/crystals/catalog.py +115 -0
  100. sage/combinat/crystals/catalog_elementary_crystals.py +18 -0
  101. sage/combinat/crystals/catalog_infinity_crystals.py +33 -0
  102. sage/combinat/crystals/catalog_kirillov_reshetikhin.py +18 -0
  103. sage/combinat/crystals/crystals.py +257 -0
  104. sage/combinat/crystals/direct_sum.py +260 -0
  105. sage/combinat/crystals/elementary_crystals.py +1251 -0
  106. sage/combinat/crystals/fast_crystals.py +441 -0
  107. sage/combinat/crystals/fully_commutative_stable_grothendieck.py +1205 -0
  108. sage/combinat/crystals/generalized_young_walls.py +1076 -0
  109. sage/combinat/crystals/highest_weight_crystals.py +436 -0
  110. sage/combinat/crystals/induced_structure.py +695 -0
  111. sage/combinat/crystals/infinity_crystals.py +730 -0
  112. sage/combinat/crystals/kac_modules.py +863 -0
  113. sage/combinat/crystals/kirillov_reshetikhin.py +4196 -0
  114. sage/combinat/crystals/kyoto_path_model.py +497 -0
  115. sage/combinat/crystals/letters.cpython-314-x86_64-linux-musl.so +0 -0
  116. sage/combinat/crystals/letters.pxd +79 -0
  117. sage/combinat/crystals/letters.pyx +3056 -0
  118. sage/combinat/crystals/littelmann_path.py +1518 -0
  119. sage/combinat/crystals/monomial_crystals.py +1262 -0
  120. sage/combinat/crystals/multisegments.py +462 -0
  121. sage/combinat/crystals/mv_polytopes.py +467 -0
  122. sage/combinat/crystals/pbw_crystal.py +511 -0
  123. sage/combinat/crystals/pbw_datum.cpython-314-x86_64-linux-musl.so +0 -0
  124. sage/combinat/crystals/pbw_datum.pxd +4 -0
  125. sage/combinat/crystals/pbw_datum.pyx +487 -0
  126. sage/combinat/crystals/polyhedral_realization.py +372 -0
  127. sage/combinat/crystals/spins.cpython-314-x86_64-linux-musl.so +0 -0
  128. sage/combinat/crystals/spins.pxd +21 -0
  129. sage/combinat/crystals/spins.pyx +756 -0
  130. sage/combinat/crystals/star_crystal.py +290 -0
  131. sage/combinat/crystals/subcrystal.py +464 -0
  132. sage/combinat/crystals/tensor_product.py +1177 -0
  133. sage/combinat/crystals/tensor_product_element.cpython-314-x86_64-linux-musl.so +0 -0
  134. sage/combinat/crystals/tensor_product_element.pxd +35 -0
  135. sage/combinat/crystals/tensor_product_element.pyx +1870 -0
  136. sage/combinat/crystals/virtual_crystal.py +420 -0
  137. sage/combinat/cyclic_sieving_phenomenon.py +204 -0
  138. sage/combinat/debruijn_sequence.cpython-314-x86_64-linux-musl.so +0 -0
  139. sage/combinat/debruijn_sequence.pyx +355 -0
  140. sage/combinat/decorated_permutation.py +270 -0
  141. sage/combinat/degree_sequences.cpython-314-x86_64-linux-musl.so +0 -0
  142. sage/combinat/degree_sequences.pyx +588 -0
  143. sage/combinat/derangements.py +527 -0
  144. sage/combinat/descent_algebra.py +1008 -0
  145. sage/combinat/diagram.py +1551 -0
  146. sage/combinat/diagram_algebras.py +5886 -0
  147. sage/combinat/dyck_word.py +4349 -0
  148. sage/combinat/e_one_star.py +1623 -0
  149. sage/combinat/enumerated_sets.py +123 -0
  150. sage/combinat/expnums.cpython-314-x86_64-linux-musl.so +0 -0
  151. sage/combinat/expnums.pyx +148 -0
  152. sage/combinat/fast_vector_partitions.cpython-314-x86_64-linux-musl.so +0 -0
  153. sage/combinat/fast_vector_partitions.pyx +346 -0
  154. sage/combinat/fqsym.py +1977 -0
  155. sage/combinat/free_dendriform_algebra.py +954 -0
  156. sage/combinat/free_prelie_algebra.py +1141 -0
  157. sage/combinat/fully_commutative_elements.py +1077 -0
  158. sage/combinat/fully_packed_loop.py +1523 -0
  159. sage/combinat/gelfand_tsetlin_patterns.py +1409 -0
  160. sage/combinat/gray_codes.py +311 -0
  161. sage/combinat/grossman_larson_algebras.py +667 -0
  162. sage/combinat/growth.py +4352 -0
  163. sage/combinat/hall_polynomial.py +188 -0
  164. sage/combinat/hillman_grassl.py +866 -0
  165. sage/combinat/integer_matrices.py +329 -0
  166. sage/combinat/integer_vectors_mod_permgroup.py +1238 -0
  167. sage/combinat/k_tableau.py +4564 -0
  168. sage/combinat/kazhdan_lusztig.py +215 -0
  169. sage/combinat/key_polynomial.py +885 -0
  170. sage/combinat/knutson_tao_puzzles.py +2286 -0
  171. sage/combinat/lr_tableau.py +311 -0
  172. sage/combinat/matrices/all.py +24 -0
  173. sage/combinat/matrices/hadamard_matrix.py +3790 -0
  174. sage/combinat/matrices/latin.py +2912 -0
  175. sage/combinat/misc.py +401 -0
  176. sage/combinat/multiset_partition_into_sets_ordered.py +3541 -0
  177. sage/combinat/ncsf_qsym/all.py +21 -0
  178. sage/combinat/ncsf_qsym/combinatorics.py +317 -0
  179. sage/combinat/ncsf_qsym/generic_basis_code.py +1427 -0
  180. sage/combinat/ncsf_qsym/ncsf.py +5637 -0
  181. sage/combinat/ncsf_qsym/qsym.py +4053 -0
  182. sage/combinat/ncsf_qsym/tutorial.py +447 -0
  183. sage/combinat/ncsym/all.py +21 -0
  184. sage/combinat/ncsym/bases.py +855 -0
  185. sage/combinat/ncsym/dual.py +593 -0
  186. sage/combinat/ncsym/ncsym.py +2076 -0
  187. sage/combinat/necklace.py +551 -0
  188. sage/combinat/non_decreasing_parking_function.py +634 -0
  189. sage/combinat/nu_dyck_word.py +1474 -0
  190. sage/combinat/output.py +861 -0
  191. sage/combinat/parallelogram_polyomino.py +4326 -0
  192. sage/combinat/parking_functions.py +1602 -0
  193. sage/combinat/partition_algebra.py +1998 -0
  194. sage/combinat/partition_kleshchev.py +1982 -0
  195. sage/combinat/partition_shifting_algebras.py +584 -0
  196. sage/combinat/partition_tuple.py +3114 -0
  197. sage/combinat/path_tableaux/all.py +13 -0
  198. sage/combinat/path_tableaux/catalog.py +29 -0
  199. sage/combinat/path_tableaux/dyck_path.py +380 -0
  200. sage/combinat/path_tableaux/frieze.py +476 -0
  201. sage/combinat/path_tableaux/path_tableau.py +728 -0
  202. sage/combinat/path_tableaux/semistandard.py +510 -0
  203. sage/combinat/perfect_matching.py +779 -0
  204. sage/combinat/plane_partition.py +3300 -0
  205. sage/combinat/q_bernoulli.cpython-314-x86_64-linux-musl.so +0 -0
  206. sage/combinat/q_bernoulli.pyx +128 -0
  207. sage/combinat/quickref.py +81 -0
  208. sage/combinat/recognizable_series.py +2051 -0
  209. sage/combinat/regular_sequence.py +4316 -0
  210. sage/combinat/regular_sequence_bounded.py +543 -0
  211. sage/combinat/restricted_growth.py +81 -0
  212. sage/combinat/ribbon.py +20 -0
  213. sage/combinat/ribbon_shaped_tableau.py +489 -0
  214. sage/combinat/ribbon_tableau.py +1180 -0
  215. sage/combinat/rigged_configurations/all.py +46 -0
  216. sage/combinat/rigged_configurations/bij_abstract_class.py +548 -0
  217. sage/combinat/rigged_configurations/bij_infinity.py +370 -0
  218. sage/combinat/rigged_configurations/bij_type_A.py +163 -0
  219. sage/combinat/rigged_configurations/bij_type_A2_dual.py +338 -0
  220. sage/combinat/rigged_configurations/bij_type_A2_even.py +218 -0
  221. sage/combinat/rigged_configurations/bij_type_A2_odd.py +199 -0
  222. sage/combinat/rigged_configurations/bij_type_B.py +900 -0
  223. sage/combinat/rigged_configurations/bij_type_C.py +267 -0
  224. sage/combinat/rigged_configurations/bij_type_D.py +771 -0
  225. sage/combinat/rigged_configurations/bij_type_D_tri.py +392 -0
  226. sage/combinat/rigged_configurations/bij_type_D_twisted.py +576 -0
  227. sage/combinat/rigged_configurations/bij_type_E67.py +402 -0
  228. sage/combinat/rigged_configurations/bijection.py +143 -0
  229. sage/combinat/rigged_configurations/kleber_tree.py +1475 -0
  230. sage/combinat/rigged_configurations/kr_tableaux.py +1898 -0
  231. sage/combinat/rigged_configurations/rc_crystal.py +461 -0
  232. sage/combinat/rigged_configurations/rc_infinity.py +540 -0
  233. sage/combinat/rigged_configurations/rigged_configuration_element.py +2403 -0
  234. sage/combinat/rigged_configurations/rigged_configurations.py +1918 -0
  235. sage/combinat/rigged_configurations/rigged_partition.cpython-314-x86_64-linux-musl.so +0 -0
  236. sage/combinat/rigged_configurations/rigged_partition.pxd +15 -0
  237. sage/combinat/rigged_configurations/rigged_partition.pyx +680 -0
  238. sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py +499 -0
  239. sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element.py +428 -0
  240. sage/combinat/rsk.py +3438 -0
  241. sage/combinat/schubert_polynomial.py +508 -0
  242. sage/combinat/set_partition.py +3318 -0
  243. sage/combinat/set_partition_iterator.cpython-314-x86_64-linux-musl.so +0 -0
  244. sage/combinat/set_partition_iterator.pyx +136 -0
  245. sage/combinat/set_partition_ordered.py +1590 -0
  246. sage/combinat/sf/abreu_nigro.py +346 -0
  247. sage/combinat/sf/all.py +52 -0
  248. sage/combinat/sf/character.py +576 -0
  249. sage/combinat/sf/classical.py +319 -0
  250. sage/combinat/sf/dual.py +996 -0
  251. sage/combinat/sf/elementary.py +549 -0
  252. sage/combinat/sf/hall_littlewood.py +1028 -0
  253. sage/combinat/sf/hecke.py +336 -0
  254. sage/combinat/sf/homogeneous.py +464 -0
  255. sage/combinat/sf/jack.py +1428 -0
  256. sage/combinat/sf/k_dual.py +1458 -0
  257. sage/combinat/sf/kfpoly.py +447 -0
  258. sage/combinat/sf/llt.py +789 -0
  259. sage/combinat/sf/macdonald.py +2019 -0
  260. sage/combinat/sf/monomial.py +525 -0
  261. sage/combinat/sf/multiplicative.py +113 -0
  262. sage/combinat/sf/new_kschur.py +1786 -0
  263. sage/combinat/sf/ns_macdonald.py +964 -0
  264. sage/combinat/sf/orthogonal.py +246 -0
  265. sage/combinat/sf/orthotriang.py +355 -0
  266. sage/combinat/sf/powersum.py +963 -0
  267. sage/combinat/sf/schur.py +880 -0
  268. sage/combinat/sf/sf.py +1653 -0
  269. sage/combinat/sf/sfa.py +7053 -0
  270. sage/combinat/sf/symplectic.py +253 -0
  271. sage/combinat/sf/witt.py +721 -0
  272. sage/combinat/shifted_primed_tableau.py +2735 -0
  273. sage/combinat/shuffle.py +830 -0
  274. sage/combinat/sidon_sets.py +146 -0
  275. sage/combinat/similarity_class_type.py +1721 -0
  276. sage/combinat/sine_gordon.py +618 -0
  277. sage/combinat/six_vertex_model.py +784 -0
  278. sage/combinat/skew_partition.py +2053 -0
  279. sage/combinat/skew_tableau.py +2989 -0
  280. sage/combinat/sloane_functions.py +8935 -0
  281. sage/combinat/specht_module.py +1403 -0
  282. sage/combinat/species/all.py +48 -0
  283. sage/combinat/species/characteristic_species.py +321 -0
  284. sage/combinat/species/composition_species.py +273 -0
  285. sage/combinat/species/cycle_species.py +284 -0
  286. sage/combinat/species/empty_species.py +155 -0
  287. sage/combinat/species/functorial_composition_species.py +148 -0
  288. sage/combinat/species/generating_series.py +673 -0
  289. sage/combinat/species/library.py +148 -0
  290. sage/combinat/species/linear_order_species.py +169 -0
  291. sage/combinat/species/misc.py +83 -0
  292. sage/combinat/species/partition_species.py +290 -0
  293. sage/combinat/species/permutation_species.py +268 -0
  294. sage/combinat/species/product_species.py +423 -0
  295. sage/combinat/species/recursive_species.py +476 -0
  296. sage/combinat/species/set_species.py +192 -0
  297. sage/combinat/species/species.py +820 -0
  298. sage/combinat/species/structure.py +539 -0
  299. sage/combinat/species/subset_species.py +243 -0
  300. sage/combinat/species/sum_species.py +225 -0
  301. sage/combinat/subword.py +564 -0
  302. sage/combinat/subword_complex.py +2122 -0
  303. sage/combinat/subword_complex_c.cpython-314-x86_64-linux-musl.so +0 -0
  304. sage/combinat/subword_complex_c.pyx +119 -0
  305. sage/combinat/super_tableau.py +821 -0
  306. sage/combinat/superpartition.py +1154 -0
  307. sage/combinat/symmetric_group_algebra.py +3774 -0
  308. sage/combinat/symmetric_group_representations.py +1830 -0
  309. sage/combinat/t_sequences.py +877 -0
  310. sage/combinat/tableau.py +9506 -0
  311. sage/combinat/tableau_residues.py +860 -0
  312. sage/combinat/tableau_tuple.py +5353 -0
  313. sage/combinat/tiling.py +2432 -0
  314. sage/combinat/triangles_FHM.py +777 -0
  315. sage/combinat/tutorial.py +1857 -0
  316. sage/combinat/vector_partition.py +337 -0
  317. sage/combinat/words/abstract_word.py +1722 -0
  318. sage/combinat/words/all.py +59 -0
  319. sage/combinat/words/alphabet.py +268 -0
  320. sage/combinat/words/finite_word.py +7201 -0
  321. sage/combinat/words/infinite_word.py +113 -0
  322. sage/combinat/words/lyndon_word.py +652 -0
  323. sage/combinat/words/morphic.py +351 -0
  324. sage/combinat/words/morphism.py +3878 -0
  325. sage/combinat/words/paths.py +2932 -0
  326. sage/combinat/words/shuffle_product.py +278 -0
  327. sage/combinat/words/suffix_trees.py +1873 -0
  328. sage/combinat/words/word.py +769 -0
  329. sage/combinat/words/word_char.cpython-314-x86_64-linux-musl.so +0 -0
  330. sage/combinat/words/word_char.pyx +847 -0
  331. sage/combinat/words/word_datatypes.cpython-314-x86_64-linux-musl.so +0 -0
  332. sage/combinat/words/word_datatypes.pxd +4 -0
  333. sage/combinat/words/word_datatypes.pyx +1067 -0
  334. sage/combinat/words/word_generators.py +2026 -0
  335. sage/combinat/words/word_infinite_datatypes.py +1218 -0
  336. sage/combinat/words/word_options.py +99 -0
  337. sage/combinat/words/words.py +2396 -0
  338. sage/data_structures/all__sagemath_combinat.py +1 -0
  339. sage/databases/all__sagemath_combinat.py +13 -0
  340. sage/databases/findstat.py +4897 -0
  341. sage/databases/oeis.py +2058 -0
  342. sage/databases/sloane.py +393 -0
  343. sage/dynamics/all__sagemath_combinat.py +14 -0
  344. sage/dynamics/cellular_automata/all.py +7 -0
  345. sage/dynamics/cellular_automata/catalog.py +34 -0
  346. sage/dynamics/cellular_automata/elementary.py +612 -0
  347. sage/dynamics/cellular_automata/glca.py +477 -0
  348. sage/dynamics/cellular_automata/solitons.py +1463 -0
  349. sage/dynamics/finite_dynamical_system.py +1249 -0
  350. sage/dynamics/finite_dynamical_system_catalog.py +382 -0
  351. sage/games/all.py +7 -0
  352. sage/games/hexad.py +704 -0
  353. sage/games/quantumino.py +591 -0
  354. sage/games/sudoku.py +889 -0
  355. sage/games/sudoku_backtrack.cpython-314-x86_64-linux-musl.so +0 -0
  356. sage/games/sudoku_backtrack.pyx +189 -0
  357. sage/groups/all__sagemath_combinat.py +1 -0
  358. sage/groups/indexed_free_group.py +489 -0
  359. sage/libs/all__sagemath_combinat.py +6 -0
  360. sage/libs/lrcalc/__init__.py +1 -0
  361. sage/libs/lrcalc/lrcalc.py +525 -0
  362. sage/libs/symmetrica/__init__.py +7 -0
  363. sage/libs/symmetrica/all.py +101 -0
  364. sage/libs/symmetrica/kostka.pxi +168 -0
  365. sage/libs/symmetrica/part.pxi +193 -0
  366. sage/libs/symmetrica/plet.pxi +42 -0
  367. sage/libs/symmetrica/sab.pxi +196 -0
  368. sage/libs/symmetrica/sb.pxi +332 -0
  369. sage/libs/symmetrica/sc.pxi +192 -0
  370. sage/libs/symmetrica/schur.pxi +956 -0
  371. sage/libs/symmetrica/symmetrica.cpython-314-x86_64-linux-musl.so +0 -0
  372. sage/libs/symmetrica/symmetrica.pxi +1172 -0
  373. sage/libs/symmetrica/symmetrica.pyx +39 -0
  374. sage/monoids/all.py +13 -0
  375. sage/monoids/automatic_semigroup.py +1054 -0
  376. sage/monoids/free_abelian_monoid.py +315 -0
  377. sage/monoids/free_abelian_monoid_element.cpython-314-x86_64-linux-musl.so +0 -0
  378. sage/monoids/free_abelian_monoid_element.pxd +16 -0
  379. sage/monoids/free_abelian_monoid_element.pyx +397 -0
  380. sage/monoids/free_monoid.py +335 -0
  381. sage/monoids/free_monoid_element.py +431 -0
  382. sage/monoids/hecke_monoid.py +65 -0
  383. sage/monoids/string_monoid.py +817 -0
  384. sage/monoids/string_monoid_element.py +547 -0
  385. sage/monoids/string_ops.py +143 -0
  386. sage/monoids/trace_monoid.py +972 -0
  387. sage/rings/all__sagemath_combinat.py +2 -0
  388. sage/sat/all.py +4 -0
  389. sage/sat/boolean_polynomials.py +405 -0
  390. sage/sat/converters/__init__.py +6 -0
  391. sage/sat/converters/anf2cnf.py +14 -0
  392. sage/sat/converters/polybori.py +611 -0
  393. sage/sat/solvers/__init__.py +5 -0
  394. sage/sat/solvers/cryptominisat.py +287 -0
  395. sage/sat/solvers/dimacs.py +783 -0
  396. sage/sat/solvers/picosat.py +228 -0
  397. sage/sat/solvers/sat_lp.py +156 -0
  398. sage/sat/solvers/satsolver.cpython-314-x86_64-linux-musl.so +0 -0
  399. sage/sat/solvers/satsolver.pxd +3 -0
  400. sage/sat/solvers/satsolver.pyx +405 -0
@@ -0,0 +1,2026 @@
1
+ # sage_setup: distribution = sagemath-combinat
2
+ r"""
3
+ Common words
4
+
5
+ AUTHORS:
6
+
7
+ - Franco Saliola (2008-12-17): merged into sage
8
+ - Sébastien Labbé (2008-12-17): merged into sage
9
+ - Arnaud Bergeron (2008-12-17): merged into sage
10
+ - Amy Glen (2008-12-17): merged into sage
11
+ - Sébastien Labbé (2009-12-19): Added S-adic words (:issue:`7543`)
12
+
13
+ USE:
14
+
15
+ To see a list of all word constructors, type ``words.`` and then press
16
+ the :kbd:`Tab` key. The documentation for each constructor includes
17
+ information about each word, which provides a useful reference.
18
+
19
+ REFERENCES:
20
+
21
+ .. [AC03] \B. Adamczewski, J. Cassaigne, On the transcendence of real
22
+ numbers with a regular expansion, J. Number Theory 103 (2003)
23
+ 27--37.
24
+
25
+ .. [BmBGL07] \A. Blondin-Massé, S. Brlek, A. Glen, and S. Labbé. On the
26
+ critical exponent of generalized Thue-Morse words. *Discrete Math.
27
+ Theor. Comput. Sci.* 9 (1):293--304, 2007.
28
+
29
+ .. [BmBGL09] \A. Blondin-Massé, S. Brlek, A. Garon, and S. Labbé. Christoffel
30
+ and Fibonacci Tiles, DGCI 2009, Montreal, to appear in LNCS.
31
+
32
+ .. [Loth02] \M. Lothaire, Algebraic Combinatorics On Words, vol. 90 of
33
+ Encyclopedia of Mathematics and its Applications, Cambridge
34
+ University Press, U.K., 2002.
35
+
36
+ .. [Fogg] Pytheas Fogg,
37
+ https://www.lirmm.fr/arith/wiki/PytheasFogg/S-adiques.
38
+
39
+ EXAMPLES::
40
+
41
+ sage: t = words.ThueMorseWord(); t
42
+ word: 0110100110010110100101100110100110010110...
43
+ """
44
+ # ****************************************************************************
45
+ # Copyright (C) 2008 Franco Saliola <saliola@gmail.com>,
46
+ # Sebastien Labbe <slabqc@gmail.com>,
47
+ # Arnaud Bergeron <abergeron@gmail.com>,
48
+ # Amy Glen <amy.glen@gmail.com>
49
+ #
50
+ # This program is free software: you can redistribute it and/or modify
51
+ # it under the terms of the GNU General Public License as published by
52
+ # the Free Software Foundation, either version 2 of the License, or
53
+ # (at your option) any later version.
54
+ # https://www.gnu.org/licenses/
55
+ # ****************************************************************************
56
+
57
+ from collections.abc import Iterable
58
+ from itertools import cycle, count
59
+ from random import randint
60
+ from sage.misc.cachefunc import cached_method
61
+ from sage.rings.integer_ring import ZZ
62
+ from sage.rings.infinity import Infinity
63
+ from sage.combinat.words.abstract_word import Word_class
64
+ from sage.combinat.words.word import FiniteWord_list
65
+ from sage.combinat.words.finite_word import FiniteWord_class, Factorization
66
+ from sage.combinat.words.words import FiniteWords, InfiniteWords
67
+ from sage.combinat.words.morphism import WordMorphism
68
+ from sage.arith.misc import gcd
69
+ from sage.misc.decorators import rename_keyword
70
+ from sage.misc.lazy_import import lazy_import
71
+
72
+ lazy_import('sage.rings.real_mpfr', 'RR')
73
+
74
+
75
+ def _build_tab(sym, tab, W):
76
+ r"""
77
+ Internal function building a coding table for the ``phi_inv_tab`` function.
78
+
79
+ TESTS::
80
+
81
+ sage: from sage.combinat.words.word_generators import _build_tab
82
+ sage: _build_tab(1, [], Words([1, 2]))
83
+ [1]
84
+ sage: _build_tab(1, [1], Words([1, 2]))
85
+ [1, 2]
86
+ sage: _build_tab(2, [1], Words([1, 2]))
87
+ [2, 2]
88
+ sage: _build_tab(2, [1, 2], Words([1, 2]))
89
+ [2, 2, 1]
90
+ sage: _build_tab(1, [2, 2], Words([1, 2]))
91
+ [1, 1, 2]
92
+ """
93
+ c = W.alphabet().cardinality()
94
+ res = [sym]
95
+ if len(tab) == 0:
96
+ return res
97
+ if sym == 1:
98
+ res += tab
99
+ res[1] = (res[1] % c) + 1
100
+ return res
101
+ w = W([sym]).delta_inv(W, tab[0])
102
+ w = w[1:]
103
+ res.append((w[-1] % c) + 1)
104
+ for i in range(1, len(tab)):
105
+ w = w.delta_inv(W, tab[i])
106
+ res.append((w[-1] % c) + 1)
107
+ return res
108
+
109
+
110
+ class LowerChristoffelWord(FiniteWord_list):
111
+ r"""
112
+ Return the lower Christoffel word of slope `p/q`, where `p` and
113
+ `q` are relatively prime nonnegative integers, over the given
114
+ two-letter alphabet.
115
+
116
+ The *Christoffel word of slope `p/q`* is obtained from the
117
+ Cayley graph of `\ZZ/(p+q)\ZZ` with generator `q` as
118
+ follows. If `u \rightarrow v` is an edge in the Cayley graph, then
119
+ `v = u + p \mod{p+q}`. Label the edge `u \rightarrow v` by
120
+ ``alphabet[1]`` if `u < v` and ``alphabet[0]`` otherwise. The Christoffel
121
+ word is the word obtained by reading the edge labels along the
122
+ cycle beginning from 0.
123
+
124
+ EXAMPLES::
125
+
126
+ sage: words.LowerChristoffelWord(4,7)
127
+ word: 00100100101
128
+
129
+ ::
130
+
131
+ sage: words.LowerChristoffelWord(4,7,alphabet='ab')
132
+ word: aabaabaabab
133
+
134
+ TESTS::
135
+
136
+ sage: words.LowerChristoffelWord(1,0)
137
+ word: 1
138
+ sage: words.LowerChristoffelWord(0,1,'xy')
139
+ word: x
140
+ sage: words.LowerChristoffelWord(1,1)
141
+ word: 01
142
+ """
143
+
144
+ def __init__(self, p, q, alphabet=(0, 1), algorithm='cf'):
145
+ r"""
146
+ INPUT:
147
+
148
+ - ``p`` -- integer coprime with `q`
149
+ - ``q`` -- integer coprime with `p`
150
+ - ``alphabet`` -- sequence of two elements (default: (0, 1))
151
+ - ``algorithm`` -- construction method (default: ``'cf'``).
152
+ It can be one of the following:
153
+
154
+ - ``'linear'`` -- linear algorithm in the length of the word
155
+ - ``'cf'`` -- fast method using continued fraction
156
+
157
+ TESTS::
158
+
159
+ sage: words.ChristoffelWord(9, 4, algorithm='linear')
160
+ word: 0110110110111
161
+ sage: words.ChristoffelWord(9, 4, algorithm='cf')
162
+ word: 0110110110111
163
+ sage: words.ChristoffelWord(4, 9, algorithm='linear')
164
+ word: 0001001001001
165
+ sage: words.ChristoffelWord(4, 9, algorithm='cf')
166
+ word: 0001001001001
167
+
168
+ ::
169
+
170
+ sage: words.LowerChristoffelWord(4,8)
171
+ Traceback (most recent call last):
172
+ ...
173
+ ValueError: 4 and 8 are not relatively prime
174
+ sage: words.LowerChristoffelWord(17, 39, 'xyz')
175
+ Traceback (most recent call last):
176
+ ...
177
+ ValueError: alphabet must contain exactly two distinct elements
178
+ sage: w = words.LowerChristoffelWord(4,7)
179
+ sage: w2 = loads(dumps(w))
180
+ sage: w == w2
181
+ True
182
+ sage: type(w2)
183
+ <class 'sage.combinat.words.word_generators.LowerChristoffelWord'>
184
+ sage: _ = w2.standard_factorization() # hackish test for self.__p and self.__q
185
+ """
186
+ if len(set(alphabet)) != 2:
187
+ raise ValueError("alphabet must contain exactly two distinct elements")
188
+ # Compute gcd of p, q; raise TypeError if not 1.
189
+ if gcd(p, q) != 1:
190
+ raise ValueError("%s and %s are not relatively prime" % (p, q))
191
+ # Compute the Christoffel word
192
+ if algorithm == 'linear':
193
+ w = []
194
+ u = 0
195
+ if (p, q) == (0, 1):
196
+ w = [alphabet[0]]
197
+ else:
198
+ for i in range(p + q):
199
+ v = (u + p) % (p + q)
200
+ new_letter = alphabet[0] if u < v else alphabet[1]
201
+ w.append(new_letter)
202
+ u = v
203
+ elif algorithm == 'cf':
204
+ if (p, q) == (0, 1):
205
+ w = [alphabet[0]]
206
+ elif (p, q) == (1, 0):
207
+ w = [alphabet[1]]
208
+ else:
209
+ from sage.rings.rational_field import QQ
210
+ cf = QQ((p, q)).continued_fraction_list()
211
+ u = [alphabet[0]]
212
+ v = [alphabet[1]]
213
+ # do not consider the first zero if p < q
214
+ start = 1 if p < q else 0
215
+ for i in range(start, len(cf)-1):
216
+ if i % 2 == 0:
217
+ u = u + v * cf[i]
218
+ else:
219
+ v = u * cf[i] + v
220
+ i = len(cf)-1
221
+ if i % 2 == 0:
222
+ u = u + v * (cf[i]-1)
223
+ else:
224
+ v = u * (cf[i]-1) + v
225
+ w = u + v
226
+ else:
227
+ raise ValueError('Unknown algorithm (=%s)' % algorithm)
228
+ super().__init__(FiniteWords(alphabet), w)
229
+ self.__p = p
230
+ self.__q = q
231
+
232
+ def markoff_number(self):
233
+ r"""
234
+ Return the Markoff number associated to the Christoffel word ``self``.
235
+
236
+ The *Markoff number* of a Christoffel word `w` is `trace(M(w))/3`,
237
+ where `M(w)` is the `2\times 2` matrix obtained by applying the
238
+ morphism:
239
+ 0 -> matrix(2,[2,1,1,1])
240
+ 1 -> matrix(2,[5,2,2,1])
241
+
242
+ EXAMPLES::
243
+
244
+ sage: w0 = words.LowerChristoffelWord(4,7)
245
+ sage: w1, w2 = w0.standard_factorization()
246
+ sage: (m0,m1,m2) = (w.markoff_number() for w in (w0,w1,w2)) # needs sage.modules
247
+ sage: (m0,m1,m2) # needs sage.modules
248
+ (294685, 13, 7561)
249
+ sage: m0**2 + m1**2 + m2**2 == 3*m0*m1*m2 # needs sage.modules
250
+ True
251
+ """
252
+ from sage.matrix.constructor import matrix
253
+ eta = {0:matrix(2,[2,1,1,1]), 1:matrix(2,[5,2,2,1])}
254
+ M = matrix(2,[1,0,0,1])
255
+ for a in self:
256
+ M *= eta[a]
257
+ return M.trace()/3
258
+
259
+ def standard_factorization(self):
260
+ r"""
261
+ Return the standard factorization of the Christoffel word ``self``.
262
+
263
+ The *standard factorization* of a Christoffel word `w` is the
264
+ unique factorization of `w` into two Christoffel words.
265
+
266
+ EXAMPLES::
267
+
268
+ sage: w = words.LowerChristoffelWord(5,9)
269
+ sage: w
270
+ word: 00100100100101
271
+ sage: w1, w2 = w.standard_factorization()
272
+ sage: w1
273
+ word: 001
274
+ sage: w2
275
+ word: 00100100101
276
+
277
+ ::
278
+
279
+ sage: w = words.LowerChristoffelWord(51,37)
280
+ sage: w1, w2 = w.standard_factorization()
281
+ sage: w1
282
+ word: 0101011010101101011
283
+ sage: w2
284
+ word: 0101011010101101011010101101010110101101...
285
+ sage: w1 * w2 == w
286
+ True
287
+ """
288
+ p, q = self.__p, self.__q
289
+ index = 0
290
+ u = 0
291
+ for i in range(p + q):
292
+ v = (u+p) % (p+q)
293
+ if v == 1:
294
+ index = i
295
+ break
296
+ u = v
297
+ w1, w2 = self[:index+1], self[index+1:]
298
+ w10 = w1.number_of_letter_occurrences(0)
299
+ w11 = w1.number_of_letter_occurrences(1)
300
+ w20 = w2.number_of_letter_occurrences(0)
301
+ w21 = w2.number_of_letter_occurrences(1)
302
+ return Factorization([LowerChristoffelWord(w11,w10),
303
+ LowerChristoffelWord(w21,w20)])
304
+
305
+ def __reduce__(self):
306
+ r"""
307
+ EXAMPLES::
308
+
309
+ sage: from sage.combinat.words.word_generators import LowerChristoffelWord
310
+ sage: w = LowerChristoffelWord(5,7)
311
+ sage: w.__reduce__()
312
+ (<class 'sage.combinat.words.word_generators.LowerChristoffelWord'>, (5, 7, {0, 1}))
313
+ """
314
+ return self.__class__, (self.__p, self.__q, self.parent().alphabet())
315
+
316
+
317
+ class WordGenerator:
318
+ r"""
319
+ Constructor of several famous words.
320
+
321
+ EXAMPLES::
322
+
323
+ sage: words.ThueMorseWord()
324
+ word: 0110100110010110100101100110100110010110...
325
+
326
+ ::
327
+
328
+ sage: words.FibonacciWord()
329
+ word: 0100101001001010010100100101001001010010...
330
+
331
+ ::
332
+
333
+ sage: words.ChristoffelWord(5, 8)
334
+ word: 0010010100101
335
+
336
+ ::
337
+
338
+ sage: words.RandomWord(10, 4) # not tested random
339
+ word: 1311131221
340
+
341
+ ::
342
+
343
+ sage: words.CodingOfRotationWord(alpha=0.618, beta=0.618)
344
+ word: 1010110101101101011010110110101101101011...
345
+
346
+ ::
347
+
348
+ sage: tm = WordMorphism('a->ab,b->ba')
349
+ sage: fib = WordMorphism('a->ab,b->a')
350
+ sage: tmword = words.ThueMorseWord([0, 1])
351
+ sage: from itertools import repeat
352
+ sage: words.s_adic(tmword, repeat('a'), {0:tm, 1:fib})
353
+ word: abbaababbaabbaabbaababbaababbaabbaababba...
354
+
355
+ .. NOTE::
356
+
357
+ To see a list of all word constructors, type ``words.`` and then
358
+ hit the :kbd:`Tab` key. The documentation for each constructor
359
+ includes information about each word, which provides a useful
360
+ reference.
361
+
362
+ TESTS::
363
+
364
+ sage: from sage.combinat.words.word_generators import WordGenerator
365
+ sage: words2 = WordGenerator()
366
+ sage: type(loads(dumps(words2)))
367
+ <class 'sage.combinat.words.word_generators.WordGenerator'>
368
+ """
369
+ def ThueMorseWord(self, alphabet=(0, 1), base=2):
370
+ r"""
371
+ Return the (Generalized) Thue-Morse word over the given alphabet.
372
+
373
+ There are several ways to define the Thue-Morse word `t`.
374
+ We use the following definition: `t[n]` is the sum modulo `m` of
375
+ the digits in the given base expansion of `n`.
376
+
377
+ See [BmBGL07]_, [Brlek89]_, and [MH38]_.
378
+
379
+ INPUT:
380
+
381
+ - ``alphabet`` -- (default: ``(0, 1)``) any container that is suitable
382
+ to build an instance of OrderedAlphabet (``list``, ``tuple``, ``str``, ...)
383
+
384
+ - ``base`` -- integer (default: 2); greater than or equal to 2
385
+
386
+ EXAMPLES:
387
+
388
+ Thue-Morse word::
389
+
390
+ sage: t = words.ThueMorseWord(); t
391
+ word: 0110100110010110100101100110100110010110...
392
+
393
+ Thue-Morse word on other alphabets::
394
+
395
+ sage: t = words.ThueMorseWord('ab'); t
396
+ word: abbabaabbaababbabaababbaabbabaabbaababba...
397
+
398
+ ::
399
+
400
+ sage: t = words.ThueMorseWord(['L1', 'L2'])
401
+ sage: t[:8]
402
+ word: L1,L2,L2,L1,L2,L1,L1,L2
403
+
404
+ Generalized Thue Morse word::
405
+
406
+ sage: words.ThueMorseWord(alphabet=(0,1,2), base=2)
407
+ word: 0112122012202001122020012001011212202001...
408
+ sage: t = words.ThueMorseWord(alphabet=(0,1,2), base=5); t
409
+ word: 0120112012201200120112012120122012001201...
410
+ sage: t[100:130].critical_exponent()
411
+ 10/3
412
+
413
+ TESTS::
414
+
415
+ sage: words.ThueMorseWord(alphabet='ab', base=1)
416
+ Traceback (most recent call last):
417
+ ...
418
+ ValueError: base (=1) and len(alphabet) (=2) must be at least 2
419
+
420
+ REFERENCES:
421
+
422
+ .. [Brlek89] Brlek, S. 1989. «Enumeration of the factors in the Thue-Morse
423
+ word», *Discrete Appl. Math.*, vol. 24, p. 83--96.
424
+
425
+ .. [MH38] Morse, M., et G. A. Hedlund. 1938. «Symbolic dynamics»,
426
+ *American Journal of Mathematics*, vol. 60, p. 815--866.
427
+ """
428
+ W = InfiniteWords(alphabet)
429
+ alphabet = W.alphabet()
430
+ m = alphabet.cardinality()
431
+ if base < 2 or m < 2:
432
+ raise ValueError("base (=%s) and len(alphabet) (=%s) must be at least 2" % (base, m))
433
+ from functools import partial
434
+ f = partial(self._ThueMorseWord_nth_digit, alphabet=alphabet, base=base)
435
+ return W(f, datatype='callable')
436
+
437
+ def _ThueMorseWord_nth_digit(self, n, alphabet=(0, 1), base=2):
438
+ r"""
439
+ Return the `n`-th letter of the (Generalized) Thue-Morse word.
440
+
441
+ The `n`-th digit of the Thue-Morse word can be defined as the number
442
+ of bits in the 2-complement representation of the position
443
+ modulo 2 which is what this function uses. The running time
444
+ is `O(\log n)` where `n` is the position desired.
445
+
446
+ The `n`-th digit of the Generalized Thue Morse word can be defined as
447
+ the sum of the digits of `n` written in the given base mod `m`,
448
+ where `m` is the length of the given alphabet.
449
+
450
+ INPUT:
451
+
452
+ - ``n`` -- integer; the position
453
+ - ``alphabet`` -- an alphabet (default: (0, 1)) of size at least 2
454
+ - ``base`` -- integer (default: 2) greater than or equal to 2
455
+
456
+ OUTPUT:
457
+
458
+ 0 or 1 -- the digit at the position
459
+ letter -- the letter of alphabet at the position
460
+
461
+ TESTS::
462
+
463
+ sage: from sage.combinat.words.word_generators import WordGenerator
464
+ sage: WordGenerator()._ThueMorseWord_nth_digit(0)
465
+ 0
466
+ sage: WordGenerator()._ThueMorseWord_nth_digit(3)
467
+ 0
468
+ sage: WordGenerator()._ThueMorseWord_nth_digit(32)
469
+ 1
470
+ sage: WordGenerator()._ThueMorseWord_nth_digit(6, 'abc', base = 7)
471
+ 'a'
472
+
473
+ Negative input::
474
+
475
+ sage: words._ThueMorseWord_nth_digit(-7)
476
+ Traceback (most recent call last):
477
+ ...
478
+ NotImplementedError: nth digit of Thue-Morse word is not implemented for negative value of n
479
+ """
480
+ if n < 0:
481
+ raise NotImplementedError("nth digit of Thue-Morse word is not implemented for negative value of n")
482
+ m = len(alphabet)
483
+ if base == 2 and m == 2:
484
+ for tn in count():
485
+ if n == 0:
486
+ return alphabet[tn & 1]
487
+ n &= n - 1
488
+ elif base < 2 or m < 2:
489
+ raise ValueError("base (=%s) and len(alphabet) (=%s) must be at least 2" % (base, m))
490
+ else:
491
+ return alphabet[ZZ(sum(ZZ(n).digits(base=base))).mod(m)]
492
+
493
+ def FibonacciWord(self, alphabet=(0, 1), construction_method='recursive'):
494
+ r"""
495
+ Return the Fibonacci word on the given two-letter alphabet.
496
+
497
+ INPUT:
498
+
499
+ - ``alphabet`` -- any container of length two that is suitable to
500
+ build an instance of OrderedAlphabet (``list``, ``tuple``, ``str``, ...)
501
+
502
+ - ``construction_method`` -- can be any of the following:
503
+ "recursive", "fixed point", "function" (see below for definitions)
504
+
505
+ Recursive construction: the Fibonacci word is the limit of the
506
+ following sequence of words: `S_0 = 0`, `S_1 = 01`,
507
+ `S_n = S_{n-1} S_{n-2}` for `n \geq 2`.
508
+
509
+ Fixed point construction: the Fibonacci word is the fixed point of the
510
+ morphism: `0 \mapsto 01` and `1 \mapsto 0`. Hence, it can be constructed
511
+ by the following read-write process:
512
+
513
+ #. beginning at the first letter of `01`,
514
+ #. if the next letter is `0`, append `01` to the word;
515
+ #. if the next letter is `1`, append `1` to the word;
516
+ #. move to the next letter of the word.
517
+
518
+ Function: Over the alphabet `\{1, 2\}`, the `n`-th letter of the
519
+ Fibonacci word is
520
+ `\lfloor (n+2) \varphi \rfloor - \lfloor (n+1) \varphi \rfloor`
521
+ where `\varphi=(1+\sqrt{5})/2` is the golden ratio.
522
+
523
+ EXAMPLES::
524
+
525
+ sage: w = words.FibonacciWord(construction_method='recursive'); w
526
+ word: 0100101001001010010100100101001001010010...
527
+
528
+ ::
529
+
530
+ sage: v = words.FibonacciWord(construction_method='recursive', alphabet='ab'); v
531
+ word: abaababaabaababaababaabaababaabaababaaba...
532
+
533
+ ::
534
+
535
+ sage: u = words.FibonacciWord(construction_method="fixed point"); u
536
+ word: 0100101001001010010100100101001001010010...
537
+
538
+ ::
539
+
540
+ sage: words.FibonacciWord(construction_method="fixed point", alphabet=[4, 1])
541
+ word: 4144141441441414414144144141441441414414...
542
+
543
+ ::
544
+
545
+ sage: words.FibonacciWord([0,1], 'function') # needs sage.symbolic
546
+ word: 0100101001001010010100100101001001010010...
547
+ sage: words.FibonacciWord('ab', 'function') # needs sage.symbolic
548
+ word: abaababaabaababaababaabaababaabaababaaba...
549
+
550
+ TESTS::
551
+
552
+ sage: from math import floor, sqrt
553
+ sage: golden_ratio = (1 + sqrt(5))/2.0
554
+ sage: a = golden_ratio / (1 + 2*golden_ratio)
555
+ sage: wn = lambda n : int(floor(a*(n+2)) - floor(a*(n+1)))
556
+ sage: f = Words([0,1])(wn); f
557
+ word: 0100101001001010010100100101001001010010...
558
+ sage: f[:10000] == w[:10000]
559
+ True
560
+ sage: f[:10000] == u[:10000] #long time
561
+ True
562
+ sage: words.FibonacciWord("abc")
563
+ Traceback (most recent call last):
564
+ ...
565
+ TypeError: alphabet does not contain two distinct elements
566
+ """
567
+ W = InfiniteWords(alphabet)
568
+ alphabet = W.alphabet()
569
+ if alphabet.cardinality() != 2:
570
+ raise TypeError("alphabet does not contain two distinct elements")
571
+ a,b = alphabet
572
+
573
+ if construction_method == "recursive":
574
+ w = W(self._FibonacciWord_RecursiveConstructionIterator(alphabet),
575
+ datatype='iter')
576
+ return w
577
+
578
+ elif construction_method in ("fixed point", "fixed_point"):
579
+ d = {b:[a],a:[a,b]}
580
+ w = self.FixedPointOfMorphism(d, a)
581
+ return w
582
+
583
+ elif construction_method == "function":
584
+ from sage.functions.other import floor
585
+ from sage.misc.functional import sqrt
586
+ phi = (1 + sqrt(5))/2 # the golden ratio
587
+ f = lambda n:a if floor((n+2)*phi) - floor((n+1)*phi) == 2 else b
588
+ return W(f)
589
+
590
+ else:
591
+ raise NotImplementedError
592
+
593
+ def _FibonacciWord_RecursiveConstructionIterator(self, alphabet=(0, 1)):
594
+ r"""
595
+ Iterate over the symbols of the Fibonacci word, as defined by
596
+ the following recursive construction: the Fibonacci word is the
597
+ limit of the sequence `S_0 = 0`, `S_1 = 01`, `S_n = S_{n-1}
598
+ S_{n-2}` for `n \geq 2`.
599
+
600
+ TESTS::
601
+
602
+ sage: from sage.combinat.words.word_generators import WordGenerator
603
+ sage: from itertools import islice
604
+ sage: it = WordGenerator()._FibonacciWord_RecursiveConstructionIterator()
605
+ sage: list(islice(it,13r))
606
+ [0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1]
607
+ """
608
+ Fib0 = [0]
609
+ Fib1 = [0,1]
610
+ n = 0
611
+ while True:
612
+ it = iter(Fib1[n:])
613
+ for i in it:
614
+ n += 1
615
+ yield alphabet[i]
616
+ Fib1, Fib0 = Fib1 + Fib0, Fib1
617
+
618
+ def FixedPointOfMorphism(self, morphism, first_letter):
619
+ r"""
620
+ Return the fixed point of the morphism beginning with
621
+ ``first_letter``.
622
+
623
+ A *fixed point* of a morphism `\varphi` is a word `w` such that
624
+ `\varphi(w) = w`.
625
+
626
+ INPUT:
627
+
628
+ - ``morphism`` -- endomorphism prolongable on ``first_letter``. It
629
+ must be something that WordMorphism's constructor understands
630
+ (dict, str, ...).
631
+
632
+ - ``first_letter`` -- the first letter of the fixed point
633
+
634
+ OUTPUT: the fixed point of the morphism beginning with ``first_letter``
635
+
636
+ EXAMPLES::
637
+
638
+ sage: mu = {0:[0,1], 1:[1,0]}
639
+ sage: tm = words.FixedPointOfMorphism(mu,0); tm
640
+ word: 0110100110010110100101100110100110010110...
641
+ sage: TM = words.ThueMorseWord()
642
+ sage: tm[:1000] == TM[:1000] # needs sage.modules
643
+ True
644
+
645
+ ::
646
+
647
+ sage: mu = {0:[0,1], 1:[0]}
648
+ sage: f = words.FixedPointOfMorphism(mu,0); f
649
+ word: 0100101001001010010100100101001001010010...
650
+ sage: F = words.FibonacciWord(); F
651
+ word: 0100101001001010010100100101001001010010...
652
+ sage: f[:1000] == F[:1000] # needs sage.modules
653
+ True
654
+
655
+ ::
656
+
657
+ sage: fp = words.FixedPointOfMorphism('a->abc,b->,c->','a'); fp
658
+ word: abc
659
+ """
660
+ return WordMorphism(morphism).fixed_point(letter=first_letter)
661
+
662
+ def CodingOfRotationWord(self, alpha, beta, x=0, alphabet=(0, 1)):
663
+ r"""
664
+ Return the infinite word obtained from the coding of rotation of
665
+ parameters `(\alpha,\beta, x)` over the given two-letter alphabet.
666
+
667
+ The *coding of rotation* corresponding to the parameters
668
+ `(\alpha,\beta, x)` is the symbolic sequence `u = (u_n)_{n\geq 0}`
669
+ defined over the binary alphabet `\{0, 1\}` by `u_n = 1` if
670
+ `x+n\alpha\in[0, \beta[` and `u_n = 0` otherwise. See [AC03]_.
671
+
672
+ EXAMPLES::
673
+
674
+ sage: alpha = 0.45
675
+ sage: beta = 0.48
676
+ sage: words.CodingOfRotationWord(0.45, 0.48)
677
+ word: 1101010101001010101011010101010010101010...
678
+
679
+ ::
680
+
681
+ sage: words.CodingOfRotationWord(0.45, 0.48, alphabet='xy')
682
+ word: yyxyxyxyxyxxyxyxyxyxyyxyxyxyxyxxyxyxyxyx...
683
+
684
+ TESTS::
685
+
686
+ sage: words.CodingOfRotationWord(0.51,0.43,alphabet=[1,0,2])
687
+ Traceback (most recent call last):
688
+ ...
689
+ TypeError: alphabet does not contain two distinct elements
690
+ """
691
+ if len(set(alphabet)) != 2:
692
+ raise TypeError("alphabet does not contain two distinct elements")
693
+ from functools import partial
694
+ f = partial(self._CodingOfRotationWord_function,alpha=alpha,beta=beta,x=x,alphabet=alphabet)
695
+ w = InfiniteWords(alphabet)(f, datatype='callable')
696
+ return w
697
+
698
+ def _CodingOfRotationWord_function(self, n, alpha, beta, x=0, alphabet=(0, 1)):
699
+ r"""
700
+ Internal function that returns the symbol in position `n` of the
701
+ coding of rotation word corresponding to the parameters `\alpha`,
702
+ `\beta`, and `x`.
703
+
704
+ TESTS::
705
+
706
+ sage: alpha, beta = 0.45, 0.48
707
+ sage: words._CodingOfRotationWord_function(3, alpha, beta)
708
+ 1
709
+ sage: words._CodingOfRotationWord_function(10, alpha, beta)
710
+ 0
711
+ sage: words._CodingOfRotationWord_function(17, alpha, beta)
712
+ 0
713
+ """
714
+ hauteur = x + n * alpha
715
+ fracH = hauteur.frac()
716
+ if fracH < 0:
717
+ fracH += 1
718
+ if 0 <= fracH < beta:
719
+ return alphabet[1]
720
+ else:
721
+ return alphabet[0]
722
+
723
+ @rename_keyword(cf='slope')
724
+ def CharacteristicSturmianWord(self, slope, alphabet=(0, 1), bits=None):
725
+ r"""
726
+ Return the characteristic Sturmian word (also called standard
727
+ Sturmian word) of given slope.
728
+
729
+ Over a binary alphabet `\{a,b\}`, the characteristic Sturmian
730
+ word `c_\alpha` of irrational slope `\alpha` is the infinite word
731
+ satisfying `s_{\alpha,0} = ac_\alpha` and `s'_{\alpha,0} = bc_\alpha`,
732
+ where `s_{\alpha,0}` and `s'_{\alpha,0}` are respectively the lower
733
+ and upper mechanical words with slope `\alpha` and intercept `0`.
734
+ Equivalently, for irrational `\alpha`,
735
+ `c_\alpha = s_{\alpha,\alpha} = s'_{\alpha,\alpha}`.
736
+
737
+ Let `\alpha = [0, d_1 + 1, d_2, d_3, \ldots]` be the continued
738
+ fraction expansion of `\alpha`. It has been shown that the
739
+ characteristic Sturmian word of slope `\alpha` is also the limit of
740
+ the sequence: `s_0 = b, s_1 = a, \ldots, s_{n+1} = s_n^{d_n} s_{n-1}`
741
+ for `n > 0`.
742
+
743
+ See Section 2.1 of [Loth02]_ for more details.
744
+
745
+ INPUT:
746
+
747
+ - ``slope`` -- the slope of the word. It can be one of the following:
748
+
749
+ - real number in `]0, 1[`
750
+
751
+ - iterable over the continued fraction expansion of a real
752
+ number in `]0, 1[`
753
+
754
+ - ``alphabet`` -- any container of length two that is suitable to
755
+ build an instance of OrderedAlphabet (``list``, ``tuple``, ``str``,
756
+ ...)
757
+
758
+ - ``bits`` -- integer (optional and considered only if ``slope`` is
759
+ a real number); the number of bits to consider when computing the
760
+ continued fraction
761
+
762
+ OUTPUT: word
763
+
764
+ ALGORITHM:
765
+
766
+ Let `[0, d_1 + 1, d_2, d_3, \ldots]` be the continued fraction
767
+ expansion of `\alpha`. Then, the characteristic Sturmian word of
768
+ slope `\alpha` is the limit of the sequence: `s_0 = b`, `s_1 = a`
769
+ and `s_{n+1} = s_n^{d_n} s_{n-1}` for `n > 0`.
770
+
771
+ EXAMPLES:
772
+
773
+ From real slope::
774
+
775
+ sage: words.CharacteristicSturmianWord(1/golden_ratio^2) # needs sage.symbolic
776
+ word: 0100101001001010010100100101001001010010...
777
+ sage: words.CharacteristicSturmianWord(4/5) # needs sage.rings.real_mpfr
778
+ word: 11110
779
+ sage: words.CharacteristicSturmianWord(5/14) # needs sage.rings.real_mpfr
780
+ word: 01001001001001
781
+ sage: words.CharacteristicSturmianWord(pi - 3) # needs sage.symbolic
782
+ word: 0000001000000100000010000001000000100000...
783
+
784
+ From an iterator of the continued fraction expansion of a real::
785
+
786
+ sage: def cf():
787
+ ....: yield 0
788
+ ....: yield 2
789
+ ....: while True: yield 1
790
+ sage: F = words.CharacteristicSturmianWord(cf()); F # needs sage.rings.real_mpfr
791
+ word: 0100101001001010010100100101001001010010...
792
+ sage: Fib = words.FibonacciWord(); Fib
793
+ word: 0100101001001010010100100101001001010010...
794
+ sage: F[:10000] == Fib[:10000] # needs sage.rings.real_mpfr
795
+ True
796
+
797
+ The alphabet may be specified::
798
+
799
+ sage: words.CharacteristicSturmianWord(cf(), 'rs') # needs sage.rings.real_mpfr
800
+ word: rsrrsrsrrsrrsrsrrsrsrrsrrsrsrrsrrsrsrrsr...
801
+
802
+ The characteristic sturmian word of slope `(\sqrt{3}-1)/2`::
803
+
804
+ sage: words.CharacteristicSturmianWord((sqrt(3)-1)/2) # needs sage.symbolic
805
+ word: 0100100101001001001010010010010100100101...
806
+
807
+ The same word defined from the continued fraction expansion of
808
+ `(\sqrt{3}-1)/2`::
809
+
810
+ sage: from itertools import cycle, chain
811
+ sage: it = chain([0], cycle([2, 1]))
812
+ sage: words.CharacteristicSturmianWord(it) # needs sage.rings.real_mpfr
813
+ word: 0100100101001001001010010010010100100101...
814
+
815
+ The first terms of the standard sequence of the characteristic
816
+ sturmian word of slope `(\sqrt{3}-1)/2`::
817
+
818
+ sage: words.CharacteristicSturmianWord([0,2])
819
+ word: 01
820
+ sage: words.CharacteristicSturmianWord([0,2,1])
821
+ word: 010
822
+ sage: words.CharacteristicSturmianWord([0,2,1,2])
823
+ word: 01001001
824
+ sage: words.CharacteristicSturmianWord([0,2,1,2,1])
825
+ word: 01001001010
826
+ sage: words.CharacteristicSturmianWord([0,2,1,2,1,2])
827
+ word: 010010010100100100101001001001
828
+ sage: words.CharacteristicSturmianWord([0,2,1,2,1,2,1])
829
+ word: 0100100101001001001010010010010100100101...
830
+
831
+ TESTS::
832
+
833
+ sage: words.CharacteristicSturmianWord([1,1,1],'xyz')
834
+ Traceback (most recent call last):
835
+ ...
836
+ TypeError: alphabet does not contain two distinct elements
837
+
838
+ ::
839
+
840
+ sage: words.CharacteristicSturmianWord(5/4)
841
+ Traceback (most recent call last):
842
+ ...
843
+ ValueError: the argument slope (=5/4) must be in ]0,1[
844
+
845
+ ::
846
+
847
+ sage: words.CharacteristicSturmianWord(1/golden_ratio^2) # needs sage.symbolic
848
+ word: 0100101001001010010100100101001001010010...
849
+ sage: _.length() # needs sage.symbolic
850
+ +Infinity
851
+
852
+ ::
853
+
854
+ sage: # needs sage.symbolic
855
+ sage: a = words.LowerMechanicalWord(1/pi)[1:]
856
+ sage: b = words.UpperMechanicalWord(1/pi)[1:]
857
+ sage: c = words.CharacteristicSturmianWord(1/pi)
858
+ sage: n = 500; a[:n] == b[:n] == c[:n]
859
+ True
860
+
861
+ ::
862
+
863
+ sage: alpha = random()
864
+ sage: c = words.CharacteristicSturmianWord(alpha)
865
+ sage: l = words.LowerMechanicalWord(alpha)[1:]
866
+ sage: u = words.UpperMechanicalWord(alpha)[1:]
867
+ sage: i = 10000; j = i + 500; c[i:j] == l[i:j] == u[i:j]
868
+ True
869
+
870
+ ::
871
+
872
+ sage: a, b = 207, 232
873
+ sage: u = words.ChristoffelWord(a, b)
874
+ sage: v = words.CharacteristicSturmianWord(a/(a+b))
875
+ sage: v.length()
876
+ 439
877
+ sage: u[1:-1] == v[:-2]
878
+ True
879
+ """
880
+ if len(set(alphabet)) != 2:
881
+ raise TypeError("alphabet does not contain two distinct elements")
882
+
883
+ if slope in RR:
884
+ if not 0 < slope < 1:
885
+ msg = "the argument slope (=%s) must be in ]0,1[" % slope
886
+ raise ValueError(msg)
887
+ from sage.rings.continued_fraction import continued_fraction
888
+ cf = continued_fraction(slope)
889
+ if cf.length() == Infinity:
890
+ parent = InfiniteWords(alphabet)
891
+ else:
892
+ parent = FiniteWords(alphabet)
893
+ cf = iter(cf)
894
+ elif isinstance(slope, Iterable):
895
+ cf = iter(slope)
896
+ parent = InfiniteWords(alphabet)
897
+ else:
898
+ raise TypeError("slope (=%s) must be a real number" % slope +
899
+ "or an iterable")
900
+ w = parent(self._CharacteristicSturmianWord_LetterIterator(cf,alphabet),
901
+ datatype='iter')
902
+ return w
903
+
904
+ def _CharacteristicSturmianWord_LetterIterator(self, cf, alphabet=(0, 1)):
905
+ r"""
906
+ Return an iterator over the symbols of the characteristic
907
+ Sturmian word of slope ``cf``.
908
+
909
+ INPUT:
910
+
911
+ - ``cf`` -- iterator, the continued fraction expansion of a real
912
+ number in `]0, 1[`
913
+ - ``alphabet`` -- the alphabet (default: ``(0,1)``) of
914
+ the output
915
+
916
+ OUTPUT: iterator of letters
917
+
918
+ ALGORITHM:
919
+
920
+ Let `[0, d_1 + 1, d_2, d_3, \ldots]` be the continued fraction
921
+ expansion of `\alpha`. Then, the characteristic Sturmian word of
922
+ slope `\alpha` is the limit of the sequence: `s_0 = 1`, `s_1 = 0`
923
+ and `s_{n+1} = s_n^{d_n} s_{n-1}` for `n > 0`.
924
+
925
+ EXAMPLES::
926
+
927
+ sage: continued_fraction(1/golden_ratio^2)[:8] # needs sage.symbolic
928
+ [0; 2, 1, 1, 1, 1, 2]
929
+ sage: cf = iter(_) # needs sage.symbolic
930
+ sage: Word(words._CharacteristicSturmianWord_LetterIterator(cf)) # needs sage.symbolic
931
+ word: 0100101001001010010100100101001010
932
+
933
+ ::
934
+
935
+ sage: # needs sage.symbolic
936
+ sage: alpha = (sqrt(3)-1)/2
937
+ sage: continued_fraction(alpha)[:10]
938
+ [0; 2, 1, 2, 1, 2, 1, 2, 1, 2]
939
+ sage: cf = iter(_)
940
+ sage: Word(words._CharacteristicSturmianWord_LetterIterator(cf))
941
+ word: 0100100101001001001010010010010100100101...
942
+ """
943
+ try:
944
+ if next(cf) != 0:
945
+ raise ValueError("the first term of the continued fraction expansion must be zero")
946
+ except StopIteration:
947
+ return
948
+
949
+ s0 = [1]
950
+ s1 = [0]
951
+ try:
952
+ e = next(cf)
953
+ except StopIteration:
954
+ return
955
+
956
+ if not e >= 1:
957
+ raise ValueError("the second term of the continued fraction expansion must be larger or equal to 1")
958
+ s1, s0 = s1*(e-1) + s0, s1
959
+ n = 0
960
+ while True:
961
+ try:
962
+ for i in s1[n:]:
963
+ n += 1
964
+ yield alphabet[i]
965
+ s1, s0 = s1*next(cf) + s0, s1
966
+ except StopIteration:
967
+ return
968
+
969
+ def KolakoskiWord(self, alphabet=(1, 2)):
970
+ r"""
971
+ Return the Kolakoski word over the given alphabet and
972
+ starting with the first letter of the alphabet.
973
+
974
+ Let `A = \{a,b\}` be an alphabet, where `a` and `b` are two
975
+ distinct positive integers. The Kolakoski word `K_{a,b}`
976
+ over `A` and starting with `a` is the unique infinite word `w`
977
+ such that `w = \Delta(w)`, where `\Delta(w)` is the word
978
+ encoding the runs of `w` (see ``delta()`` method on words for
979
+ more details).
980
+
981
+ Note that `K_{a,b} \neq K_{b,a}`. On the other hand, the
982
+ words `K_{a,b}` and `K_{b,a}` are the unique two words over `A`
983
+ that are fixed by `\Delta`.
984
+
985
+ Also note that the Kolakoski word is also known as the
986
+ Oldenburger word.
987
+
988
+ INPUT:
989
+
990
+ - ``alphabet`` -- (default: (1,2)) an iterable of two positive
991
+ integers
992
+
993
+ OUTPUT: infinite word
994
+
995
+ EXAMPLES:
996
+
997
+ The usual Kolakoski word::
998
+
999
+ sage: w = words.KolakoskiWord()
1000
+ sage: w
1001
+ word: 1221121221221121122121121221121121221221...
1002
+ sage: w.delta()
1003
+ word: 1221121221221121122121121221121121221221...
1004
+
1005
+ The other Kolakoski word on the same alphabet::
1006
+
1007
+ sage: w = words.KolakoskiWord(alphabet = (2,1))
1008
+ sage: w
1009
+ word: 2211212212211211221211212211211212212211...
1010
+ sage: w.delta()
1011
+ word: 2211212212211211221211212211211212212211...
1012
+
1013
+ It is naturally generalized to any two integers alphabet::
1014
+
1015
+ sage: w = words.KolakoskiWord(alphabet = (2,5))
1016
+ sage: w
1017
+ word: 2255222225555522552255225555522222555552...
1018
+ sage: w.delta()
1019
+ word: 2255222225555522552255225555522222555552...
1020
+
1021
+ TESTS::
1022
+
1023
+ sage: for i in range(1,10):
1024
+ ....: for j in range(1,10):
1025
+ ....: if i != j:
1026
+ ....: w = words.KolakoskiWord(alphabet=(i,j))
1027
+ ....: assert w[:50] == w.delta()[:50]
1028
+
1029
+ ::
1030
+
1031
+ sage: words.KolakoskiWord((0, 2))
1032
+ Traceback (most recent call last):
1033
+ ...
1034
+ ValueError: the alphabet (=(0, 2)) must consist of two distinct positive integers
1035
+
1036
+ REFERENCES:
1037
+
1038
+ .. [Kolakoski66] William Kolakoski, proposal 5304, American Mathematical Monthly
1039
+ 72 (1965), 674; for a partial solution, see "Self Generating Runs,"
1040
+ by Necdet Üçoluk, Amer. Math. Mon. 73 (1966), 681-2.
1041
+ """
1042
+ a, b = alphabet
1043
+ if a not in ZZ or a <= 0 or b not in ZZ or b <= 0 or a == b:
1044
+ msg = 'the alphabet (=%s) must consist of two distinct positive integers' % (alphabet,)
1045
+ raise ValueError(msg)
1046
+ return InfiniteWords(alphabet)(self._KolakoskiWord_iterator(a, b), datatype='iter')
1047
+
1048
+ def _KolakoskiWord_iterator(self, a=1, b=2):
1049
+ r"""
1050
+ Return an iterator over the Kolakoski word over ``{a,b}``
1051
+ and starting with ``a``.
1052
+
1053
+ Let `A = \{a,b\}` be an alphabet, where `a` and `b` are two
1054
+ distinct positive integers. The Kolakoski word `K_{a,b}`
1055
+ over `A` and starting with `a` is the unique infinite word `w`
1056
+ such that `w = \Delta(w)`, where `\Delta(w)` is the word
1057
+ encoding the runs of `w` (see ``delta()`` method on words for
1058
+ more details).
1059
+
1060
+ Note that `K_{a,b} \neq K_{b,a}`. On the other hand, the
1061
+ words `K_{a,b}` and `K_{b,a}` are the unique two words over `A`
1062
+ that are fixed by `\Delta`.
1063
+
1064
+ INPUT:
1065
+
1066
+ - ``a`` -- positive integer (default: 1); the first letter occurring
1067
+ in the returned Kolakoski word
1068
+ - ``b`` -- positive integer (default: 2); the second and last letter
1069
+ occurring in the returned Kolakoski word
1070
+
1071
+ OUTPUT: iterator
1072
+
1073
+ EXAMPLES:
1074
+
1075
+ The first ten letters of `K_{3,5}`::
1076
+
1077
+ sage: iter = words._KolakoskiWord_iterator(3, 5)
1078
+ sage: Word(iter)[:10]
1079
+ word: 3335553335
1080
+
1081
+ See ``words.KolakoskiWord()`` for more documentation.
1082
+ """
1083
+ # First, we need to treat the basis case
1084
+ w = [a] * a
1085
+ for _ in range(a):
1086
+ yield a
1087
+ if a == 1:
1088
+ w.extend([b] * b)
1089
+ for _ in range(b):
1090
+ yield b
1091
+ w.pop(0)
1092
+ w.pop(0)
1093
+ # Letters swap function
1094
+ bar = lambda x: a if x == b else b
1095
+ current_letter = bar(w[-1])
1096
+ # Now we are ready to go in the recursive part
1097
+ while True:
1098
+ for _ in range(w[0]):
1099
+ yield current_letter
1100
+ w.append(current_letter)
1101
+ w.pop(0)
1102
+ current_letter = bar(current_letter)
1103
+
1104
+ def LowerMechanicalWord(self, alpha, rho=0, alphabet=None):
1105
+ r"""
1106
+ Return the lower mechanical word with slope `\alpha` and
1107
+ intercept `\rho`
1108
+
1109
+ The lower mechanical word `s_{\alpha,\rho}` with
1110
+ slope `\alpha` and intercept `\rho` is defined by
1111
+ `s_{\alpha,\rho}(n) = \lfloor\alpha(n+1) + \rho\rfloor -
1112
+ \lfloor\alpha n + \rho\rfloor`. [Loth02]_
1113
+
1114
+ INPUT:
1115
+
1116
+ - ``alpha`` -- real number such that `0 \leq\alpha\leq 1`
1117
+
1118
+ - ``rho`` -- real number (default: 0)
1119
+
1120
+ - ``alphabet`` -- iterable of two elements or ``None``
1121
+ (default: ``None``)
1122
+
1123
+ OUTPUT: infinite word
1124
+
1125
+ EXAMPLES::
1126
+
1127
+ sage: words.LowerMechanicalWord(1/golden_ratio^2) # needs sage.symbolic
1128
+ word: 0010010100100101001010010010100100101001...
1129
+ sage: words.LowerMechanicalWord(1/5) # needs sage.symbolic
1130
+ word: 0000100001000010000100001000010000100001...
1131
+ sage: words.LowerMechanicalWord(1/pi) # needs sage.symbolic
1132
+ word: 0001001001001001001001000100100100100100...
1133
+
1134
+ TESTS::
1135
+
1136
+ sage: m = words.LowerMechanicalWord(1/golden_ratio^2)[1:] # needs sage.symbolic
1137
+ sage: s = words.CharacteristicSturmianWord(1/golden_ratio^2) # needs sage.symbolic
1138
+ sage: m[:500] == s[:500] # needs sage.symbolic
1139
+ True
1140
+
1141
+ Check that this returns a word in an alphabet (:issue:`10054`)::
1142
+
1143
+ sage: words.UpperMechanicalWord(1/golden_ratio^2).parent() # needs sage.symbolic
1144
+ Infinite words over {0, 1}
1145
+ """
1146
+ if not 0 <= alpha <= 1:
1147
+ raise ValueError("parameter alpha (=%s) must be in [0,1]" % alpha)
1148
+
1149
+ from sage.functions.other import floor
1150
+ from sage.combinat.words.alphabet import build_alphabet
1151
+ if alphabet is None or alphabet in ((0, 1), [0, 1]):
1152
+ alphabet = build_alphabet([0, 1])
1153
+ s = lambda n: floor(alpha*(n+1) + rho) - floor(alpha*n + rho)
1154
+ else:
1155
+ alphabet = build_alphabet(alphabet)
1156
+ card = alphabet.cardinality()
1157
+ if card != 2:
1158
+ raise TypeError("size of alphabet (=%s) must be two" % card)
1159
+ s = lambda n: alphabet[floor(alpha*(n+1) + rho) - floor(alpha*n + rho)]
1160
+ return InfiniteWords(alphabet)(s)
1161
+
1162
+ def UpperMechanicalWord(self, alpha, rho=0, alphabet=None):
1163
+ r"""
1164
+ Return the upper mechanical word with slope `\alpha` and
1165
+ intercept `\rho`
1166
+
1167
+ The upper mechanical word `s'_{\alpha,\rho}` with
1168
+ slope `\alpha` and intercept `\rho` is defined by
1169
+ `s'_{\alpha,\rho}(n) = \lceil\alpha(n+1) + \rho\rceil -
1170
+ \lceil\alpha n + \rho\rceil`. [Loth02]_
1171
+
1172
+ INPUT:
1173
+
1174
+ - ``alpha`` -- real number such that `0 \leq\alpha\leq 1`
1175
+
1176
+ - ``rho`` -- real number (default: 0)
1177
+
1178
+ - ``alphabet`` -- iterable of two elements or ``None``
1179
+ (default: ``None``)
1180
+
1181
+ OUTPUT: infinite word
1182
+
1183
+ EXAMPLES::
1184
+
1185
+ sage: words.UpperMechanicalWord(1/golden_ratio^2) # needs sage.symbolic
1186
+ word: 1010010100100101001010010010100100101001...
1187
+ sage: words.UpperMechanicalWord(1/5) # needs sage.symbolic
1188
+ word: 1000010000100001000010000100001000010000...
1189
+ sage: words.UpperMechanicalWord(1/pi) # needs sage.symbolic
1190
+ word: 1001001001001001001001000100100100100100...
1191
+
1192
+ TESTS::
1193
+
1194
+ sage: m = words.UpperMechanicalWord(1/golden_ratio^2)[1:] # needs sage.symbolic
1195
+ sage: s = words.CharacteristicSturmianWord(1/golden_ratio^2) # needs sage.symbolic
1196
+ sage: m[:500] == s[:500] # needs sage.symbolic
1197
+ True
1198
+
1199
+ Check that this returns a word in an alphabet (:issue:`10054`)::
1200
+
1201
+ sage: words.UpperMechanicalWord(1/golden_ratio^2).parent() # needs sage.symbolic
1202
+ Infinite words over {0, 1}
1203
+ """
1204
+ if not 0 <= alpha <= 1:
1205
+ raise ValueError("parameter alpha (=%s) must be in [0,1]" % alpha)
1206
+
1207
+ from sage.functions.other import ceil
1208
+ from sage.combinat.words.alphabet import build_alphabet
1209
+ if alphabet is None or alphabet in ((0, 1), [0, 1]):
1210
+ alphabet = build_alphabet([0, 1])
1211
+ s = lambda n: ceil(alpha*(n+1) + rho) - ceil(alpha*n + rho)
1212
+ else:
1213
+ alphabet = build_alphabet(alphabet)
1214
+ card = alphabet.cardinality()
1215
+ if card != 2:
1216
+ raise TypeError("size of alphabet (=%s) must be two" % card)
1217
+ s = lambda n: alphabet[ceil(alpha*(n+1) + rho) - ceil(alpha*n + rho)]
1218
+ return InfiniteWords(alphabet)(s)
1219
+
1220
+ def StandardEpisturmianWord(self, directive_word):
1221
+ r"""
1222
+ Return the standard episturmian word (or epistandard word) directed by
1223
+ directive_word. Over a 2-letter alphabet, this function
1224
+ gives characteristic Sturmian words.
1225
+
1226
+ An infinite word `w` over a finite alphabet `A` is said to be
1227
+ *standard episturmian* (or *epistandard*) iff there exists an
1228
+ infinite word `x_1x_2x_3\cdots` over `A` (called the *directive
1229
+ word* of `w`) such that `w` is the limit as `n` goes to infinity of
1230
+ `Pal(x_1\cdots x_n)`, where `Pal` is the iterated palindromic closure
1231
+ function.
1232
+
1233
+ Note that an infinite word is *episturmian* if it has the same set
1234
+ of factors as some epistandard word.
1235
+
1236
+ See for instance [DJP2001]_, [JP2002]_, and [GJ2007]_.
1237
+
1238
+ INPUT:
1239
+
1240
+ - ``directive_word`` -- an infinite word or a period of a periodic
1241
+ infinite word
1242
+
1243
+ EXAMPLES::
1244
+
1245
+ sage: Fibonacci = words.StandardEpisturmianWord(Words('ab')('ab')); Fibonacci
1246
+ word: abaababaabaababaababaabaababaabaababaaba...
1247
+ sage: Tribonacci = words.StandardEpisturmianWord(Words('abc')('abc')); Tribonacci
1248
+ word: abacabaabacababacabaabacabacabaabacababa...
1249
+ sage: S = words.StandardEpisturmianWord(Words('abcd')('aabcabada')); S
1250
+ word: aabaacaabaaabaacaabaabaacaabaaabaacaabaa...
1251
+ sage: S = words.StandardEpisturmianWord(Fibonacci); S
1252
+ word: abaabaababaabaabaababaabaababaabaabaabab...
1253
+ sage: S[:25]
1254
+ word: abaabaababaabaabaababaaba
1255
+ sage: S = words.StandardEpisturmianWord(Tribonacci); S
1256
+ word: abaabacabaabaabacabaababaabacabaabaabaca...
1257
+ sage: words.StandardEpisturmianWord(123)
1258
+ Traceback (most recent call last):
1259
+ ...
1260
+ TypeError: directive_word is not a word, so it cannot be used to build an episturmian word
1261
+ sage: words.StandardEpisturmianWord(Words('ab'))
1262
+ Traceback (most recent call last):
1263
+ ...
1264
+ TypeError: directive_word is not a word, so it cannot be used to build an episturmian word
1265
+ """
1266
+ if not isinstance(directive_word, Word_class):
1267
+ raise TypeError("directive_word is not a word, so it cannot be used to build an episturmian word")
1268
+ epistandard = directive_word.parent()(
1269
+ self._StandardEpisturmianWord_LetterIterator(directive_word),
1270
+ datatype='iter')
1271
+ return epistandard
1272
+
1273
+ def _StandardEpisturmianWord_LetterIterator(self, directive_word):
1274
+ r"""
1275
+ Internal iterating over the symbols of the standard episturmian
1276
+ word defined by the (directive) word directive_word.
1277
+
1278
+ An infinite word `w` over a finite alphabet `A` is standard episturmian
1279
+ (or epistandard) iff there exists an infinite word `x_1x_2x_3\ldots`
1280
+ over `A` (called the directive word of `w`) such that `w` is the limit
1281
+ as `n` goes to infinity of `Pal(x_1x_2\cdots x_n)`, where `Pal` is the
1282
+ iterated palindromic closure function.
1283
+
1284
+ INPUT:
1285
+
1286
+ - ``directive_word`` -- an infinite word or a finite word; if
1287
+ directive_word is finite, then it is repeated to give
1288
+ an infinite word
1289
+
1290
+ TESTS::
1291
+
1292
+ sage: import itertools
1293
+ sage: it = words._StandardEpisturmianWord_LetterIterator(Word('ab'))
1294
+ sage: list(itertools.islice(it, 13r))
1295
+ ['a', 'b', 'a', 'a', 'b', 'a', 'b', 'a', 'a', 'b', 'a', 'a', 'b']
1296
+ """
1297
+ if isinstance(directive_word, FiniteWord_class):
1298
+ d = cycle(directive_word)
1299
+ else:
1300
+ d = iter(directive_word)
1301
+ W = directive_word.parent()
1302
+ w = W(next(d))
1303
+ n = 0
1304
+ while True:
1305
+ for x in w[n:]:
1306
+ n += 1
1307
+ yield x
1308
+ w = W(w * W(next(d))).palindromic_closure()
1309
+
1310
+ def MinimalSmoothPrefix(self, n):
1311
+ r"""
1312
+ This function finds and returns the minimal smooth prefix of length
1313
+ ``n``.
1314
+
1315
+ See [BMP2007]_ for a definition.
1316
+
1317
+ INPUT:
1318
+
1319
+ - ``n`` -- the desired length of the prefix
1320
+
1321
+ OUTPUT: word; the prefix
1322
+
1323
+ .. NOTE::
1324
+
1325
+ Be patient, this function can take a really long time if asked
1326
+ for a large prefix.
1327
+
1328
+ EXAMPLES::
1329
+
1330
+ sage: words.MinimalSmoothPrefix(10)
1331
+ word: 1212212112
1332
+ """
1333
+ tab = []
1334
+ W = FiniteWords([1, 2])
1335
+ suff1 = W([1, 2, 2]).phi_inv()
1336
+ suff2 = W([2, 2]).phi_inv()
1337
+ w = [1]
1338
+ tab = _build_tab(1, tab, W)
1339
+ for k in range(1, n):
1340
+ if suff1._phi_inv_tab(tab) < suff2._phi_inv_tab(tab):
1341
+ w.append(1)
1342
+ tab = _build_tab(1, tab, W)
1343
+ else:
1344
+ w.append(2)
1345
+ tab = _build_tab(2, tab, W)
1346
+ return W(w)
1347
+
1348
+ def RandomWord(self, n, m=2, alphabet=None):
1349
+ r"""
1350
+ Return a random word of length `n` over the given `m`-letter
1351
+ alphabet.
1352
+
1353
+ INPUT:
1354
+
1355
+ - ``n`` -- integer; the length of the word
1356
+ - ``m`` -- integer (default: 2); the size of the output alphabet
1357
+ - ``alphabet`` -- (default: `\{0,1,...,m-1\}`) any container of
1358
+ length m that is suitable to build an instance of
1359
+ OrderedAlphabet (``list``, ``tuple``, ``str``, ...)
1360
+
1361
+ EXAMPLES::
1362
+
1363
+ sage: words.RandomWord(10) # random results
1364
+ word: 0110100101
1365
+ sage: words.RandomWord(10, 4) # random results
1366
+ word: 0322313320
1367
+ sage: words.RandomWord(100, 7) # random results
1368
+ word: 2630644023642516442650025611300034413310...
1369
+ sage: words.RandomWord(100, 7, range(-3,4)) # random results
1370
+ word: 1,3,-1,-1,3,2,2,0,1,-2,1,-1,-3,-2,2,0,3,0,-3,0,3,0,-2,-2,2,0,1,-3,2,-2,-2,2,0,2,1,-2,-3,-2,-1,0,...
1371
+ sage: words.RandomWord(100, 5, "abcde") # random results
1372
+ word: acebeaaccdbedbbbdeadeebbdeeebeaaacbadaac...
1373
+ sage: words.RandomWord(17, 5, "abcde") # random results
1374
+ word: dcacbbecbddebaadd
1375
+
1376
+ TESTS::
1377
+
1378
+ sage: words.RandomWord(2,3,"abcd")
1379
+ Traceback (most recent call last):
1380
+ ...
1381
+ TypeError: alphabet does not contain 3 distinct elements
1382
+ """
1383
+ if alphabet is None:
1384
+ alphabet = list(range(m))
1385
+ if len(set(alphabet)) != m:
1386
+ raise TypeError("alphabet does not contain %s distinct elements" % m)
1387
+ return FiniteWords(alphabet)([alphabet[randint(0,m-1)] for i in range(n)])
1388
+
1389
+ LowerChristoffelWord = LowerChristoffelWord
1390
+
1391
+ ChristoffelWord = LowerChristoffelWord
1392
+
1393
+ def UpperChristoffelWord(self, p, q, alphabet=(0, 1)):
1394
+ r"""
1395
+ Return the upper Christoffel word of slope `p/q`, where
1396
+ `p` and `q` are relatively prime nonnegative
1397
+ integers, over the given alphabet.
1398
+
1399
+ The *upper Christoffel word of slope `p/q`* is equal to the
1400
+ reversal of the lower Christoffel word of slope `p/q`.
1401
+ Equivalently, if `xuy` is the lower Christoffel word of
1402
+ slope `p/q`, where `x` and `y` are letters,
1403
+ then `yux` is the upper Christoffel word of slope
1404
+ `p/q` (because `u` is a palindrome).
1405
+
1406
+ INPUT:
1407
+
1408
+ - ``alphabet`` -- any container of length two that is suitable to build
1409
+ an instance of OrderedAlphabet (``list``, ``tuple``, ``str``, ...)
1410
+
1411
+ EXAMPLES::
1412
+
1413
+ sage: words.UpperChristoffelWord(1,0)
1414
+ word: 1
1415
+
1416
+ ::
1417
+
1418
+ sage: words.UpperChristoffelWord(0,1)
1419
+ word: 0
1420
+
1421
+ ::
1422
+
1423
+ sage: words.UpperChristoffelWord(1,1)
1424
+ word: 10
1425
+
1426
+ ::
1427
+
1428
+ sage: words.UpperChristoffelWord(4,7)
1429
+ word: 10100100100
1430
+
1431
+ TESTS::
1432
+
1433
+ sage: words.UpperChristoffelWord(51,43,"abc")
1434
+ Traceback (most recent call last):
1435
+ ...
1436
+ ValueError: alphabet must contain exactly two distinct elements
1437
+ """
1438
+ w = words.LowerChristoffelWord(p, q, alphabet=alphabet).reversal()
1439
+ return w
1440
+
1441
+ @cached_method
1442
+ def _fibonacci_tile(self, n, q_0=None, q_1=3):
1443
+ r"""
1444
+ Return the word `q_n` defined by the recurrence below.
1445
+
1446
+ The sequence `(q_n)_{n\in\NN}` is defined by `q_0=\varepsilon`,
1447
+ `q_1=3` and
1448
+
1449
+ .. MATH::
1450
+
1451
+ q_n = \begin{cases}
1452
+ q_{n-1}q_{n-2} & \text{if} n\equiv 2 \mod 3, \\
1453
+ q_{n-1}\bar{q_{n-2}} & \text{if} n\equiv 0,1 \mod 3.
1454
+ \end{cases}
1455
+
1456
+ where the operator `\bar{\,}` exchanges the `1` and `3`.
1457
+
1458
+ INPUT:
1459
+
1460
+ - ``n`` -- nonnegative integer
1461
+ - ``q_0`` -- first initial value (default: ``None``); it can be
1462
+ ``None``, 0, 1, 2 or 3
1463
+ - ``q_1`` -- second initial value (default: 3); it can be ``None``, 0,
1464
+ 1, 2 or 3
1465
+
1466
+ EXAMPLES::
1467
+
1468
+ sage: for i in range(10): words._fibonacci_tile(i)
1469
+ word:
1470
+ word: 3
1471
+ word: 3
1472
+ word: 31
1473
+ word: 311
1474
+ word: 31131
1475
+ word: 31131133
1476
+ word: 3113113313313
1477
+ word: 311311331331331131133
1478
+ word: 3113113313313311311331331331131131
1479
+
1480
+ REFERENCES:
1481
+
1482
+ [BmBGL09]_
1483
+ """
1484
+ from sage.combinat.words.morphism import WordMorphism
1485
+ W = FiniteWords([0,1,2,3])
1486
+ bar = WordMorphism({0:0,1:3,3:1,2:2},codomain=W)
1487
+ if n == 0:
1488
+ a = [] if q_0 is None else [q_0]
1489
+ return W(a)
1490
+ elif n == 1:
1491
+ b = [] if q_1 is None else [q_1]
1492
+ return W(b)
1493
+ elif n % 3 == 2:
1494
+ u = self._fibonacci_tile(n-1,q_0,q_1)
1495
+ v = self._fibonacci_tile(n-2,q_0,q_1)
1496
+ return u * v
1497
+ else:
1498
+ u = self._fibonacci_tile(n-1,q_0,q_1)
1499
+ v = bar(self._fibonacci_tile(n-2,q_0,q_1))
1500
+ return u * v
1501
+
1502
+ def fibonacci_tile(self, n):
1503
+ r"""
1504
+ Return the `n`-th Fibonacci Tile [BmBGL09]_.
1505
+
1506
+ EXAMPLES::
1507
+
1508
+ sage: for i in range(3): words.fibonacci_tile(i) # needs sage.modules
1509
+ Path: 3210
1510
+ Path: 323030101212
1511
+ Path: 3230301030323212323032321210121232121010...
1512
+ """
1513
+ w = self._fibonacci_tile(3*n+1)
1514
+ w = w**4
1515
+ from sage.combinat.words.paths import WordPaths
1516
+ P = WordPaths([0,1,2,3])
1517
+ l = list(w.partial_sums(start=3,mod=4))
1518
+ return P(l)[:-1]
1519
+
1520
+ def dual_fibonacci_tile(self, n):
1521
+ r"""
1522
+ Return the `n`-th dual Fibonacci Tile [BmBGL09]_.
1523
+
1524
+ EXAMPLES::
1525
+
1526
+ sage: for i in range(4): words.dual_fibonacci_tile(i) # needs sage.modules
1527
+ Path: 3210
1528
+ Path: 32123032301030121012
1529
+ Path: 3212303230103230321232101232123032123210...
1530
+ Path: 3212303230103230321232101232123032123210...
1531
+ """
1532
+ w = self._fibonacci_tile(3*n+1,3,3)
1533
+ w = w**4
1534
+ from sage.combinat.words.paths import WordPaths
1535
+ P = WordPaths([0,1,2,3])
1536
+ l = list(w.partial_sums(start=3,mod=4))
1537
+ return P(l)[:-1]
1538
+
1539
+ def _s_adic_iterator(self, sequence, letters):
1540
+ r"""
1541
+ Return the iterator over the `s`-adic infinite word obtained from a
1542
+ sequence of morphisms applied on letters where the hypothesis of
1543
+ nested prefixes is used.
1544
+
1545
+ DEFINITION (from [Fogg]_):
1546
+
1547
+ Let `w` be a infinite word over an alphabet `A = A_0`. A
1548
+ standard representation of `w` is obtained from a sequence of
1549
+ substitutions `\sigma_k : A_{k+1} \to A_k` and a sequence of letters
1550
+ `a_k \in A_k` such that:
1551
+
1552
+ .. MATH::
1553
+
1554
+ \lim_{k\to\infty} \sigma_0 \circ \sigma_1 \circ \cdots
1555
+ \sigma_k(a_k).
1556
+
1557
+ Given a set of substitutions `S`, we say that the representation is
1558
+ `S`-adic standard if the substitutions are chosen in `S`.
1559
+
1560
+ INPUT:
1561
+
1562
+ - ``sequence`` -- an iterable sequence of morphisms. It may be finite
1563
+ or infinite
1564
+ - ``letters`` -- an iterable sequence of letters. The image of the
1565
+ (i+1)-th letter under the (i+1)-th morphism must start with the i-th
1566
+ letter
1567
+
1568
+ OUTPUT: iterator of letters
1569
+
1570
+ EXAMPLES:
1571
+
1572
+ Let's define three morphisms and compute the first nested successive
1573
+ prefixes of the `s`-adic word::
1574
+
1575
+ sage: m1 = WordMorphism('e->gh,f->hg')
1576
+ sage: m2 = WordMorphism('c->ef,d->e')
1577
+ sage: m3 = WordMorphism('a->cd,b->dc')
1578
+ sage: Word(words._s_adic_iterator([m1],'e'))
1579
+ word: gh
1580
+ sage: Word(words._s_adic_iterator([m1,m2],'ec'))
1581
+ word: ghhg
1582
+ sage: Word(words._s_adic_iterator([m1,m2,m3],'eca'))
1583
+ word: ghhggh
1584
+
1585
+ If the letters don't satisfy the hypothesis of the algorithm, an
1586
+ error is raised::
1587
+
1588
+ sage: Word(words._s_adic_iterator([m1,m2,m3],'ecb'))
1589
+ Traceback (most recent call last):
1590
+ ...
1591
+ ValueError: the hypothesis of the algorithm used is not satisfied; the image of the 3-th letter (=b) under the 3-th morphism (=a->cd, b->dc) should start with the 2-th letter (=c)
1592
+
1593
+ Two examples of infinite `s`-adic words::
1594
+
1595
+ sage: tm = WordMorphism('a->ab,b->ba')
1596
+ sage: fib = WordMorphism('a->ab,b->a')
1597
+ sage: from itertools import repeat
1598
+ sage: Word(words._s_adic_iterator(repeat(tm),repeat('a')))
1599
+ word: abbabaabbaababbabaababbaabbabaabbaababba...
1600
+ sage: Word(words._s_adic_iterator(repeat(fib),repeat('a')))
1601
+ word: abaababaabaababaababaabaababaabaababaaba...
1602
+
1603
+ A less trivial infinite `s`-adic word::
1604
+
1605
+ sage: D = {4:tm,5:fib}
1606
+ sage: tmword = words.ThueMorseWord([4,5])
1607
+ sage: it = (D[a] for a in tmword)
1608
+ sage: Word(words._s_adic_iterator(it, repeat('a')))
1609
+ word: abbaababbaabbaabbaababbaababbaabbaababba...
1610
+
1611
+ The morphism `\sigma: a \mapsto ba, b \mapsto b` cannot satisfy the
1612
+ hypothesis of the algorithm (nested prefixes)::
1613
+
1614
+ sage: sigma = WordMorphism('a->ba,b->b')
1615
+ sage: Word(words._s_adic_iterator(repeat(sigma),repeat('a')))
1616
+ Traceback (most recent call last):
1617
+ ...
1618
+ ValueError: the hypothesis of the algorithm used is not satisfied; the image of the 2-th letter (=a) under the 2-th morphism (=a->ba, b->b) should start with the 1-th letter (=a)
1619
+
1620
+ AUTHORS:
1621
+
1622
+ - Sébastien Labbé (2009-12-18): initial version
1623
+ """
1624
+ from itertools import tee
1625
+ sequence_it,sequence = tee(sequence)
1626
+ m = next(sequence_it)
1627
+ codomain = m.codomain()
1628
+ p = codomain.identity_morphism()
1629
+ letters_it,letters = tee(letters)
1630
+ precedent_letter = m(next(letters_it))[0]
1631
+
1632
+ yield precedent_letter
1633
+ for (i,(m,a)) in enumerate(zip(sequence, letters)):
1634
+ if not precedent_letter == m(a)[0]:
1635
+ raise ValueError("the hypothesis of the algorithm used is not satisfied; the image of the %s-th letter (=%s) under the %s-th morphism (=%s) should start with the %s-th letter (=%s)" % (i+1,a,i+1,m,i,precedent_letter))
1636
+ w = p(m(a)[1:])
1637
+ yield from w
1638
+ p = p * m
1639
+ precedent_letter = a
1640
+
1641
+ def s_adic(self, sequence, letters, morphisms=None):
1642
+ r"""
1643
+ Return the `s`-adic infinite word obtained from a sequence of
1644
+ morphisms applied on a letter.
1645
+
1646
+ DEFINITION (from [Fogg]_):
1647
+
1648
+ Let `w` be a infinite word over an alphabet `A = A_0`. A
1649
+ standard representation of `w` is obtained from a sequence of
1650
+ substitutions `\sigma_k : A_{k+1} \to A_k` and a sequence of letters
1651
+ `a_k \in A_k` such that:
1652
+
1653
+ .. MATH::
1654
+
1655
+ \lim_{k\to\infty} \sigma_0 \circ \sigma_1 \circ \cdots
1656
+ \sigma_k(a_k).
1657
+
1658
+ Given a set of substitutions `S`, we say that the representation is
1659
+ `S`-adic standard if the substitutions are chosen in `S`.
1660
+
1661
+ INPUT:
1662
+
1663
+ - ``sequence`` -- an iterable sequence of indices or of morphisms. It
1664
+ may be finite or infinite. If ``sequence`` is infinite, the image
1665
+ of the `(i+1)`-th letter under the `(i+1)`-th morphism must start
1666
+ with the `i`-th letter.
1667
+
1668
+ - ``letters`` -- a letter or a sequence of letters
1669
+
1670
+ - ``morphisms`` -- dict, list, callable or ``None`` (default:
1671
+ ``None``) an object that maps indices to morphisms. If ``None``, then
1672
+ ``sequence`` must consist of morphisms.
1673
+
1674
+ OUTPUT: a word
1675
+
1676
+ EXAMPLES:
1677
+
1678
+ Let us define three morphisms and compute the first nested successive
1679
+ prefixes of the `s`-adic word::
1680
+
1681
+ sage: m1 = WordMorphism('e->gh,f->hg')
1682
+ sage: m2 = WordMorphism('c->ef,d->e')
1683
+ sage: m3 = WordMorphism('a->cd,b->dc')
1684
+ sage: words.s_adic([m1],'e')
1685
+ word: gh
1686
+ sage: words.s_adic([m1,m2],'ec')
1687
+ word: ghhg
1688
+ sage: words.s_adic([m1,m2,m3],'eca')
1689
+ word: ghhggh
1690
+
1691
+ When the given sequence of morphism is finite, one may simply give
1692
+ the last letter, i.e. ``'a'``, instead of giving all of them,
1693
+ i.e. ``'eca'``::
1694
+
1695
+ sage: words.s_adic([m1,m2,m3],'a')
1696
+ word: ghhggh
1697
+ sage: words.s_adic([m1,m2,m3],'b')
1698
+ word: ghghhg
1699
+
1700
+ If the letters don't satisfy the hypothesis of the algorithm
1701
+ (nested prefixes), an error is raised::
1702
+
1703
+ sage: words.s_adic([m1,m2,m3],'ecb')
1704
+ Traceback (most recent call last):
1705
+ ...
1706
+ ValueError: the hypothesis of the algorithm used is not satisfied; the image of the 3-th letter (=b) under the 3-th morphism (=a->cd, b->dc) should start with the 2-th letter (=c)
1707
+
1708
+ Let's define the Thue-Morse morphism and the Fibonacci morphism
1709
+ which will be used below to illustrate more examples and let's import
1710
+ the ``repeat`` tool from the ``itertools``::
1711
+
1712
+ sage: tm = WordMorphism('a->ab,b->ba')
1713
+ sage: fib = WordMorphism('a->ab,b->a')
1714
+ sage: from itertools import repeat
1715
+
1716
+ Two trivial examples of infinite `s`-adic words::
1717
+
1718
+ sage: words.s_adic(repeat(tm),repeat('a'))
1719
+ word: abbabaabbaababbabaababbaabbabaabbaababba...
1720
+
1721
+ ::
1722
+
1723
+ sage: words.s_adic(repeat(fib),repeat('a'))
1724
+ word: abaababaabaababaababaabaababaabaababaaba...
1725
+
1726
+ A less trivial infinite `s`-adic word::
1727
+
1728
+ sage: D = {4:tm,5:fib}
1729
+ sage: tmword = words.ThueMorseWord([4,5])
1730
+ sage: it = (D[a] for a in tmword)
1731
+ sage: words.s_adic(it, repeat('a'))
1732
+ word: abbaababbaabbaabbaababbaababbaabbaababba...
1733
+
1734
+ The same thing using a sequence of indices::
1735
+
1736
+ sage: tmword = words.ThueMorseWord([0,1])
1737
+ sage: words.s_adic(tmword, repeat('a'), [tm,fib])
1738
+ word: abbaababbaabbaabbaababbaababbaabbaababba...
1739
+
1740
+ The correspondence of the indices may be given as a dict::
1741
+
1742
+ sage: words.s_adic(tmword, repeat('a'), {0:tm,1:fib})
1743
+ word: abbaababbaabbaabbaababbaababbaabbaababba...
1744
+
1745
+ because dict are more versatile for indices::
1746
+
1747
+ sage: tmwordTF = words.ThueMorseWord('TF')
1748
+ sage: words.s_adic(tmwordTF, repeat('a'), {'T':tm,'F':fib})
1749
+ word: abbaababbaabbaabbaababbaababbaabbaababba...
1750
+
1751
+ or by a callable::
1752
+
1753
+ sage: f = lambda n: tm if n == 0 else fib
1754
+ sage: words.s_adic(words.ThueMorseWord(), repeat('a'), f)
1755
+ word: abbaababbaabbaabbaababbaababbaabbaababba...
1756
+
1757
+ Random infinite `s`-adic words::
1758
+
1759
+ sage: from sage.misc.prandom import randint
1760
+ sage: def it():
1761
+ ....: while True: yield randint(0,1)
1762
+ sage: words.s_adic(it(), repeat('a'), [tm,fib]) # random
1763
+ word: abbaabababbaababbaabbaababbaabababbaabba...
1764
+ sage: words.s_adic(it(), repeat('a'), [tm,fib]) # random
1765
+ word: abbaababbaabbaababbaababbaabbaababbaabba...
1766
+ sage: words.s_adic(it(), repeat('a'), [tm,fib]) # random
1767
+ word: abaaababaabaabaaababaabaaababaaababaabaa...
1768
+
1769
+ An example where the sequences cycle on two morphisms and two
1770
+ letters::
1771
+
1772
+ sage: G = WordMorphism('a->cd,b->dc')
1773
+ sage: H = WordMorphism('c->ab,d->ba')
1774
+ sage: from itertools import cycle
1775
+ sage: words.s_adic([G,H],'ac')
1776
+ word: cddc
1777
+ sage: words.s_adic(cycle([G,H]),cycle('ac'))
1778
+ word: cddcdccddccdcddcdccdcddccddcdccddccdcddc...
1779
+
1780
+ The morphism `\sigma: a\mapsto ba, b\mapsto b` can't satisfy the
1781
+ hypothesis of the nested prefixes, but one may compute arbitrarily
1782
+ long finite words having the limit `\sigma^\omega(a)`::
1783
+
1784
+ sage: sigma = WordMorphism('a->ba,b->b')
1785
+ sage: words.s_adic(repeat(sigma),repeat('a'))
1786
+ Traceback (most recent call last):
1787
+ ...
1788
+ ValueError: the hypothesis of the algorithm used is not satisfied; the image of the 2-th letter (=a) under the 2-th morphism (=a->ba, b->b) should start with the 1-th letter (=a)
1789
+ sage: words.s_adic([sigma],'a')
1790
+ word: ba
1791
+ sage: words.s_adic([sigma,sigma],'a')
1792
+ word: bba
1793
+ sage: words.s_adic([sigma]*3,'a')
1794
+ word: bbba
1795
+ sage: words.s_adic([sigma]*4,'a')
1796
+ word: bbbba
1797
+ sage: words.s_adic([sigma]*5,'a')
1798
+ word: bbbbba
1799
+ sage: words.s_adic([sigma]*6,'a')
1800
+ word: bbbbbba
1801
+ sage: words.s_adic([sigma]*7,'a')
1802
+ word: bbbbbbba
1803
+
1804
+ The following examples illustrates an `S`-adic word defined over an
1805
+ infinite set `S` of morphisms `x_h`::
1806
+
1807
+ sage: x = lambda h:WordMorphism({1:[2],2:[3]+[1]*(h+1),3:[3]+[1]*h})
1808
+ sage: for h in [0,1,2,3]:
1809
+ ....: print("{} {}".format(h, x(h)))
1810
+ 0 1->2, 2->31, 3->3
1811
+ 1 1->2, 2->311, 3->31
1812
+ 2 1->2, 2->3111, 3->311
1813
+ 3 1->2, 2->31111, 3->3111
1814
+ sage: w = Word(lambda n : valuation(n+1, 2) ); w
1815
+ word: 0102010301020104010201030102010501020103...
1816
+ sage: s = words.s_adic(w, repeat(3), x); s
1817
+ word: 3232232232322322322323223223232232232232...
1818
+ sage: prefixe = s[:10000]
1819
+ sage: list(map(prefixe.number_of_factors, range(15)))
1820
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
1821
+ sage: [_[i+1] - _[i] for i in range(len(_)-1)]
1822
+ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
1823
+
1824
+ TESTS::
1825
+
1826
+ sage: tm = WordMorphism('a->ab,b->ba')
1827
+ sage: fib = WordMorphism('a->ab,b->a')
1828
+ sage: w = words.s_adic([fib,tm,tm,fib,tm,fib]*3,'a')
1829
+ sage: w
1830
+ word: abaaabaababaabaaababaaababaaabaababaabaa...
1831
+ sage: w.length()
1832
+ 32400
1833
+ sage: w.parent()
1834
+ Finite words over {'a', 'b'}
1835
+ sage: type(w)
1836
+ <class 'sage.combinat.words.word.FiniteWord_callable_with_caching'>
1837
+
1838
+ ::
1839
+
1840
+ sage: words.s_adic([fib,tm,tm,fib,tm,fib],'aaaaaaa')
1841
+ word: abaaabaababaabaaababaaababaaabaababa
1842
+
1843
+ ::
1844
+
1845
+ sage: words.s_adic([0,1,0,1,0,1,0,1],'a',[tm,fib])
1846
+ word: abbaabababbaabbaababbaababbaabababbaabba...
1847
+
1848
+ ::
1849
+
1850
+ sage: words.s_adic([fib,fib],'bb')
1851
+ Traceback (most recent call last):
1852
+ ...
1853
+ ValueError: the hypothesis of the algorithm used is not satisfied; the image of the 2-th letter (=b) under the 2-th morphism (=a->ab, b->a) should start with the 1-th letter (=b)
1854
+
1855
+ Test on different letters::
1856
+
1857
+ sage: tm = WordMorphism({0:[0,1], 1:[1,0]})
1858
+ sage: fib = WordMorphism({0:[0,1], 1:[0]})
1859
+ sage: f = lambda n: tm if n == 0 else fib
1860
+ sage: words.s_adic(words.ThueMorseWord(), repeat(0), f)
1861
+ word: 0110010110011001100101100101100110010110...
1862
+
1863
+ Testing the message error for the third argument::
1864
+
1865
+ sage: words.s_adic(words.ThueMorseWord(), repeat(0), 5)
1866
+ Traceback (most recent call last):
1867
+ ...
1868
+ TypeError: morphisms (=5) must be None, callable or provide a __getitem__ method
1869
+
1870
+ AUTHORS:
1871
+
1872
+ - Sébastien Labbé (2009-12-18): initial version
1873
+ """
1874
+ if morphisms is None:
1875
+ seq = sequence
1876
+ elif hasattr(morphisms, '__getitem__'):
1877
+ seq = (morphisms[i] for i in sequence)
1878
+ elif callable(morphisms):
1879
+ seq = (morphisms(i) for i in sequence)
1880
+ else:
1881
+ raise TypeError("morphisms (=%s) must be None, callable or provide a __getitem__ method" % morphisms)
1882
+
1883
+ from sage.combinat.words.word import FiniteWord_class
1884
+ if isinstance(sequence,(tuple,list,str,FiniteWord_class)) \
1885
+ and hasattr(letters, "__len__") and len(letters) == 1:
1886
+ from sage.misc.misc_c import prod
1887
+ return prod(seq)(letters)
1888
+
1889
+ from itertools import tee
1890
+ seq_it, seq = tee(seq)
1891
+ m = next(seq_it)
1892
+ W = m.codomain()
1893
+
1894
+ kwds = {}
1895
+ kwds['data'] = self._s_adic_iterator(seq, letters)
1896
+ kwds['datatype'] = 'iter'
1897
+ kwds['caching'] = True
1898
+ #kwds['check'] = False
1899
+ return W.shift()(**kwds)
1900
+
1901
+ def PalindromicDefectWord(self, k=1, alphabet='ab'):
1902
+ r"""
1903
+ Return the finite word `w = a b^k a b^{k-1} a a b^{k-1} a b^{k} a`.
1904
+
1905
+ As described by Brlek, Hamel, Nivat and Reutenauer in [BHNR2004]_, this
1906
+ finite word `w` is such that the infinite periodic word `w^{\omega}`
1907
+ has palindromic defect ``k``.
1908
+
1909
+ INPUT:
1910
+
1911
+ - ``k`` -- positive integer (default: 1)
1912
+
1913
+ - ``alphabet`` -- iterable of size two (default: ``'ab'``)
1914
+
1915
+ OUTPUT: finite word
1916
+
1917
+ EXAMPLES::
1918
+
1919
+ sage: words.PalindromicDefectWord(10)
1920
+ word: abbbbbbbbbbabbbbbbbbbaabbbbbbbbbabbbbbbb...
1921
+
1922
+ ::
1923
+
1924
+ sage: w = words.PalindromicDefectWord(3)
1925
+ sage: w
1926
+ word: abbbabbaabbabbba
1927
+ sage: w.defect()
1928
+ 0
1929
+ sage: (w^2).defect()
1930
+ 3
1931
+ sage: (w^3).defect()
1932
+ 3
1933
+
1934
+ On other alphabets::
1935
+
1936
+ sage: words.PalindromicDefectWord(3, alphabet='cd')
1937
+ word: cdddcddccddcdddc
1938
+ sage: words.PalindromicDefectWord(3, alphabet=['c', 3])
1939
+ word: c333c33cc33c333c
1940
+
1941
+ TESTS::
1942
+
1943
+ sage: k = 25
1944
+ sage: (words.PalindromicDefectWord(k)^2).defect()
1945
+ 25
1946
+
1947
+ If k is negative or zero, then we get the same word::
1948
+
1949
+ sage: words.PalindromicDefectWord(0)
1950
+ word: aaaaaa
1951
+ sage: words.PalindromicDefectWord(-3)
1952
+ word: aaaaaa
1953
+ """
1954
+ kk = k-1
1955
+ a, b = alphabet
1956
+ if not (isinstance(a, str) and isinstance(b, str)):
1957
+ a, b = (a,), (b,)
1958
+ w = a + b*k + a + b*kk + a + a + b*kk + a + b*k + a
1959
+ return FiniteWords(alphabet)(w)
1960
+
1961
+ def BaumSweetWord(self):
1962
+ r"""
1963
+ Return the Baum-Sweet Word.
1964
+
1965
+ The Baum-Sweet Sequence is an infinite word over the alphabet `\{0,1\}`
1966
+ defined by the following string substitution rules:
1967
+
1968
+ `00 \rightarrow 0000`
1969
+
1970
+ `01 \rightarrow 1001`
1971
+
1972
+ `10 \rightarrow 0100`
1973
+
1974
+ `11 \rightarrow 1101`
1975
+
1976
+ The substitution rule above can be considered as a morphism on the
1977
+ submonoid of `\{0,1\}` generated by `\{00,01,10,11\}` (which is a free
1978
+ monoid on these generators).
1979
+
1980
+ It is also defined as the concatenation of the terms from the Baum-Sweet
1981
+ Sequence:
1982
+
1983
+ .. MATH::
1984
+
1985
+ b_n = \begin{cases}
1986
+ 0, & \text{if } n = 0 \\
1987
+ 1, & \text{if } m \text{ is even} \\
1988
+ b_{\frac{m-1}{2}}, & \text{if } m \text{ is odd}
1989
+ \end{cases}
1990
+
1991
+ where `n=m4^k` and `m` is not divisible by 4 if `m \neq 0`.
1992
+
1993
+ The individual terms of the Baum-Sweet Sequence are also given by:
1994
+
1995
+ .. MATH::
1996
+
1997
+ b_n = \begin{cases}
1998
+ 1, & \text{if the binary representation of} n \text{ contains no block of consecutive 0s of odd length}\\
1999
+ 0, & \text{otherwise}\\
2000
+ \end{cases}\\
2001
+
2002
+ for `n > 0` with `b_0 = 1`.
2003
+
2004
+ For more information see:
2005
+ :wikipedia:`Baum-Sweet_sequence`.
2006
+
2007
+ EXAMPLES:
2008
+
2009
+ Baum-Sweet Word::
2010
+
2011
+ sage: w = words.BaumSweetWord(); w
2012
+ word: 1101100101001001100100000100100101001001...
2013
+
2014
+ Block Definition::
2015
+
2016
+ sage: w = words.BaumSweetWord()
2017
+ sage: f = lambda n: '1' if all(len(x)%2==0 for x in bin(n)[2:].split('1')) else '0'
2018
+ sage: all(f(i) == w[i] for i in range(1,100))
2019
+ True
2020
+ """
2021
+ outer = WordMorphism('a->00,b->01,c->10,d->11')
2022
+ inner = WordMorphism('a->aa,b->cb,c->ba,d->db')
2023
+ return outer(inner.fixed_point('d'))
2024
+
2025
+
2026
+ words = WordGenerator()