passagemath-combinat 10.6.42__cp314-cp314t-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (401) hide show
  1. passagemath_combinat/__init__.py +3 -0
  2. passagemath_combinat-10.6.42.dist-info/DELVEWHEEL +2 -0
  3. passagemath_combinat-10.6.42.dist-info/METADATA +160 -0
  4. passagemath_combinat-10.6.42.dist-info/RECORD +401 -0
  5. passagemath_combinat-10.6.42.dist-info/WHEEL +5 -0
  6. passagemath_combinat-10.6.42.dist-info/top_level.txt +3 -0
  7. passagemath_combinat.libs/libgmp-10-3a5f019e2510aeaad918cab2b57a689d.dll +0 -0
  8. passagemath_combinat.libs/libsymmetrica-3-7dcf900932804d0df5fd0919b4668720.dll +0 -0
  9. sage/algebras/affine_nil_temperley_lieb.py +263 -0
  10. sage/algebras/all.py +24 -0
  11. sage/algebras/all__sagemath_combinat.py +35 -0
  12. sage/algebras/askey_wilson.py +935 -0
  13. sage/algebras/associated_graded.py +345 -0
  14. sage/algebras/cellular_basis.py +350 -0
  15. sage/algebras/cluster_algebra.py +2766 -0
  16. sage/algebras/down_up_algebra.py +860 -0
  17. sage/algebras/free_algebra.py +1698 -0
  18. sage/algebras/free_algebra_element.py +345 -0
  19. sage/algebras/free_algebra_quotient.py +405 -0
  20. sage/algebras/free_algebra_quotient_element.py +295 -0
  21. sage/algebras/free_zinbiel_algebra.py +885 -0
  22. sage/algebras/hall_algebra.py +783 -0
  23. sage/algebras/hecke_algebras/all.py +4 -0
  24. sage/algebras/hecke_algebras/ariki_koike_algebra.py +1796 -0
  25. sage/algebras/hecke_algebras/ariki_koike_specht_modules.py +475 -0
  26. sage/algebras/hecke_algebras/cubic_hecke_algebra.py +3520 -0
  27. sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +1473 -0
  28. sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +1079 -0
  29. sage/algebras/iwahori_hecke_algebra.py +3095 -0
  30. sage/algebras/jordan_algebra.py +1773 -0
  31. sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py +113 -0
  32. sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py +156 -0
  33. sage/algebras/lie_conformal_algebras/all.py +18 -0
  34. sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +134 -0
  35. sage/algebras/lie_conformal_algebras/examples.py +43 -0
  36. sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py +131 -0
  37. sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py +139 -0
  38. sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py +174 -0
  39. sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py +167 -0
  40. sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py +107 -0
  41. sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py +135 -0
  42. sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py +353 -0
  43. sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py +236 -0
  44. sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py +78 -0
  45. sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py +328 -0
  46. sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py +117 -0
  47. sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py +86 -0
  48. sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py +82 -0
  49. sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +205 -0
  50. sage/algebras/nil_coxeter_algebra.py +191 -0
  51. sage/algebras/q_commuting_polynomials.py +673 -0
  52. sage/algebras/q_system.py +608 -0
  53. sage/algebras/quantum_clifford.py +959 -0
  54. sage/algebras/quantum_groups/ace_quantum_onsager.py +693 -0
  55. sage/algebras/quantum_groups/all.py +9 -0
  56. sage/algebras/quantum_groups/fock_space.py +2219 -0
  57. sage/algebras/quantum_groups/q_numbers.py +207 -0
  58. sage/algebras/quantum_groups/quantum_group_gap.py +2695 -0
  59. sage/algebras/quantum_groups/representations.py +591 -0
  60. sage/algebras/quantum_matrix_coordinate_algebra.py +1006 -0
  61. sage/algebras/quantum_oscillator.py +623 -0
  62. sage/algebras/quaternion_algebra.py +20 -0
  63. sage/algebras/quaternion_algebra_element.py +55 -0
  64. sage/algebras/rational_cherednik_algebra.py +525 -0
  65. sage/algebras/schur_algebra.py +670 -0
  66. sage/algebras/shuffle_algebra.py +1011 -0
  67. sage/algebras/splitting_algebra.py +779 -0
  68. sage/algebras/tensor_algebra.py +709 -0
  69. sage/algebras/yangian.py +1082 -0
  70. sage/algebras/yokonuma_hecke_algebra.py +1018 -0
  71. sage/all__sagemath_combinat.py +44 -0
  72. sage/combinat/SJT.py +255 -0
  73. sage/combinat/affine_permutation.py +2405 -0
  74. sage/combinat/algebraic_combinatorics.py +55 -0
  75. sage/combinat/all.py +53 -0
  76. sage/combinat/all__sagemath_combinat.py +195 -0
  77. sage/combinat/alternating_sign_matrix.py +2063 -0
  78. sage/combinat/baxter_permutations.py +346 -0
  79. sage/combinat/bijectionist.py +3220 -0
  80. sage/combinat/binary_recurrence_sequences.py +1180 -0
  81. sage/combinat/blob_algebra.py +685 -0
  82. sage/combinat/catalog_partitions.py +27 -0
  83. sage/combinat/chas/all.py +23 -0
  84. sage/combinat/chas/fsym.py +1180 -0
  85. sage/combinat/chas/wqsym.py +2601 -0
  86. sage/combinat/cluster_complex.py +326 -0
  87. sage/combinat/colored_permutations.py +2039 -0
  88. sage/combinat/colored_permutations_representations.py +964 -0
  89. sage/combinat/composition_signed.py +142 -0
  90. sage/combinat/composition_tableau.py +855 -0
  91. sage/combinat/constellation.py +1729 -0
  92. sage/combinat/core.py +751 -0
  93. sage/combinat/counting.py +12 -0
  94. sage/combinat/crystals/affine.py +742 -0
  95. sage/combinat/crystals/affine_factorization.py +518 -0
  96. sage/combinat/crystals/affinization.py +331 -0
  97. sage/combinat/crystals/alcove_path.py +2013 -0
  98. sage/combinat/crystals/all.py +22 -0
  99. sage/combinat/crystals/bkk_crystals.py +141 -0
  100. sage/combinat/crystals/catalog.py +115 -0
  101. sage/combinat/crystals/catalog_elementary_crystals.py +18 -0
  102. sage/combinat/crystals/catalog_infinity_crystals.py +33 -0
  103. sage/combinat/crystals/catalog_kirillov_reshetikhin.py +18 -0
  104. sage/combinat/crystals/crystals.py +257 -0
  105. sage/combinat/crystals/direct_sum.py +260 -0
  106. sage/combinat/crystals/elementary_crystals.py +1251 -0
  107. sage/combinat/crystals/fast_crystals.py +441 -0
  108. sage/combinat/crystals/fully_commutative_stable_grothendieck.py +1205 -0
  109. sage/combinat/crystals/generalized_young_walls.py +1076 -0
  110. sage/combinat/crystals/highest_weight_crystals.py +436 -0
  111. sage/combinat/crystals/induced_structure.py +695 -0
  112. sage/combinat/crystals/infinity_crystals.py +730 -0
  113. sage/combinat/crystals/kac_modules.py +863 -0
  114. sage/combinat/crystals/kirillov_reshetikhin.py +4196 -0
  115. sage/combinat/crystals/kyoto_path_model.py +497 -0
  116. sage/combinat/crystals/letters.cp314t-win_amd64.pyd +0 -0
  117. sage/combinat/crystals/letters.pxd +79 -0
  118. sage/combinat/crystals/letters.pyx +3056 -0
  119. sage/combinat/crystals/littelmann_path.py +1518 -0
  120. sage/combinat/crystals/monomial_crystals.py +1262 -0
  121. sage/combinat/crystals/multisegments.py +462 -0
  122. sage/combinat/crystals/mv_polytopes.py +467 -0
  123. sage/combinat/crystals/pbw_crystal.py +511 -0
  124. sage/combinat/crystals/pbw_datum.cp314t-win_amd64.pyd +0 -0
  125. sage/combinat/crystals/pbw_datum.pxd +4 -0
  126. sage/combinat/crystals/pbw_datum.pyx +487 -0
  127. sage/combinat/crystals/polyhedral_realization.py +372 -0
  128. sage/combinat/crystals/spins.cp314t-win_amd64.pyd +0 -0
  129. sage/combinat/crystals/spins.pxd +21 -0
  130. sage/combinat/crystals/spins.pyx +756 -0
  131. sage/combinat/crystals/star_crystal.py +290 -0
  132. sage/combinat/crystals/subcrystal.py +464 -0
  133. sage/combinat/crystals/tensor_product.py +1177 -0
  134. sage/combinat/crystals/tensor_product_element.cp314t-win_amd64.pyd +0 -0
  135. sage/combinat/crystals/tensor_product_element.pxd +35 -0
  136. sage/combinat/crystals/tensor_product_element.pyx +1870 -0
  137. sage/combinat/crystals/virtual_crystal.py +420 -0
  138. sage/combinat/cyclic_sieving_phenomenon.py +204 -0
  139. sage/combinat/debruijn_sequence.cp314t-win_amd64.pyd +0 -0
  140. sage/combinat/debruijn_sequence.pyx +355 -0
  141. sage/combinat/decorated_permutation.py +270 -0
  142. sage/combinat/degree_sequences.cp314t-win_amd64.pyd +0 -0
  143. sage/combinat/degree_sequences.pyx +588 -0
  144. sage/combinat/derangements.py +527 -0
  145. sage/combinat/descent_algebra.py +1008 -0
  146. sage/combinat/diagram.py +1551 -0
  147. sage/combinat/diagram_algebras.py +5886 -0
  148. sage/combinat/dyck_word.py +4349 -0
  149. sage/combinat/e_one_star.py +1623 -0
  150. sage/combinat/enumerated_sets.py +123 -0
  151. sage/combinat/expnums.cp314t-win_amd64.pyd +0 -0
  152. sage/combinat/expnums.pyx +148 -0
  153. sage/combinat/fast_vector_partitions.cp314t-win_amd64.pyd +0 -0
  154. sage/combinat/fast_vector_partitions.pyx +346 -0
  155. sage/combinat/fqsym.py +1977 -0
  156. sage/combinat/free_dendriform_algebra.py +954 -0
  157. sage/combinat/free_prelie_algebra.py +1141 -0
  158. sage/combinat/fully_commutative_elements.py +1077 -0
  159. sage/combinat/fully_packed_loop.py +1523 -0
  160. sage/combinat/gelfand_tsetlin_patterns.py +1409 -0
  161. sage/combinat/gray_codes.py +311 -0
  162. sage/combinat/grossman_larson_algebras.py +667 -0
  163. sage/combinat/growth.py +4352 -0
  164. sage/combinat/hall_polynomial.py +188 -0
  165. sage/combinat/hillman_grassl.py +866 -0
  166. sage/combinat/integer_matrices.py +329 -0
  167. sage/combinat/integer_vectors_mod_permgroup.py +1238 -0
  168. sage/combinat/k_tableau.py +4564 -0
  169. sage/combinat/kazhdan_lusztig.py +215 -0
  170. sage/combinat/key_polynomial.py +885 -0
  171. sage/combinat/knutson_tao_puzzles.py +2286 -0
  172. sage/combinat/lr_tableau.py +311 -0
  173. sage/combinat/matrices/all.py +24 -0
  174. sage/combinat/matrices/hadamard_matrix.py +3790 -0
  175. sage/combinat/matrices/latin.py +2912 -0
  176. sage/combinat/misc.py +401 -0
  177. sage/combinat/multiset_partition_into_sets_ordered.py +3541 -0
  178. sage/combinat/ncsf_qsym/all.py +21 -0
  179. sage/combinat/ncsf_qsym/combinatorics.py +317 -0
  180. sage/combinat/ncsf_qsym/generic_basis_code.py +1427 -0
  181. sage/combinat/ncsf_qsym/ncsf.py +5637 -0
  182. sage/combinat/ncsf_qsym/qsym.py +4053 -0
  183. sage/combinat/ncsf_qsym/tutorial.py +447 -0
  184. sage/combinat/ncsym/all.py +21 -0
  185. sage/combinat/ncsym/bases.py +855 -0
  186. sage/combinat/ncsym/dual.py +593 -0
  187. sage/combinat/ncsym/ncsym.py +2076 -0
  188. sage/combinat/necklace.py +551 -0
  189. sage/combinat/non_decreasing_parking_function.py +634 -0
  190. sage/combinat/nu_dyck_word.py +1474 -0
  191. sage/combinat/output.py +861 -0
  192. sage/combinat/parallelogram_polyomino.py +4326 -0
  193. sage/combinat/parking_functions.py +1602 -0
  194. sage/combinat/partition_algebra.py +1998 -0
  195. sage/combinat/partition_kleshchev.py +1982 -0
  196. sage/combinat/partition_shifting_algebras.py +584 -0
  197. sage/combinat/partition_tuple.py +3114 -0
  198. sage/combinat/path_tableaux/all.py +13 -0
  199. sage/combinat/path_tableaux/catalog.py +29 -0
  200. sage/combinat/path_tableaux/dyck_path.py +380 -0
  201. sage/combinat/path_tableaux/frieze.py +476 -0
  202. sage/combinat/path_tableaux/path_tableau.py +728 -0
  203. sage/combinat/path_tableaux/semistandard.py +510 -0
  204. sage/combinat/perfect_matching.py +779 -0
  205. sage/combinat/plane_partition.py +3300 -0
  206. sage/combinat/q_bernoulli.cp314t-win_amd64.pyd +0 -0
  207. sage/combinat/q_bernoulli.pyx +128 -0
  208. sage/combinat/quickref.py +81 -0
  209. sage/combinat/recognizable_series.py +2051 -0
  210. sage/combinat/regular_sequence.py +4316 -0
  211. sage/combinat/regular_sequence_bounded.py +543 -0
  212. sage/combinat/restricted_growth.py +81 -0
  213. sage/combinat/ribbon.py +20 -0
  214. sage/combinat/ribbon_shaped_tableau.py +489 -0
  215. sage/combinat/ribbon_tableau.py +1180 -0
  216. sage/combinat/rigged_configurations/all.py +46 -0
  217. sage/combinat/rigged_configurations/bij_abstract_class.py +548 -0
  218. sage/combinat/rigged_configurations/bij_infinity.py +370 -0
  219. sage/combinat/rigged_configurations/bij_type_A.py +163 -0
  220. sage/combinat/rigged_configurations/bij_type_A2_dual.py +338 -0
  221. sage/combinat/rigged_configurations/bij_type_A2_even.py +218 -0
  222. sage/combinat/rigged_configurations/bij_type_A2_odd.py +199 -0
  223. sage/combinat/rigged_configurations/bij_type_B.py +900 -0
  224. sage/combinat/rigged_configurations/bij_type_C.py +267 -0
  225. sage/combinat/rigged_configurations/bij_type_D.py +771 -0
  226. sage/combinat/rigged_configurations/bij_type_D_tri.py +392 -0
  227. sage/combinat/rigged_configurations/bij_type_D_twisted.py +576 -0
  228. sage/combinat/rigged_configurations/bij_type_E67.py +402 -0
  229. sage/combinat/rigged_configurations/bijection.py +143 -0
  230. sage/combinat/rigged_configurations/kleber_tree.py +1475 -0
  231. sage/combinat/rigged_configurations/kr_tableaux.py +1898 -0
  232. sage/combinat/rigged_configurations/rc_crystal.py +461 -0
  233. sage/combinat/rigged_configurations/rc_infinity.py +540 -0
  234. sage/combinat/rigged_configurations/rigged_configuration_element.py +2403 -0
  235. sage/combinat/rigged_configurations/rigged_configurations.py +1918 -0
  236. sage/combinat/rigged_configurations/rigged_partition.cp314t-win_amd64.pyd +0 -0
  237. sage/combinat/rigged_configurations/rigged_partition.pxd +15 -0
  238. sage/combinat/rigged_configurations/rigged_partition.pyx +680 -0
  239. sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py +499 -0
  240. sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element.py +428 -0
  241. sage/combinat/rsk.py +3438 -0
  242. sage/combinat/schubert_polynomial.py +508 -0
  243. sage/combinat/set_partition.py +3318 -0
  244. sage/combinat/set_partition_iterator.cp314t-win_amd64.pyd +0 -0
  245. sage/combinat/set_partition_iterator.pyx +136 -0
  246. sage/combinat/set_partition_ordered.py +1590 -0
  247. sage/combinat/sf/abreu_nigro.py +346 -0
  248. sage/combinat/sf/all.py +52 -0
  249. sage/combinat/sf/character.py +576 -0
  250. sage/combinat/sf/classical.py +319 -0
  251. sage/combinat/sf/dual.py +996 -0
  252. sage/combinat/sf/elementary.py +549 -0
  253. sage/combinat/sf/hall_littlewood.py +1028 -0
  254. sage/combinat/sf/hecke.py +336 -0
  255. sage/combinat/sf/homogeneous.py +464 -0
  256. sage/combinat/sf/jack.py +1428 -0
  257. sage/combinat/sf/k_dual.py +1458 -0
  258. sage/combinat/sf/kfpoly.py +447 -0
  259. sage/combinat/sf/llt.py +789 -0
  260. sage/combinat/sf/macdonald.py +2019 -0
  261. sage/combinat/sf/monomial.py +525 -0
  262. sage/combinat/sf/multiplicative.py +113 -0
  263. sage/combinat/sf/new_kschur.py +1786 -0
  264. sage/combinat/sf/ns_macdonald.py +964 -0
  265. sage/combinat/sf/orthogonal.py +246 -0
  266. sage/combinat/sf/orthotriang.py +355 -0
  267. sage/combinat/sf/powersum.py +963 -0
  268. sage/combinat/sf/schur.py +880 -0
  269. sage/combinat/sf/sf.py +1653 -0
  270. sage/combinat/sf/sfa.py +7053 -0
  271. sage/combinat/sf/symplectic.py +253 -0
  272. sage/combinat/sf/witt.py +721 -0
  273. sage/combinat/shifted_primed_tableau.py +2735 -0
  274. sage/combinat/shuffle.py +830 -0
  275. sage/combinat/sidon_sets.py +146 -0
  276. sage/combinat/similarity_class_type.py +1721 -0
  277. sage/combinat/sine_gordon.py +618 -0
  278. sage/combinat/six_vertex_model.py +784 -0
  279. sage/combinat/skew_partition.py +2053 -0
  280. sage/combinat/skew_tableau.py +2989 -0
  281. sage/combinat/sloane_functions.py +8935 -0
  282. sage/combinat/specht_module.py +1403 -0
  283. sage/combinat/species/all.py +48 -0
  284. sage/combinat/species/characteristic_species.py +321 -0
  285. sage/combinat/species/composition_species.py +273 -0
  286. sage/combinat/species/cycle_species.py +284 -0
  287. sage/combinat/species/empty_species.py +155 -0
  288. sage/combinat/species/functorial_composition_species.py +148 -0
  289. sage/combinat/species/generating_series.py +673 -0
  290. sage/combinat/species/library.py +148 -0
  291. sage/combinat/species/linear_order_species.py +169 -0
  292. sage/combinat/species/misc.py +83 -0
  293. sage/combinat/species/partition_species.py +290 -0
  294. sage/combinat/species/permutation_species.py +268 -0
  295. sage/combinat/species/product_species.py +423 -0
  296. sage/combinat/species/recursive_species.py +476 -0
  297. sage/combinat/species/set_species.py +192 -0
  298. sage/combinat/species/species.py +820 -0
  299. sage/combinat/species/structure.py +539 -0
  300. sage/combinat/species/subset_species.py +243 -0
  301. sage/combinat/species/sum_species.py +225 -0
  302. sage/combinat/subword.py +564 -0
  303. sage/combinat/subword_complex.py +2122 -0
  304. sage/combinat/subword_complex_c.cp314t-win_amd64.pyd +0 -0
  305. sage/combinat/subword_complex_c.pyx +119 -0
  306. sage/combinat/super_tableau.py +821 -0
  307. sage/combinat/superpartition.py +1154 -0
  308. sage/combinat/symmetric_group_algebra.py +3774 -0
  309. sage/combinat/symmetric_group_representations.py +1830 -0
  310. sage/combinat/t_sequences.py +877 -0
  311. sage/combinat/tableau.py +9506 -0
  312. sage/combinat/tableau_residues.py +860 -0
  313. sage/combinat/tableau_tuple.py +5353 -0
  314. sage/combinat/tiling.py +2432 -0
  315. sage/combinat/triangles_FHM.py +777 -0
  316. sage/combinat/tutorial.py +1857 -0
  317. sage/combinat/vector_partition.py +337 -0
  318. sage/combinat/words/abstract_word.py +1722 -0
  319. sage/combinat/words/all.py +59 -0
  320. sage/combinat/words/alphabet.py +268 -0
  321. sage/combinat/words/finite_word.py +7201 -0
  322. sage/combinat/words/infinite_word.py +113 -0
  323. sage/combinat/words/lyndon_word.py +652 -0
  324. sage/combinat/words/morphic.py +351 -0
  325. sage/combinat/words/morphism.py +3878 -0
  326. sage/combinat/words/paths.py +2932 -0
  327. sage/combinat/words/shuffle_product.py +278 -0
  328. sage/combinat/words/suffix_trees.py +1873 -0
  329. sage/combinat/words/word.py +769 -0
  330. sage/combinat/words/word_char.cp314t-win_amd64.pyd +0 -0
  331. sage/combinat/words/word_char.pyx +847 -0
  332. sage/combinat/words/word_datatypes.cp314t-win_amd64.pyd +0 -0
  333. sage/combinat/words/word_datatypes.pxd +4 -0
  334. sage/combinat/words/word_datatypes.pyx +1067 -0
  335. sage/combinat/words/word_generators.py +2026 -0
  336. sage/combinat/words/word_infinite_datatypes.py +1218 -0
  337. sage/combinat/words/word_options.py +99 -0
  338. sage/combinat/words/words.py +2396 -0
  339. sage/data_structures/all__sagemath_combinat.py +1 -0
  340. sage/databases/all__sagemath_combinat.py +13 -0
  341. sage/databases/findstat.py +4897 -0
  342. sage/databases/oeis.py +2058 -0
  343. sage/databases/sloane.py +393 -0
  344. sage/dynamics/all__sagemath_combinat.py +14 -0
  345. sage/dynamics/cellular_automata/all.py +7 -0
  346. sage/dynamics/cellular_automata/catalog.py +34 -0
  347. sage/dynamics/cellular_automata/elementary.py +612 -0
  348. sage/dynamics/cellular_automata/glca.py +477 -0
  349. sage/dynamics/cellular_automata/solitons.py +1463 -0
  350. sage/dynamics/finite_dynamical_system.py +1249 -0
  351. sage/dynamics/finite_dynamical_system_catalog.py +382 -0
  352. sage/games/all.py +7 -0
  353. sage/games/hexad.py +704 -0
  354. sage/games/quantumino.py +591 -0
  355. sage/games/sudoku.py +889 -0
  356. sage/games/sudoku_backtrack.cp314t-win_amd64.pyd +0 -0
  357. sage/games/sudoku_backtrack.pyx +189 -0
  358. sage/groups/all__sagemath_combinat.py +1 -0
  359. sage/groups/indexed_free_group.py +489 -0
  360. sage/libs/all__sagemath_combinat.py +6 -0
  361. sage/libs/lrcalc/__init__.py +1 -0
  362. sage/libs/lrcalc/lrcalc.py +525 -0
  363. sage/libs/symmetrica/__init__.py +7 -0
  364. sage/libs/symmetrica/all.py +101 -0
  365. sage/libs/symmetrica/kostka.pxi +168 -0
  366. sage/libs/symmetrica/part.pxi +193 -0
  367. sage/libs/symmetrica/plet.pxi +42 -0
  368. sage/libs/symmetrica/sab.pxi +196 -0
  369. sage/libs/symmetrica/sb.pxi +332 -0
  370. sage/libs/symmetrica/sc.pxi +192 -0
  371. sage/libs/symmetrica/schur.pxi +956 -0
  372. sage/libs/symmetrica/symmetrica.cp314t-win_amd64.pyd +0 -0
  373. sage/libs/symmetrica/symmetrica.pxi +1172 -0
  374. sage/libs/symmetrica/symmetrica.pyx +39 -0
  375. sage/monoids/all.py +13 -0
  376. sage/monoids/automatic_semigroup.py +1054 -0
  377. sage/monoids/free_abelian_monoid.py +315 -0
  378. sage/monoids/free_abelian_monoid_element.cp314t-win_amd64.pyd +0 -0
  379. sage/monoids/free_abelian_monoid_element.pxd +16 -0
  380. sage/monoids/free_abelian_monoid_element.pyx +397 -0
  381. sage/monoids/free_monoid.py +335 -0
  382. sage/monoids/free_monoid_element.py +431 -0
  383. sage/monoids/hecke_monoid.py +65 -0
  384. sage/monoids/string_monoid.py +817 -0
  385. sage/monoids/string_monoid_element.py +547 -0
  386. sage/monoids/string_ops.py +143 -0
  387. sage/monoids/trace_monoid.py +972 -0
  388. sage/rings/all__sagemath_combinat.py +2 -0
  389. sage/sat/all.py +4 -0
  390. sage/sat/boolean_polynomials.py +405 -0
  391. sage/sat/converters/__init__.py +6 -0
  392. sage/sat/converters/anf2cnf.py +14 -0
  393. sage/sat/converters/polybori.py +611 -0
  394. sage/sat/solvers/__init__.py +5 -0
  395. sage/sat/solvers/cryptominisat.py +287 -0
  396. sage/sat/solvers/dimacs.py +783 -0
  397. sage/sat/solvers/picosat.py +228 -0
  398. sage/sat/solvers/sat_lp.py +156 -0
  399. sage/sat/solvers/satsolver.cp314t-win_amd64.pyd +0 -0
  400. sage/sat/solvers/satsolver.pxd +3 -0
  401. sage/sat/solvers/satsolver.pyx +405 -0
@@ -0,0 +1,1249 @@
1
+ # sage_setup: distribution = sagemath-combinat
2
+ r"""
3
+ Discrete dynamical systems
4
+ ==========================
5
+
6
+ A *discrete dynamical system* (henceforth *DDS*) is a pair
7
+ `(X, \phi)` of a set `X` and a map `\phi : X \to X`.
8
+ (This is one of several things known as a "discrete dynamical
9
+ system" in mathematics.)
10
+
11
+ This file implements the following classes for discrete
12
+ dynamical systems:
13
+
14
+ - :class:`DiscreteDynamicalSystem`: general discrete dynamical
15
+ system, as above.
16
+ Inherit from this class if the ground set of your DDS is
17
+ infinite or large enough that you want to avoid it getting
18
+ stored as a list.
19
+ See the doc of this class for further details.
20
+
21
+ - :class:`FiniteDynamicalSystem`: finite discrete dynamical
22
+ system.
23
+ This can be instantiated by calling
24
+ :class:`DiscreteDynamicalSystem` with the parameter
25
+ ``is_finite`` set to ``True``.
26
+
27
+ - :class:`InvertibleDiscreteDynamicalSystem`: invertible
28
+ discrete dynamical system.
29
+ This implements an ``inverse_evolution`` method for `\phi^{-1}`
30
+ (the default implementation simply applies `\phi` over and
31
+ over until the original value is revisited; the last value
32
+ before that is then taken to be the result).
33
+ This can be instantiated by calling
34
+ :class:`DiscreteDynamicalSystem` with the parameter
35
+ ``inverse`` provided.
36
+
37
+ - :class:`InvertibleFiniteDynamicalSystem`: invertible
38
+ finite discrete dynamical system.
39
+ This can be instantiated by calling
40
+ :class:`DiscreteDynamicalSystem` with the parameter
41
+ ``is_finite`` set to ``True`` and the parameter
42
+ ``inverse`` provided.
43
+
44
+ .. TODO::
45
+
46
+ - Implement some more functionality for homomesy and
47
+ invariance testing:
48
+ Checking invariance on a sublist;
49
+ computing the first `k` entries of an orbit (useful
50
+ when orbits can be too large);
51
+ orbits_iterator (for when there are too many orbits to
52
+ list);
53
+ etc.
54
+
55
+ - Further examples for non-auto functionality: e.g.,
56
+ infection on a chessboard; Conway's game of life.
57
+
58
+ - Subclasses for DDSes whose ground set is an enumerated set.
59
+ Should we have those?
60
+
61
+ - Implement caching for orbits (can be useful: some DDSes
62
+ have a complicated evolution that shouldn't be recomputed
63
+ every time).
64
+ Does this require a whole new class?
65
+
66
+ - Further functionality for non-invertible DDSes:
67
+ is_recurrent, recurrent_entries, idempotent_power, etc.
68
+
69
+ - Wrap (some of) the cyclic_sieving_phenomenon.py methods
70
+ (:mod:`sage.combinat.cyclic_sieving_phenomenon`).
71
+
72
+ - Interact with sage.dynamics. This requires someone who
73
+ knows the latter part of the Sage library well.
74
+ """
75
+ # ****************************************************************************
76
+ # Copyright (C) 2018 Darij Grinberg <darijgrinberg@gmail.com>,
77
+ # 2018 Tom Roby <tomrobyuconn@gmail.com>
78
+ #
79
+ # Distributed under the terms of the GNU General Public License (GPL)
80
+ #
81
+ # This code is distributed in the hope that it will be useful,
82
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
83
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
84
+ # General Public License for more details.
85
+ #
86
+ # The full text of the GPL is available at:
87
+ #
88
+ # https://www.gnu.org/licenses/
89
+ # ****************************************************************************
90
+ from sage.categories.sets_cat import Sets
91
+ from sage.structure.sage_object import SageObject
92
+ from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall
93
+
94
+
95
+ class DiscreteDynamicalSystem(SageObject, metaclass=ClasscallMetaclass):
96
+ r"""
97
+ A discrete dynamical system.
98
+
99
+ A *discrete dynamical system* (henceforth *DDS*) is a
100
+ pair `(X, \phi)` of a set `X` and a map `\phi : X \to X`.
101
+ The set `X` is called the *ground set* of the DDS;
102
+ the map `\phi` is called the *evolution* of the DDS;
103
+ the inverse map `\phi^{-1}` (when it exists) is called the
104
+ *inverse evolution* of the DDS.
105
+
106
+ The DDS is called *finite* if `X` is finite.
107
+ The DDS is called *invertible* if the map `\phi` is
108
+ invertible.
109
+
110
+ Given a DDS `(X, \phi)`, we can study
111
+
112
+ * its orbits (i.e., the lists
113
+ `(s, \phi(s), \phi^2(s), \phi^3(s), \ldots)` for `s \in X`),
114
+
115
+ * its invariants (i.e., maps `f : X \to Y` satisfying
116
+ `f \circ \phi = f`),
117
+
118
+ * its cycles (i.e., lists `(u_1, u_2, \ldots, u_k)` of elements
119
+ of `X` such that `\phi(u_i) = u_{i+1}` for each `i \leq k`,
120
+ where we set `u_{k+1} = u_1`),
121
+
122
+ * its homomesies (i.e., maps `h : X \to A` to a
123
+ `\QQ`-vector space `A` such that the average of the values
124
+ of `h` on each cycle is the same),
125
+
126
+ and various other features.
127
+ (Some of these require `X` to be finite or at least to have
128
+ finite orbits.)
129
+
130
+ INPUT:
131
+
132
+ - ``X`` -- set, list, tuple, or another iterable, or
133
+ ``None`` (default: ``None``); the ground set for the DDS.
134
+ This can be ``None`` (in which case Sage will not know
135
+ the ground set, but can still apply evolution to any
136
+ elements that are provided to it).
137
+ Make sure to set the ``create_tuple`` argument to
138
+ ``True`` if the ``X`` you provide is an iterator or
139
+ a list, as otherwise your ``X`` would be exposed
140
+ (and thus subject to mutation or exhaustion).
141
+
142
+ - ``phi`` -- function, or callable that acts like a
143
+ function; the evolution of the DDS
144
+
145
+ - ``cache_orbits`` -- boolean (default: ``False``);
146
+ whether or not the orbits should be cached once they
147
+ are computed.
148
+ This currently does nothing, as we are not caching
149
+ orbits yet.
150
+
151
+ - ``create_tuple`` -- boolean (default: ``False``);
152
+ whether or not the input ``X`` should be translated
153
+ into a tuple. Set this to ``True`` to prevent
154
+ mutation if ``X`` is a list, and to prevent
155
+ exhaustion if ``X`` is an iterator.
156
+
157
+ - ``inverse`` -- function, or callable that acts like a
158
+ function, or boolean or ``None`` (default: ``None``);
159
+ the inverse evolution of the DDS, if the DDS is
160
+ invertible. Set this to ``None`` or ``False``
161
+ if the DDS is not invertible (or you don't want Sage
162
+ to treat it as such).
163
+ Alternatively, by setting this argument to ``True``,
164
+ you can signal that the DDS is invertible
165
+ without providing the inverse evolution. (In this case,
166
+ Sage will compute the inverse, assuming the orbits
167
+ to be finite.)
168
+
169
+ - ``is_finite`` -- boolean or ``None`` (default: ``None``);
170
+ whether the DDS is finite. The default option ``None``
171
+ leaves this to Sage to decide.
172
+ Only set this to ``True`` if you provide the ground
173
+ set ``X``.
174
+
175
+ EXAMPLES:
176
+
177
+ The following discrete dynamical system is neither
178
+ finite nor invertible::
179
+
180
+ sage: D = DiscreteDynamicalSystem(NN, lambda x: x + 2)
181
+ sage: D.ground_set()
182
+ Non negative integer semiring
183
+ sage: D.evolution()(5)
184
+ 7
185
+ sage: D.evolution_power(7)(5)
186
+ 19
187
+ sage: D.evolution_power(0)(5)
188
+ 5
189
+
190
+ The necessity of ``create_tuple=True``::
191
+
192
+ sage: X = [0, 1, 2, 3, 4]
193
+ sage: D_wrong = DiscreteDynamicalSystem(X, lambda x: (x**3) % 5)
194
+ sage: D_right = DiscreteDynamicalSystem(X, lambda x: (x**3) % 5, create_tuple=True)
195
+ sage: X[4] = 666 # evil
196
+ sage: D_wrong.ground_set()
197
+ [0, 1, 2, 3, 666]
198
+ sage: D_right.ground_set()
199
+ (0, 1, 2, 3, 4)
200
+
201
+ Here is an invertible (but infinite) discrete dynamical
202
+ system whose orbits are finite::
203
+
204
+ sage: D = DiscreteDynamicalSystem(NN, lambda x: (x + 2 if x % 6 < 4 else x - 4), inverse=True)
205
+ sage: D.ground_set()
206
+ Non negative integer semiring
207
+ sage: D.evolution()(5)
208
+ 1
209
+ sage: D.evolution()(1)
210
+ 3
211
+ sage: D.evolution()(3)
212
+ 5
213
+ sage: D.evolution_power(2)(5)
214
+ 3
215
+ sage: D.evolution_power(3)(5)
216
+ 5
217
+ sage: D.evolution_power(-2)(5)
218
+ 1
219
+ sage: D.inverse_evolution()(4)
220
+ 2
221
+ sage: D.orbit(3)
222
+ [3, 5, 1]
223
+
224
+ Setting the ``inverse`` parameter to ``None`` or ``False``
225
+ would give the same system without the functionality that
226
+ relies on invertibility::
227
+
228
+ sage: D = DiscreteDynamicalSystem(NN, lambda x: (x + 2 if x % 6 < 4 else x - 4), inverse=False)
229
+ sage: D.ground_set()
230
+ Non negative integer semiring
231
+ sage: D.evolution()(5)
232
+ 1
233
+ sage: D.inverse_evolution()(4)
234
+ Traceback (most recent call last):
235
+ ...
236
+ AttributeError: 'DiscreteDynamicalSystem' object has no attribute 'inverse_evolution'...
237
+ sage: D.orbit(3)
238
+ [3, 5, 1]
239
+
240
+ sage: D = DiscreteDynamicalSystem(NN, lambda x: (x + 2 if x % 6 < 4 else x - 4), inverse=None)
241
+ sage: D.ground_set()
242
+ Non negative integer semiring
243
+ sage: D.evolution()(5)
244
+ 1
245
+ sage: D.inverse_evolution()(4)
246
+ Traceback (most recent call last):
247
+ ...
248
+ AttributeError: 'DiscreteDynamicalSystem' object has no attribute 'inverse_evolution'...
249
+ sage: D.orbit(3)
250
+ [3, 5, 1]
251
+
252
+ Next, let us try out a finite non-invertible DDS::
253
+
254
+ sage: D = DiscreteDynamicalSystem(tuple(range(13)), lambda x: (x**2) % 13)
255
+ sage: D.ground_set()
256
+ (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
257
+ sage: D.evolution()(4)
258
+ 3
259
+ sage: D.orbit(4)
260
+ [4, 3, 9]
261
+ sage: D.orbit(1)
262
+ [1]
263
+ sage: D.orbit(3)
264
+ [3, 9]
265
+
266
+ Note that the finiteness is automatically being inferred here,
267
+ since the (finite) tuple ``tuple(range(13))`` has been
268
+ provided as the ground set.
269
+
270
+ Finally, here is a finite invertible DDS::
271
+
272
+ sage: X = cartesian_product([[0, 1]]*8)
273
+ sage: Y = [s for s in X if sum(s) == 4]
274
+ sage: rot = lambda s : s[1:] + (s[0],)
275
+ sage: D = DiscreteDynamicalSystem(Y, rot, inverse=True)
276
+ sage: D.evolution()((0, 1, 1, 0, 1, 0, 0, 1))
277
+ (1, 1, 0, 1, 0, 0, 1, 0)
278
+ sage: D.inverse_evolution()((0, 1, 1, 0, 1, 0, 0, 1))
279
+ (1, 0, 1, 1, 0, 1, 0, 0)
280
+ sage: sorted(D.orbit_lengths())
281
+ [2, 4, 8, 8, 8, 8, 8, 8, 8, 8]
282
+
283
+ We could have just as well provided its inverse explicitly::
284
+
285
+ sage: rot7 = lambda s: (s[-1],) + s[:-1]
286
+ sage: D = DiscreteDynamicalSystem(Y, rot, inverse=rot7)
287
+ sage: D.evolution()((0, 1, 1, 0, 1, 0, 0, 1))
288
+ (1, 1, 0, 1, 0, 0, 1, 0)
289
+ sage: D.inverse_evolution()((0, 1, 1, 0, 1, 0, 0, 1))
290
+ (1, 0, 1, 1, 0, 1, 0, 0)
291
+ """
292
+ @staticmethod
293
+ def __classcall_private__(cls, X, phi, cache_orbits=False, create_tuple=False, inverse=None, is_finite=None):
294
+ """
295
+ Return the correct object based on input.
296
+
297
+ The main purpose of this method is to decide which
298
+ subclass the object will belong to based on the
299
+ ``inverse`` and ``is_finite`` arguments.
300
+
301
+ EXAMPLES::
302
+
303
+ sage: D = DiscreteDynamicalSystem(NN, lambda x: x + 1)
304
+ sage: parent(D)
305
+ <class 'sage.dynamics.finite_dynamical_system.DiscreteDynamicalSystem'>
306
+
307
+ sage: f1 = lambda x: (x + 2 if x % 6 < 4 else x - 4)
308
+
309
+ sage: D = DiscreteDynamicalSystem(NN, f1, inverse=False)
310
+ sage: parent(D)
311
+ <class 'sage.dynamics.finite_dynamical_system.DiscreteDynamicalSystem'>
312
+
313
+ sage: D = DiscreteDynamicalSystem(NN, f1, inverse=None)
314
+ sage: parent(D)
315
+ <class 'sage.dynamics.finite_dynamical_system.DiscreteDynamicalSystem'>
316
+
317
+ sage: D = DiscreteDynamicalSystem(NN, f1, inverse=True)
318
+ sage: parent(D)
319
+ <class 'sage.dynamics.finite_dynamical_system.InvertibleDiscreteDynamicalSystem'>
320
+
321
+ sage: D = DiscreteDynamicalSystem(NN, lambda x: x + 1, is_finite=False)
322
+ sage: parent(D)
323
+ <class 'sage.dynamics.finite_dynamical_system.DiscreteDynamicalSystem'>
324
+
325
+ sage: f2 = lambda x: (x + 1 if x < 3 else 1)
326
+ sage: f3 = lambda x: (x - 1 if x > 3 else 3)
327
+
328
+ sage: D = DiscreteDynamicalSystem([1, 2, 3], f2)
329
+ sage: parent(D)
330
+ <class 'sage.dynamics.finite_dynamical_system.FiniteDynamicalSystem'>
331
+
332
+ sage: D = DiscreteDynamicalSystem([1, 2, 3], f2, inverse=True)
333
+ sage: parent(D)
334
+ <class 'sage.dynamics.finite_dynamical_system.InvertibleFiniteDynamicalSystem'>
335
+
336
+ sage: D = DiscreteDynamicalSystem([1, 2, 3], f2, inverse=f3)
337
+ sage: parent(D)
338
+ <class 'sage.dynamics.finite_dynamical_system.InvertibleFiniteDynamicalSystem'>
339
+
340
+ sage: D = DiscreteDynamicalSystem([1, 2, 3], f2, inverse=False)
341
+ sage: parent(D)
342
+ <class 'sage.dynamics.finite_dynamical_system.FiniteDynamicalSystem'>
343
+
344
+ sage: D = DiscreteDynamicalSystem([1, 2, 3], f2, inverse=None)
345
+ sage: parent(D)
346
+ <class 'sage.dynamics.finite_dynamical_system.FiniteDynamicalSystem'>
347
+ """
348
+ if is_finite is None:
349
+ is_finite = (X in Sets().Finite() or isinstance(X, (list,tuple,set,frozenset)))
350
+ if inverse:
351
+ if inverse is True: # invertibility claimed, but inverse not provided
352
+ # This is how the input for these subclasses work
353
+ inverse = None
354
+ ret_cls = (InvertibleFiniteDynamicalSystem if is_finite
355
+ else InvertibleDiscreteDynamicalSystem)
356
+ return ret_cls(X, phi, cache_orbits=cache_orbits,
357
+ create_tuple=create_tuple, inverse=inverse)
358
+ if is_finite:
359
+ return FiniteDynamicalSystem(X, phi, cache_orbits=cache_orbits,
360
+ create_tuple=create_tuple)
361
+ return typecall(cls, X, phi, cache_orbits=cache_orbits, create_tuple=create_tuple)
362
+
363
+ def __init__(self, X, phi, cache_orbits=False, create_tuple=False):
364
+ r"""
365
+ Initialize ``self``.
366
+
367
+ EXAMPLES::
368
+
369
+ sage: D = DiscreteDynamicalSystem([1, 3, 4], lambda x: (3 if x == 4 else 1), create_tuple=True)
370
+ sage: TestSuite(D).run(skip ='_test_pickling') # indirect doctest
371
+ sage: D = DiscreteDynamicalSystem([1, 3, 4], lambda x: (3 if x == 4 else 1), create_tuple=True, is_finite=False)
372
+ sage: TestSuite(D).run(skip ='_test_pickling') # indirect doctest
373
+ sage: D = DiscreteDynamicalSystem(NN, lambda x: (3 if x == 4 else 1))
374
+ sage: TestSuite(D).run(skip ='_test_pickling') # indirect doctest
375
+ sage: D = DiscreteDynamicalSystem(None, lambda x: (3 if x == 4 else 1))
376
+ sage: TestSuite(D).run(skip ='_test_pickling') # indirect doctest
377
+ sage: D = DiscreteDynamicalSystem([1, 3, 4], lambda x: x, create_tuple=True)
378
+ sage: TestSuite(D).run(skip ='_test_pickling') # indirect doctest
379
+ """
380
+ if create_tuple:
381
+ X = tuple(X)
382
+ self._X = X
383
+ self._phi = phi
384
+ self._cache_orbits = cache_orbits
385
+
386
+ def ground_set(self):
387
+ r"""
388
+ Return the ground set of ``self``.
389
+
390
+ This will return ``None`` if no ground set was
391
+ provided in the construction of ``self``.
392
+
393
+ .. WARNING::
394
+
395
+ Unless ``self`` has been constructed with the
396
+ ``create_tuple`` parameter set to ``True``,
397
+ this method will return whatever ground set was
398
+ provided to the constructor.
399
+ In particular, if a list was provided, then this
400
+ precise list will be returned; mutating this list
401
+ will then corrupt ``self``.
402
+
403
+ EXAMPLES::
404
+
405
+ sage: D = DiscreteDynamicalSystem([1, 3, 4], lambda x: (3 if x == 4 else 1), create_tuple=True)
406
+ sage: D.ground_set()
407
+ (1, 3, 4)
408
+ """
409
+ return self._X
410
+
411
+ def evolution(self):
412
+ r"""
413
+ Return the evolution of ``self``.
414
+
415
+ EXAMPLES::
416
+
417
+ sage: D = DiscreteDynamicalSystem([1, 3, 4], lambda x: (3 if x == 4 else 1), create_tuple=True)
418
+ sage: ev = D.evolution()
419
+ sage: ev(1)
420
+ 1
421
+ sage: ev(4)
422
+ 3
423
+ """
424
+ return self._phi
425
+
426
+ def evolution_power(self, n):
427
+ r"""
428
+ Return the `n`-th power (with respect to composition)
429
+ of the evolution of ``self``.
430
+
431
+ This requires `n` to be a nonnegative integer.
432
+
433
+ EXAMPLES::
434
+
435
+ sage: D = DiscreteDynamicalSystem(range(10), lambda x: (x + 3) % 10, create_tuple=True)
436
+ sage: ev3 = D.evolution_power(3)
437
+ sage: ev3(1)
438
+ 0
439
+ sage: ev3(2)
440
+ 1
441
+ sage: ev0 = D.evolution_power(0)
442
+ sage: ev0(1)
443
+ 1
444
+ sage: ev0(2)
445
+ 2
446
+ sage: D.evolution_power(-1)
447
+ Traceback (most recent call last):
448
+ ...
449
+ ValueError: the n-th power of evolution is only defined for nonnegative integers n
450
+ """
451
+ from sage.rings.semirings.non_negative_integer_semiring import NN
452
+ if n not in NN:
453
+ raise ValueError("the n-th power of evolution is only defined for nonnegative integers n")
454
+ ev = self.evolution()
455
+
456
+ def evn(x):
457
+ y = x
458
+ for _ in range(n):
459
+ y = ev(y)
460
+ return y
461
+ return evn
462
+
463
+ def __iter__(self):
464
+ r"""
465
+ Iterate over the ground set of ``self``.
466
+
467
+ This assumes that an iterable ground set of ``self``
468
+ has been provided.
469
+
470
+ EXAMPLES::
471
+
472
+ sage: D = DiscreteDynamicalSystem(NN, lambda x: x + 2)
473
+ sage: D[:3]
474
+ [0, 1, 2]
475
+ """
476
+ return iter(self._X)
477
+
478
+ def __getitem__(self, i):
479
+ r"""
480
+ Accessor for the ``i``-th entry of the ground set of
481
+ ``self``, assuming that the latter ground set was
482
+ provided as a list or tuple when ``self`` was constructed.
483
+
484
+ EXAMPLES::
485
+
486
+ sage: X = (5, 6, 7, 8)
487
+ sage: D = DiscreteDynamicalSystem(X, lambda x: (x**3) % 4 + 5)
488
+ sage: X[3]
489
+ 8
490
+ sage: X[2]
491
+ 7
492
+ """
493
+ return self._X[i]
494
+
495
+ def _repr_(self):
496
+ r"""
497
+ String representation of ``self``.
498
+
499
+ EXAMPLES::
500
+
501
+ sage: D = DiscreteDynamicalSystem(NN, lambda x: x + 2)
502
+ sage: D # indirect doctest
503
+ A discrete dynamical system with ground set
504
+ Non negative integer semiring
505
+ sage: D = DiscreteDynamicalSystem(None, lambda x: x + 2)
506
+ sage: D # indirect doctest
507
+ A discrete dynamical system with unspecified ground set
508
+ """
509
+ if self._X is None:
510
+ return "A discrete dynamical system with unspecified ground set"
511
+ return "A discrete dynamical system with ground set " \
512
+ + repr(self._X)
513
+
514
+ def orbit(self, x, preperiod=False):
515
+ r"""
516
+ Return the orbit of the element ``x`` of the ground set
517
+ of ``self`` under the evolution `\phi` of ``self``.
518
+
519
+ This orbit is a list beginning with ``x`` and ending
520
+ with the last element that is not a repetition of a
521
+ previous element.
522
+ If the orbit is infinite, then this method does not
523
+ terminate!
524
+
525
+ If the optional argument ``preperiod`` is set to
526
+ ``True``, then this method returns a pair ``(o, k)``,
527
+ where ``o`` is the orbit of ``self``, while `k` is the
528
+ smallest nonnegative integer such that
529
+ `\phi^k(x) \in \left\{ \phi^i(x) \mid i > k \right\}`.
530
+
531
+ The orbit of the element ``x`` is also called the
532
+ "rho" of ``x``, due to its shape when it is depicted
533
+ as a directed graph.
534
+
535
+ EXAMPLES::
536
+
537
+ sage: D = DiscreteDynamicalSystem(tuple(range(11)), lambda x: (x ** 2) % 11)
538
+ sage: D.orbit(6)
539
+ [6, 3, 9, 4, 5]
540
+ sage: D.orbit(6, preperiod=True)
541
+ ([6, 3, 9, 4, 5], 1)
542
+ sage: D.orbit(3)
543
+ [3, 9, 4, 5]
544
+ sage: D.orbit(3, preperiod=True)
545
+ ([3, 9, 4, 5], 0)
546
+ sage: D.orbit(9)
547
+ [9, 4, 5, 3]
548
+ sage: D.orbit(0)
549
+ [0]
550
+ """
551
+ orb = [x]
552
+ phi = self._phi
553
+ curr = phi(x)
554
+ while curr not in orb:
555
+ orb.append(curr)
556
+ curr = phi(curr)
557
+ if not preperiod:
558
+ return orb
559
+ return (orb, orb.index(curr))
560
+
561
+ def is_homomesic(self, h, average=None, find_average=False, elements=None):
562
+ r"""
563
+ Check if ``h`` (a map from the ground set of ``self`` to
564
+ a `\QQ`-vector space) is homomesic with respect to ``self``.
565
+
566
+ If the optional argument ``average`` is provided, then
567
+ this also checks that the averages are equal to ``average``.
568
+
569
+ If the optional argument ``find_average`` is set to
570
+ ``True``, then this method returns the average of ``h``
571
+ in case ``h`` is homomesic (instead of returning ``True``).
572
+
573
+ If the optional argument ``elements`` (an iterable of
574
+ elements of the ground set of ``self``) is provided, then
575
+ this method only checks homomesy for the cycles in the
576
+ orbits of the elements given in the list ``elements``.
577
+ Note that ``elements`` must be provided if the ground set of
578
+ ``self`` is infinite (or cannot be iterated through for any
579
+ other reason), since there is no way to check all the cycles
580
+ in this case.
581
+
582
+ This method will fail to terminate if any element of
583
+ ``elements`` has an infinite orbit.
584
+
585
+ Let us recall the definition of homomesy:
586
+ Let `(X, \phi)` be a DDS.
587
+ A *cycle* of `(X, \phi)` is a finite list
588
+ `u = (u_1, u_2, \ldots, u_k)` of elements of `X` such
589
+ that `\phi(u_i) = u_{i+1}` for each `i \leq k`, where we
590
+ set `u_{k+1} = u_1`.
591
+ Note that any element of `X` whose orbit is finite has a
592
+ cycle in its orbit.
593
+ Now, let `h` be a map from `X` to a `\QQ`-vector space `A`.
594
+ If `u = (u_1, u_2, \ldots, u_k)` is any cycle of
595
+ `(X, \phi)`, then the *average* of `h` on this cycle is
596
+ defined to be the element
597
+ `(h(u_1) + h(u_2) + \cdots + h(u_k)) / k` of `A`.
598
+ We say that `h` is *homomesic* (with respect to the DDS
599
+ `(X, \phi)`) if and only if the averages of `h` on all
600
+ cycles of `(X, \phi)` are equal.
601
+
602
+ EXAMPLES::
603
+
604
+ sage: W = Words(2, 5)
605
+ sage: F = DiscreteDynamicalSystem(W, lambda x: x[1:] + Word([x[0]]), is_finite=True, inverse=True)
606
+ sage: F.is_homomesic(lambda w: sum(w))
607
+ False
608
+ sage: F.is_homomesic(lambda w: 1, average=1)
609
+ True
610
+ sage: F.is_homomesic(lambda w: 1, average=0)
611
+ False
612
+ sage: F.is_homomesic(lambda w: 1)
613
+ True
614
+ sage: F.is_homomesic(lambda w: 1, find_average=True)
615
+ 1
616
+ sage: F.is_homomesic(lambda w: w[0] - w[1], average=0)
617
+ True
618
+ sage: F.is_homomesic(lambda w: w[0] - w[1], find_average=True)
619
+ 0
620
+
621
+ Now, let us check homomesy restricted to specific cycles::
622
+
623
+ sage: F = finite_dynamical_systems.bitstring_rotation(7)
624
+ sage: descents = lambda x: sum(1 for i in range(6) if x[i] > x[i+1])
625
+ sage: F.is_homomesic(descents)
626
+ False
627
+ sage: F.is_homomesic(descents, elements=[(1, 0, 1, 0, 0, 0, 0), (1, 0, 0, 1, 0, 0, 0)])
628
+ True
629
+ sage: F.is_homomesic(descents, elements=[(1, 0, 1, 0, 0, 0, 0), (1, 1, 0, 0, 0, 0, 0)])
630
+ False
631
+ sage: F.is_homomesic(descents, elements=[(1, 0, 1, 0, 0, 0, 0)])
632
+ True
633
+ sage: F.is_homomesic(descents, elements=[])
634
+ True
635
+
636
+ And here is a non-invertible finite dynamical system::
637
+
638
+ sage: F = finite_dynamical_systems.one_line([9, 1, 1, 6, 5, 4, 5, 5, 1])
639
+ sage: F.is_homomesic(lambda i: i)
640
+ True
641
+ sage: F.is_homomesic(lambda i: i % 2)
642
+ False
643
+ sage: F.is_homomesic(lambda i: i % 2, elements=[2, 9, 7])
644
+ True
645
+ sage: F.is_homomesic(lambda i: i % 2, elements=[2, 9, 4])
646
+ False
647
+ sage: F.is_homomesic(lambda i: i % 2, elements=[2, 9, 5, 7, 8, 2])
648
+ True
649
+ """
650
+ from sage.rings.rational_field import QQ
651
+ orbavgs = [] # This will be the list of all averages on cycles.
652
+ if elements is None:
653
+ # The user has not provided elements, so we need to
654
+ # check all cycles of the DDS.
655
+ for cyc in self.cycles():
656
+ l = len(cyc)
657
+ avg = ~(QQ(l)) * sum(h(i) for i in cyc)
658
+ if avg not in orbavgs:
659
+ if orbavgs:
660
+ return False
661
+ orbavgs.append(avg)
662
+ else:
663
+ # Checking only the cycles of the elements provided
664
+ # by the user.
665
+ for element in elements:
666
+ (orb, ix) = self.orbit(element, preperiod=True)
667
+ cyc = orb[ix:] # the cycle in the orbit of element
668
+ l = len(cyc)
669
+ avg = ~(QQ(l)) * sum(h(i) for i in cyc)
670
+ if avg not in orbavgs:
671
+ if orbavgs:
672
+ return False
673
+ orbavgs.append(avg)
674
+ if not orbavgs:
675
+ return True
676
+ if average is None:
677
+ if find_average:
678
+ return orbavgs[0]
679
+ return True
680
+ return orbavgs[0] == average
681
+
682
+
683
+ class InvertibleDiscreteDynamicalSystem(DiscreteDynamicalSystem):
684
+ r"""
685
+ An invertible discrete dynamical system.
686
+
687
+ A *discrete dynamical system* (henceforth *DDS*) is a
688
+ pair `(X, \phi)` of a set `X` and a map `\phi : X \to X`.
689
+ This set `X` is called the *ground set* of the DDS, while
690
+ the map `\phi` is called the *evolution* of the DDS.
691
+ An *invertible DDS* is a DDS `(X, \phi)` whose evolution
692
+ `\phi` is invertible.
693
+ In that case, `\phi^{-1}` is called the *inverse evolution*
694
+ of the DDS.
695
+
696
+ See :class:`DiscreteDynamicalSystem` for details.
697
+
698
+ INPUT:
699
+
700
+ - ``X`` -- set, list, tuple, or another iterable, or
701
+ ``None``; the ground set for the DDS. This can be
702
+ ``None`` in case of a
703
+ :class:`DiscreteDynamicalSystem` or a
704
+ :class:`InvertibleDiscreteDynamicalSystem`.
705
+ Make sure to set the ``create_tuple`` argument to
706
+ ``True`` if you provide an iterator or a list for
707
+ ``X``, as otherwise the input would be exposed.
708
+
709
+ - ``phi`` -- function, or callable that acts like a
710
+ function; the evolution of the DDS
711
+
712
+ - ``inverse`` -- function, or callable that acts like a
713
+ function; the inverse evolution of the DDS. (A
714
+ default implementation is implemented when this
715
+ argument is not provided; but it assumes the orbits
716
+ to be finite.)
717
+
718
+ - ``cache_orbits`` -- boolean (default: ``False``);
719
+ whether or not the orbits should be cached once they
720
+ are computed.
721
+
722
+ - ``create_tuple`` -- boolean (default: ``False``);
723
+ whether or not the input ``X`` should be translated
724
+ into a tuple (set this to ``True`` to prevent
725
+ mutation if ``X`` is a list, and to prevent
726
+ exhaustion if ``X`` is an iterator).
727
+
728
+ EXAMPLES::
729
+
730
+ sage: from sage.dynamics.finite_dynamical_system import InvertibleDiscreteDynamicalSystem
731
+ sage: D = InvertibleDiscreteDynamicalSystem(NN, lambda x: (x + 2 if x % 4 < 2 else x - 2))
732
+ sage: D.ground_set()
733
+ Non negative integer semiring
734
+ sage: D.evolution()(5)
735
+ 7
736
+ sage: D.evolution()(6)
737
+ 4
738
+ sage: D.evolution()(4)
739
+ 6
740
+ sage: D.inverse_evolution()(4)
741
+ 6
742
+
743
+ The necessity of ``create_tuple=True``::
744
+
745
+ sage: X = [0, 1, 2, 3, 4]
746
+ sage: D_wrong = InvertibleDiscreteDynamicalSystem(X, lambda x: (x**3) % 5)
747
+ sage: D_right = InvertibleDiscreteDynamicalSystem(X, lambda x: (x**3) % 5, create_tuple=True)
748
+ sage: X[4] = 666 # evil
749
+ sage: D_wrong.ground_set()
750
+ [0, 1, 2, 3, 666]
751
+ sage: D_right.ground_set()
752
+ (0, 1, 2, 3, 4)
753
+ """
754
+ def __init__(self, X, phi, inverse=None, cache_orbits=False, create_tuple=False):
755
+ r"""
756
+ Initialize ``self``.
757
+
758
+ EXAMPLES::
759
+
760
+ sage: D = DiscreteDynamicalSystem([1, 3, 4], lambda x: x, create_tuple=True, inverse=True)
761
+ sage: TestSuite(D).run(skip ='_test_pickling') # indirect doctest
762
+ sage: D = DiscreteDynamicalSystem([1, 3, 4], lambda x: x, create_tuple=True, is_finite=False, inverse=True)
763
+ sage: TestSuite(D).run(skip ='_test_pickling') # indirect doctest
764
+ sage: D = DiscreteDynamicalSystem(NN, lambda x: x, inverse=True)
765
+ sage: TestSuite(D).run(skip ='_test_pickling') # indirect doctest
766
+ sage: D = DiscreteDynamicalSystem(None, lambda x: x, inverse=True)
767
+ sage: TestSuite(D).run(skip ='_test_pickling') # indirect doctest
768
+ """
769
+ if create_tuple:
770
+ X = tuple(X)
771
+ self._X = X
772
+ self._phi = phi
773
+ if inverse is None:
774
+ self._inverse = self.inverse_evolution_default
775
+ else:
776
+ self._inverse = inverse
777
+ self._cache_orbits = cache_orbits
778
+
779
+ def evolution_power(self, n):
780
+ r"""
781
+ Return the `n`-th power (with respect to composition)
782
+ of the evolution of ``self``.
783
+
784
+ This requires `n` to be an integer.
785
+
786
+ EXAMPLES::
787
+
788
+ sage: D = DiscreteDynamicalSystem(range(10), lambda x: (x + 3) % 10, create_tuple=True, inverse=True)
789
+ sage: ev3 = D.evolution_power(3)
790
+ sage: ev3(1)
791
+ 0
792
+ sage: ev3(2)
793
+ 1
794
+ sage: ev0 = D.evolution_power(0)
795
+ sage: ev0(1)
796
+ 1
797
+ sage: ev0(2)
798
+ 2
799
+ sage: evm1 = D.evolution_power(-1)
800
+ sage: evm1(1)
801
+ 8
802
+ sage: evm1(2)
803
+ 9
804
+ sage: evm2 = D.evolution_power(-2)
805
+ sage: evm2(1)
806
+ 5
807
+ sage: evm2(2)
808
+ 6
809
+ """
810
+ from sage.rings.integer_ring import ZZ
811
+ if n not in ZZ:
812
+ raise ValueError("the n-th power of evolution is only defined for integers n")
813
+ if n >= 0:
814
+ ev = self.evolution()
815
+ else:
816
+ ev = self.inverse_evolution()
817
+ n = -n
818
+
819
+ def evn(x):
820
+ y = x
821
+ for _ in range(n):
822
+ y = ev(y)
823
+ return y
824
+ return evn
825
+
826
+ def _repr_(self):
827
+ r"""
828
+ String representation of ``self``.
829
+
830
+ EXAMPLES::
831
+
832
+ sage: D = DiscreteDynamicalSystem(NN, lambda x: (x + 2 if x % 4 < 2 else x - 2), inverse=True)
833
+ sage: D # indirect doctest
834
+ An invertible discrete dynamical system with ground set
835
+ Non negative integer semiring
836
+ sage: D = DiscreteDynamicalSystem(None, lambda x: x + 2, inverse=True)
837
+ sage: D # indirect doctest
838
+ An invertible discrete dynamical system with unspecified ground set
839
+ """
840
+ if self._X is None:
841
+ return "An invertible discrete dynamical system with unspecified ground set"
842
+ return "An invertible discrete dynamical system with ground set " \
843
+ + repr(self._X)
844
+
845
+ def inverse_evolution(self):
846
+ r"""
847
+ Return the inverse evolution of ``self`` (as a map
848
+ from the ground set of ``self`` to itself).
849
+
850
+ EXAMPLES::
851
+
852
+ sage: D = DiscreteDynamicalSystem(tuple(range(8)), lambda x: (x + 2) % 8, inverse=True)
853
+ sage: D.inverse_evolution()(1)
854
+ 7
855
+ sage: D.inverse_evolution()(3)
856
+ 1
857
+
858
+ sage: D = DiscreteDynamicalSystem(ZZ, lambda x: (x + 2) % 8, inverse=True)
859
+ sage: D.inverse_evolution()(1)
860
+ 7
861
+ sage: D.inverse_evolution()(3)
862
+ 1
863
+ """
864
+ return self._inverse
865
+
866
+ def verify_inverse_evolution(self, x=None):
867
+ r"""
868
+ Verify that the composition of evolution and
869
+ inverse evolution on ``self`` is the identity
870
+ (both ways).
871
+
872
+ The optional argument ``x``, if provided, restricts
873
+ the testing to the element ``x`` only.
874
+ Otherwise, all elements of the ground set are
875
+ tested (if they can be enumerated).
876
+
877
+ This is mostly used to check the correctness of
878
+ self-implemented inverse evolution methods.
879
+
880
+ EXAMPLES::
881
+
882
+ sage: D = DiscreteDynamicalSystem(tuple(range(8)), lambda x: (x + 2) % 8, inverse=True)
883
+ sage: D.verify_inverse_evolution()
884
+ True
885
+ sage: D.verify_inverse_evolution(3)
886
+ True
887
+ sage: fake_inverse = lambda x: x
888
+ sage: D = DiscreteDynamicalSystem(tuple(range(8)), lambda x: (x + 2) % 8, inverse=fake_inverse)
889
+ sage: D.verify_inverse_evolution()
890
+ False
891
+ sage: D.verify_inverse_evolution(3)
892
+ False
893
+ """
894
+ ev = self.evolution()
895
+ iev = self.inverse_evolution()
896
+ if x is None:
897
+ els = self.ground_set()
898
+ else:
899
+ els = [x]
900
+ for y in els:
901
+ if ev(iev(y)) != y:
902
+ return False
903
+ if iev(ev(y)) != y:
904
+ return False
905
+ return True
906
+
907
+ def orbit(self, x, preperiod=False):
908
+ r"""
909
+ Return the orbit of the element ``x`` of the ground set
910
+ of ``self``.
911
+
912
+ This orbit is a list beginning with ``x`` and ending
913
+ with the last element until ``x`` reappears.
914
+ If ``x`` never reappears, then this will not terminate!
915
+
916
+ If the optional argument ``preperiod`` is set to
917
+ ``True``, then this method returns a pair ``(o, k)``,
918
+ where ``o`` is the orbit of ``self``, while `k` is the
919
+ smallest nonnegative integer such that
920
+ `\phi^k(x) \in \left\{ \phi^i(x) \mid i > k \right\}`.
921
+ Note that `k` is necessarily `0`, since the DDS
922
+ ``self`` is invertible!
923
+
924
+ EXAMPLES::
925
+
926
+ sage: D = DiscreteDynamicalSystem(tuple(range(8)), lambda x: (x + 2) % 8, inverse=True)
927
+ sage: D.ground_set()
928
+ (0, 1, 2, 3, 4, 5, 6, 7)
929
+ sage: D.orbit(2)
930
+ [2, 4, 6, 0]
931
+ sage: D.orbit(5)
932
+ [5, 7, 1, 3]
933
+ sage: D.orbit(5, preperiod=True)
934
+ ([5, 7, 1, 3], 0)
935
+
936
+ sage: D = DiscreteDynamicalSystem(ZZ, lambda x: (x + 2) % 8, inverse=True)
937
+ sage: D.ground_set()
938
+ Integer Ring
939
+ sage: D.orbit(2)
940
+ [2, 4, 6, 0]
941
+ sage: D.orbit(5)
942
+ [5, 7, 1, 3]
943
+ sage: D.orbit(5, preperiod=True)
944
+ ([5, 7, 1, 3], 0)
945
+ """
946
+ orb = [x]
947
+ phi = self._phi
948
+ curr = phi(x)
949
+ while curr != x:
950
+ orb.append(curr)
951
+ curr = phi(curr)
952
+ if not preperiod:
953
+ return orb
954
+ return (orb, 0)
955
+
956
+ def inverse_evolution_default(self, x):
957
+ r"""
958
+ Return the inverse evolution of ``self``, applied
959
+ to the element ``x`` of the ground set of ``self``.
960
+
961
+ This is the default implementation, assuming that
962
+ the orbit of ``x`` is finite.
963
+
964
+ EXAMPLES::
965
+
966
+ sage: D = DiscreteDynamicalSystem(tuple(range(8)), lambda x: (x + 2) % 8, inverse=True)
967
+ sage: D.inverse_evolution_default(1)
968
+ 7
969
+ sage: D.inverse_evolution_default(3)
970
+ 1
971
+ """
972
+ return self.orbit(x)[-1]
973
+
974
+
975
+ class FiniteDynamicalSystem(DiscreteDynamicalSystem):
976
+ r"""
977
+ A finite discrete dynamical system.
978
+
979
+ A *finite discrete dynamical system* (henceforth *FDDS*) is a
980
+ pair `(X, \phi)` of a finite set `X` and a map `\phi : X \to X`.
981
+ This set `X` is called the *ground set* of the FDDS, while
982
+ the map `\phi` is called the *evolution* of the FDDS.
983
+
984
+ The ground set `X` should always be provided as an
985
+ iterable when defining a :class:`FiniteDynamicalSystem`.
986
+
987
+ EXAMPLES::
988
+
989
+ sage: from sage.dynamics.finite_dynamical_system import FiniteDynamicalSystem
990
+ sage: D = FiniteDynamicalSystem(tuple(range(11)), lambda x: (x**2) % 11)
991
+ sage: D.ground_set()
992
+ (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
993
+ sage: D.evolution()(4)
994
+ 5
995
+ sage: D.orbit(4)
996
+ [4, 5, 3, 9]
997
+ sage: D.orbit(1)
998
+ [1]
999
+ sage: D.orbit(2)
1000
+ [2, 4, 5, 3, 9]
1001
+
1002
+ sage: X = cartesian_product([[0, 1]]*8)
1003
+ sage: Y = [s for s in X if sum(s) == 4]
1004
+ sage: rot = lambda s : s[1:] + (0,)
1005
+ sage: D = FiniteDynamicalSystem(Y, rot)
1006
+ sage: D.evolution()((1, 1, 1, 0, 1, 0, 0, 1))
1007
+ (1, 1, 0, 1, 0, 0, 1, 0)
1008
+ """
1009
+ def _repr_(self):
1010
+ r"""
1011
+ String representation of ``self``.
1012
+
1013
+ EXAMPLES::
1014
+
1015
+ sage: D = DiscreteDynamicalSystem(tuple(range(11)), lambda x: (x**2) % 11)
1016
+ sage: D
1017
+ A finite discrete dynamical system with ground set
1018
+ (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
1019
+ """
1020
+ return "A finite discrete dynamical system with ground set " \
1021
+ + repr(self._X)
1022
+
1023
+ def is_invariant(self, f):
1024
+ r"""
1025
+ Check if ``f`` is an invariant of ``self``.
1026
+
1027
+ Let `(X, \phi)` be a discrete dynamical system.
1028
+ Let `Y` be any set. Let `f : X \to Y` be any map.
1029
+ Then, we say that `f` is an *invariant* of `(X, \phi)`
1030
+ if and only if `f \circ \phi = f`.
1031
+
1032
+ EXAMPLES::
1033
+
1034
+ sage: W = Words(2, 5)
1035
+ sage: F = DiscreteDynamicalSystem(W, lambda x: x[1:] + Word([x[0]]), is_finite=True)
1036
+ sage: F.is_invariant(lambda w: sum(w))
1037
+ True
1038
+ sage: F.is_invariant(lambda w: 1)
1039
+ True
1040
+ sage: F.is_invariant(lambda w: w[0] - w[1])
1041
+ False
1042
+ sage: F.is_invariant(lambda w: sum(i**2 for i in w))
1043
+ True
1044
+
1045
+ Invariants and non-invariants of a permutation::
1046
+
1047
+ sage: F = finite_dynamical_systems.permutation([3, 4, 5, 6, 1, 2])
1048
+ sage: F.is_invariant(lambda i: i % 2)
1049
+ True
1050
+ sage: F.is_invariant(lambda i: i % 3)
1051
+ False
1052
+ sage: F.is_invariant(lambda i: i > 1)
1053
+ False
1054
+ sage: F.is_invariant(lambda i: i % 2 == 0)
1055
+ True
1056
+ """
1057
+ phi = self._phi
1058
+ return all(f(phi(i)) == f(i) for i in self._X)
1059
+
1060
+ def cycles(self):
1061
+ r"""
1062
+ Return a list of all cycles of ``self``, up to
1063
+ cyclic rotation.
1064
+
1065
+ We recall the definition of cycles:
1066
+ Let `(X, \phi)` be a DDS.
1067
+ A *cycle* of `(X, \phi)` is a finite list
1068
+ `u = (u_1, u_2, \ldots, u_k)` of elements of `X` such
1069
+ that `\phi(u_i) = u_{i+1}` for each `i \leq k`, where we
1070
+ set `u_{k+1} = u_1`.
1071
+ Note that any element of `X` whose orbit is finite has a
1072
+ cycle in its orbit.
1073
+
1074
+ EXAMPLES::
1075
+
1076
+ sage: BS = finite_dynamical_systems.bulgarian_solitaire
1077
+ sage: BS(8).cycles()
1078
+ [[[4, 3, 1], [3, 3, 2], [3, 2, 2, 1], [4, 2, 1, 1]],
1079
+ [[4, 2, 2], [3, 3, 1, 1]]]
1080
+ sage: BS(6).cycles()
1081
+ [[[3, 2, 1]]]
1082
+
1083
+ sage: D = DiscreteDynamicalSystem(tuple(range(6)), lambda x: (x + 2) % 6)
1084
+ sage: D.cycles()
1085
+ [[5, 1, 3], [4, 0, 2]]
1086
+ sage: D = DiscreteDynamicalSystem(tuple(range(6)), lambda x: (x ** 2) % 6)
1087
+ sage: D.cycles()
1088
+ [[1], [4], [3], [0]]
1089
+ sage: D = DiscreteDynamicalSystem(tuple(range(11)), lambda x: (x ** 2 - 1) % 11)
1090
+ sage: D.cycles()
1091
+ [[10, 0], [8], [4]]
1092
+
1093
+ sage: F = finite_dynamical_systems.one_line([4, 7, 2, 6, 2, 10, 9, 11, 5, 6, 12, 12, 12, 6])
1094
+ sage: F.cycles()
1095
+ [[6, 10], [12], [9, 5, 2, 7]]
1096
+ """
1097
+ l = list(self)
1098
+ cycs = []
1099
+ while l:
1100
+ start = l[-1]
1101
+ (orb, ix) = self.orbit(start, preperiod=True)
1102
+ if orb[ix] in l:
1103
+ # This means we've actually found a new cycle,
1104
+ # not just a new path to an old cycle.
1105
+ cycs.append(orb[ix:])
1106
+ for j in orb:
1107
+ try:
1108
+ l.remove(j)
1109
+ except ValueError:
1110
+ # Here we break out of the for-loop, because
1111
+ # if ``j`` has already been removed from
1112
+ # ``l``, then all later elements of the orbit
1113
+ # must have been removed from ``l`` as well
1114
+ # (indeed, the set of elements that have been
1115
+ # removed from ``l`` is closed under ``phi``).
1116
+ break
1117
+ return cycs
1118
+
1119
+
1120
+ class InvertibleFiniteDynamicalSystem(InvertibleDiscreteDynamicalSystem, FiniteDynamicalSystem):
1121
+ r"""
1122
+ An invertible finite discrete dynamical system.
1123
+
1124
+ A *finite discrete dynamical system* (henceforth *FDDS*) is a
1125
+ pair `(X, \phi)` of a finite set `X` and a map `\phi : X \to X`.
1126
+ This set `X` is called the *ground set* of the FDDS, while
1127
+ the map `\phi` is called the *evolution* of the FDDS.
1128
+ An FDDS `(X, \phi)` is called *invertible* if the map `\phi`
1129
+ is invertible; in this case, `\phi^{-1}` is called the
1130
+ *inverse evolution* of the FDDS.
1131
+
1132
+ The ground set `X` should always be provided as an
1133
+ iterable when defining a :class:`FiniteDynamicalSystem`.
1134
+
1135
+ EXAMPLES::
1136
+
1137
+ sage: from sage.dynamics.finite_dynamical_system import InvertibleFiniteDynamicalSystem
1138
+ sage: D = InvertibleFiniteDynamicalSystem(tuple(range(5)), lambda x: (x + 2) % 5)
1139
+ sage: D.ground_set()
1140
+ (0, 1, 2, 3, 4)
1141
+ sage: D.evolution()(4)
1142
+ 1
1143
+ sage: D.orbits()
1144
+ [[4, 1, 3, 0, 2]]
1145
+ sage: D.inverse_evolution()(2)
1146
+ 0
1147
+ sage: D.inverse_evolution()(1)
1148
+ 4
1149
+ sage: D.evolution_power(-1)(1)
1150
+ 4
1151
+ sage: D.evolution_power(-2)(1)
1152
+ 2
1153
+
1154
+ sage: X = cartesian_product([[0, 1]]*8)
1155
+ sage: Y = [s for s in X if sum(s) == 4]
1156
+ sage: rot = lambda s : s[1:] + (s[0],)
1157
+ sage: D = InvertibleFiniteDynamicalSystem(Y, rot)
1158
+ sage: D.evolution()((0, 1, 1, 0, 1, 0, 0, 1))
1159
+ (1, 1, 0, 1, 0, 0, 1, 0)
1160
+ sage: D.inverse_evolution()((0, 1, 1, 0, 1, 0, 0, 1))
1161
+ (1, 0, 1, 1, 0, 1, 0, 0)
1162
+ sage: sorted(D.orbit_lengths())
1163
+ [2, 4, 8, 8, 8, 8, 8, 8, 8, 8]
1164
+ """
1165
+ def _repr_(self):
1166
+ r"""
1167
+ String representation of ``self``.
1168
+
1169
+ EXAMPLES::
1170
+
1171
+ sage: D = DiscreteDynamicalSystem(tuple(range(5)), lambda x: (x + 2) % 5, inverse=True)
1172
+ sage: D
1173
+ An invertible finite discrete dynamical system with ground set
1174
+ (0, 1, 2, 3, 4)
1175
+ """
1176
+ return "An invertible finite discrete dynamical system with ground set " \
1177
+ + repr(self._X)
1178
+
1179
+ def orbits(self):
1180
+ r"""
1181
+ Return a list of all orbits of ``self``, up to
1182
+ cyclic rotation.
1183
+
1184
+ EXAMPLES::
1185
+
1186
+ sage: D = DiscreteDynamicalSystem(tuple(range(6)), lambda x: (x + 2) % 6, inverse=True)
1187
+ sage: D.orbits()
1188
+ [[5, 1, 3], [4, 0, 2]]
1189
+ sage: D = DiscreteDynamicalSystem(tuple(range(6)), lambda x: (x + 3) % 6, inverse=True)
1190
+ sage: D.orbits()
1191
+ [[5, 2], [4, 1], [3, 0]]
1192
+ """
1193
+ phi = self._phi
1194
+ l = list(self)
1195
+ orbs = []
1196
+ while l:
1197
+ start = l.pop()
1198
+ orb = [start]
1199
+ curr = phi(start)
1200
+ while curr != start:
1201
+ l.remove(curr)
1202
+ orb.append(curr)
1203
+ curr = phi(curr)
1204
+ orbs.append(orb)
1205
+ return orbs
1206
+
1207
+ def cycles(self):
1208
+ r"""
1209
+ Return a list of all cycles of ``self``, up to
1210
+ cyclic rotation.
1211
+
1212
+ We recall the definition of cycles:
1213
+ Let `(X, \phi)` be a DDS.
1214
+ A *cycle* of `(X, \phi)` is a finite list
1215
+ `u = (u_1, u_2, \ldots, u_k)` of elements of `X` such
1216
+ that `\phi(u_i) = u_{i+1}` for each `i \leq k`, where we
1217
+ set `u_{k+1} = u_1`.
1218
+ Note that any element of `X` whose orbit is finite has a
1219
+ cycle in its orbit.
1220
+
1221
+ Since ``self`` is invertible, the cycles of ``self``
1222
+ are the same as its orbits.
1223
+
1224
+ EXAMPLES::
1225
+
1226
+ sage: D = DiscreteDynamicalSystem(tuple(range(6)), lambda x: (x + 2) % 6, inverse=True)
1227
+ sage: D.cycles()
1228
+ [[5, 1, 3], [4, 0, 2]]
1229
+ sage: D = DiscreteDynamicalSystem(tuple(range(6)), lambda x: (x + 3) % 6, inverse=True)
1230
+ sage: D.cycles()
1231
+ [[5, 2], [4, 1], [3, 0]]
1232
+ """
1233
+ return self.orbits()
1234
+
1235
+ def orbit_lengths(self):
1236
+ r"""
1237
+ Return a list of the lengths of all orbits of
1238
+ ``self``.
1239
+
1240
+ EXAMPLES::
1241
+
1242
+ sage: D = DiscreteDynamicalSystem(tuple(range(6)), lambda x: (x + 2) % 6, inverse=True)
1243
+ sage: D.orbit_lengths()
1244
+ [3, 3]
1245
+ sage: D = DiscreteDynamicalSystem(tuple(range(6)), lambda x: (x + 3) % 6, inverse=True)
1246
+ sage: D.orbit_lengths()
1247
+ [2, 2, 2]
1248
+ """
1249
+ return [len(orb) for orb in self.orbits()]