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,4316 @@
1
+ # sage_setup: distribution = sagemath-combinat
2
+ # sage.doctest: needs sage.combinat sage.modules sage.symbolic
3
+ r"""
4
+ `k`-regular sequences
5
+
6
+ An introduction and formal definition of `k`-regular sequences can be
7
+ found, for example, on the :wikipedia:`k-regular_sequence` or in
8
+ [AS2003]_.
9
+
10
+ ::
11
+
12
+ sage: import logging
13
+ sage: logging.basicConfig()
14
+
15
+ Examples
16
+ ========
17
+
18
+ Binary sum of digits
19
+ --------------------
20
+
21
+ The binary sum of digits `S(n)` of a nonnegative integer `n` satisfies
22
+ `S(2n) = S(n)` and `S(2n+1) = S(n) + 1`. We model this by the following::
23
+
24
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
25
+ sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])),
26
+ ....: left=vector([0, 1]), right=vector([1, 0]))
27
+ sage: S
28
+ 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ...
29
+ sage: all(S[n] == sum(n.digits(2)) for n in srange(10))
30
+ True
31
+
32
+ Number of odd entries in Pascal's triangle
33
+ ------------------------------------------
34
+
35
+ Let us consider the number of odd entries in the first `n` rows
36
+ of Pascals's triangle::
37
+
38
+ sage: @cached_function
39
+ ....: def u(n):
40
+ ....: if n <= 1:
41
+ ....: return n
42
+ ....: return 2 * u(n // 2) + u((n+1) // 2)
43
+ sage: tuple(u(n) for n in srange(10))
44
+ (0, 1, 3, 5, 9, 11, 15, 19, 27, 29)
45
+
46
+ There is a `2`-regular sequence describing the numbers above as well::
47
+
48
+ sage: U = Seq2((Matrix([[3, 0], [2, 1]]), Matrix([[2, 1], [0, 3]])),
49
+ ....: left=vector([1, 0]), right=vector([0, 1]))
50
+ sage: all(U[n] == u(n) for n in srange(30))
51
+ True
52
+
53
+
54
+ Various
55
+ =======
56
+
57
+ .. SEEALSO::
58
+
59
+ :mod:`recognizable series <sage.combinat.recognizable_series>`,
60
+ :mod:`sage.rings.cfinite_sequence`,
61
+ :mod:`sage.combinat.binary_recurrence_sequences`.
62
+
63
+ AUTHORS:
64
+
65
+ - Daniel Krenn (2016, 2021)
66
+ - Gabriel F. Lipnik (2021)
67
+
68
+ ACKNOWLEDGEMENT:
69
+
70
+ - Daniel Krenn is supported by the
71
+ Austrian Science Fund (FWF): P 24644-N26.
72
+ - Gabriel F. Lipnik is supported by the
73
+ Austrian Science Fund (FWF): W 1230.
74
+
75
+
76
+ Classes and Methods
77
+ ===================
78
+ """
79
+ # ****************************************************************************
80
+ # Copyright (C) 2016 Daniel Krenn <dev@danielkrenn.at>
81
+ # 2021 Gabriel F. Lipnik <dev@gabriellipnik.at>
82
+ #
83
+ # This program is free software: you can redistribute it and/or modify
84
+ # it under the terms of the GNU General Public License as published by
85
+ # the Free Software Foundation, either version 3 of the License, or
86
+ # (at your option) any later version.
87
+ # https://www.gnu.org/licenses/
88
+ # ****************************************************************************
89
+ from .recognizable_series import RecognizableSeries
90
+ from .recognizable_series import RecognizableSeriesSpace
91
+ from .recognizable_series import minimize_result
92
+ from sage.misc.cachefunc import cached_function, cached_method
93
+
94
+
95
+ def pad_right(T, length, zero=0):
96
+ r"""
97
+ Pad ``T`` to the right by using ``zero`` to have
98
+ at least the given ``length``.
99
+
100
+ INPUT:
101
+
102
+ - ``T`` -- tuple, list or other iterable
103
+
104
+ - ``length`` -- nonnegative integer
105
+
106
+ - ``zero`` -- (default: ``0``) the elements to pad with
107
+
108
+ OUTPUT: an object of the same type as ``T``
109
+
110
+ EXAMPLES::
111
+
112
+ sage: from sage.combinat.regular_sequence import pad_right
113
+ sage: pad_right((1, 2, 3), 10)
114
+ (1, 2, 3, 0, 0, 0, 0, 0, 0, 0)
115
+ sage: pad_right((1, 2, 3), 2)
116
+ (1, 2, 3)
117
+ sage: pad_right([(1, 2), (3, 4)], 4, (0, 0))
118
+ [(1, 2), (3, 4), (0, 0), (0, 0)]
119
+
120
+ TESTS::
121
+
122
+ sage: pad_right([1, 2, 3], 10)
123
+ [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]
124
+ """
125
+ return T + type(T)(zero for _ in range(length - len(T)))
126
+
127
+
128
+ def value(D, k):
129
+ r"""
130
+ Return the value of the expansion with digits `D` in base `k`, i.e.
131
+
132
+ .. MATH::
133
+
134
+ \sum_{0\leq j < \operatorname{len}D} D[j] k^j.
135
+
136
+ INPUT:
137
+
138
+ - ``D`` -- tuple or other iterable
139
+
140
+ - ``k`` -- the base
141
+
142
+ OUTPUT:
143
+
144
+ An element in the common parent of the base `k` and of the entries
145
+ of `D`
146
+
147
+ EXAMPLES::
148
+
149
+ sage: from sage.combinat.regular_sequence import value
150
+ sage: value(42.digits(7), 7)
151
+ 42
152
+ """
153
+ return sum(d * k**j for j, d in enumerate(D))
154
+
155
+
156
+ class DegeneratedSequenceError(RuntimeError):
157
+ r"""
158
+ Exception raised if a degenerated sequence
159
+ (see :meth:`~RegularSequence.is_degenerated`) is detected.
160
+
161
+ EXAMPLES::
162
+
163
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
164
+ sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]))
165
+ Traceback (most recent call last):
166
+ ...
167
+ DegeneratedSequenceError: degenerated sequence: mu[0]*right != right.
168
+ Using such a sequence might lead to wrong results.
169
+ You can use 'allow_degenerated_sequence=True' followed
170
+ by a call of method .regenerated() for correcting this.
171
+ """
172
+ pass
173
+
174
+
175
+ class RegularSequence(RecognizableSeries):
176
+ def __init__(self, parent, mu, left=None, right=None):
177
+ r"""
178
+ A `k`-regular sequence.
179
+
180
+ INPUT:
181
+
182
+ - ``parent`` -- an instance of :class:`RegularSequenceRing`
183
+
184
+ - ``mu`` -- a family of square matrices, all of which have the
185
+ same dimension. The indices of this family are `0,...,k-1`.
186
+ ``mu`` may be a list or tuple of cardinality `k`
187
+ as well. See also
188
+ :meth:`~sage.combinat.recognizable_series.RecognizableSeries.mu`.
189
+
190
+ - ``left`` -- (default: ``None``) a vector.
191
+ When evaluating the sequence, this vector is multiplied
192
+ from the left to the matrix product. If ``None``, then this
193
+ multiplication is skipped.
194
+
195
+ - ``right`` -- (default: ``None``) a vector.
196
+ When evaluating the sequence, this vector is multiplied
197
+ from the right to the matrix product. If ``None``, then this
198
+ multiplication is skipped.
199
+
200
+ When created via the parent :class:`RegularSequenceRing`, then
201
+ the following option is available.
202
+
203
+ - ``allow_degenerated_sequence`` -- boolean (default: ``False``); if
204
+ set, then there will be no check if the input is a degenerated
205
+ sequence (see :meth:`is_degenerated`). Otherwise the input is checked
206
+ and a :exc:`DegeneratedSequenceError` is raised if such a sequence
207
+ is detected.
208
+
209
+ EXAMPLES::
210
+
211
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
212
+ sage: S = Seq2((Matrix([[3, 0], [6, 1]]), Matrix([[0, 1], [-6, 5]])),
213
+ ....: vector([1, 0]), vector([0, 1])); S
214
+ 2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ...
215
+
216
+ We can access the coefficients of a sequence by
217
+ ::
218
+
219
+ sage: S[5]
220
+ 11
221
+
222
+ or iterating over the first, say `10`, by
223
+ ::
224
+
225
+ sage: from itertools import islice
226
+ sage: list(islice(S, 10))
227
+ [0, 1, 3, 5, 9, 11, 15, 19, 27, 29]
228
+
229
+ .. SEEALSO::
230
+
231
+ :doc:`k-regular sequence <regular_sequence>`,
232
+ :class:`RegularSequenceRing`.
233
+
234
+ TESTS::
235
+
236
+ sage: Seq2(([[1, 0], [0, 1]], [[1, 1], [0, 1]]), (1, 0), (0, 1))
237
+ 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ...
238
+ """
239
+ super().__init__(parent=parent, mu=mu, left=left, right=right)
240
+
241
+ def _repr_(self):
242
+ r"""
243
+ Return a representation string of this `k`-regular sequence.
244
+
245
+ OUTPUT: string
246
+
247
+ TESTS::
248
+
249
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
250
+ sage: s = Seq2((Matrix([[3, 0], [6, 1]]), Matrix([[0, 1], [-6, 5]])),
251
+ ....: vector([1, 0]), vector([0, 1]))
252
+ sage: repr(s) # indirect doctest
253
+ '2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ...'
254
+ """
255
+ from sage.misc.lazy_list import lazy_list_formatter
256
+ return lazy_list_formatter(
257
+ self,
258
+ name='{}-regular sequence'.format(self.parent().k),
259
+ opening_delimiter='', closing_delimiter='',
260
+ preview=10)
261
+
262
+ @cached_method
263
+ def coefficient_of_n(self, n, **kwds):
264
+ r"""
265
+ Return the `n`-th entry of this sequence.
266
+
267
+ INPUT:
268
+
269
+ - ``n`` -- nonnegative integer
270
+
271
+ OUTPUT: an element of the universe of the sequence
272
+
273
+ EXAMPLES::
274
+
275
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
276
+ sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[0, -1], [1, 2]])),
277
+ ....: left=vector([0, 1]), right=vector([1, 0]))
278
+ sage: S[7]
279
+ 3
280
+
281
+ This is equivalent to::
282
+
283
+ sage: S.coefficient_of_n(7)
284
+ 3
285
+
286
+ TESTS::
287
+
288
+ sage: S[-1]
289
+ Traceback (most recent call last):
290
+ ...
291
+ ValueError: value -1 of index is negative
292
+
293
+ ::
294
+
295
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
296
+ sage: W = Seq2.indices()
297
+ sage: M0 = Matrix([[1, 0], [0, 1]])
298
+ sage: M1 = Matrix([[0, -1], [1, 2]])
299
+ sage: S = Seq2((M0, M1), vector([0, 1]), vector([1, 1]))
300
+ sage: S._mu_of_word_(W(0.digits(2))) == M0
301
+ True
302
+ sage: S._mu_of_word_(W(1.digits(2))) == M1
303
+ True
304
+ sage: S._mu_of_word_(W(3.digits(2))) == M1^2
305
+ True
306
+ """
307
+ return self.coefficient_of_word(self.parent()._n_to_index_(n), **kwds)
308
+
309
+ __getitem__ = coefficient_of_n
310
+
311
+ def __iter__(self):
312
+ r"""
313
+ Return an iterator over the coefficients of this sequence.
314
+
315
+ EXAMPLES::
316
+
317
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
318
+ sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[0, -1], [1, 2]])),
319
+ ....: left=vector([0, 1]), right=vector([1, 0]))
320
+ sage: from itertools import islice
321
+ sage: tuple(islice(S, 10))
322
+ (0, 1, 1, 2, 1, 2, 2, 3, 1, 2)
323
+
324
+ TESTS::
325
+
326
+ sage: it = iter(S)
327
+ sage: iter(it) is it
328
+ True
329
+ sage: iter(S) is not it
330
+ True
331
+ """
332
+ from itertools import count
333
+ return iter(self[n] for n in count())
334
+
335
+ @cached_method
336
+ def is_degenerated(self):
337
+ r"""
338
+ Return whether this `k`-regular sequence is degenerated,
339
+ i.e., whether this `k`-regular sequence does not satisfy
340
+ `\mu[0] \mathit{right} = \mathit{right}`.
341
+
342
+ EXAMPLES::
343
+
344
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
345
+ sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1])) # indirect doctest
346
+ Traceback (most recent call last):
347
+ ...
348
+ DegeneratedSequenceError: degenerated sequence: mu[0]*right != right.
349
+ Using such a sequence might lead to wrong results.
350
+ You can use 'allow_degenerated_sequence=True' followed
351
+ by a call of method .regenerated() for correcting this.
352
+ sage: S = Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]),
353
+ ....: allow_degenerated_sequence=True)
354
+ sage: S
355
+ 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ...
356
+ sage: S.is_degenerated()
357
+ True
358
+
359
+ ::
360
+
361
+ sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])),
362
+ ....: vector([1, 0]), vector([0, 1]))
363
+ sage: C.is_degenerated()
364
+ False
365
+ """
366
+ from sage.rings.integer_ring import ZZ
367
+ return (self.mu[ZZ(0)] * self.right) != self.right
368
+
369
+ def _error_if_degenerated_(self):
370
+ r"""
371
+ Raise an error if this `k`-regular sequence is degenerated,
372
+ i.e., if this `k`-regular sequence does not satisfy
373
+ `\mu[0] \mathit{right} = \mathit{right}`.
374
+
375
+ TESTS::
376
+
377
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
378
+ sage: Seq2((Matrix([[3, 2], [0, 1]]), Matrix([[2, 0], [1, 3]])), # indirect doctest
379
+ ....: left=vector([0, 1]), right=vector([1, 0]))
380
+ Traceback (most recent call last):
381
+ ...
382
+ DegeneratedSequenceError: degenerated sequence: mu[0]*right != right.
383
+ Using such a sequence might lead to wrong results.
384
+ You can use 'allow_degenerated_sequence=True' followed
385
+ by a call of method .regenerated() for correcting this.
386
+ """
387
+ if self.is_degenerated():
388
+ raise DegeneratedSequenceError(
389
+ "degenerated sequence: mu[0]*right != right. "
390
+ "Using such a sequence might lead to wrong results. "
391
+ "You can use 'allow_degenerated_sequence=True' followed by "
392
+ "a call of method .regenerated() "
393
+ "for correcting this.")
394
+
395
+ @cached_method
396
+ @minimize_result
397
+ def regenerated(self):
398
+ r"""
399
+ Return a `k`-regular sequence that satisfies
400
+ `\mu[0] \mathit{right} = \mathit{right}` with the same values as
401
+ this sequence.
402
+
403
+ INPUT:
404
+
405
+ - ``minimize`` -- (default: ``None``) a boolean or ``None``.
406
+ If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation,
407
+ if ``False``, then not. If this argument is ``None``, then
408
+ the default specified by the parent's ``minimize_results`` is used.
409
+
410
+ OUTPUT: a :class:`RegularSequence`
411
+
412
+ ALGORITHM:
413
+
414
+ Theorem B of [HKL2022]_ with `n_0 = 1`.
415
+
416
+ EXAMPLES::
417
+
418
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
419
+
420
+ The following linear representation of `S` is chosen badly (is
421
+ degenerated, see :meth:`is_degenerated`), as `\mu(0)` applied on
422
+ `\mathit{right}` does not equal `\mathit{right}`::
423
+
424
+ sage: S = Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]),
425
+ ....: allow_degenerated_sequence=True)
426
+ sage: S
427
+ 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ...
428
+ sage: S.is_degenerated()
429
+ True
430
+
431
+ However, we can regenerate the sequence `S`::
432
+
433
+ sage: H = S.regenerated()
434
+ sage: H
435
+ 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ...
436
+ sage: H.linear_representation()
437
+ ((1, 0),
438
+ Finite family {0: [ 0 1]
439
+ [-2 3],
440
+ 1: [3 0]
441
+ [6 0]},
442
+ (1, 1))
443
+ sage: H.is_degenerated()
444
+ False
445
+
446
+ TESTS::
447
+
448
+ sage: S = Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]),
449
+ ....: allow_degenerated_sequence=True)
450
+ sage: H = S.regenerated(minimize=False)
451
+ sage: H.linear_representation()
452
+ ((1, 0),
453
+ Finite family {0: [ 2|-1]
454
+ [--+--]
455
+ [ 0| 1],
456
+ 1: [3|0]
457
+ [-+-]
458
+ [0|0]},
459
+ (1, 1))
460
+ sage: H.is_degenerated()
461
+ False
462
+ """
463
+ if not self.is_degenerated():
464
+ return self
465
+
466
+ from sage.matrix.constructor import Matrix
467
+ from sage.matrix.special import zero_matrix, identity_matrix
468
+ from sage.modules.free_module_element import vector
469
+
470
+ P = self.parent()
471
+ dim = self.dimension()
472
+ Zc = zero_matrix(dim, 1)
473
+ Zr = zero_matrix(1, dim)
474
+ I = identity_matrix(dim)
475
+
476
+ itA = iter(P.alphabet())
477
+ z = next(itA)
478
+ W0 = Matrix(dim, 1, (I - self.mu[z]) * self.right)
479
+ mu = {z: Matrix.block([[self.mu[z], W0], [Zr, 1]])}
480
+ mu.update((r, Matrix.block([[self.mu[r], Zc], [Zr, 0]]))
481
+ for r in itA)
482
+
483
+ return P.element_class(
484
+ P, mu,
485
+ vector(tuple(self.left) + (0,)),
486
+ vector(tuple(self.right) + (1,)))
487
+
488
+ def transposed(self, allow_degenerated_sequence=False):
489
+ r"""
490
+ Return the transposed sequence.
491
+
492
+ INPUT:
493
+
494
+ - ``allow_degenerated_sequence`` -- boolean (default: ``False``); if
495
+ set, then there will be no check if the transposed sequence is a
496
+ degenerated sequence (see :meth:`is_degenerated`). Otherwise the
497
+ transposed sequence is checked and a :exc:`DegeneratedSequenceError`
498
+ is raised if such a sequence is detected.
499
+
500
+ OUTPUT: a :class:`RegularSequence`
501
+
502
+ Each of the matrices in :meth:`mu <mu>` is transposed. Additionally
503
+ the vectors :meth:`left <left>` and :meth:`right <right>` are switched.
504
+
505
+ EXAMPLES::
506
+
507
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
508
+ sage: U = Seq2((Matrix([[3, 2], [0, 1]]), Matrix([[2, 0], [1, 3]])),
509
+ ....: left=vector([0, 1]), right=vector([1, 0]),
510
+ ....: allow_degenerated_sequence=True)
511
+ sage: U.is_degenerated()
512
+ True
513
+ sage: Ut = U.transposed()
514
+ sage: Ut.linear_representation()
515
+ ((1, 0),
516
+ Finite family {0: [3 0]
517
+ [2 1],
518
+ 1: [2 1]
519
+ [0 3]},
520
+ (0, 1))
521
+ sage: Ut.is_degenerated()
522
+ False
523
+
524
+ sage: Ut.transposed()
525
+ Traceback (most recent call last):
526
+ ...
527
+ DegeneratedSequenceError: degenerated sequence: mu[0]*right != right.
528
+ Using such a sequence might lead to wrong results.
529
+ You can use 'allow_degenerated_sequence=True' followed
530
+ by a call of method .regenerated() for correcting this.
531
+ sage: Utt = Ut.transposed(allow_degenerated_sequence=True)
532
+ sage: Utt.is_degenerated()
533
+ True
534
+
535
+ .. SEEALSO::
536
+
537
+ :meth:`RecognizableSeries.transposed <sage.combinat.recognizable_series.RecognizableSeries.transposed>`
538
+ """
539
+ element = super().transposed()
540
+ if not allow_degenerated_sequence:
541
+ element._error_if_degenerated_()
542
+ return element
543
+
544
+ def _minimized_right_(self):
545
+ r"""
546
+ Return a regular sequence equivalent to this series, but
547
+ with a right minimized linear representation.
548
+
549
+ OUTPUT: a :class:`RegularSequence`
550
+
551
+ .. SEEALSO::
552
+
553
+ :meth:`RecognizableSeries._minimized_right_ <sage.combinat.recognizable_series.RecognizableSeries._minimized_right_>`
554
+
555
+ TESTS::
556
+
557
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
558
+ sage: Seq2((Matrix([[3, 0], [2, 1]]), Matrix([[2, 1], [0, 3]])), # indirect doctest
559
+ ....: left=vector([1, 0]), right=vector([0, 1])).minimized()
560
+ 2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ...
561
+ """
562
+ return self.transposed(allow_degenerated_sequence=True)._minimized_left_().transposed(allow_degenerated_sequence=True)
563
+
564
+ @minimize_result
565
+ def subsequence(self, a, b):
566
+ r"""
567
+ Return the subsequence with indices `an+b` of this
568
+ `k`-regular sequence.
569
+
570
+ INPUT:
571
+
572
+ - ``a`` -- nonnegative integer
573
+
574
+ - ``b`` -- integer
575
+
576
+ Alternatively, this is allowed to be a dictionary
577
+ `b_j \mapsto c_j`. If so and applied on `f(n)`,
578
+ the result will be the sum of all `c_j \cdot f(an+b_j)`.
579
+
580
+ - ``minimize`` -- (default: ``None``) a boolean or ``None``.
581
+ If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation,
582
+ if ``False``, then not. If this argument is ``None``, then
583
+ the default specified by the parent's ``minimize_results`` is used.
584
+
585
+ OUTPUT: a :class:`RegularSequence`
586
+
587
+ .. NOTE::
588
+
589
+ If `b` is negative (i.e., right-shift), then the
590
+ coefficients when accessing negative indices are `0`.
591
+
592
+ EXAMPLES::
593
+
594
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
595
+
596
+ We consider the sequence `C` with `C(n) = n` and
597
+ the following linear representation
598
+ corresponding to the vector `(n, 1)`::
599
+
600
+ sage: C = Seq2((Matrix([[2, 0], [0, 1]]), Matrix([[2, 1], [0, 1]])),
601
+ ....: vector([1, 0]), vector([0, 1])); C
602
+ 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
603
+
604
+ We now extract various subsequences of `C`::
605
+
606
+ sage: C.subsequence(2, 0)
607
+ 2-regular sequence 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, ...
608
+
609
+ sage: S31 = C.subsequence(3, 1); S31
610
+ 2-regular sequence 1, 4, 7, 10, 13, 16, 19, 22, 25, 28, ...
611
+ sage: S31.linear_representation()
612
+ ((1, 0),
613
+ Finite family {0: [ 0 1]
614
+ [-2 3],
615
+ 1: [ 6 -2]
616
+ [10 -3]},
617
+ (1, 1))
618
+
619
+ sage: C.subsequence(3, 2)
620
+ 2-regular sequence 2, 5, 8, 11, 14, 17, 20, 23, 26, 29, ...
621
+
622
+ ::
623
+
624
+ sage: Srs = C.subsequence(1, -1); Srs
625
+ 2-regular sequence 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, ...
626
+ sage: Srs.linear_representation()
627
+ ((1, 0, 0),
628
+ Finite family {0: [ 0 1 0]
629
+ [-2 3 0]
630
+ [-4 4 1],
631
+ 1: [ -2 2 0]
632
+ [ 0 0 1]
633
+ [ 12 -12 5]},
634
+ (0, 0, 1))
635
+
636
+ We can build :meth:`backward_differences` manually by passing
637
+ a dictionary for the parameter ``b``::
638
+
639
+ sage: Sbd = C.subsequence(1, {0: 1, -1: -1}); Sbd
640
+ 2-regular sequence 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
641
+
642
+ TESTS:
643
+
644
+ We check if the linear representation of the subsequences above
645
+ indeed represent the correct vector valued sequences::
646
+
647
+ sage: var('n')
648
+ n
649
+
650
+ sage: def v(n):
651
+ ....: return vector([3*n + 1, 6*n + 1])
652
+ sage: S31.mu[0] * v(n) == v(2*n)
653
+ True
654
+ sage: S31.mu[1] * v(n) == v(2*n + 1)
655
+ True
656
+
657
+ sage: function('delta_0')
658
+ delta_0
659
+
660
+ sage: def simplify_delta(expr):
661
+ ....: return expr.subs({delta_0(2*n): delta_0(n), delta_0(2*n + 1): 0})
662
+
663
+ sage: def v(n):
664
+ ....: return vector([n -1 + delta_0(n), 2*n - 1 + delta_0(n), 4*n + 1])
665
+ sage: simplify_delta(v(2*n) - Srs.mu[0]*v(n)).is_zero()
666
+ True
667
+ sage: simplify_delta(v(2*n + 1) - Srs.mu[1]*v(n)).is_zero()
668
+ True
669
+
670
+ sage: def v(n):
671
+ ....: return vector([1 - delta_0(n), 1])
672
+
673
+ sage: simplify_delta(v(2*n) - Sbd.mu[0]*v(n)).is_zero()
674
+ True
675
+ sage: simplify_delta(v(2*n + 1) - Sbd.mu[1]*v(n)).is_zero()
676
+ True
677
+
678
+ We check some corner-cases::
679
+
680
+ sage: C.subsequence(0, 4)
681
+ 2-regular sequence 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, ...
682
+
683
+ ::
684
+
685
+ sage: C.subsequence(1, 0, minimize=False) is C
686
+ True
687
+
688
+ The following test that the range for `c` in the code
689
+ is sufficient::
690
+
691
+ sage: C.subsequence(1, -1, minimize=False)
692
+ 2-regular sequence 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, ...
693
+ sage: C.subsequence(1, -2, minimize=False)
694
+ 2-regular sequence 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, ...
695
+ sage: C.subsequence(2, -1, minimize=False)
696
+ 2-regular sequence 0, 1, 3, 5, 7, 9, 11, 13, 15, 17, ...
697
+ sage: C.subsequence(2, -2, minimize=False)
698
+ 2-regular sequence 0, 0, 2, 4, 6, 8, 10, 12, 14, 16, ...
699
+
700
+ sage: C.subsequence(2, 21, minimize=False)
701
+ 2-regular sequence 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, ...
702
+ sage: C.subsequence(2, 20, minimize=False)
703
+ 2-regular sequence 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, ...
704
+ sage: C.subsequence(2, 19, minimize=False)
705
+ 2-regular sequence 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, ...
706
+ sage: C.subsequence(2, -9, minimize=False)
707
+ 2-regular sequence 0, 0, 0, 0, 0, 1, 3, 5, 7, 9, ...
708
+
709
+ sage: C.subsequence(3, 21, minimize=False)
710
+ 2-regular sequence 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, ...
711
+ sage: C.subsequence(3, 20, minimize=False)
712
+ 2-regular sequence 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, ...
713
+ sage: C.subsequence(3, 19, minimize=False)
714
+ 2-regular sequence 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, ...
715
+ sage: C.subsequence(3, 18, minimize=False)
716
+ 2-regular sequence 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, ...
717
+
718
+ sage: C.subsequence(10, 2, minimize=False)
719
+ 2-regular sequence 2, 12, 22, 32, 42, 52, 62, 72, 82, 92, ...
720
+ sage: C.subsequence(10, 1, minimize=False)
721
+ 2-regular sequence 1, 11, 21, 31, 41, 51, 61, 71, 81, 91, ...
722
+ sage: C.subsequence(10, 0, minimize=False)
723
+ 2-regular sequence 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, ...
724
+ sage: C.subsequence(10, -1, minimize=False)
725
+ 2-regular sequence 0, 9, 19, 29, 39, 49, 59, 69, 79, 89, ...
726
+ sage: C.subsequence(10, -2, minimize=False)
727
+ 2-regular sequence 0, 8, 18, 28, 38, 48, 58, 68, 78, 88, ...
728
+
729
+ ::
730
+
731
+ sage: C.subsequence(-1, 0)
732
+ Traceback (most recent call last):
733
+ ...
734
+ ValueError: a=-1 is not nonnegative.
735
+
736
+ The following linear representation of `S` is chosen badly (is
737
+ degenerated, see :meth:`is_degenerated`), as `\mu(0)` applied on
738
+ `\mathit{right}` does not equal `\mathit{right}`::
739
+
740
+ sage: S = Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]),
741
+ ....: allow_degenerated_sequence=True)
742
+ sage: S
743
+ 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ...
744
+
745
+ This leads to the wrong result
746
+ ::
747
+
748
+ sage: S.subsequence(1, -4)
749
+ 2-regular sequence 0, 0, 0, 0, 8, 12, 12, 18, 24, 36, ...
750
+
751
+ We get the correct result by
752
+ ::
753
+
754
+ sage: S.regenerated().subsequence(1, -4)
755
+ 2-regular sequence 0, 0, 0, 0, 1, 3, 6, 9, 12, 18, ...
756
+
757
+ Check that the zero sequence is handled correctly (issue:`37282`)
758
+ ::
759
+
760
+ sage: Seq2.zero().subsequence(1, 1)
761
+ 2-regular sequence 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...
762
+ """
763
+ from itertools import chain
764
+ from sage.rings.integer_ring import ZZ
765
+
766
+ zero = ZZ(0)
767
+ a = ZZ(a)
768
+ if not isinstance(b, dict):
769
+ b = {ZZ(b): ZZ(1)}
770
+
771
+ if a == 0:
772
+ return sum(c_j * self[b_j] * self.parent().one_hadamard()
773
+ for b_j, c_j in b.items())
774
+ elif a == 1 and len(b) == 1 and zero in b:
775
+ return b[zero] * self
776
+ elif a < 0:
777
+ raise ValueError('a={} is not nonnegative.'.format(a))
778
+
779
+ from sage.matrix.constructor import Matrix
780
+ from sage.modules.free_module_element import vector
781
+ P = self.parent()
782
+ A = P.alphabet()
783
+ k = P.k
784
+
785
+ # Below, we use a dynamic approach to find the shifts of the
786
+ # sequences in the kernel. Note that according to [AS2003]_,
787
+ # the static range
788
+ # [min(b, 0), max(a, a + b))
789
+ # suffices. With B = |b| and A = max(a, B), we here obtain the range
790
+ # [-B, A]
791
+ # because of the following estimates:
792
+ # Let -B <= c <= A und set d = floor((ar+c) / k). Then
793
+ # -B = floor(-B)
794
+ # <= floor(-B / k)
795
+ # <= floor(c / k)
796
+ # <= d
797
+ # <= (ar+c) / k
798
+ # <= (A(k-1) + A) / k
799
+ # = A
800
+ # holds.
801
+ # For list-valued b, we use B = max{|beta| : beta in b} above.
802
+
803
+ kernel = list(b)
804
+
805
+ zero_M = self.mu[0].parent().zero()
806
+ zero_R = self.right.parent().zero()
807
+ # Let v(n) = self.coefficient_of_n(n, multiply_left=False)
808
+ rule = {}
809
+ # We will construct `kernel` and `rule` in such a way that for all
810
+ # c in `kernel`,
811
+ # rule[r, c] = (f, d)
812
+ # holds for some 0 <= f < r and some d in `kernel` such that
813
+ # v(a(kn+r)+c) [a(kn+r) +c >= 0] = mu[f] v(an+d) [an+d >= 0].
814
+
815
+ ci = 0
816
+ while ci < len(kernel):
817
+ c = kernel[ci]
818
+ for r in A:
819
+ # We now compute the contributions of v(an+c)[an >= 0] to
820
+ # the linear representation by using
821
+ # v(a(kn+r)+c) [a(kn+r)+c >= 0]
822
+ # = v(kan+ar+c) [kan+ar+c >= 0]
823
+ # = v(k(an+d)+f) [an+d >= 0]
824
+ # = mu[f] v(an+d) [an+d >= 0].
825
+ d, f = (a * r + c).quo_rem(k)
826
+ if d not in kernel:
827
+ kernel.append(d)
828
+ rule[r, c] = (d, f)
829
+ ci += 1
830
+
831
+ def matrix_row(r, c):
832
+ d, f = rule[r, c]
833
+ return [self.mu[f] if d == j else zero_M for j in kernel]
834
+
835
+ # We explicitly set the ring when creating vectors in order to avoid
836
+ # problems with the zero sequence, see issue:`37282`.
837
+ result = P.element_class(
838
+ P,
839
+ {r: Matrix.block([matrix_row(r, c) for c in kernel])
840
+ for r in A},
841
+ vector(P.coefficient_ring(), chain.from_iterable(
842
+ b.get(c, 0) * self.left
843
+ for c in kernel)),
844
+ vector(P.coefficient_ring(), chain.from_iterable(
845
+ (self.coefficient_of_n(c, multiply_left=False) if c >= 0 else zero_R)
846
+ for c in kernel)))
847
+
848
+ return result
849
+
850
+ def shift_left(self, b=1, **kwds):
851
+ r"""
852
+ Return the sequence obtained by shifting
853
+ this `k`-regular sequence `b` steps to the left.
854
+
855
+ INPUT:
856
+
857
+ - ``b`` -- integer
858
+
859
+ - ``minimize`` -- (default: ``None``) a boolean or ``None``.
860
+ If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation,
861
+ if ``False``, then not. If this argument is ``None``, then
862
+ the default specified by the parent's ``minimize_results`` is used.
863
+
864
+ OUTPUT: a :class:`RegularSequence`
865
+
866
+ .. NOTE::
867
+
868
+ If `b` is negative (i.e., actually a right-shift), then the
869
+ coefficients when accessing negative indices are `0`.
870
+
871
+ EXAMPLES::
872
+
873
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
874
+ sage: C = Seq2((Matrix([[2, 0], [0, 1]]), Matrix([[2, 1], [0, 1]])),
875
+ ....: vector([1, 0]), vector([0, 1])); C
876
+ 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
877
+
878
+ sage: C.shift_left()
879
+ 2-regular sequence 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...
880
+ sage: C.shift_left(3)
881
+ 2-regular sequence 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ...
882
+ sage: C.shift_left(-2)
883
+ 2-regular sequence 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, ...
884
+
885
+ TESTS::
886
+
887
+ sage: C.shift_left(0) == C
888
+ True
889
+ sage: C.shift_left(2).shift_right(2)
890
+ 2-regular sequence 0, 0, 2, 3, 4, 5, 6, 7, 8, 9, ...
891
+ """
892
+ return self.subsequence(1, b, **kwds)
893
+
894
+ def shift_right(self, b=1, **kwds):
895
+ r"""
896
+ Return the sequence obtained by shifting
897
+ this `k`-regular sequence `b` steps to the right.
898
+
899
+ INPUT:
900
+
901
+ - ``b`` -- integer
902
+
903
+ - ``minimize`` -- (default: ``None``) a boolean or ``None``.
904
+ If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation,
905
+ if ``False``, then not. If this argument is ``None``, then
906
+ the default specified by the parent's ``minimize_results`` is used.
907
+
908
+ OUTPUT: a :class:`RegularSequence`
909
+
910
+ .. NOTE::
911
+
912
+ If `b` is positive (i.e., indeed a right-shift), then the
913
+ coefficients when accessing negative indices are `0`.
914
+
915
+ EXAMPLES::
916
+
917
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
918
+ sage: C = Seq2((Matrix([[2, 0], [0, 1]]), Matrix([[2, 1], [0, 1]])),
919
+ ....: vector([1, 0]), vector([0, 1])); C
920
+ 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
921
+
922
+ sage: C.shift_right()
923
+ 2-regular sequence 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, ...
924
+ sage: C.shift_right(3)
925
+ 2-regular sequence 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, ...
926
+ sage: C.shift_right(-2)
927
+ 2-regular sequence 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...
928
+
929
+ TESTS::
930
+
931
+ sage: C.shift_right(0) == C
932
+ True
933
+ sage: C.shift_right().shift_left()
934
+ 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
935
+ sage: C.shift_right(2).shift_left(2)
936
+ 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
937
+ sage: _ == C
938
+ True
939
+ """
940
+ return self.subsequence(1, -b, **kwds)
941
+
942
+ def backward_differences(self, **kwds):
943
+ r"""
944
+ Return the sequence of backward differences of this
945
+ `k`-regular sequence.
946
+
947
+ INPUT:
948
+
949
+ - ``minimize`` -- (default: ``None``) a boolean or ``None``.
950
+ If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation,
951
+ if ``False``, then not. If this argument is ``None``, then
952
+ the default specified by the parent's ``minimize_results`` is used.
953
+
954
+ OUTPUT: a :class:`RegularSequence`
955
+
956
+ .. NOTE::
957
+
958
+ The coefficient to the index `-1` is `0`.
959
+
960
+ EXAMPLES::
961
+
962
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
963
+ sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])),
964
+ ....: vector([1, 0]), vector([0, 1]))
965
+ sage: C
966
+ 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
967
+ sage: C.backward_differences()
968
+ 2-regular sequence 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
969
+
970
+ ::
971
+
972
+ sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])),
973
+ ....: vector([1, 0]), vector([1, 1]))
974
+ sage: E
975
+ 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ...
976
+ sage: E.backward_differences()
977
+ 2-regular sequence 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, ...
978
+ """
979
+ return self.subsequence(1, {0: 1, -1: -1}, **kwds)
980
+
981
+ def forward_differences(self, **kwds):
982
+ r"""
983
+ Return the sequence of forward differences of this
984
+ `k`-regular sequence.
985
+
986
+ INPUT:
987
+
988
+ - ``minimize`` -- (default: ``None``) a boolean or ``None``.
989
+ If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation,
990
+ if ``False``, then not. If this argument is ``None``, then
991
+ the default specified by the parent's ``minimize_results`` is used.
992
+
993
+ OUTPUT: a :class:`RegularSequence`
994
+
995
+ EXAMPLES::
996
+
997
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
998
+ sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])),
999
+ ....: vector([1, 0]), vector([0, 1]))
1000
+ sage: C
1001
+ 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
1002
+ sage: C.forward_differences()
1003
+ 2-regular sequence 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
1004
+
1005
+ ::
1006
+
1007
+ sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])),
1008
+ ....: vector([1, 0]), vector([1, 1]))
1009
+ sage: E
1010
+ 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ...
1011
+ sage: E.forward_differences()
1012
+ 2-regular sequence -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, ...
1013
+ """
1014
+ return self.subsequence(1, {1: 1, 0: -1}, **kwds)
1015
+
1016
+ @minimize_result
1017
+ def _mul_(self, other):
1018
+ r"""
1019
+ Return the product of this `k`-regular sequence with ``other``,
1020
+ where the multiplication is convolution of power series.
1021
+
1022
+ The operator `*` is mapped to :meth:`convolution`.
1023
+
1024
+ INPUT:
1025
+
1026
+ - ``other`` -- a :class:`RegularSequence`
1027
+
1028
+ - ``minimize`` -- (default: ``None``) a boolean or ``None``.
1029
+ If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation,
1030
+ if ``False``, then not. If this argument is ``None``, then
1031
+ the default specified by the parent's ``minimize_results`` is used.
1032
+
1033
+ OUTPUT: a :class:`RegularSequence`
1034
+
1035
+ ALGORITHM:
1036
+
1037
+ See pdf attached to
1038
+ `github pull request #35894 <https://github.com/sagemath/sage/pull/35894>`_
1039
+ which contains a draft describing the details of the used algorithm.
1040
+
1041
+ EXAMPLES::
1042
+
1043
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
1044
+ sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])),
1045
+ ....: vector([1, 0]), vector([1, 1]))
1046
+ sage: E
1047
+ 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ...
1048
+
1049
+ We can build the convolution (in the sense of power-series) of `E` by
1050
+ itself via::
1051
+
1052
+ sage: E.convolution(E)
1053
+ 2-regular sequence 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, ...
1054
+
1055
+ This is the same as using multiplication operator::
1056
+
1057
+ sage: E * E
1058
+ 2-regular sequence 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, ...
1059
+
1060
+ Building :meth:`partial_sums` can also be seen as a convolution::
1061
+
1062
+ sage: o = Seq2.one_hadamard()
1063
+ sage: E * o
1064
+ 2-regular sequence 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, ...
1065
+ sage: E * o == E.partial_sums(include_n=True)
1066
+ True
1067
+
1068
+ TESTS::
1069
+
1070
+ sage: E * o == o * E
1071
+ True
1072
+ """
1073
+ from sage.arith.srange import srange
1074
+ from sage.matrix.constructor import Matrix
1075
+ from sage.matrix.special import zero_matrix
1076
+ from sage.modules.free_module_element import vector
1077
+
1078
+ P = self.parent()
1079
+ k = P.k
1080
+
1081
+ def tensor_product(left, right):
1082
+ T = left.tensor_product(right)
1083
+ T.subdivide()
1084
+ return T
1085
+
1086
+ matrices_0 = {r: sum(tensor_product(self.mu[s], other.mu[r-s])
1087
+ for s in srange(0, r+1))
1088
+ for r in P.alphabet()}
1089
+ matrices_1 = {r: sum(tensor_product(self.mu[s], other.mu[k+r-s])
1090
+ for s in srange(r+1, k))
1091
+ for r in P.alphabet()}
1092
+ left = vector(tensor_product(Matrix(self.left), Matrix(other.left)))
1093
+ right = vector(tensor_product(Matrix(self.right), Matrix(other.right)))
1094
+
1095
+ def linear_representation_morphism_recurrence_order_1(C, D):
1096
+ r"""
1097
+ Return the morphism of a linear representation
1098
+ for the sequence `z_n` satisfying
1099
+ `z_{kn+r} = C_r z_n + D_r z_{n-1}`.
1100
+ """
1101
+ Z = zero_matrix(C[0].dimensions()[0])
1102
+
1103
+ def blocks(r):
1104
+ upper = list([C[s], D[s], Z]
1105
+ for s in reversed(srange(max(0, r-2), r+1)))
1106
+ lower = list([Z, C[s], D[s]]
1107
+ for s in reversed(srange(k-3+len(upper), k)))
1108
+ return upper + lower
1109
+
1110
+ return {r: Matrix.block(blocks(r)) for r in P.alphabet()}
1111
+
1112
+ result = P.element_class(
1113
+ P,
1114
+ linear_representation_morphism_recurrence_order_1(matrices_0,
1115
+ matrices_1),
1116
+ vector(list(left) + (2*len(list(left)))*[0]),
1117
+ vector(list(right) + (2*len(list(right)))*[0]))
1118
+
1119
+ return result
1120
+
1121
+ convolution = _mul_
1122
+
1123
+ @minimize_result
1124
+ def partial_sums(self, include_n=False):
1125
+ r"""
1126
+ Return the sequence of partial sums of this
1127
+ `k`-regular sequence. That is, the `n`-th entry of the result
1128
+ is the sum of the first `n` entries in the original sequence.
1129
+
1130
+ INPUT:
1131
+
1132
+ - ``include_n`` -- boolean (default: ``False``); if set, then
1133
+ the `n`-th entry of the result is the sum of the entries up
1134
+ to index `n` (included)
1135
+
1136
+ - ``minimize`` -- (default: ``None``) a boolean or ``None``.
1137
+ If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation,
1138
+ if ``False``, then not. If this argument is ``None``, then
1139
+ the default specified by the parent's ``minimize_results`` is used.
1140
+
1141
+ OUTPUT: a :class:`RegularSequence`
1142
+
1143
+ EXAMPLES::
1144
+
1145
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
1146
+
1147
+ sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])),
1148
+ ....: vector([1, 0]), vector([1, 1]))
1149
+ sage: E
1150
+ 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ...
1151
+ sage: E.partial_sums()
1152
+ 2-regular sequence 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, ...
1153
+ sage: E.partial_sums(include_n=True)
1154
+ 2-regular sequence 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, ...
1155
+
1156
+ ::
1157
+
1158
+ sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])),
1159
+ ....: vector([1, 0]), vector([0, 1]))
1160
+ sage: C
1161
+ 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
1162
+ sage: C.partial_sums()
1163
+ 2-regular sequence 0, 0, 1, 3, 6, 10, 15, 21, 28, 36, ...
1164
+ sage: C.partial_sums(include_n=True)
1165
+ 2-regular sequence 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, ...
1166
+
1167
+ The following linear representation of `S` is chosen badly (is
1168
+ degenerated, see :meth:`is_degenerated`), as `\mu(0)` applied on
1169
+ `\mathit{right}` does not equal `\mathit{right}`::
1170
+
1171
+ sage: S = Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]),
1172
+ ....: allow_degenerated_sequence=True)
1173
+ sage: S
1174
+ 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ...
1175
+
1176
+ Therefore, building partial sums produces a wrong result::
1177
+
1178
+ sage: H = S.partial_sums(include_n=True, minimize=False)
1179
+ sage: H
1180
+ 2-regular sequence 1, 5, 16, 25, 62, 80, 98, 125, 274, 310, ...
1181
+ sage: H = S.partial_sums(minimize=False)
1182
+ sage: H
1183
+ 2-regular sequence 0, 2, 10, 16, 50, 62, 80, 98, 250, 274, ...
1184
+
1185
+ We can :meth:`~RegularSequenceRing.guess` the correct representation::
1186
+
1187
+ sage: from itertools import islice
1188
+ sage: L = []; ps = 0
1189
+ sage: for s in islice(S, 110):
1190
+ ....: ps += s
1191
+ ....: L.append(ps)
1192
+ sage: G = Seq2.guess(lambda n: L[n])
1193
+ sage: G
1194
+ 2-regular sequence 1, 4, 10, 19, 31, 49, 67, 94, 118, 154, ...
1195
+ sage: G.linear_representation()
1196
+ ((1, 0, 0, 0),
1197
+ Finite family {0: [ 0 1 0 0]
1198
+ [ 0 0 0 1]
1199
+ [ -5 5 1 0]
1200
+ [ 10 -17 0 8],
1201
+ 1: [ 0 0 1 0]
1202
+ [ -5 3 3 0]
1203
+ [ -5 0 6 0]
1204
+ [-30 21 10 0]},
1205
+ (1, 1, 4, 1))
1206
+ sage: G.minimized().dimension() == G.dimension()
1207
+ True
1208
+
1209
+ Or we regenerate the sequence `S` first::
1210
+
1211
+ sage: S.regenerated().partial_sums(include_n=True, minimize=False)
1212
+ 2-regular sequence 1, 4, 10, 19, 31, 49, 67, 94, 118, 154, ...
1213
+ sage: S.regenerated().partial_sums(minimize=False)
1214
+ 2-regular sequence 0, 1, 4, 10, 19, 31, 49, 67, 94, 118, ...
1215
+
1216
+ TESTS::
1217
+
1218
+ sage: E.linear_representation()
1219
+ ((1, 0),
1220
+ Finite family {0: [0 1]
1221
+ [0 1],
1222
+ 1: [0 0]
1223
+ [0 1]},
1224
+ (1, 1))
1225
+
1226
+ sage: P = E.partial_sums(minimize=False)
1227
+ sage: P.linear_representation()
1228
+ ((1, 0, 0, 0),
1229
+ Finite family {0: [0 1|0 0]
1230
+ [0 2|0 0]
1231
+ [---+---]
1232
+ [0 0|0 1]
1233
+ [0 0|0 1],
1234
+ 1: [0 1|0 1]
1235
+ [0 2|0 1]
1236
+ [---+---]
1237
+ [0 0|0 0]
1238
+ [0 0|0 1]},
1239
+ (0, 0, 1, 1))
1240
+
1241
+ sage: P = E.partial_sums(include_n=True, minimize=False)
1242
+ sage: P.linear_representation()
1243
+ ((1, 0, 1, 0),
1244
+ Finite family {0: [0 1|0 0]
1245
+ [0 2|0 0]
1246
+ [---+---]
1247
+ [0 0|0 1]
1248
+ [0 0|0 1],
1249
+ 1: [0 1|0 1]
1250
+ [0 2|0 1]
1251
+ [---+---]
1252
+ [0 0|0 0]
1253
+ [0 0|0 1]},
1254
+ (0, 0, 1, 1))
1255
+ """
1256
+ from itertools import chain
1257
+ from sage.matrix.constructor import Matrix
1258
+ from sage.matrix.special import zero_matrix
1259
+ from sage.modules.free_module_element import vector
1260
+
1261
+ P = self.parent()
1262
+ A = P.alphabet()
1263
+ k = P.k
1264
+ dim = self.dimension()
1265
+ Z = zero_matrix(dim)
1266
+
1267
+ z = A[0]
1268
+ assert z == 0
1269
+ B = {z: Z}
1270
+ for r in A:
1271
+ B[r+1] = B[r] + self.mu[r]
1272
+ C = B[k]
1273
+
1274
+ result = P.element_class(
1275
+ P,
1276
+ {r: Matrix.block([[C, B[r]], [Z, self.mu[r]]]) for r in A},
1277
+ vector(chain(self.left,
1278
+ (dim * (0,) if not include_n else self.left))),
1279
+ vector(chain(dim * (0,), self.right)))
1280
+
1281
+ return result
1282
+
1283
+ @cached_method
1284
+ def is_bounded(self):
1285
+ r"""
1286
+ Return whether this `k`-regular sequence is bounded.
1287
+
1288
+ EXAMPLES:
1289
+
1290
+ Thue--Morse Sequence::
1291
+
1292
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
1293
+ sage: TM = Seq2([Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [1, 0]])],
1294
+ ....: left=vector([1, 0]), right=vector([0, 1]))
1295
+ sage: TM.is_bounded()
1296
+ True
1297
+
1298
+ Binary Sum of Digits::
1299
+
1300
+ sage: SD = Seq2([Matrix([[1, 0], [0, 1]]), Matrix([[0, -1], [1, 2]])],
1301
+ ....: left=vector([0, 1]), right=vector([1, 0]))
1302
+ sage: SD.is_bounded()
1303
+ False
1304
+
1305
+ Sequence of All Natural Numbers::
1306
+
1307
+ sage: N = Seq2([Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])],
1308
+ ....: left=vector([1, 0]), right=vector([0, 1]))
1309
+ sage: N.is_bounded()
1310
+ False
1311
+
1312
+ Indicator Function of Even Integers::
1313
+
1314
+ sage: E = Seq2([Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])],
1315
+ ....: left=vector([1, 0]), right=vector([1, 1]))
1316
+ sage: E.is_bounded()
1317
+ True
1318
+
1319
+ Indicator Function of Odd Integers::
1320
+
1321
+ sage: O = Seq2([Matrix([[0, 0], [0, 1]]), Matrix([[0, 1], [0, 1]])],
1322
+ ....: left=vector([1, 0]), right=vector([0, 1]))
1323
+ sage: O.is_bounded()
1324
+ True
1325
+
1326
+ Number of Odd Entries in Pascal's Triangle::
1327
+
1328
+ sage: U = Seq2([Matrix([[3, 0], [6, 1]]), Matrix([[0, 1], [-6, 5]])],
1329
+ ....: left=vector([1, 0]), right=vector([0, 1]))
1330
+ sage: U.is_bounded()
1331
+ False
1332
+
1333
+ Counting '10' in the Binary Representation::
1334
+
1335
+ sage: C = Seq2([Matrix([[0, 1, 0, 0], [0, 0, 0, 1],
1336
+ ....: [-1, 0, 1, 1], [0, 0, 0, 1]]),
1337
+ ....: Matrix([[0, 0, 1, 0], [0, 1, 0, 0],
1338
+ ....: [0, 0, 1, 0], [-1, 0, 1, 1]])],
1339
+ ....: left=vector([1, 0, 0, 0]),
1340
+ ....: right=vector([0, 0, 1, 0]))
1341
+ sage: C.is_bounded()
1342
+ False
1343
+
1344
+ Numbers Starting with '10'::
1345
+
1346
+ sage: D = Seq2([Matrix([[0, 1, 0, 0], [0, 0, 1, 0],
1347
+ ....: [0, -2, 3, 0], [0, -2, 2, 1]]),
1348
+ ....: Matrix([[2, 0, 0, 0], [0, 0, 0, 1],
1349
+ ....: [0, 2, 0, 1], [0, -2, 0, 3]])],
1350
+ ....: left=vector([1, 0, 0, 0]),
1351
+ ....: right=vector([2, 2, 2, 5]))
1352
+ sage: D.is_bounded()
1353
+ False
1354
+
1355
+ Signum Function::
1356
+
1357
+ sage: S = Seq2([Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 1]])],
1358
+ ....: left=vector([1, 0]), right=vector([0, 1]))
1359
+ sage: S.is_bounded()
1360
+ True
1361
+
1362
+ Number of Digits from the Right to the First '1'::
1363
+
1364
+ sage: S = Seq2([Matrix([[0, 1, 0], [-1, 2, 0], [0, 0, 1]]),
1365
+ ....: Matrix([[0, 0, 1], [0, 0, 2], [0, 0, 1]])],
1366
+ ....: left=vector([1, 0, 0]), right=vector([0, 0, 1]))
1367
+ sage: S.is_bounded()
1368
+ False
1369
+
1370
+ .. SEEALSO::
1371
+
1372
+ :mod:`boundedness of k-regular sequences <sage.combinat.regular_sequence_bounded>`
1373
+
1374
+ TESTS::
1375
+
1376
+ sage: S = Seq2((Matrix([[0, 1, 0], [0, 0, 1], [-1, 2, 0]]),
1377
+ ....: Matrix([[-1, 0, 0], [-3/4, -1/4, 3/4], [-1/4, 1/4, -3/4]])),
1378
+ ....: left=vector([1, 0, 0]), right=vector([-4, -4, -4]))
1379
+ sage: S.is_bounded()
1380
+ False
1381
+
1382
+ ::
1383
+
1384
+ sage: S = Seq2((Matrix([[1, 0], [1, 0]]), Matrix([[0, 1],[1, 0]])),
1385
+ ....: left = vector([1, 1]), right = vector([1, 0]),
1386
+ ....: allow_degenerated_sequence=True)
1387
+ sage: S.is_degenerated()
1388
+ True
1389
+ sage: S.is_bounded()
1390
+ True
1391
+ """
1392
+ from sage.combinat.regular_sequence_bounded import regular_sequence_is_bounded
1393
+ return regular_sequence_is_bounded(self)
1394
+
1395
+
1396
+ def _pickle_RegularSequenceRing(k, coefficients, category):
1397
+ r"""
1398
+ Pickle helper.
1399
+
1400
+ TESTS::
1401
+
1402
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
1403
+ sage: from sage.combinat.regular_sequence import _pickle_RegularSequenceRing
1404
+ sage: _pickle_RegularSequenceRing(
1405
+ ....: Seq2.k, Seq2.coefficient_ring(), Seq2.category())
1406
+ Space of 2-regular sequences over Integer Ring
1407
+ """
1408
+ return RegularSequenceRing(k, coefficients, category=category)
1409
+
1410
+
1411
+ class RegularSequenceRing(RecognizableSeriesSpace):
1412
+ r"""
1413
+ The space of `k`-regular Sequences over the given ``coefficient_ring``.
1414
+
1415
+ INPUT:
1416
+
1417
+ - ``k`` -- integer at least `2` specifying the base
1418
+
1419
+ - ``coefficient_ring`` -- a (semi-)ring
1420
+
1421
+ - ``category`` -- (default: ``None``) the category of this
1422
+ space
1423
+
1424
+ EXAMPLES::
1425
+
1426
+ sage: RegularSequenceRing(2, ZZ)
1427
+ Space of 2-regular sequences over Integer Ring
1428
+ sage: RegularSequenceRing(3, ZZ)
1429
+ Space of 3-regular sequences over Integer Ring
1430
+
1431
+ .. SEEALSO::
1432
+
1433
+ :doc:`k-regular sequence <regular_sequence>`,
1434
+ :class:`RegularSequence`.
1435
+ """
1436
+ Element = RegularSequence
1437
+
1438
+ @classmethod
1439
+ def __normalize__(cls, k,
1440
+ coefficient_ring,
1441
+ category=None,
1442
+ **kwds):
1443
+ r"""
1444
+ Normalize the input in order to ensure a unique
1445
+ representation.
1446
+
1447
+ For more information see :class:`RegularSequenceRing`.
1448
+
1449
+ TESTS::
1450
+
1451
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
1452
+ sage: Seq2.category()
1453
+ Category of algebras over Integer Ring
1454
+ sage: Seq2.alphabet()
1455
+ {0, 1}
1456
+ """
1457
+ from sage.arith.srange import srange
1458
+ from sage.categories.algebras import Algebras
1459
+ category = category or Algebras(coefficient_ring)
1460
+ nargs = super().__normalize__(coefficient_ring,
1461
+ alphabet=srange(k),
1462
+ category=category,
1463
+ **kwds)
1464
+ return (k,) + nargs
1465
+
1466
+ def __init__(self, k, *args, **kwds):
1467
+ r"""
1468
+ See :class:`RegularSequenceRing` for details.
1469
+
1470
+ INPUT:
1471
+
1472
+ - ``k`` -- integer at least `2` specifying the base
1473
+
1474
+ Other input arguments are passed on to
1475
+ :meth:`~sage.combinat.recognizable_series.RecognizableSeriesSpace.__init__`.
1476
+
1477
+ TESTS::
1478
+
1479
+ sage: RegularSequenceRing(2, ZZ)
1480
+ Space of 2-regular sequences over Integer Ring
1481
+ sage: RegularSequenceRing(3, ZZ)
1482
+ Space of 3-regular sequences over Integer Ring
1483
+
1484
+ ::
1485
+
1486
+ sage: from itertools import islice
1487
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
1488
+ sage: TestSuite(Seq2).run( # long time
1489
+ ....: elements=tuple(islice(Seq2.some_elements(), 4)))
1490
+
1491
+ .. SEEALSO::
1492
+
1493
+ :doc:`k-regular sequence <regular_sequence>`,
1494
+ :class:`RegularSequence`.
1495
+ """
1496
+ self.k = k
1497
+ super().__init__(*args, **kwds)
1498
+
1499
+ def __reduce__(self):
1500
+ r"""
1501
+ Pickling support.
1502
+
1503
+ TESTS::
1504
+
1505
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
1506
+ sage: loads(dumps(Seq2)) # indirect doctest
1507
+ Space of 2-regular sequences over Integer Ring
1508
+ """
1509
+ return _pickle_RegularSequenceRing, \
1510
+ (self.k, self.coefficient_ring(), self.category())
1511
+
1512
+ def _repr_(self):
1513
+ r"""
1514
+ Return a representation string of this `k`-regular sequence space.
1515
+
1516
+ OUTPUT: string
1517
+
1518
+ TESTS::
1519
+
1520
+ sage: repr(RegularSequenceRing(2, ZZ)) # indirect doctest
1521
+ 'Space of 2-regular sequences over Integer Ring'
1522
+ """
1523
+ return 'Space of {}-regular sequences over {}'.format(self.k, self.base())
1524
+
1525
+ def _n_to_index_(self, n):
1526
+ r"""
1527
+ Convert `n` to an index usable by the underlying
1528
+ recognizable series.
1529
+
1530
+ INPUT:
1531
+
1532
+ - ``n`` -- nonnegative integer
1533
+
1534
+ OUTPUT: a word
1535
+
1536
+ TESTS::
1537
+
1538
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
1539
+ sage: Seq2._n_to_index_(6)
1540
+ word: 011
1541
+ sage: Seq2._n_to_index_(-1)
1542
+ Traceback (most recent call last):
1543
+ ...
1544
+ ValueError: value -1 of index is negative
1545
+ """
1546
+ from sage.rings.integer_ring import ZZ
1547
+ n = ZZ(n)
1548
+ W = self.indices()
1549
+ try:
1550
+ return W(n.digits(self.k))
1551
+ except OverflowError:
1552
+ raise ValueError('value {} of index is negative'.format(n)) from None
1553
+
1554
+ @cached_method
1555
+ def one(self):
1556
+ r"""
1557
+ Return the one element of this :class:`RegularSequenceRing`,
1558
+ i.e. the unique neutral element for `*` and also
1559
+ the embedding of the one of the coefficient ring into
1560
+ this :class:`RegularSequenceRing`.
1561
+
1562
+ EXAMPLES::
1563
+
1564
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
1565
+ sage: O = Seq2.one(); O
1566
+ 2-regular sequence 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...
1567
+ sage: O.linear_representation()
1568
+ ((1), Finite family {0: [1], 1: [0]}, (1))
1569
+
1570
+ TESTS::
1571
+
1572
+ sage: Seq2.one() is Seq2.one()
1573
+ True
1574
+ """
1575
+ from sage.matrix.constructor import Matrix
1576
+ from sage.modules.free_module_element import vector
1577
+
1578
+ R = self.coefficient_ring()
1579
+ one = R.one()
1580
+ zero = R.zero()
1581
+ return self.element_class(self,
1582
+ [Matrix([[one]])]
1583
+ + (self.k-1)*[Matrix([[zero]])],
1584
+ vector([one]),
1585
+ vector([one]))
1586
+
1587
+ def some_elements(self):
1588
+ r"""
1589
+ Return some elements of this `k`-regular sequence.
1590
+
1591
+ See :class:`TestSuite` for a typical use case.
1592
+
1593
+ OUTPUT: an iterator
1594
+
1595
+ EXAMPLES::
1596
+
1597
+ sage: tuple(RegularSequenceRing(2, ZZ).some_elements())
1598
+ (2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ...,
1599
+ 2-regular sequence 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, ...,
1600
+ 2-regular sequence 1, 1, 0, 1, -1, 0, 0, 1, -2, -1, ...,
1601
+ 2-regular sequence 2, -1, 0, 0, 0, -1, 0, 0, 0, 0, ...,
1602
+ 2-regular sequence 1, 1, 0, 1, 5, 0, 0, 1, -33, 5, ...,
1603
+ 2-regular sequence -5, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...,
1604
+ 2-regular sequence -59, -20, 0, -20, 0, 0, 0, -20, 0, 0, ...,
1605
+ ...
1606
+ 2-regular sequence 2210, 170, 0, 0, 0, 0, 0, 0, 0, 0, ...)
1607
+ """
1608
+ return iter(element.regenerated()
1609
+ for element
1610
+ in super().some_elements(
1611
+ allow_degenerated_sequence=True))
1612
+
1613
+ def _element_constructor_(self, *args, **kwds):
1614
+ r"""
1615
+ Return a `k`-regular sequence.
1616
+
1617
+ See :class:`RegularSequenceRing` for details.
1618
+
1619
+ TESTS::
1620
+
1621
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
1622
+ sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]))
1623
+ Traceback (most recent call last):
1624
+ ...
1625
+ DegeneratedSequenceError: degenerated sequence: mu[0]*right != right.
1626
+ Using such a sequence might lead to wrong results.
1627
+ You can use 'allow_degenerated_sequence=True' followed
1628
+ by a call of method .regenerated() for correcting this.
1629
+ sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]),
1630
+ ....: allow_degenerated_sequence=True)
1631
+ 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ...
1632
+ sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]),
1633
+ ....: allow_degenerated_sequence=True).regenerated()
1634
+ 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ...
1635
+ """
1636
+ allow_degenerated_sequence = kwds.pop('allow_degenerated_sequence', False)
1637
+ element = super()._element_constructor_(*args, **kwds)
1638
+ if not allow_degenerated_sequence:
1639
+ element._error_if_degenerated_()
1640
+ return element
1641
+
1642
+ def guess(self, f, n_verify=100, max_exponent=10, sequence=None):
1643
+ r"""
1644
+ Guess a `k`-regular sequence whose first terms coincide with `(f(n))_{n\geq0}`.
1645
+
1646
+ INPUT:
1647
+
1648
+ - ``f`` -- a function (callable) which determines the sequence.
1649
+ It takes nonnegative integers as an input
1650
+
1651
+ - ``n_verify`` -- (default: ``100``) a positive integer. The resulting
1652
+ `k`-regular sequence coincides with `f` on the first ``n_verify``
1653
+ terms.
1654
+
1655
+ - ``max_exponent`` -- (default: ``10``) a positive integer specifying
1656
+ the maximum exponent of `k` which is tried when guessing the sequence,
1657
+ i.e., relations between `f(k^t n+r)` are used for
1658
+ `0\le t\le \mathtt{max\_exponent}` and `0\le r < k^j`
1659
+
1660
+ - ``sequence`` -- (default: ``None``) a `k`-regular sequence used
1661
+ for bootstrapping the guessing by adding information of the
1662
+ linear representation of ``sequence`` to the guessed representation
1663
+
1664
+ OUTPUT: a :class:`RegularSequence`
1665
+
1666
+ ALGORITHM:
1667
+
1668
+ For the purposes of this description, the right vector valued sequence
1669
+ associated with a regular sequence consists of the
1670
+ corresponding matrix product multiplied by the right vector,
1671
+ but without the left vector of the regular sequence.
1672
+
1673
+ The algorithm maintains a right vector valued sequence consisting
1674
+ of the right vector valued sequence of the argument ``sequence``
1675
+ (replaced by an empty tuple if ``sequence`` is ``None``) plus several
1676
+ components of the shape `m \mapsto f(k^t\cdot m +r)` for suitable
1677
+ ``t`` and ``r``.
1678
+
1679
+ Implicitly, the algorithm also maintains a `d \times n_\mathrm{verify}` matrix ``A``
1680
+ (where ``d`` is the dimension of the right vector valued sequence)
1681
+ whose columns are the current right vector valued sequence evaluated at
1682
+ the nonnegative integers less than `n_\mathrm{verify}` and ensures that this
1683
+ matrix has full row rank.
1684
+
1685
+ EXAMPLES:
1686
+
1687
+ Binary sum of digits::
1688
+
1689
+ sage: @cached_function
1690
+ ....: def s(n):
1691
+ ....: if n == 0:
1692
+ ....: return 0
1693
+ ....: return s(n//2) + ZZ(is_odd(n))
1694
+ sage: all(s(n) == sum(n.digits(2)) for n in srange(10))
1695
+ True
1696
+ sage: [s(n) for n in srange(10)]
1697
+ [0, 1, 1, 2, 1, 2, 2, 3, 1, 2]
1698
+
1699
+ Let us guess a `2`-linear representation for `s(n)`::
1700
+
1701
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
1702
+ sage: import logging
1703
+ sage: logging.getLogger().setLevel(logging.INFO)
1704
+ sage: S1 = Seq2.guess(s); S1
1705
+ INFO:...:including f_{1*m+0}
1706
+ INFO:...:including f_{2*m+1}
1707
+ 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ...
1708
+ sage: S1.linear_representation()
1709
+ ((1, 0),
1710
+ Finite family {0: [1 0]
1711
+ [0 1],
1712
+ 1: [ 0 1]
1713
+ [-1 2]},
1714
+ (0, 1))
1715
+
1716
+ The ``INFO`` messages mean that the right vector valued sequence is the sequence `(s(n), s(2n+1))^\top`.
1717
+
1718
+ We guess again, but this time, we use a constant sequence
1719
+ for bootstrapping the guessing process::
1720
+
1721
+ sage: C = Seq2.one_hadamard(); C
1722
+ 2-regular sequence 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
1723
+ sage: S2 = Seq2.guess(s, sequence=C); S2
1724
+ INFO:...:including 2-regular sequence 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
1725
+ INFO:...:including f_{1*m+0}
1726
+ 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ...
1727
+ sage: S2.linear_representation()
1728
+ ((0, 1),
1729
+ Finite family {0: [1 0]
1730
+ [0 1],
1731
+ 1: [1 0]
1732
+ [1 1]},
1733
+ (1, 0))
1734
+ sage: S1 == S2
1735
+ True
1736
+
1737
+ The sequence of all natural numbers::
1738
+
1739
+ sage: S = Seq2.guess(lambda n: n); S
1740
+ INFO:...:including f_{1*m+0}
1741
+ INFO:...:including f_{2*m+1}
1742
+ 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
1743
+ sage: S.linear_representation()
1744
+ ((1, 0),
1745
+ Finite family {0: [2 0]
1746
+ [2 1],
1747
+ 1: [ 0 1]
1748
+ [-2 3]},
1749
+ (0, 1))
1750
+
1751
+ The indicator function of the even integers::
1752
+
1753
+ sage: S = Seq2.guess(lambda n: ZZ(is_even(n))); S
1754
+ INFO:...:including f_{1*m+0}
1755
+ INFO:...:including f_{2*m+0}
1756
+ 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ...
1757
+ sage: S.linear_representation()
1758
+ ((1, 0),
1759
+ Finite family {0: [0 1]
1760
+ [0 1],
1761
+ 1: [0 0]
1762
+ [0 1]},
1763
+ (1, 1))
1764
+
1765
+ The indicator function of the odd integers::
1766
+
1767
+ sage: S = Seq2.guess(lambda n: ZZ(is_odd(n))); S
1768
+ INFO:...:including f_{1*m+0}
1769
+ INFO:...:including f_{2*m+1}
1770
+ 2-regular sequence 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, ...
1771
+ sage: S.linear_representation()
1772
+ ((1, 0),
1773
+ Finite family {0: [0 0]
1774
+ [0 1],
1775
+ 1: [0 1]
1776
+ [0 1]},
1777
+ (0, 1))
1778
+ sage: logging.getLogger().setLevel(logging.WARN)
1779
+
1780
+ The following linear representation of `S` is chosen badly (is
1781
+ degenerated, see :meth:`is_degenerated`), as `\mu(0)` applied on
1782
+ `\mathit{right}` does not equal `\mathit{right}`::
1783
+
1784
+ sage: S = Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1]),
1785
+ ....: allow_degenerated_sequence=True)
1786
+ sage: S
1787
+ 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ...
1788
+ sage: S.is_degenerated()
1789
+ True
1790
+
1791
+ However, we can :meth:`~RegularSequenceRing.guess` a `2`-regular sequence of dimension `2`::
1792
+
1793
+ sage: G = Seq2.guess(lambda n: S[n])
1794
+ sage: G
1795
+ 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ...
1796
+ sage: G.linear_representation()
1797
+ ((1, 0),
1798
+ Finite family {0: [ 0 1]
1799
+ [-2 3],
1800
+ 1: [3 0]
1801
+ [6 0]},
1802
+ (1, 1))
1803
+
1804
+ sage: G == S.regenerated()
1805
+ True
1806
+
1807
+ TESTS::
1808
+
1809
+ sage: from importlib import reload
1810
+ sage: logging.shutdown(); _ = reload(logging)
1811
+ sage: logging.basicConfig(level=logging.DEBUG)
1812
+ sage: Seq2.guess(s)
1813
+ INFO:...:including f_{1*m+0}
1814
+ DEBUG:...:M_0: f_{2*m+0} = (1) * F_m
1815
+ INFO:...:including f_{2*m+1}
1816
+ DEBUG:...:M_1: f_{2*m+1} = (0, 1) * F_m
1817
+ DEBUG:...:M_0: f_{4*m+1} = (0, 1) * F_m
1818
+ DEBUG:...:M_1: f_{4*m+3} = (-1, 2) * F_m
1819
+ 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ...
1820
+ sage: from importlib import reload
1821
+ sage: logging.shutdown(); _ = reload(logging)
1822
+
1823
+ ::
1824
+
1825
+ sage: S = Seq2.guess(lambda n: 2, sequence=C)
1826
+ sage: S
1827
+ 2-regular sequence 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ...
1828
+ sage: S.linear_representation()
1829
+ ((2),
1830
+ Finite family {0: [1],
1831
+ 1: [1]},
1832
+ (1))
1833
+
1834
+ We :meth:`~RegularSequenceRing.guess` some partial sums sequences::
1835
+
1836
+ sage: S = Seq2((Matrix([1]), Matrix([2])), vector([1]), vector([1]))
1837
+ sage: S
1838
+ 2-regular sequence 1, 2, 2, 4, 2, 4, 4, 8, 2, 4, ...
1839
+ sage: from itertools import islice
1840
+ sage: L = []; ps = 0
1841
+ sage: for j in islice(S, 110):
1842
+ ....: ps += j
1843
+ ....: L.append(ps)
1844
+ sage: G = Seq2.guess(lambda n: L[n])
1845
+ sage: G
1846
+ 2-regular sequence 1, 3, 5, 9, 11, 15, 19, 27, 29, 33, ...
1847
+ sage: G.linear_representation()
1848
+ ((1, 0),
1849
+ Finite family {0: [ 0 1]
1850
+ [-3 4],
1851
+ 1: [3 0]
1852
+ [3 2]},
1853
+ (1, 1))
1854
+ sage: G == S.partial_sums(include_n=True)
1855
+ True
1856
+
1857
+ ::
1858
+
1859
+ sage: Seq3 = RegularSequenceRing(3, QQ)
1860
+ sage: S = Seq3((Matrix([1]), Matrix([3]), Matrix([2])), vector([1]), vector([1]))
1861
+ sage: S
1862
+ 3-regular sequence 1, 3, 2, 3, 9, 6, 2, 6, 4, 3, ...
1863
+ sage: from itertools import islice
1864
+ sage: L = []; ps = 0
1865
+ sage: for j in islice(S, 110):
1866
+ ....: ps += j
1867
+ ....: L.append(ps)
1868
+ sage: G = Seq3.guess(lambda n: L[n])
1869
+ sage: G
1870
+ 3-regular sequence 1, 4, 6, 9, 18, 24, 26, 32, 36, 39, ...
1871
+ sage: G.linear_representation()
1872
+ ((1, 0),
1873
+ Finite family {0: [ 0 1]
1874
+ [-6 7],
1875
+ 1: [18/5 2/5]
1876
+ [18/5 27/5],
1877
+ 2: [ 6 0]
1878
+ [24 2]},
1879
+ (1, 1))
1880
+ sage: G == S.partial_sums(include_n=True)
1881
+ True
1882
+
1883
+ ::
1884
+
1885
+ sage: Seq2.guess(s, max_exponent=1)
1886
+ Traceback (most recent call last):
1887
+ ...
1888
+ RuntimeError: aborting as exponents would be larger than max_exponent=1
1889
+
1890
+ ::
1891
+
1892
+ sage: R = RegularSequenceRing(2, QQ)
1893
+ sage: one = R.one_hadamard()
1894
+ sage: S = R.guess(lambda n: sum(n.bits()), sequence=one) + one
1895
+ sage: T = R.guess(lambda n: n*n, sequence=S, n_verify=4); T
1896
+ 2-regular sequence 0, 1, 4, 9, 16, 25, 36, 163/3, 64, 89, ...
1897
+ sage: T.linear_representation()
1898
+ ((0, 0, 1),
1899
+ Finite family {0: [1 0 0]
1900
+ [0 1 0]
1901
+ [0 0 4],
1902
+ 1: [ 0 1 0]
1903
+ [ -1 2 0]
1904
+ [13/3 -5/3 16/3]},
1905
+ (1, 2, 0))
1906
+
1907
+ ::
1908
+
1909
+ sage: two = Seq2.one_hadamard() * 2
1910
+ sage: two.linear_representation()
1911
+ ((1), Finite family {0: [1], 1: [1]}, (2))
1912
+ sage: two_again = Seq2.guess(lambda n: 2, sequence=two)
1913
+ sage: two_again.linear_representation()
1914
+ ((1), Finite family {0: [1], 1: [1]}, (2))
1915
+
1916
+ ::
1917
+
1918
+ sage: def s(k):
1919
+ ....: return k
1920
+ sage: S1 = Seq2.guess(s)
1921
+ sage: S2 = Seq2.guess(s, sequence=S1)
1922
+ sage: S1
1923
+ 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
1924
+ sage: S2
1925
+ 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
1926
+
1927
+ ::
1928
+
1929
+ sage: A = Seq2(
1930
+ ....: (Matrix([[1, 1], [1, 1]]), Matrix([[1, 1], [1, 1]])),
1931
+ ....: left=(1, 1), right=(1, 1),
1932
+ ....: allow_degenerated_sequence=True)
1933
+ sage: Seq2.guess(lambda n: n, sequence=A, n_verify=5)
1934
+ Traceback (most recent call last):
1935
+ ...
1936
+ RuntimeError: no invertible submatrix found
1937
+ """
1938
+ import logging
1939
+ logger = logging.getLogger(__name__)
1940
+
1941
+ from sage.arith.srange import srange, xsrange
1942
+ from sage.matrix.constructor import Matrix
1943
+ from sage.misc.mrange import cantor_product
1944
+ from sage.modules.free_module_element import vector
1945
+
1946
+ k = self.k
1947
+ domain = self.coefficient_ring()
1948
+ if sequence is None:
1949
+ mu = [[] for _ in srange(k)]
1950
+ seq = lambda m: vector([])
1951
+ else:
1952
+ mu = [M.rows() for M in sequence.mu]
1953
+ seq = lambda m: sequence.coefficient_of_n(m, multiply_left=False)
1954
+ logger.info('including %s', sequence)
1955
+
1956
+ zero = domain(0)
1957
+ one = domain(1)
1958
+
1959
+ # A `line` will be a pair `(t, r)` corresponding to an entry
1960
+ # `k**t * m + r`
1961
+
1962
+ # The elements of `lines` will correspond to the current components
1963
+ # of the right vector valued sequence described in the algorithm section
1964
+ # of the docstring.
1965
+
1966
+ def values(m, lines):
1967
+ """
1968
+ Return current (as defined by ``lines``) right vector valued
1969
+ sequence for argument ``m``.
1970
+ """
1971
+ return tuple(seq(m)) + tuple(f(k**t_R * m + r_R) for t_R, r_R in lines)
1972
+
1973
+ @cached_function(key=lambda lines: len(lines))
1974
+ # we assume that existing lines are not changed
1975
+ # (we allow appending of new lines)
1976
+ def some_inverse_U_matrix(lines):
1977
+ r"""
1978
+ Find an invertible `d \times d` submatrix of the matrix
1979
+ ``A`` described in the algorithm section of the docstring.
1980
+
1981
+ The output is the inverse of the invertible submatrix and
1982
+ the corresponding list of column indices (i.e., arguments to
1983
+ the current right vector valued sequence).
1984
+ """
1985
+ d = len(seq(0)) + len(lines)
1986
+
1987
+ # The following search for an inverse works but is inefficient;
1988
+ # see :issue:`35748` for details.
1989
+ for m_indices in cantor_product(xsrange(n_verify), repeat=d, min_slope=1):
1990
+ # Iterate over all increasing lists of length d consisting
1991
+ # of nonnegative integers less than `n_verify`.
1992
+
1993
+ U = Matrix(domain, d, d, [values(m, lines) for m in m_indices]).transpose()
1994
+ try:
1995
+ return U.inverse(), m_indices
1996
+ except ZeroDivisionError:
1997
+ pass
1998
+ raise RuntimeError('no invertible submatrix found')
1999
+
2000
+ def linear_combination_candidate(t_L, r_L, lines):
2001
+ r"""
2002
+ Based on an invertible submatrix of ``A`` as described in the
2003
+ algorithm section of the docstring, find a candidate for a
2004
+ linear combination of the rows of ``A`` yielding the subsequence
2005
+ with parameters ``t_L`` and ``r_L``, i.e.,
2006
+ `m \mapsto f(k**t_L * m + r_L)`.
2007
+ """
2008
+ iU, m_indices = some_inverse_U_matrix(lines)
2009
+ X_L = vector(f(k**t_L * m + r_L) for m in m_indices)
2010
+ return X_L * iU
2011
+
2012
+ def verify_linear_combination(t_L, r_L, linear_combination, lines):
2013
+ r"""
2014
+ Determine whether the subsequence with parameters ``t_L`` and
2015
+ ``r_L``, i.e., `m \mapsto f(k**t_L * m + r_L)`, is the linear
2016
+ combination ``linear_combination`` of the current vector valued
2017
+ sequence.
2018
+
2019
+ Note that we only evaluate the subsequence of ``f`` where arguments
2020
+ of ``f`` are at most ``n_verify``. This might lead to detection of
2021
+ linear dependence which would not be true for higher values, but this
2022
+ coincides with the documentation of ``n_verify``.
2023
+ However, this is not a guarantee that the given function will never
2024
+ be evaluated beyond ``n_verify``, determining an invertible submatrix
2025
+ in ``some_inverse_U_matrix`` might require us to do so.
2026
+ """
2027
+ return all(f(k**t_L * m + r_L) ==
2028
+ linear_combination * vector(values(m, lines))
2029
+ for m in xsrange(0, (n_verify - r_L) // k**t_L + 1))
2030
+
2031
+ class NoLinearCombination(RuntimeError):
2032
+ pass
2033
+
2034
+ def find_linear_combination(t_L, r_L, lines):
2035
+ linear_combination = linear_combination_candidate(t_L, r_L, lines)
2036
+ if not verify_linear_combination(t_L, r_L, linear_combination, lines):
2037
+ raise NoLinearCombination
2038
+ return linear_combination
2039
+
2040
+ if seq(0).is_zero():
2041
+ left = None
2042
+ else:
2043
+ try:
2044
+ left = vector(find_linear_combination(0, 0, []))
2045
+ except NoLinearCombination:
2046
+ left = None
2047
+
2048
+ to_branch = []
2049
+ lines = []
2050
+
2051
+ def include(t, r):
2052
+ to_branch.append((t, r))
2053
+ lines.append((t, r))
2054
+ logger.info('including f_{%s*m+%s}', k**t, r)
2055
+
2056
+ if left is None:
2057
+ include(0, 0) # entries (t, r) --> k**t * m + r
2058
+ assert len(lines) == 1
2059
+ left = vector(len(seq(0))*(zero,) + (one,))
2060
+
2061
+ while to_branch:
2062
+ t_R, r_R = to_branch.pop(0)
2063
+ if t_R >= max_exponent:
2064
+ raise RuntimeError(f'aborting as exponents would be larger '
2065
+ f'than max_exponent={max_exponent}')
2066
+
2067
+ t_L = t_R + 1
2068
+ for s_L in srange(k):
2069
+ r_L = k**t_R * s_L + r_R
2070
+ try:
2071
+ linear_combination = find_linear_combination(t_L, r_L, lines)
2072
+ except NoLinearCombination:
2073
+ include(t_L, r_L) # entries (t, r) --> k**t * m + r
2074
+ linear_combination = (len(lines)-1)*(zero,) + (one,)
2075
+ logger.debug('M_%s: f_{%s*m+%s} = %s * F_m',
2076
+ s_L, k**t_L, r_L, linear_combination)
2077
+ mu[s_L].append(linear_combination)
2078
+
2079
+ d = len(seq(0)) + len(lines)
2080
+ mu = tuple(Matrix(domain, [pad_right(tuple(row), d, zero=zero) for row in M])
2081
+ for M in mu)
2082
+ right = vector(values(0, lines))
2083
+ left = vector(pad_right(tuple(left), d, zero=zero))
2084
+ return self(mu, left, right)
2085
+
2086
+ def from_recurrence(self, *args, **kwds):
2087
+ r"""
2088
+ Construct the unique `k`-regular sequence which fulfills the given
2089
+ recurrence relations and initial values. The recurrence relations have to
2090
+ have the specific shape of `k`-recursive sequences as described in [HKL2022]_,
2091
+ and are either given as symbolic equations, e.g.,
2092
+
2093
+ ::
2094
+
2095
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
2096
+ sage: var('n')
2097
+ n
2098
+ sage: function('f')
2099
+ f
2100
+ sage: Seq2.from_recurrence([
2101
+ ....: f(2*n) == 2*f(n), f(2*n + 1) == 3*f(n) + 4*f(n - 1),
2102
+ ....: f(0) == 0, f(1) == 1], f, n)
2103
+ 2-regular sequence 0, 0, 0, 1, 2, 3, 4, 10, 6, 17, ...
2104
+
2105
+ or via the parameters of the `k`-recursive sequence as described in the input
2106
+ block below::
2107
+
2108
+ sage: Seq2.from_recurrence(M=1, m=0,
2109
+ ....: coeffs={(0, 0): 2, (1, 0): 3, (1, -1): 4},
2110
+ ....: initial_values={0: 0, 1: 1})
2111
+ 2-regular sequence 0, 0, 0, 1, 2, 3, 4, 10, 6, 17, ...
2112
+
2113
+ INPUT:
2114
+
2115
+ Positional arguments:
2116
+
2117
+ If the recurrence relations are represented by symbolic equations, then
2118
+ the following arguments are required:
2119
+
2120
+ - ``equations`` -- list of equations where the elements have
2121
+ either the form
2122
+
2123
+ - `f(k^M n + r) = c_{r,l} f(k^m n + l) + c_{r,l + 1} f(k^m n
2124
+ + l + 1) + ... + c_{r,u} f(k^m n + u)` for some integers
2125
+ `0 \leq r < k^M`, `M > m \geq 0` and `l \leq u`, and some
2126
+ coefficients `c_{r,j}` from the (semi)ring ``coefficients``
2127
+ of the corresponding :class:`RegularSequenceRing`, valid
2128
+ for all integers `n \geq \text{offset}` for some integer
2129
+ `\text{offset} \geq \max(-l/k^m, 0)` (default: ``0``), and
2130
+ there is an equation of this form (with the same
2131
+ parameters `M` and `m`) for all `r`
2132
+
2133
+ or the form
2134
+
2135
+ - ``f(k) == t`` for some integer ``k`` and some ``t`` from the (semi)ring
2136
+ ``coefficient_ring``.
2137
+
2138
+ The recurrence relations above uniquely determine a `k`-regular sequence;
2139
+ see [HKL2022]_ for further information.
2140
+
2141
+ - ``function`` -- symbolic function ``f`` occurring in the equations
2142
+
2143
+ - ``var`` -- symbolic variable (``n`` in the above description of
2144
+ ``equations``)
2145
+
2146
+ The following second representation of the recurrence relations is
2147
+ particularly useful for cases where ``coefficient_ring`` is not
2148
+ compatible with :class:`sage.symbolic.ring.SymbolicRing`. Then the
2149
+ following arguments are required:
2150
+
2151
+ - ``M`` -- parameter of the recursive sequences,
2152
+ see [HKL2022]_, Definition 3.1, as well as in the description of
2153
+ ``equations`` above
2154
+
2155
+ - ``m`` -- parameter of the recursive sequences,
2156
+ see [HKL2022]_, Definition 3.1, as well as in the description of
2157
+ ``equations`` above
2158
+
2159
+ - ``coeffs`` -- dictionary where ``coeffs[(r, j)]`` is the
2160
+ coefficient `c_{r,j}` as given in the description of ``equations`` above.
2161
+ If ``coeffs[(r, j)]`` is not given for some ``r`` and ``j``, then it is
2162
+ assumed to be zero.
2163
+
2164
+ - ``initial_values`` -- dictionary mapping integers ``n`` to the
2165
+ ``n``-th value of the sequence
2166
+
2167
+ Optional keyword-only argument:
2168
+
2169
+ - ``offset`` -- integer (default: `0`); see explanation of
2170
+ ``equations`` above
2171
+
2172
+ - ``inhomogeneities`` -- (default: ``{}``) a dictionary
2173
+ mapping integers ``r`` to the inhomogeneity `g_r` as given
2174
+ in [HKL2022]_, Corollary D. All inhomogeneities have to be
2175
+ regular sequences from ``self`` or elements of ``coefficient_ring``.
2176
+
2177
+ OUTPUT: a :class:`RegularSequence`
2178
+
2179
+ EXAMPLES:
2180
+
2181
+ Stern--Brocot Sequence::
2182
+
2183
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
2184
+ sage: var('n')
2185
+ n
2186
+ sage: function('f')
2187
+ f
2188
+ sage: SB = Seq2.from_recurrence([
2189
+ ....: f(2*n) == f(n), f(2*n + 1) == f(n) + f(n + 1),
2190
+ ....: f(0) == 0, f(1) == 1], f, n)
2191
+ sage: SB
2192
+ 2-regular sequence 0, 1, 1, 2, 1, 3, 2, 3, 1, 4, ...
2193
+
2194
+ Number of Odd Entries in Pascal's Triangle::
2195
+
2196
+ sage: Seq2.from_recurrence([
2197
+ ....: f(2*n) == 3*f(n), f(2*n + 1) == 2*f(n) + f(n + 1),
2198
+ ....: f(0) == 0, f(1) == 1], f, n)
2199
+ 2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ...
2200
+
2201
+ Number of Unbordered Factors in the Thue--Morse Sequence::
2202
+
2203
+ sage: UB = Seq2.from_recurrence([
2204
+ ....: f(8*n) == 2*f(4*n),
2205
+ ....: f(8*n + 1) == f(4*n + 1),
2206
+ ....: f(8*n + 2) == f(4*n + 1) + f(4*n + 3),
2207
+ ....: f(8*n + 3) == -f(4*n + 1) + f(4*n + 2),
2208
+ ....: f(8*n + 4) == 2*f(4*n + 2),
2209
+ ....: f(8*n + 5) == f(4*n + 3),
2210
+ ....: f(8*n + 6) == -f(4*n + 1) + f(4*n + 2) + f(4*n + 3),
2211
+ ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3),
2212
+ ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2,
2213
+ ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4,
2214
+ ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4,
2215
+ ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0,
2216
+ ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n, offset=3)
2217
+ sage: UB
2218
+ 2-regular sequence 1, 2, 2, 4, 2, 4, 6, 0, 4, 4, ...
2219
+
2220
+ Binary sum of digits `S(n)`, characterized by the recurrence relations
2221
+ `S(4n) = S(2n)`, `S(4n + 1) = S(2n + 1)`, `S(4n + 2) = S(2n + 1)` and
2222
+ `S(4n + 3) = -S(2n) + 2S(2n + 1)`::
2223
+
2224
+ sage: S = Seq2.from_recurrence([
2225
+ ....: f(4*n) == f(2*n),
2226
+ ....: f(4*n + 1) == f(2*n + 1),
2227
+ ....: f(4*n + 2) == f(2*n + 1),
2228
+ ....: f(4*n + 3) == -f(2*n) + 2*f(2*n + 1),
2229
+ ....: f(0) == 0, f(1) == 1], f, n)
2230
+ sage: S
2231
+ 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ...
2232
+
2233
+ In order to check if this sequence is indeed the binary sum of digits,
2234
+ we construct it directly via its linear representation and compare it
2235
+ with ``S``::
2236
+
2237
+ sage: S2 = Seq2(
2238
+ ....: (Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])),
2239
+ ....: left=vector([0, 1]), right=vector([1, 0]))
2240
+ sage: (S - S2).is_trivial_zero()
2241
+ True
2242
+
2243
+ Alternatively, we can also use the simpler but inhomogeneous recurrence relations
2244
+ `S(2n) = S(n)` and `S(2n+1) = S(n) + 1` via direct parameters::
2245
+
2246
+ sage: S3 = Seq2.from_recurrence(M=1, m=0,
2247
+ ....: coeffs={(0, 0): 1, (1, 0): 1},
2248
+ ....: initial_values={0: 0, 1: 1},
2249
+ ....: inhomogeneities={1: 1})
2250
+ sage: S3
2251
+ 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ...
2252
+ sage: (S3 - S2).is_trivial_zero()
2253
+ True
2254
+
2255
+ Number of Non-Zero Elements in the Generalized Pascal's Triangle (see [LRS2017]_)::
2256
+
2257
+ sage: Seq2 = RegularSequenceRing(2, QQ)
2258
+ sage: P = Seq2.from_recurrence([
2259
+ ....: f(4*n) == 5/3*f(2*n) - 1/3*f(2*n + 1),
2260
+ ....: f(4*n + 1) == 4/3*f(2*n) + 1/3*f(2*n + 1),
2261
+ ....: f(4*n + 2) == 1/3*f(2*n) + 4/3*f(2*n + 1),
2262
+ ....: f(4*n + 3) == -1/3*f(2*n) + 5/3*f(2*n + 1),
2263
+ ....: f(0) == 1, f(1) == 2], f, n)
2264
+ sage: P
2265
+ 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ...
2266
+
2267
+ Finally, the same sequence can also be obtained via direct parameters
2268
+ without symbolic equations::
2269
+
2270
+ sage: Seq2.from_recurrence(M=2, m=1,
2271
+ ....: coeffs={(0, 0): 5/3, (0, 1): -1/3,
2272
+ ....: (1, 0): 4/3, (1, 1): 1/3,
2273
+ ....: (2, 0): 1/3, (2, 1): 4/3,
2274
+ ....: (3, 0): -1/3, (3, 1): 5/3},
2275
+ ....: initial_values={0: 1, 1: 2})
2276
+ 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ...
2277
+
2278
+ TESTS::
2279
+
2280
+ sage: Seq2.from_recurrence([ # long time
2281
+ ....: f(4*n) == f(2*n),
2282
+ ....: f(4*n + 1) == f(2*n),
2283
+ ....: f(4*n + 2) == f(2*n),
2284
+ ....: f(4*n + 3) == f(2*n + 1024),
2285
+ ....: f(0) == 1, f(1) == 1], f, n, offset=2)
2286
+ Traceback (most recent call last):
2287
+ ...
2288
+ ValueError: Initial values for arguments in [2, ..., 2044] are missing.
2289
+
2290
+ ::
2291
+
2292
+ sage: S = Seq2.from_recurrence([
2293
+ ....: f(4*n) == f(2*n),
2294
+ ....: f(4*n + 1) == f(2*n),
2295
+ ....: f(4*n + 2) == f(2*n),
2296
+ ....: f(4*n + 3) == f(2*n + 16),
2297
+ ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3, f(4) == 4,
2298
+ ....: f(5) == 5, f(6) == 6, f(7) == 7, f(16) == 4, f(18) == 4,
2299
+ ....: f(20) == 4, f(22) == 4, f(24) == 6, f(26) == 6, f(28) == 6],
2300
+ ....: f, n, offset=2)
2301
+ sage: all([S[4*i] == S[2*i] and
2302
+ ....: S[4*i + 1] == S[2*i] and
2303
+ ....: S[4*i + 2] == S[2*i] and
2304
+ ....: S[4*i + 3] == S[2*i + 16] for i in srange(2, 100)])
2305
+ True
2306
+
2307
+ ::
2308
+
2309
+ sage: S = Seq2.from_recurrence([
2310
+ ....: f(4*n) == f(2*n),
2311
+ ....: f(4*n + 1) == f(2*n),
2312
+ ....: f(4*n + 2) == f(2*n),
2313
+ ....: f(4*n + 3) == f(2*n - 16),
2314
+ ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3, f(4) == 4,
2315
+ ....: f(5) == 5, f(6) == 6, f(7) == 7, f(8) == 8, f(9) == 9,
2316
+ ....: f(10) == 10, f(11) == 11, f(12) == 12, f(13) == 13,
2317
+ ....: f(14) == 14, f(15) == 15, f(16) == 16, f(17) == 17,
2318
+ ....: f(18) == 18, f(19) == 19, f(20) == 20, f(21) == 21,
2319
+ ....: f(22) == 22, f(23) == 23, f(24) == 24, f(25) == 25,
2320
+ ....: f(26) == 26, f(27) == 27, f(28) == 28, f(29) == 29,
2321
+ ....: f(30) == 30, f(31) == 31], f, n, offset=8)
2322
+ sage: all([S[4*i] == S[2*i] and
2323
+ ....: S[4*i + 1] == S[2*i] and
2324
+ ....: S[4*i + 2] == S[2*i] and
2325
+ ....: S[4*i + 3] == S[2*i - 16] for i in srange(8, 100)])
2326
+ True
2327
+
2328
+ Same test with different variable and function names::
2329
+
2330
+ sage: var('m')
2331
+ m
2332
+ sage: function('g')
2333
+ g
2334
+ sage: T = Seq2.from_recurrence([
2335
+ ....: g(4*m) == g(2*m),
2336
+ ....: g(4*m + 1) == g(2*m),
2337
+ ....: g(4*m + 2) == g(2*m),
2338
+ ....: g(4*m + 3) == g(2*m - 16),
2339
+ ....: g(0) == 1, g(1) == 1, g(2) == 2, g(3) == 3, g(4) == 4,
2340
+ ....: g(5) == 5, g(6) == 6, g(7) == 7, g(8) == 8, g(9) == 9,
2341
+ ....: g(10) == 10, g(11) == 11, g(12) == 12, g(13) == 13,
2342
+ ....: g(14) == 14, g(15) == 15, g(16) == 16, g(17) == 17,
2343
+ ....: g(18) == 18, g(19) == 19, g(20) == 20, g(21) == 21,
2344
+ ....: g(22) == 22, g(23) == 23, g(24) == 24, g(25) == 25,
2345
+ ....: g(26) == 26, g(27) == 27, g(28) == 28, g(29) == 29,
2346
+ ....: g(30) == 30, g(31) == 31], g, m, offset=8)
2347
+ sage: (S - T).is_trivial_zero() # long time
2348
+ True
2349
+
2350
+ Zero-sequence with nonzero initial values::
2351
+
2352
+ sage: Seq2.from_recurrence([
2353
+ ....: f(2*n) == 0, f(2*n + 1) == 0,
2354
+ ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3], f, n)
2355
+ Traceback (most recent call last):
2356
+ ...
2357
+ ValueError: Initial value for argument 0 does not match with the given recurrence relations.
2358
+
2359
+ ::
2360
+
2361
+ sage: Seq2.from_recurrence([
2362
+ ....: f(2*n) == 0, f(2*n + 1) == 0,
2363
+ ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3], f, n, offset=2)
2364
+ 2-regular sequence 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, ...
2365
+
2366
+ Check if inhomogeneities `0` do not change the sequence::
2367
+
2368
+ sage: Seq2.from_recurrence([
2369
+ ....: f(2*n) == 0, f(2*n + 1) == 0,
2370
+ ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3], f, n, offset=2,
2371
+ ....: inhomogeneities={0: 0, 1: Seq2.zero()})
2372
+ 2-regular sequence 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, ...
2373
+
2374
+ ::
2375
+
2376
+ sage: S = Seq2([matrix([[3/2, -1, 1], [0, 1/2, 1/2], [0, -1, 2]]),
2377
+ ....: matrix([[-1, 0, 1], [1, 5, -5], [-4, 0, 0]])],
2378
+ ....: left=vector([1, 2, 3]),
2379
+ ....: right=vector([0, 1, 1]))
2380
+ sage: T = Seq2.from_recurrence(M=3, m=2,
2381
+ ....: coeffs={},
2382
+ ....: initial_values={0: S[0]},
2383
+ ....: inhomogeneities={i: S.subsequence(2**3, i) for i in srange(2**3)})
2384
+ sage: (S - T).is_trivial_zero()
2385
+ True
2386
+
2387
+ Connection between the Stern--Brocot sequence and the number
2388
+ of nonzero elements in the generalized Pascal's triangle (see
2389
+ [LRS2017]_)::
2390
+
2391
+ sage: U = Seq2.from_recurrence(M=1, m=0,
2392
+ ....: coeffs={(0, 0): 1},
2393
+ ....: initial_values={0: 0, 1: 1},
2394
+ ....: inhomogeneities={1: P})
2395
+ sage: (U - Seq2(SB)).is_trivial_zero()
2396
+ True
2397
+
2398
+ ::
2399
+
2400
+ sage: U = Seq2.from_recurrence(M=1, m=0,
2401
+ ....: coeffs={},
2402
+ ....: initial_values={0: 0, 1: 1},
2403
+ ....: inhomogeneities={0: SB, 1: P})
2404
+ sage: (U - Seq2(SB)).is_trivial_zero()
2405
+ True
2406
+
2407
+ Number of Unbordered Factors in the Thue--Morse Sequence, but partly
2408
+ encoded with inhomogeneities::
2409
+
2410
+ sage: UB2 = Seq2.from_recurrence([
2411
+ ....: f(8*n) == 2*f(4*n),
2412
+ ....: f(8*n + 1) == f(4*n + 1),
2413
+ ....: f(8*n + 2) == f(4*n + 1),
2414
+ ....: f(8*n + 3) == f(4*n + 2),
2415
+ ....: f(8*n + 4) == 2*f(4*n + 2),
2416
+ ....: f(8*n + 5) == f(4*n + 3),
2417
+ ....: f(8*n + 6) == -f(4*n + 1),
2418
+ ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3),
2419
+ ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2,
2420
+ ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4,
2421
+ ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4,
2422
+ ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0,
2423
+ ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n, offset=3,
2424
+ ....: inhomogeneities={2: UB.subsequence(4, 3), 3: -UB.subsequence(4, 1),
2425
+ ....: 6: UB.subsequence(4, 2) + UB.subsequence(4, 3)})
2426
+ sage: (UB2 - Seq2(UB)).is_trivial_zero()
2427
+ True
2428
+ """
2429
+ RP = RecurrenceParser(self.k, self.coefficient_ring())
2430
+ mu, left, right = RP(*args, **kwds)
2431
+ return self(mu, left, right)
2432
+
2433
+
2434
+ class RecurrenceParser:
2435
+ r"""
2436
+ A parser for recurrence relations that allow
2437
+ the construction of a `k`-linear representation
2438
+ for the sequence satisfying these recurrence relations.
2439
+
2440
+ This is used by :meth:`RegularSequenceRing.from_recurrence`
2441
+ to construct a :class:`RegularSequence`.
2442
+ """
2443
+
2444
+ def __init__(self, k, coefficient_ring):
2445
+ r"""
2446
+ See :class:`RecurrenceParser`.
2447
+
2448
+ INPUT:
2449
+
2450
+ - ``k`` -- integer at least `2` specifying the base
2451
+
2452
+ - ``coefficient_ring`` -- a ring
2453
+
2454
+ These are the same parameters used when creating
2455
+ a :class:`RegularSequenceRing`.
2456
+
2457
+ TESTS::
2458
+
2459
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
2460
+ sage: RecurrenceParser(2, ZZ)
2461
+ <sage.combinat.regular_sequence.RecurrenceParser object at 0x...>
2462
+ """
2463
+ self.k = k
2464
+ self.coefficient_ring = coefficient_ring
2465
+
2466
+ def parse_recurrence(self, equations, function, var):
2467
+ r"""
2468
+ Parse recurrence relations as admissible in :meth:`RegularSequenceRing.from_recurrence`.
2469
+
2470
+ INPUT:
2471
+
2472
+ All parameters are explained in the high-level method
2473
+ :meth:`RegularSequenceRing.from_recurrence`.
2474
+
2475
+ OUTPUT: a tuple consisting of
2476
+
2477
+ - ``M``, ``m`` -- see :meth:`RegularSequenceRing.from_recurrence`
2478
+
2479
+ - ``coeffs`` -- see :meth:`RegularSequenceRing.from_recurrence`
2480
+
2481
+ - ``initial_values`` -- see :meth:`RegularSequenceRing.from_recurrence`
2482
+
2483
+ EXAMPLES::
2484
+
2485
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
2486
+ sage: RP = RecurrenceParser(2, ZZ)
2487
+ sage: var('n')
2488
+ n
2489
+ sage: function('f')
2490
+ f
2491
+ sage: RP.parse_recurrence([
2492
+ ....: f(4*n) == f(2*n) + 2*f(2*n + 1) + 3*f(2*n - 2),
2493
+ ....: f(4*n + 1) == 4*f(2*n) + 5*f(2*n + 1) + 6*f(2*n - 2),
2494
+ ....: f(4*n + 2) == 7*f(2*n) + 8*f(2*n + 1) + 9*f(2*n - 2),
2495
+ ....: f(4*n + 3) == 10*f(2*n) + 11*f(2*n + 1) + 12*f(2*n - 2),
2496
+ ....: f(0) == 1, f(1) == 2, f(2) == 1], f, n)
2497
+ (2, 1, {(0, -2): 3, (0, 0): 1, (0, 1): 2, (1, -2): 6, (1, 0): 4,
2498
+ (1, 1): 5, (2, -2): 9, (2, 0): 7, (2, 1): 8, (3, -2): 12, (3, 0): 10,
2499
+ (3, 1): 11}, {0: 1, 1: 2, 2: 1})
2500
+
2501
+ Stern--Brocot Sequence::
2502
+
2503
+ sage: RP.parse_recurrence([
2504
+ ....: f(2*n) == f(n), f(2*n + 1) == f(n) + f(n + 1),
2505
+ ....: f(0) == 0, f(1) == 1], f, n)
2506
+ (1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, {0: 0, 1: 1})
2507
+
2508
+ .. SEEALSO::
2509
+
2510
+ :meth:`RegularSequenceRing.from_recurrence`
2511
+
2512
+ TESTS:
2513
+
2514
+ The following tests check that the equations are well-formed::
2515
+
2516
+ sage: RP.parse_recurrence([], f, n)
2517
+ Traceback (most recent call last):
2518
+ ...
2519
+ ValueError: List of recurrence equations is empty.
2520
+
2521
+ ::
2522
+
2523
+ sage: RP.parse_recurrence([f(4*n + 1)], f, n)
2524
+ Traceback (most recent call last):
2525
+ ...
2526
+ ValueError: f(4*n + 1) is not an equation with ==.
2527
+
2528
+ ::
2529
+
2530
+ sage: RP.parse_recurrence([42], f, n)
2531
+ Traceback (most recent call last):
2532
+ ...
2533
+ ValueError: 42 is not a symbolic expression.
2534
+
2535
+ ::
2536
+
2537
+ sage: RP.parse_recurrence([f(2*n) + 1 == f(n)], f, n)
2538
+ Traceback (most recent call last):
2539
+ ...
2540
+ ValueError: Term f(2*n) + 1 in the equation f(2*n) + 1 == f(n) is
2541
+ not an evaluation of f.
2542
+
2543
+ ::
2544
+
2545
+ sage: RP.parse_recurrence([f(2*n, 5) == 3], f, n)
2546
+ Traceback (most recent call last):
2547
+ ...
2548
+ ValueError: Term f(2*n, 5) in the equation f(2*n, 5) == 3 does not
2549
+ have one argument.
2550
+
2551
+ ::
2552
+
2553
+ sage: RP.parse_recurrence([f() == 3], f, n)
2554
+ Traceback (most recent call last):
2555
+ ...
2556
+ ValueError: Term f() in the equation f() == 3 does not have one
2557
+ argument.
2558
+
2559
+ ::
2560
+
2561
+ sage: RP.parse_recurrence([f(1/n + 1) == f(n)], f, n)
2562
+ Traceback (most recent call last):
2563
+ ...
2564
+ ValueError: Term f(1/n + 1) in the equation f(1/n + 1) == f(n):
2565
+ 1/n + 1 is not a polynomial in n with integer coefficients.
2566
+
2567
+ ::
2568
+
2569
+ sage: RP.parse_recurrence([f(2*n + 1/2) == f(n)], f, n)
2570
+ Traceback (most recent call last):
2571
+ ...
2572
+ ValueError: Term f(2*n + 1/2) in the equation f(2*n + 1/2) == f(n):
2573
+ 2*n + 1/2 is not a polynomial in n with integer coefficients.
2574
+
2575
+ ::
2576
+
2577
+ sage: RP.parse_recurrence([f(4*n^2) == f(2*n^2)], f, n)
2578
+ Traceback (most recent call last):
2579
+ ...
2580
+ ValueError: Term f(4*n^2) in the equation f(4*n^2) == f(2*n^2):
2581
+ 4*n^2 is not a polynomial in n of degree smaller than 2.
2582
+
2583
+ ::
2584
+
2585
+ sage: RP.parse_recurrence([f(42) == 1/2], f, n)
2586
+ Traceback (most recent call last):
2587
+ ...
2588
+ ValueError: Initial value 1/2 given by the equation f(42) == (1/2)
2589
+ is not in Integer Ring.
2590
+
2591
+ ::
2592
+
2593
+ sage: RP.parse_recurrence([f(42) == 0, f(42) == 1], f, n)
2594
+ Traceback (most recent call last):
2595
+ ...
2596
+ ValueError: Initial value f(42) is given twice.
2597
+
2598
+ ::
2599
+
2600
+ sage: RP.parse_recurrence([f(42) == f(n)], f, n)
2601
+ Traceback (most recent call last):
2602
+ ...
2603
+ ValueError: Initial value f(n) given by the equation f(42) == f(n)
2604
+ is not in Integer Ring.
2605
+
2606
+ ::
2607
+
2608
+ sage: RP.parse_recurrence([f(4*n) == f(n), f(2*n) == f(n)], f, n)
2609
+ Traceback (most recent call last):
2610
+ ...
2611
+ ValueError: Term f(2*n) in the equation f(2*n) == f(n): 2 does not
2612
+ equal 4. Expected subsequence modulo 4 as in another equation, got
2613
+ subsequence modulo 2.
2614
+
2615
+ ::
2616
+
2617
+ sage: RP.parse_recurrence([f(3*n + 1) == f(n)], f, n)
2618
+ Traceback (most recent call last):
2619
+ ...
2620
+ ValueError: Term f(3*n + 1) in the equation f(3*n + 1) == f(n):
2621
+ 3 is not a power of 2.
2622
+
2623
+ ::
2624
+
2625
+ sage: RP.parse_recurrence([f(n + 1) == f(n)], f, n)
2626
+ Traceback (most recent call last):
2627
+ ...
2628
+ ValueError: Term f(n + 1) in the equation f(n + 1) == f(n):
2629
+ 1 is less than 2. Modulus must be at least 2.
2630
+
2631
+ ::
2632
+
2633
+ sage: RP.parse_recurrence([f(2*n) == f(n), f(2*n) == 0], f, n)
2634
+ Traceback (most recent call last):
2635
+ ...
2636
+ ValueError: There are more than one recurrence relation for f(2*n).
2637
+
2638
+ ::
2639
+
2640
+ sage: RP.parse_recurrence([f(2*n + 2) == f(n)], f, n)
2641
+ Traceback (most recent call last):
2642
+ ...
2643
+ ValueError: Term f(2*n + 2) in the equation f(2*n + 2) == f(n):
2644
+ remainder 2 is not smaller than modulus 2.
2645
+
2646
+ ::
2647
+
2648
+ sage: RP.parse_recurrence([f(2*n - 1) == f(n)], f, n)
2649
+ Traceback (most recent call last):
2650
+ ...
2651
+ ValueError: Term f(2*n - 1) in the equation f(2*n - 1) == f(n):
2652
+ remainder -1 is smaller than 0.
2653
+
2654
+ ::
2655
+
2656
+ sage: RP.parse_recurrence([f(2*n) == 2*n], f, n)
2657
+ Traceback (most recent call last):
2658
+ ...
2659
+ ValueError: Term 2*n in the equation f(2*n) == 2*n does not
2660
+ contain f.
2661
+
2662
+ ::
2663
+
2664
+ sage: RP.parse_recurrence([f(2*n) == 1/2*f(n)], f, n)
2665
+ Traceback (most recent call last):
2666
+ ...
2667
+ ValueError: Term 1/2*f(n) in the equation f(2*n) == 1/2*f(n):
2668
+ 1/2 is not a valid coefficient since it is not in Integer Ring.
2669
+
2670
+ ::
2671
+
2672
+ sage: RP.parse_recurrence([f(2*n) == 1/f(n)], f, n)
2673
+ Traceback (most recent call last):
2674
+ ...
2675
+ ValueError: 1/f(n) is not a valid right hand side.
2676
+
2677
+ ::
2678
+
2679
+ sage: RP.parse_recurrence([f(2*n) == 2*n*f(n)], f, n)
2680
+ Traceback (most recent call last):
2681
+ ...
2682
+ ValueError: 2*n*f(n) is not a valid right hand side.
2683
+
2684
+ ::
2685
+
2686
+ sage: RP.parse_recurrence([f(2*n) == 2*f(n, 5)], f, n)
2687
+ Traceback (most recent call last):
2688
+ ...
2689
+ ValueError: Term f(n, 5) in the equation f(2*n) == 2*f(n, 5)
2690
+ has more than one argument.
2691
+
2692
+ ::
2693
+
2694
+ sage: RP.parse_recurrence([f(2*n) == 2*f()], f, n)
2695
+ Traceback (most recent call last):
2696
+ ...
2697
+ ValueError: Term f() in the equation f(2*n) == 2*f() has no argument.
2698
+
2699
+ ::
2700
+
2701
+ sage: RP.parse_recurrence([f(2*n) == 1/f(n) + 2*f(n)], f, n)
2702
+ Traceback (most recent call last):
2703
+ ...
2704
+ ValueError: Term 1/f(n) in the equation f(2*n) == 1/f(n) + 2*f(n)
2705
+ is not a valid summand.
2706
+
2707
+ ::
2708
+
2709
+ sage: RP.parse_recurrence([f(2*n) == 2*f(1/n)], f, n)
2710
+ Traceback (most recent call last):
2711
+ ...
2712
+ ValueError: Term f(1/n) in the equation f(2*n) == 2*f(1/n):
2713
+ 1/n is not a polynomial in n with integer coefficients.
2714
+
2715
+ ::
2716
+
2717
+ sage: RP.parse_recurrence([f(2*n) == f(n + 1/2)], f, n)
2718
+ Traceback (most recent call last):
2719
+ ...
2720
+ ValueError: Term f(n + 1/2) in the equation f(2*n) == f(n + 1/2):
2721
+ n + 1/2 is not a polynomial in n with integer coefficients.
2722
+
2723
+ ::
2724
+
2725
+ sage: RP.parse_recurrence([f(2*n) == f(1/2*n)], f, n)
2726
+ Traceback (most recent call last):
2727
+ ...
2728
+ ValueError: Term f(1/2*n) in the equation f(2*n) == f(1/2*n):
2729
+ 1/2*n is not a polynomial in n with integer coefficients.
2730
+
2731
+ ::
2732
+
2733
+ sage: RP.parse_recurrence([f(2*n) == f(n^2 + 1)], f, n)
2734
+ Traceback (most recent call last):
2735
+ ...
2736
+ ValueError: Term f(n^2 + 1) in the equation f(2*n) == f(n^2 + 1):
2737
+ polynomial n^2 + 1 does not have degree 1.
2738
+
2739
+ ::
2740
+
2741
+ sage: RP.parse_recurrence([f(2*n) == f(1)], f, n)
2742
+ Traceback (most recent call last):
2743
+ ...
2744
+ ValueError: Term f(1) in the equation f(2*n) == f(1):
2745
+ polynomial 1 does not have degree 1.
2746
+
2747
+ ::
2748
+
2749
+ sage: RP.parse_recurrence([f(4*n) == f(2*n) + f(n)], f, n)
2750
+ Traceback (most recent call last):
2751
+ ...
2752
+ ValueError: Term f(n) in the equation f(4*n) == f(2*n) + f(n):
2753
+ 1 does not equal 2. Expected subsequence modulo 2 as in another
2754
+ summand or equation, got subsequence modulo 1.
2755
+
2756
+ ::
2757
+
2758
+ sage: RP.parse_recurrence([f(4*n) == f(2*n), f(4*n + 1) == f(n)],
2759
+ ....: f, n)
2760
+ Traceback (most recent call last):
2761
+ ...
2762
+ ValueError: Term f(n) in the equation f(4*n + 1) == f(n): 1 does not
2763
+ equal 2. Expected subsequence modulo 2 as in another summand or
2764
+ equation, got subsequence modulo 1.
2765
+
2766
+ ::
2767
+
2768
+ sage: RP.parse_recurrence([f(4*n) == f(3*n)], f, n)
2769
+ Traceback (most recent call last):
2770
+ ...
2771
+ ValueError: Term f(3*n) in the equation f(4*n) == f(3*n): 3 is not
2772
+ a power of 2.
2773
+
2774
+ ::
2775
+
2776
+ sage: RP.parse_recurrence([f(2*n) == f(4*n)], f, n)
2777
+ Traceback (most recent call last):
2778
+ ...
2779
+ ValueError: Term f(4*n) in the equation f(2*n) == f(4*n):
2780
+ 4 is not smaller than 2.
2781
+
2782
+ ::
2783
+
2784
+ sage: RP.parse_recurrence([f(2*n) == f(2*n)], f, n)
2785
+ Traceback (most recent call last):
2786
+ ...
2787
+ ValueError: Term f(2*n) in the equation f(2*n) == f(2*n):
2788
+ 2 is not smaller than 2.
2789
+
2790
+ ::
2791
+
2792
+ sage: RP.parse_recurrence([f(2*n) == f(n)], f, n)
2793
+ Traceback (most recent call last):
2794
+ ...
2795
+ ValueError: Recurrence relations for [f(2*n + 1)] are missing.
2796
+
2797
+ ::
2798
+
2799
+ sage: RP.parse_recurrence([f(4*n) == f(n), f(4*n + 3) == 0], f, n)
2800
+ Traceback (most recent call last):
2801
+ ...
2802
+ ValueError: Recurrence relations for [f(4*n + 1), f(4*n + 2)]
2803
+ are missing.
2804
+
2805
+ ::
2806
+
2807
+ sage: RP.parse_recurrence([f(42) == 0], f, n)
2808
+ Traceback (most recent call last):
2809
+ ...
2810
+ ValueError: No recurrence relations are given.
2811
+
2812
+ ::
2813
+
2814
+ sage: RP.parse_recurrence(
2815
+ ....: [f(4*n + r) == f(n) for r in srange(4)], f, n)
2816
+ (2, 0, {(0, 0): 1, (1, 0): 1, (2, 0): 1, (3, 0): 1}, {})
2817
+
2818
+ ::
2819
+
2820
+ sage: RP.parse_recurrence(
2821
+ ....: [f(8*n) == f(n)] +
2822
+ ....: [f(8*n + r) == f(2*n) for r in srange(1,8)], f, n)
2823
+ Traceback (most recent call last):
2824
+ ...
2825
+ ValueError: Term f(2*n) in the equation f(8*n + 1) == f(2*n):
2826
+ 2 does not equal 1. Expected subsequence modulo 1 as in another
2827
+ summand or equation, got subsequence modulo 2.
2828
+
2829
+ Finally, also for the zero-sequence the output is as expected::
2830
+
2831
+ sage: RP.parse_recurrence([f(2*n) == 0, f(2*n + 1) == 0], f, n)
2832
+ (1, 0, {}, {})
2833
+
2834
+ We check that the output is of the correct type (:issue:`33158`)::
2835
+
2836
+ sage: RP = RecurrenceParser(2, QQ)
2837
+ sage: equations = [
2838
+ ....: f(4*n) == 5/3*f(2*n) - 1/3*f(2*n + 1),
2839
+ ....: f(4*n + 1) == 4/3*f(2*n) + 1/3*f(2*n + 1),
2840
+ ....: f(4*n + 2) == 1/3*f(2*n) + 4/3*f(2*n + 1),
2841
+ ....: f(4*n + 3) == -1/3*f(2*n) + 5/3*f(2*n + 1),
2842
+ ....: f(0) == 1, f(1) == 2]
2843
+ sage: M, m, coeffs, initial_values = RP.parse_recurrence(equations, f, n)
2844
+ sage: M.parent()
2845
+ Integer Ring
2846
+ sage: m.parent()
2847
+ Integer Ring
2848
+ sage: all(v.parent() == QQ for v in coeffs.values())
2849
+ True
2850
+ sage: all(v.parent() == QQ for v in initial_values.values())
2851
+ True
2852
+
2853
+ This results in giving the correct (see :issue:`33158`) minimization in::
2854
+
2855
+ sage: Seq2 = RegularSequenceRing(2, QQ)
2856
+ sage: P = Seq2.from_recurrence(equations, f, n)
2857
+ sage: P
2858
+ 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ...
2859
+ sage: P.minimized()
2860
+ 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ...
2861
+ """
2862
+ from sage.arith.srange import srange
2863
+ from sage.functions.log import log
2864
+ from sage.rings.integer_ring import ZZ
2865
+ from sage.symbolic.operators import add_vararg, mul_vararg, operator
2866
+
2867
+ k = self.k
2868
+ coefficient_ring = self.coefficient_ring
2869
+ M = None
2870
+ m = None
2871
+ coeffs = {}
2872
+ initial_values = {}
2873
+ remainders = set()
2874
+
2875
+ def parse_multiplication(op, eq):
2876
+ operands = op.operands()
2877
+ assert op.operator() == mul_vararg and len(operands) == 2
2878
+ if operands[1].operator() == function:
2879
+ return [operands[0], operands[1]]
2880
+ elif operands[0].operator() == function:
2881
+ return [operands[1], operands[0]]
2882
+ else:
2883
+ raise ValueError('Term %s in the equation %s '
2884
+ 'does not contain %s.'
2885
+ % (op, eq, function))
2886
+
2887
+ def parse_one_summand(summand, eq):
2888
+ if summand.operator() == mul_vararg:
2889
+ coeff, op = parse_multiplication(summand, eq)
2890
+ elif summand.operator() == function:
2891
+ coeff, op = 1, summand
2892
+ else:
2893
+ raise ValueError('Term %s in the equation %s is not a valid summand.'
2894
+ % (summand, eq))
2895
+ try:
2896
+ coeff = coefficient_ring(coeff)
2897
+ except (TypeError, ValueError):
2898
+ raise ValueError("Term %s in the equation %s: "
2899
+ "%s is not a valid coefficient "
2900
+ "since it is not in %s."
2901
+ % (summand, eq, coeff, coefficient_ring)) from None
2902
+ if len(op.operands()) > 1:
2903
+ raise ValueError('Term %s in the equation %s has more than one argument.'
2904
+ % (op, eq))
2905
+ elif len(op.operands()) == 0:
2906
+ raise ValueError('Term %s in the equation %s has no argument.'
2907
+ % (op, eq))
2908
+ try:
2909
+ poly = ZZ[var](op.operands()[0])
2910
+ except TypeError:
2911
+ raise ValueError('Term %s in the equation %s: '
2912
+ '%s is not a polynomial in %s with integer coefficients.'
2913
+ % (op, eq, op.operands()[0], var)) from None
2914
+ if poly.degree() != 1:
2915
+ raise ValueError("Term %s in the equation %s: "
2916
+ "polynomial %s does not have degree 1."
2917
+ % (op, eq, poly))
2918
+ d, base_power_m = list(poly)
2919
+ m = log(base_power_m, base=k)
2920
+ try:
2921
+ m = ZZ(m)
2922
+ except (TypeError, ValueError):
2923
+ raise ValueError("Term %s in the equation %s: "
2924
+ "%s is not a power of %s."
2925
+ % (summand, eq,
2926
+ k**m, k)) from None
2927
+ return [coeff, m, d]
2928
+
2929
+ if not equations:
2930
+ raise ValueError("List of recurrence equations is empty.")
2931
+
2932
+ for eq in equations:
2933
+ try:
2934
+ if eq.operator() != operator.eq:
2935
+ raise ValueError("%s is not an equation with ==."
2936
+ % eq)
2937
+ except AttributeError:
2938
+ raise ValueError("%s is not a symbolic expression."
2939
+ % eq) from None
2940
+ left_side, right_side = eq.operands()
2941
+ if left_side.operator() != function:
2942
+ raise ValueError("Term %s in the equation %s is not an evaluation of %s."
2943
+ % (left_side, eq, function))
2944
+ if len(left_side.operands()) != 1:
2945
+ raise ValueError("Term %s in the equation %s does not have "
2946
+ "one argument."
2947
+ % (left_side, eq))
2948
+ try:
2949
+ polynomial_left = ZZ[var](left_side.operands()[0])
2950
+ except TypeError:
2951
+ raise ValueError("Term %s in the equation %s: "
2952
+ "%s is not a polynomial in %s with "
2953
+ "integer coefficients."
2954
+ % (left_side, eq,
2955
+ left_side.operands()[0], var)) from None
2956
+ if polynomial_left.degree() > 1:
2957
+ raise ValueError("Term %s in the equation %s: "
2958
+ "%s is not a polynomial in %s of degree smaller than 2."
2959
+ % (left_side, eq, polynomial_left, var))
2960
+ if polynomial_left in ZZ:
2961
+ try:
2962
+ right_side = coefficient_ring(right_side)
2963
+ except (TypeError, ValueError):
2964
+ raise ValueError("Initial value %s given by the equation %s "
2965
+ "is not in %s."
2966
+ % (right_side, eq, coefficient_ring)) from None
2967
+ if (polynomial_left in initial_values.keys() and
2968
+ initial_values[polynomial_left] != right_side):
2969
+ raise ValueError("Initial value %s is given twice."
2970
+ % (function(polynomial_left)))
2971
+ initial_values.update({polynomial_left: right_side})
2972
+ else:
2973
+ [r, base_power_M] = list(polynomial_left)
2974
+ M_new = log(base_power_M, base=k)
2975
+ try:
2976
+ M_new = ZZ(M_new)
2977
+ except (TypeError, ValueError):
2978
+ raise ValueError("Term %s in the equation %s: "
2979
+ "%s is not a power of %s."
2980
+ % (left_side, eq,
2981
+ base_power_M, k)) from None
2982
+ if M is not None and M != M_new:
2983
+ raise ValueError(("Term {0} in the equation {1}: "
2984
+ "{2} does not equal {3}. Expected "
2985
+ "subsequence modulo {3} as in another "
2986
+ "equation, got subsequence modulo {2}.").format(
2987
+ left_side, eq,
2988
+ base_power_M, k**M))
2989
+ elif M is None:
2990
+ M = M_new
2991
+ if M < 1:
2992
+ raise ValueError(("Term {0} in the equation {1}: "
2993
+ "{2} is less than {3}. Modulus must "
2994
+ "be at least {3}.").format(
2995
+ left_side, eq,
2996
+ base_power_M, k))
2997
+ if r in remainders:
2998
+ raise ValueError("There are more than one recurrence relation for %s."
2999
+ % (left_side,))
3000
+ if r >= k**M:
3001
+ raise ValueError("Term %s in the equation %s: "
3002
+ "remainder %s is not smaller than modulus %s."
3003
+ % (left_side, eq, r, k**M))
3004
+ elif r < 0:
3005
+ raise ValueError("Term %s in the equation %s: "
3006
+ "remainder %s is smaller than 0."
3007
+ % (left_side, eq, r))
3008
+ else:
3009
+ remainders.add(r)
3010
+ if right_side != 0:
3011
+ if (len(right_side.operands()) == 1 and right_side.operator() == function
3012
+ or right_side.operator() == mul_vararg and len(right_side.operands()) == 2):
3013
+ summands = [right_side]
3014
+ elif right_side.operator() == add_vararg:
3015
+ summands = right_side.operands()
3016
+ else:
3017
+ raise ValueError("%s is not a valid right hand side."
3018
+ % (right_side,))
3019
+ for summand in summands:
3020
+ coeff, new_m, d = parse_one_summand(summand, eq)
3021
+ if m is not None and m != new_m:
3022
+ raise ValueError(("Term {0} in the equation {1}: "
3023
+ "{2} does not equal {3}. Expected "
3024
+ "subsequence modulo {3} as in another "
3025
+ "summand or equation, got subsequence "
3026
+ "modulo {2}.").format(
3027
+ summand, eq,
3028
+ k**new_m, k**m))
3029
+ elif m is None:
3030
+ m = new_m
3031
+ if M <= m:
3032
+ raise ValueError("Term %s in the equation %s: "
3033
+ "%s is not smaller than %s."
3034
+ % (summand, eq,
3035
+ k**m, k**M))
3036
+ coeffs.update({(r, d): coeff})
3037
+
3038
+ if not M:
3039
+ raise ValueError("No recurrence relations are given.")
3040
+ elif M and m is None: # for the zero sequence
3041
+ m = M - 1
3042
+
3043
+ missing_remainders = [rem for rem in srange(k**M)
3044
+ if rem not in remainders]
3045
+ if missing_remainders:
3046
+ raise ValueError("Recurrence relations for %s are missing."
3047
+ % ([function(k**M*var + rem)
3048
+ for rem in missing_remainders],))
3049
+
3050
+ return (M, m, coeffs, initial_values)
3051
+
3052
+ def parse_direct_arguments(self, M, m, coeffs, initial_values):
3053
+ r"""
3054
+ Check whether the direct arguments as admissible in
3055
+ :meth:`RegularSequenceRing.from_recurrence` are valid.
3056
+
3057
+ INPUT:
3058
+
3059
+ All parameters are explained in the high-level method
3060
+ :meth:`RegularSequenceRing.from_recurrence`.
3061
+
3062
+ OUTPUT: a tuple consisting of the input parameters
3063
+
3064
+ EXAMPLES::
3065
+
3066
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
3067
+ sage: RP = RecurrenceParser(2, ZZ)
3068
+ sage: RP.parse_direct_arguments(2, 1,
3069
+ ....: {(0, -2): 3, (0, 0): 1, (0, 1): 2,
3070
+ ....: (1, -2): 6, (1, 0): 4, (1, 1): 5,
3071
+ ....: (2, -2): 9, (2, 0): 7, (2, 1): 8,
3072
+ ....: (3, -2): 12, (3, 0): 10, (3, 1): 11},
3073
+ ....: {0: 1, 1: 2, 2: 1})
3074
+ (2, 1, {(0, -2): 3, (0, 0): 1, (0, 1): 2,
3075
+ (1, -2): 6, (1, 0): 4, (1, 1): 5,
3076
+ (2, -2): 9, (2, 0): 7, (2, 1): 8,
3077
+ (3, -2): 12, (3, 0): 10, (3, 1): 11},
3078
+ {0: 1, 1: 2, 2: 1})
3079
+
3080
+ Stern--Brocot Sequence::
3081
+
3082
+ sage: RP.parse_direct_arguments(1, 0,
3083
+ ....: {(0, 0): 1, (1, 0): 1, (1, 1): 1},
3084
+ ....: {0: 0, 1: 1})
3085
+ (1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, {0: 0, 1: 1})
3086
+
3087
+ .. SEEALSO::
3088
+
3089
+ :meth:`RegularSequenceRing.from_recurrence`
3090
+
3091
+ TESTS:
3092
+
3093
+ The following tests check that the equations are well-formed::
3094
+
3095
+ sage: RP.parse_direct_arguments(1/2, 0, {}, {})
3096
+ Traceback (most recent call last):
3097
+ ...
3098
+ ValueError: 1/2 is not a positive integer.
3099
+
3100
+ ::
3101
+
3102
+ sage: RP.parse_direct_arguments(0, 0, {}, {})
3103
+ Traceback (most recent call last):
3104
+ ....
3105
+ ValueError: 0 is not a positive integer.
3106
+
3107
+ ::
3108
+
3109
+ sage: RP.parse_direct_arguments(1, 1/2, {}, {})
3110
+ Traceback (most recent call last):
3111
+ ...
3112
+ ValueError: 1/2 is not a nonnegative integer.
3113
+
3114
+ ::
3115
+
3116
+ sage: RP.parse_direct_arguments(1, -1, {}, {})
3117
+ Traceback (most recent call last):
3118
+ ...
3119
+ ValueError: -1 is not a nonnegative integer.
3120
+
3121
+ ::
3122
+
3123
+ sage: RP.parse_direct_arguments(1, 1, {}, {})
3124
+ Traceback (most recent call last):
3125
+ ...
3126
+ ValueError: 1 is not larger than 1.
3127
+
3128
+ ::
3129
+
3130
+ sage: RP.parse_direct_arguments(1, 42, {}, {})
3131
+ Traceback (most recent call last):
3132
+ ...
3133
+ ValueError: 1 is not larger than 42.
3134
+
3135
+ ::
3136
+
3137
+ sage: RP.parse_direct_arguments(2, 1, {(0, 0): 1/2, (1, 0): i}, {})
3138
+ Traceback (most recent call last):
3139
+ ...
3140
+ ValueError: Coefficients [1/2, I] are not valid since they are not
3141
+ in Integer Ring.
3142
+
3143
+ ::
3144
+
3145
+ sage: RP.parse_direct_arguments(2, 1, {(i, 0): 0, (0, 1/2): 0}, {})
3146
+ Traceback (most recent call last):
3147
+ ...
3148
+ ValueError: Keys [(I, 0), (0, 1/2)] for coefficients are not valid
3149
+ since one of their components is no integer.
3150
+
3151
+ ::
3152
+
3153
+ sage: RP.parse_direct_arguments(2, 1, {(-1, 0): 0, (42, 0): 0}, {})
3154
+ Traceback (most recent call last):
3155
+ ...
3156
+ ValueError: Keys [(-1, 0), (42, 0)] for coefficients are not valid since
3157
+ their first component is either smaller than 0 or larger than
3158
+ or equal to 4.
3159
+
3160
+ ::
3161
+
3162
+ sage: RP.parse_direct_arguments(2, 1, {}, {0: 1/2, 1: i})
3163
+ Traceback (most recent call last):
3164
+ ...
3165
+ ValueError: Initial values [1/2, I] are not valid since they are
3166
+ not in Integer Ring.
3167
+
3168
+ ::
3169
+
3170
+ sage: RP.parse_direct_arguments(2, 1, {}, {1/2: 0, i: 0})
3171
+ Traceback (most recent call last):
3172
+ ...
3173
+ ValueError: Keys [1/2, I] for the initial values are not valid since
3174
+ they are no integers.
3175
+ """
3176
+ from sage.rings.integer_ring import ZZ
3177
+
3178
+ if M not in ZZ or M < 1:
3179
+ raise ValueError("%s is not a positive integer."
3180
+ % (M,)) from None
3181
+ if m not in ZZ or m < 0:
3182
+ raise ValueError("%s is not a nonnegative integer."
3183
+ % (m,)) from None
3184
+ if M <= m:
3185
+ raise ValueError("%s is not larger than %s."
3186
+ % (M, m)) from None
3187
+
3188
+ coefficient_ring = self.coefficient_ring
3189
+ k = self.k
3190
+
3191
+ invalid_coeffs = [coeff for coeff in coeffs.values()
3192
+ if coeff not in coefficient_ring]
3193
+ if invalid_coeffs:
3194
+ raise ValueError("Coefficients %s are not valid "
3195
+ "since they are not in %s."
3196
+ % (invalid_coeffs, coefficient_ring)) from None
3197
+
3198
+ coeffs_keys = coeffs.keys()
3199
+ invalid_coeffs_keys = [key for key in coeffs_keys
3200
+ if key[0] not in ZZ or key[1] not in ZZ]
3201
+ if invalid_coeffs_keys:
3202
+ raise ValueError("Keys %s for coefficients are not valid "
3203
+ "since one of their components is no integer."
3204
+ % (invalid_coeffs_keys,)) from None
3205
+
3206
+ invalid_coeffs_keys = [key for key in coeffs_keys if key[0] < 0 or key[0] >= k**M]
3207
+ if invalid_coeffs_keys:
3208
+ raise ValueError("Keys %s for coefficients are not valid "
3209
+ "since their first component is either smaller than 0 "
3210
+ " or larger than or equal to %s."
3211
+ % (invalid_coeffs_keys, k**M)) from None
3212
+
3213
+ invalid_initial_values = [value for value in initial_values.values()
3214
+ if value not in coefficient_ring]
3215
+ if invalid_initial_values:
3216
+ raise ValueError("Initial values %s are not valid "
3217
+ "since they are not in %s."
3218
+ % (invalid_initial_values, coefficient_ring)) from None
3219
+
3220
+ invalid_initial_keys = [key for key in initial_values.keys()
3221
+ if key not in ZZ]
3222
+ if invalid_initial_keys:
3223
+ raise ValueError("Keys %s for the initial values are not valid "
3224
+ "since they are no integers."
3225
+ % (invalid_initial_keys,)) from None
3226
+
3227
+ return (M, m, coeffs, initial_values)
3228
+
3229
+ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}):
3230
+ r"""
3231
+ Determine parameters from recurrence relations as admissible in
3232
+ :meth:`RegularSequenceRing.from_recurrence`.
3233
+
3234
+ INPUT:
3235
+
3236
+ All parameters are explained in the high-level method
3237
+ :meth:`RegularSequenceRing.from_recurrence`.
3238
+
3239
+ OUTPUT: a namedtuple ``recurrence_rules`` consisting of
3240
+
3241
+ - ``M``, ``m``, ``l``, ``u``, ``offset`` -- parameters of the recursive
3242
+ sequences, see [HKL2022]_, Definition 3.1
3243
+
3244
+ - ``ll``, ``uu``, ``n1``, ``dim`` -- parameters and dimension of the
3245
+ resulting linear representation, see [HKL2022]_, Theorem A
3246
+
3247
+ - ``coeffs`` -- dictionary mapping ``(r, j)`` to the coefficients
3248
+ `c_{r, j}` as given in [HKL2022]_, Equation (3.1).
3249
+ If ``coeffs[(r, j)]`` is not given for some ``r`` and ``j``,
3250
+ then it is assumed to be zero.
3251
+
3252
+ - ``initial_values`` -- dictionary mapping integers ``n`` to the
3253
+ ``n``-th value of the sequence
3254
+
3255
+ - ``inhomogeneities`` -- dictionary mapping integers ``r``
3256
+ to the inhomogeneity `g_r` as given in [HKL2022]_, Corollary D
3257
+
3258
+ EXAMPLES::
3259
+
3260
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
3261
+ sage: RP = RecurrenceParser(2, ZZ)
3262
+ sage: RP.parameters(2, 1,
3263
+ ....: {(0, -2): 3, (0, 0): 1, (0, 1): 2, (1, -2): 6, (1, 0): 4,
3264
+ ....: (1, 1): 5, (2, -2): 9, (2, 0): 7, (2, 1): 8, (3, -2): 12,
3265
+ ....: (3, 0): 10, (3, 1): 11}, {0: 1, 1: 2, 2: 1, 3: 4}, 0, {0: 1})
3266
+ recurrence_rules(M=2, m=1, l=-2, u=1, ll=-6, uu=3, dim=14,
3267
+ coeffs={(0, -2): 3, (0, 0): 1, (0, 1): 2, (1, -2): 6, (1, 0): 4,
3268
+ (1, 1): 5, (2, -2): 9, (2, 0): 7, (2, 1): 8, (3, -2): 12,
3269
+ (3, 0): 10, (3, 1): 11}, initial_values={0: 1, 1: 2, 2: 1, 3: 4,
3270
+ 4: 13, 5: 30, 6: 48, 7: 66, 8: 77, 9: 208, 10: 340, 11: 472,
3271
+ 12: 220, 13: 600, -6: 0, -5: 0, -4: 0, -3: 0, -2: 0, -1: 0},
3272
+ offset=1, n1=3, inhomogeneities={0: 2-regular sequence 1, 1, 1, 1,
3273
+ 1, 1, 1, 1, 1, 1, ...})
3274
+
3275
+ .. SEEALSO::
3276
+
3277
+ :meth:`RegularSequenceRing.from_recurrence`
3278
+
3279
+ TESTS::
3280
+
3281
+ sage: var('n')
3282
+ n
3283
+ sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0,
3284
+ ....: {-1: 0, 1: 0, 10: 0, I: 0, n: 0})
3285
+ Traceback (most recent call last):
3286
+ ...
3287
+ ValueError: Indices [-1, 10, I, n] for inhomogeneities are
3288
+ no integers between 0 and 1.
3289
+
3290
+ ::
3291
+
3292
+ sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0,
3293
+ ....: {0: n})
3294
+ Traceback (most recent call last):
3295
+ ...
3296
+ ValueError: Inhomogeneities {0: n} are neither 2-regular sequences
3297
+ nor elements of Integer Ring.
3298
+
3299
+ ::
3300
+
3301
+ sage: Seq3 = RegularSequenceRing(3, ZZ)
3302
+ sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0,
3303
+ ....: {0: Seq3.zero()})
3304
+ Traceback (most recent call last):
3305
+ ...
3306
+ ValueError: Inhomogeneities {0: 3-regular sequence 0, 0, 0, 0, 0, 0,
3307
+ 0, 0, 0, 0, ...} are neither 2-regular sequences nor elements of
3308
+ Integer Ring.
3309
+
3310
+ ::
3311
+
3312
+ sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0)
3313
+ Traceback (most recent call last):
3314
+ ...
3315
+ ValueError: No initial values are given.
3316
+
3317
+ ::
3318
+
3319
+ sage: RP.parameters(1, 0,
3320
+ ....: {(0, 0): 1, (1, 0): 1, (1, 1): 1}, {0: 1/2, 1: 2*i}, 0)
3321
+ Traceback (most recent call last):
3322
+ ...
3323
+ ValueError: Initial values for arguments in [0, 1] are not in Integer Ring.
3324
+
3325
+ ::
3326
+
3327
+ sage: RP.parameters(1, 0, {(0, 0): 1},
3328
+ ....: {0: 1, 1: 0}, 0)
3329
+ recurrence_rules(M=1, m=0, l=0, u=0, ll=0, uu=0, dim=1,
3330
+ coeffs={(0, 0): 1}, initial_values={0: 1, 1: 0}, offset=0, n1=0,
3331
+ inhomogeneities={})
3332
+
3333
+ Finally, also for the zero-sequence the output is as expected::
3334
+
3335
+ sage: RP.parameters(1, 0, {}, {0: 0}, 0)
3336
+ recurrence_rules(M=1, m=0, l=0, u=0, ll=0, uu=0, dim=1,
3337
+ coeffs={}, initial_values={0: 0}, offset=0, n1=0, inhomogeneities={})
3338
+
3339
+ ::
3340
+
3341
+ sage: RP.parameters(1, 0,
3342
+ ....: {(0, 0): 0, (1, 1): 0}, {0: 0}, 0)
3343
+ recurrence_rules(M=1, m=0, l=0, u=0, ll=0, uu=0, dim=1,
3344
+ coeffs={(0, 0): 0, (1, 1): 0}, initial_values={0: 0},
3345
+ offset=0, n1=0, inhomogeneities={})
3346
+ """
3347
+ from collections import namedtuple
3348
+
3349
+ from sage.arith.srange import srange
3350
+ from sage.functions.other import ceil, floor
3351
+
3352
+ coefficient_ring = self.coefficient_ring
3353
+ k = self.k
3354
+ keys_coeffs = coeffs.keys()
3355
+ indices_right = [key[1] for key in keys_coeffs if coeffs[key]]
3356
+
3357
+ if not indices_right: # the sequence is the zero sequence
3358
+ l = 0
3359
+ u = 0
3360
+ else:
3361
+ l = min(indices_right)
3362
+ u = max(indices_right)
3363
+
3364
+ if offset < max(0, -l/k**m):
3365
+ offset = max(0, ceil(-l/k**m))
3366
+
3367
+ ll = (floor((l*k**(M-m) - k**M + 1)/(k**(M-m) - 1)) + 1)*(l < 0)
3368
+ uu = max([ceil((u*k**(M-m) + k**M - k**m)/(k**(M-m) - 1)) - 1, k**m - 1])
3369
+ n1 = offset - floor(ll/k**M)
3370
+ dim = (k**M - 1)/(k - 1) + (M - m)*(uu - ll - k**m + 1) + n1
3371
+
3372
+ if inhomogeneities:
3373
+ invalid_indices = [i for i in inhomogeneities
3374
+ if i not in srange(k**M)]
3375
+ if invalid_indices:
3376
+ raise ValueError(f"Indices {invalid_indices} for inhomogeneities are no "
3377
+ f"integers between 0 and {k**M - 1}.")
3378
+
3379
+ Seq = RegularSequenceRing(k, coefficient_ring)
3380
+ inhomogeneities.update({i: inhomogeneities[i] * Seq.one_hadamard()
3381
+ for i in inhomogeneities
3382
+ if inhomogeneities[i] in coefficient_ring})
3383
+ invalid = {i: inhomogeneities[i] for i in inhomogeneities
3384
+ if not (isinstance(inhomogeneities[i].parent(), RegularSequenceRing) and
3385
+ inhomogeneities[i].parent().k == k)}
3386
+ if invalid:
3387
+ raise ValueError(f"Inhomogeneities {invalid} are neither {k}-regular "
3388
+ f"sequences nor elements of {coefficient_ring}.")
3389
+
3390
+ if not initial_values:
3391
+ raise ValueError("No initial values are given.")
3392
+ keys_initial = initial_values.keys()
3393
+ values_not_in_ring = []
3394
+
3395
+ def converted_value(n, v):
3396
+ try:
3397
+ return coefficient_ring(v)
3398
+ except (TypeError, ValueError):
3399
+ values_not_in_ring.append(n)
3400
+ initial_values = {n: converted_value(n, v)
3401
+ for n, v in initial_values.items()}
3402
+ if values_not_in_ring:
3403
+ raise ValueError("Initial values for arguments in %s are not in %s."
3404
+ % (values_not_in_ring, coefficient_ring))
3405
+
3406
+ last_value_needed = max(
3407
+ k**(M-1) - k**m + uu + (n1 > 0)*k**(M-1)*(k*(n1 - 1) + k - 1), # for matrix W
3408
+ k**m*offset + u,
3409
+ max(keys_initial))
3410
+ initial_values = self.values(
3411
+ M=M, m=m, l=l, u=u, ll=ll, coeffs=coeffs,
3412
+ initial_values=initial_values, last_value_needed=last_value_needed,
3413
+ offset=offset, inhomogeneities=inhomogeneities)
3414
+
3415
+ recurrence_rules = namedtuple('recurrence_rules',
3416
+ ['M', 'm', 'l', 'u', 'll', 'uu', 'dim',
3417
+ 'coeffs', 'initial_values', 'offset', 'n1',
3418
+ 'inhomogeneities'])
3419
+
3420
+ return recurrence_rules(M=M, m=m, l=l, u=u, ll=ll, uu=uu, dim=dim,
3421
+ coeffs=coeffs, initial_values=initial_values,
3422
+ offset=offset, n1=n1, inhomogeneities=inhomogeneities)
3423
+
3424
+ def values(self, *, M, m, l, u, ll, coeffs,
3425
+ initial_values, last_value_needed, offset, inhomogeneities):
3426
+ r"""
3427
+ Determine enough values of the corresponding recursive sequence by
3428
+ applying the recurrence relations given in :meth:`RegularSequenceRing.from_recurrence`
3429
+ to the values given in ``initial_values``.
3430
+
3431
+ INPUT:
3432
+
3433
+ - ``M``, ``m``, ``l``, ``u``, ``offset`` -- parameters of the
3434
+ recursive sequences, see [HKL2022]_, Definition 3.1
3435
+
3436
+ - ``ll`` -- parameter of the resulting linear representation,
3437
+ see [HKL2022]_, Theorem A
3438
+
3439
+ - ``coeffs`` -- dictionary where ``coeffs[(r, j)]`` is the
3440
+ coefficient `c_{r,j}` as given in :meth:`RegularSequenceRing.from_recurrence`.
3441
+ If ``coeffs[(r, j)]`` is not given for some ``r`` and ``j``,
3442
+ then it is assumed to be zero.
3443
+
3444
+ - ``initial_values`` -- dictionary mapping integers ``n`` to the
3445
+ ``n``-th value of the sequence
3446
+
3447
+ - ``last_value_needed`` -- last initial value which is needed to
3448
+ determine the linear representation
3449
+
3450
+ - ``inhomogeneities`` -- dictionary mapping integers ``r``
3451
+ to the inhomogeneity `g_r` as given in [HKL2022]_, Corollary D
3452
+
3453
+ OUTPUT:
3454
+
3455
+ A dictionary mapping integers ``n`` to the ``n``-th value of the
3456
+ sequence for all ``n`` up to ``last_value_needed``.
3457
+
3458
+ EXAMPLES:
3459
+
3460
+ Stern--Brocot Sequence::
3461
+
3462
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
3463
+ sage: RP = RecurrenceParser(2, ZZ)
3464
+ sage: RP.values(M=1, m=0, l=0, u=1, ll=0,
3465
+ ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1},
3466
+ ....: initial_values={0: 0, 1: 1, 2: 1}, last_value_needed=20,
3467
+ ....: offset=0, inhomogeneities={})
3468
+ {0: 0, 1: 1, 2: 1, 3: 2, 4: 1, 5: 3, 6: 2, 7: 3, 8: 1, 9: 4, 10: 3,
3469
+ 11: 5, 12: 2, 13: 5, 14: 3, 15: 4, 16: 1, 17: 5, 18: 4, 19: 7, 20: 3}
3470
+
3471
+ .. SEEALSO::
3472
+
3473
+ :meth:`RegularSequenceRing.from_recurrence`
3474
+
3475
+ TESTS:
3476
+
3477
+ For the equations `f(2n) = f(n)` and `f(2n + 1) = f(n) + f(n + 1)`::
3478
+
3479
+ sage: RP.values(M=1, m=0, l=0, u=1, ll=0,
3480
+ ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1},
3481
+ ....: initial_values={0: 0, 1: 2}, last_value_needed=20,
3482
+ ....: offset=0, inhomogeneities={})
3483
+ {0: 0, 1: 2, 2: 2, 3: 4, 4: 2, 5: 6, 6: 4, 7: 6, 8: 2, 9: 8, 10: 6,
3484
+ 11: 10, 12: 4, 13: 10, 14: 6, 15: 8, 16: 2, 17: 10, 18: 8, 19: 14,
3485
+ 20: 6}
3486
+
3487
+ ::
3488
+
3489
+ sage: RP.values(M=1, m=0, l=0, u=1, ll=0,
3490
+ ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1},
3491
+ ....: initial_values={}, last_value_needed=20, offset=0,
3492
+ ....: inhomogeneities={})
3493
+ Traceback (most recent call last):
3494
+ ...
3495
+ ValueError: Initial values for arguments in [0, 1] are missing.
3496
+
3497
+ ::
3498
+
3499
+ sage: RP.values(M=1, m=0, l=0, u=1, ll=0,
3500
+ ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1},
3501
+ ....: initial_values={0: 0}, last_value_needed=20, offset=0,
3502
+ ....: inhomogeneities={})
3503
+ Traceback (most recent call last):
3504
+ ...
3505
+ ValueError: Initial values for arguments in [1] are missing.
3506
+
3507
+ ::
3508
+
3509
+ sage: RP.values(M=1, m=0, l=0, u=1, ll=0,
3510
+ ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1},
3511
+ ....: initial_values={0: 0, 2: 1}, last_value_needed=20,
3512
+ ....: offset=0, inhomogeneities={})
3513
+ Traceback (most recent call last):
3514
+ ...
3515
+ ValueError: Initial values for arguments in [1] are missing.
3516
+
3517
+ ::
3518
+
3519
+ sage: RP.values(M=1, m=0, l=0, u=1, ll=0,
3520
+ ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1},
3521
+ ....: initial_values={0: 0, 1: 2, 2:0}, last_value_needed=20,
3522
+ ....: offset=0, inhomogeneities={})
3523
+ Traceback (most recent call last):
3524
+ ...
3525
+ ValueError: Initial value for argument 2 does not match with the given
3526
+ recurrence relations.
3527
+
3528
+ ::
3529
+
3530
+ sage: RP.values(M=1, m=0, l=-2, u=2, ll=-2,
3531
+ ....: coeffs={(0, -2): 1, (0, 2): 1, (1, -2): 1, (1, 2): 1},
3532
+ ....: initial_values={0: 0, 1: 2, 2: 4, 3: 3, 4: 2},
3533
+ ....: last_value_needed=20, offset=2, inhomogeneities={})
3534
+ {-2: 0, -1: 0, 0: 0, 1: 2, 2: 4, 3: 3, 4: 2, 5: 2, 6: 4, 7: 4,
3535
+ 8: 8, 9: 8, 10: 7, 11: 7, 12: 10, 13: 10, 14: 10, 15: 10, 16: 11,
3536
+ 17: 11, 18: 11, 19: 11, 20: 18}
3537
+
3538
+ Finally, also for the zero-sequence the output is as expected::
3539
+
3540
+ sage: RP.values(M=1, m=0, l=0, u=0, ll=0,
3541
+ ....: coeffs={}, initial_values={}, last_value_needed=10,
3542
+ ....: offset=0, inhomogeneities={})
3543
+ {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0}
3544
+
3545
+ ::
3546
+
3547
+ sage: RP.values(M=1, m=0, l=0, u=0, ll=0,
3548
+ ....: coeffs={(0, 0): 0, (1, 1): 0}, initial_values={},
3549
+ ....: last_value_needed=10, offset=0, inhomogeneities={})
3550
+ {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0}
3551
+
3552
+ ::
3553
+
3554
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
3555
+ sage: RP.values(M=1, m=0, l=0, u=0, ll=0,
3556
+ ....: coeffs={(0, 0): 0, (1, 1): 0}, initial_values={},
3557
+ ....: last_value_needed=10, offset=0,
3558
+ ....: inhomogeneities={0: Seq2.one_hadamard()})
3559
+ {0: 1, 1: 0, 2: 1, 3: 0, 4: 1, 5: 0, 6: 1, 7: 0, 8: 1, 9: 0, 10: 1}
3560
+ """
3561
+ from sage.arith.srange import srange
3562
+ from sage.rings.integer_ring import ZZ
3563
+
3564
+ k = self.k
3565
+ keys_initial = initial_values.keys()
3566
+
3567
+ values = {n: None if n not in keys_initial else initial_values[n]
3568
+ for n in srange(last_value_needed + 1)}
3569
+ missing_values = []
3570
+
3571
+ @cached_function
3572
+ def coeff(r, k):
3573
+ try:
3574
+ return coeffs[(r, k)]
3575
+ except KeyError:
3576
+ return 0
3577
+
3578
+ @cached_function
3579
+ def inhomogeneity(r, n):
3580
+ try:
3581
+ return inhomogeneities[r][n]
3582
+ except KeyError:
3583
+ return 0
3584
+
3585
+ def f(n):
3586
+ f_n = values[n]
3587
+ if f_n is not None and f_n != "pending":
3588
+ return f_n
3589
+ elif f_n == "pending":
3590
+ missing_values.append(n)
3591
+ return 0
3592
+ else:
3593
+ values.update({n: "pending"})
3594
+ q, r = ZZ(n).quo_rem(k**M)
3595
+ if q < offset:
3596
+ missing_values.append(n)
3597
+ return sum([coeff(r, j)*f(k**m*q + j)
3598
+ for j in srange(l, u + 1)
3599
+ if coeff(r, j)]) + inhomogeneity(r, q)
3600
+
3601
+ for n in srange(last_value_needed + 1):
3602
+ values.update({n: f(n)})
3603
+
3604
+ if missing_values:
3605
+ raise ValueError("Initial values for arguments in %s are missing."
3606
+ % (list(set(missing_values)),))
3607
+
3608
+ for n in keys_initial:
3609
+ q, r = ZZ(n).quo_rem(k**M)
3610
+ if (q >= offset and
3611
+ values[n] != (sum([coeff(r, j)*values[k**m*q + j]
3612
+ for j in srange(l, u + 1)])) + inhomogeneity(r, q)):
3613
+ raise ValueError("Initial value for argument %s does not match with "
3614
+ "the given recurrence relations."
3615
+ % (n,))
3616
+
3617
+ values.update({n: 0 for n in srange(ll, 0)})
3618
+
3619
+ return values
3620
+
3621
+ @cached_method
3622
+ def ind(self, M, m, ll, uu):
3623
+ r"""
3624
+ Determine the index operator corresponding to the recursive
3625
+ sequence as defined in [HKL2022]_.
3626
+
3627
+ INPUT:
3628
+
3629
+ - ``M``, ``m`` -- parameters of the recursive sequences,
3630
+ see [HKL2022]_, Definition 3.1
3631
+
3632
+ - ``ll``, ``uu`` -- parameters of the resulting linear representation,
3633
+ see [HKL2022]_, Theorem A
3634
+
3635
+ OUTPUT:
3636
+
3637
+ A dictionary which maps both row numbers to subsequence parameters and
3638
+ vice versa, i.e.,
3639
+
3640
+ - ``ind[i]`` -- a pair ``(j, d)`` representing the sequence `x(k^j n + d)`
3641
+ in the `i`-th component (0-based) of the resulting linear representation
3642
+
3643
+ - ``ind[(j, d)]`` -- the (0-based) row number of the sequence
3644
+ `x(k^j n + d)` in the linear representation
3645
+
3646
+ EXAMPLES::
3647
+
3648
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
3649
+ sage: RP = RecurrenceParser(2, ZZ)
3650
+ sage: RP.ind(3, 1, -3, 3)
3651
+ {(0, 0): 0, (1, -1): 3, (1, -2): 2, (1, -3): 1,
3652
+ (1, 0): 4, (1, 1): 5, (1, 2): 6, (1, 3): 7, (2, -1): 10,
3653
+ (2, -2): 9, (2, -3): 8, (2, 0): 11, (2, 1): 12, (2, 2): 13,
3654
+ (2, 3): 14, (2, 4): 15, (2, 5): 16, 0: (0, 0), 1: (1, -3),
3655
+ 10: (2, -1), 11: (2, 0), 12: (2, 1), 13: (2, 2), 14: (2, 3),
3656
+ 15: (2, 4), 16: (2, 5), 2: (1, -2), 3: (1, -1), 4: (1, 0),
3657
+ 5: (1, 1), 6: (1, 2), 7: (1, 3), 8: (2, -3), 9: (2, -2)}
3658
+
3659
+ .. SEEALSO::
3660
+
3661
+ :meth:`RegularSequenceRing.from_recurrence`
3662
+ """
3663
+ from sage.arith.srange import srange
3664
+
3665
+ k = self.k
3666
+ ind = {}
3667
+
3668
+ pos = 0
3669
+ for j in srange(m):
3670
+ for d in srange(k**j):
3671
+ ind.update({(j, d): pos, pos: (j, d)})
3672
+ pos += 1
3673
+ for j in srange(m, M):
3674
+ for d in srange(ll, k**j - k**m + uu + 1):
3675
+ ind.update({(j, d): pos, pos: (j, d)})
3676
+ pos += 1
3677
+
3678
+ return ind
3679
+
3680
+ @cached_method(key=lambda self, recurrence_rules:
3681
+ (recurrence_rules.M,
3682
+ recurrence_rules.m,
3683
+ recurrence_rules.ll,
3684
+ recurrence_rules.uu,
3685
+ tuple(recurrence_rules.inhomogeneities.items())))
3686
+ def shifted_inhomogeneities(self, recurrence_rules):
3687
+ r"""
3688
+ Return a dictionary of all needed shifted inhomogeneities as described
3689
+ in the proof of Corollary D in [HKL2022]_.
3690
+
3691
+ INPUT:
3692
+
3693
+ - ``recurrence_rules`` -- a namedtuple generated by
3694
+ :meth:`parameters`
3695
+
3696
+ OUTPUT:
3697
+
3698
+ A dictionary mapping `r` to the regular sequence
3699
+ `\sum_i g_r(n + i)` for `g_r` as given in [HKL2022]_, Corollary D,
3700
+ and `i` between `\lfloor\ell'/k^{M}\rfloor` and
3701
+ `\lfloor (k^{M-1} - k^{m} + u')/k^{M}\rfloor + 1`; see [HKL2022]_,
3702
+ proof of Corollary D. The first blocks of the corresponding
3703
+ vector-valued sequence (obtained from its linear
3704
+ representation) correspond to the sequences `g_r(n + i)` where
3705
+ `i` is as in the sum above; the remaining blocks consist of
3706
+ other shifts which are required for the regular sequence.
3707
+
3708
+ EXAMPLES::
3709
+
3710
+ sage: from collections import namedtuple
3711
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
3712
+ sage: RP = RecurrenceParser(2, ZZ)
3713
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
3714
+ sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])),
3715
+ ....: left=vector([0, 1]), right=vector([1, 0]))
3716
+ sage: S
3717
+ 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ...
3718
+ sage: RR = namedtuple('recurrence_rules',
3719
+ ....: ['M', 'm', 'll', 'uu', 'inhomogeneities'])
3720
+ sage: recurrence_rules = RR(M=3, m=0, ll=-14, uu=14,
3721
+ ....: inhomogeneities={0: S, 1: S})
3722
+ sage: SI = RP.shifted_inhomogeneities(recurrence_rules)
3723
+ sage: SI
3724
+ {0: 2-regular sequence 4, 5, 7, 9, 11, 11, 11, 12, 13, 13, ...,
3725
+ 1: 2-regular sequence 4, 5, 7, 9, 11, 11, 11, 12, 13, 13, ...}
3726
+
3727
+ The first blocks of the corresponding vector-valued sequence correspond
3728
+ to the corresponding shifts of the inhomogeneity. In this particular
3729
+ case, there are no other blocks::
3730
+
3731
+ sage: lower = -2
3732
+ sage: upper = 3
3733
+ sage: SI[0].dimension() == S.dimension() * (upper - lower + 1)
3734
+ True
3735
+ sage: all(
3736
+ ....: Seq2(
3737
+ ....: SI[0].mu,
3738
+ ....: vector((i - lower)*[0, 0] + list(S.left) + (upper - i)*[0, 0]),
3739
+ ....: SI[0].right)
3740
+ ....: == S.subsequence(1, i)
3741
+ ....: for i in range(lower, upper+1))
3742
+ True
3743
+
3744
+ TESTS::
3745
+
3746
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
3747
+ sage: var('n')
3748
+ n
3749
+ sage: function('f')
3750
+ f
3751
+ sage: UB = Seq2.from_recurrence([
3752
+ ....: f(8*n) == 2*f(4*n),
3753
+ ....: f(8*n + 1) == f(4*n + 1),
3754
+ ....: f(8*n + 2) == f(4*n + 1) + f(4*n + 3),
3755
+ ....: f(8*n + 3) == -f(4*n + 1) + f(4*n + 2),
3756
+ ....: f(8*n + 4) == 2*f(4*n + 2),
3757
+ ....: f(8*n + 5) == f(4*n + 3),
3758
+ ....: f(8*n + 6) == -f(4*n + 1) + f(4*n + 2) + f(4*n + 3),
3759
+ ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3),
3760
+ ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2,
3761
+ ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4,
3762
+ ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4,
3763
+ ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0,
3764
+ ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n, offset=3)
3765
+ sage: inhomogeneities={2: UB.subsequence(4, 3), 3: -UB.subsequence(4, 1),
3766
+ ....: 6: UB.subsequence(4, 2) + UB.subsequence(4, 3)}
3767
+ sage: recurrence_rules_UB = RR(M=3, m=2, ll=0, uu=9,
3768
+ ....: inhomogeneities=inhomogeneities)
3769
+ sage: shifted_inhomog = RP.shifted_inhomogeneities(recurrence_rules_UB)
3770
+ sage: shifted_inhomog
3771
+ {2: 2-regular sequence 8, 8, 8, 12, 12, 16, 12, 16, 12, 24, ...,
3772
+ 3: 2-regular sequence -10, -8, -8, -8, -8, -8, -8, -8, -8, -12, ...,
3773
+ 6: 2-regular sequence 20, 22, 24, 28, 28, 32, 28, 32, 32, 48, ...}
3774
+ sage: shifted_inhomog[2].mu[0].ncols() == 3*inhomogeneities[2].mu[0].ncols()
3775
+ True
3776
+
3777
+ .. SEEALSO::
3778
+
3779
+ :meth:`RegularSequenceRing.from_recurrence`
3780
+ """
3781
+ from sage.arith.srange import srange
3782
+ from sage.functions.other import floor
3783
+
3784
+ k = self.k
3785
+ M = recurrence_rules.M
3786
+ m = recurrence_rules.m
3787
+ ll = recurrence_rules.ll
3788
+ uu = recurrence_rules.uu
3789
+ inhomogeneities = recurrence_rules.inhomogeneities
3790
+
3791
+ lower = floor(ll/k**M)
3792
+ upper = floor((k**(M-1) - k**m + uu)/k**M) + 1
3793
+
3794
+ return {i: inhomogeneities[i].subsequence(1, {b: 1 for b in srange(lower, upper + 1)},
3795
+ minimize=False)
3796
+ for i in inhomogeneities}
3797
+
3798
+ def v_eval_n(self, recurrence_rules, n):
3799
+ r"""
3800
+ Return the vector `v(n)` as given in [HKL2022]_, Theorem A.
3801
+
3802
+ INPUT:
3803
+
3804
+ - ``recurrence_rules`` -- a namedtuple generated by
3805
+ :meth:`parameters`
3806
+
3807
+ - ``n`` -- integer
3808
+
3809
+ OUTPUT: a vector
3810
+
3811
+ EXAMPLES:
3812
+
3813
+ Stern--Brocot Sequence::
3814
+
3815
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
3816
+ sage: RP = RecurrenceParser(2, ZZ)
3817
+ sage: SB_rules = RP.parameters(
3818
+ ....: 1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1},
3819
+ ....: {0: 0, 1: 1, 2: 1}, 0)
3820
+ sage: RP.v_eval_n(SB_rules, 0)
3821
+ (0, 1, 1)
3822
+
3823
+ .. SEEALSO::
3824
+
3825
+ :meth:`RegularSequenceRing.from_recurrence`
3826
+ """
3827
+ from itertools import chain
3828
+
3829
+ from sage.arith.srange import srange
3830
+ from sage.modules.free_module_element import vector
3831
+ from sage.rings.integer_ring import ZZ
3832
+
3833
+ k = self.k
3834
+ M = recurrence_rules.M
3835
+ m = recurrence_rules.m
3836
+ ll = recurrence_rules.ll
3837
+ uu = recurrence_rules.uu
3838
+ dim = recurrence_rules.dim - recurrence_rules.n1
3839
+ initial_values = recurrence_rules.initial_values
3840
+ inhomogeneities = recurrence_rules.inhomogeneities
3841
+ ind = self.ind(M, m, ll, uu)
3842
+
3843
+ v = vector([initial_values[k**ind[i][0]*n + ind[i][1]] for i in srange(dim)])
3844
+
3845
+ if not all(S.is_trivial_zero() for S in inhomogeneities.values()):
3846
+ Seq = list(inhomogeneities.values())[0].parent()
3847
+ W = Seq.indices()
3848
+ shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules)
3849
+ vv = [(S.coefficient_of_word(W(ZZ(n).digits(k)), multiply_left=False))
3850
+ for S in shifted_inhomogeneities.values()]
3851
+ v = vector(chain(v, *vv))
3852
+
3853
+ return v
3854
+
3855
+ def matrix(self, recurrence_rules, rem, correct_offset=True):
3856
+ r"""
3857
+ Construct the matrix for remainder ``rem`` of the linear
3858
+ representation of the sequence represented by ``recurrence_rules``.
3859
+
3860
+ INPUT:
3861
+
3862
+ - ``recurrence_rules`` -- a namedtuple generated by
3863
+ :meth:`parameters`
3864
+
3865
+ - ``rem`` -- integer between `0` and `k - 1`
3866
+
3867
+ - ``correct_offset`` -- boolean (default: ``True``); if
3868
+ ``True``, then the resulting linear representation has no
3869
+ offset. See [HKL2022]_ for more information.
3870
+
3871
+ OUTPUT: a matrix
3872
+
3873
+ EXAMPLES:
3874
+
3875
+ The following example illustrates how the coefficients in the
3876
+ right-hand sides of the recurrence relations correspond to the entries of
3877
+ the matrices. ::
3878
+
3879
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
3880
+ sage: RP = RecurrenceParser(2, ZZ)
3881
+ sage: var('n')
3882
+ n
3883
+ sage: function('f')
3884
+ f
3885
+ sage: M, m, coeffs, initial_values = RP.parse_recurrence([
3886
+ ....: f(8*n) == -1*f(2*n - 1) + 1*f(2*n + 1),
3887
+ ....: f(8*n + 1) == -11*f(2*n - 1) + 10*f(2*n) + 11*f(2*n + 1),
3888
+ ....: f(8*n + 2) == -21*f(2*n - 1) + 20*f(2*n) + 21*f(2*n + 1),
3889
+ ....: f(8*n + 3) == -31*f(2*n - 1) + 30*f(2*n) + 31*f(2*n + 1),
3890
+ ....: f(8*n + 4) == -41*f(2*n - 1) + 40*f(2*n) + 41*f(2*n + 1),
3891
+ ....: f(8*n + 5) == -51*f(2*n - 1) + 50*f(2*n) + 51*f(2*n + 1),
3892
+ ....: f(8*n + 6) == -61*f(2*n - 1) + 60*f(2*n) + 61*f(2*n + 1),
3893
+ ....: f(8*n + 7) == -71*f(2*n - 1) + 70*f(2*n) + 71*f(2*n + 1),
3894
+ ....: f(0) == 0, f(1) == 1, f(2) == 2, f(3) == 3, f(4) == 4,
3895
+ ....: f(5) == 5, f(6) == 6, f(7) == 7], f, n)
3896
+ sage: rules = RP.parameters(
3897
+ ....: M, m, coeffs, initial_values, 0)
3898
+ sage: RP.matrix(rules, 0, False)
3899
+ [ 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0]
3900
+ [ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0]
3901
+ [ 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0]
3902
+ [ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0]
3903
+ [ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0]
3904
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0]
3905
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0]
3906
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0]
3907
+ [ 0 -51 50 51 0 0 0 0 0 0 0 0 0 0 0 0 0]
3908
+ [ 0 -61 60 61 0 0 0 0 0 0 0 0 0 0 0 0 0]
3909
+ [ 0 -71 70 71 0 0 0 0 0 0 0 0 0 0 0 0 0]
3910
+ [ 0 0 0 -1 0 1 0 0 0 0 0 0 0 0 0 0 0]
3911
+ [ 0 0 0 -11 10 11 0 0 0 0 0 0 0 0 0 0 0]
3912
+ [ 0 0 0 -21 20 21 0 0 0 0 0 0 0 0 0 0 0]
3913
+ [ 0 0 0 -31 30 31 0 0 0 0 0 0 0 0 0 0 0]
3914
+ [ 0 0 0 -41 40 41 0 0 0 0 0 0 0 0 0 0 0]
3915
+ [ 0 0 0 -51 50 51 0 0 0 0 0 0 0 0 0 0 0]
3916
+ sage: RP.matrix(rules, 1, False)
3917
+ [ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0]
3918
+ [ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0]
3919
+ [ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0]
3920
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0]
3921
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0]
3922
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0]
3923
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0]
3924
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1]
3925
+ [ 0 0 0 -11 10 11 0 0 0 0 0 0 0 0 0 0 0]
3926
+ [ 0 0 0 -21 20 21 0 0 0 0 0 0 0 0 0 0 0]
3927
+ [ 0 0 0 -31 30 31 0 0 0 0 0 0 0 0 0 0 0]
3928
+ [ 0 0 0 -41 40 41 0 0 0 0 0 0 0 0 0 0 0]
3929
+ [ 0 0 0 -51 50 51 0 0 0 0 0 0 0 0 0 0 0]
3930
+ [ 0 0 0 -61 60 61 0 0 0 0 0 0 0 0 0 0 0]
3931
+ [ 0 0 0 -71 70 71 0 0 0 0 0 0 0 0 0 0 0]
3932
+ [ 0 0 0 0 0 -1 0 1 0 0 0 0 0 0 0 0 0]
3933
+ [ 0 0 0 0 0 -11 10 11 0 0 0 0 0 0 0 0 0]
3934
+
3935
+ Stern--Brocot Sequence::
3936
+
3937
+ sage: SB_rules = RP.parameters(
3938
+ ....: 1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1},
3939
+ ....: {0: 0, 1: 1, 2: 1}, 0)
3940
+ sage: RP.matrix(SB_rules, 0)
3941
+ [1 0 0]
3942
+ [1 1 0]
3943
+ [0 1 0]
3944
+ sage: RP.matrix(SB_rules, 1)
3945
+ [1 1 0]
3946
+ [0 1 0]
3947
+ [0 1 1]
3948
+
3949
+ Number of Unbordered Factors in the Thue--Morse Sequence::
3950
+
3951
+ sage: M, m, coeffs, initial_values = RP.parse_recurrence([
3952
+ ....: f(8*n) == 2*f(4*n),
3953
+ ....: f(8*n + 1) == f(4*n + 1),
3954
+ ....: f(8*n + 2) == f(4*n + 1) + f(4*n + 3),
3955
+ ....: f(8*n + 3) == -f(4*n + 1) + f(4*n + 2),
3956
+ ....: f(8*n + 4) == 2*f(4*n + 2),
3957
+ ....: f(8*n + 5) == f(4*n + 3),
3958
+ ....: f(8*n + 6) == -f(4*n + 1) + f(4*n + 2) + f(4*n + 3),
3959
+ ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3),
3960
+ ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2,
3961
+ ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4,
3962
+ ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4,
3963
+ ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0,
3964
+ ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n)
3965
+ sage: UB_rules = RP.parameters(
3966
+ ....: M, m, coeffs, initial_values, 3)
3967
+ sage: RP.matrix(UB_rules, 0)
3968
+ [ 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
3969
+ [ 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0]
3970
+ [ 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0]
3971
+ [ 0 0 0 2 0 0 0 0 0 0 0 0 0 -1 0 0]
3972
+ [ 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0]
3973
+ [ 0 0 0 0 1 0 1 0 0 0 0 0 0 -4 0 0]
3974
+ [ 0 0 0 0 -1 1 0 0 0 0 0 0 0 4 2 0]
3975
+ [ 0 0 0 0 0 2 0 0 0 0 0 0 0 -2 0 0]
3976
+ [ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0]
3977
+ [ 0 0 0 0 -1 1 1 0 0 0 0 0 0 2 2 0]
3978
+ [ 0 0 0 0 2 0 1 0 0 0 0 0 0 -8 -4 -4]
3979
+ [ 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0]
3980
+ [ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0]
3981
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0]
3982
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
3983
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0]
3984
+ sage: RP.matrix(UB_rules, 1)
3985
+ [ 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0]
3986
+ [ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0]
3987
+ [ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0]
3988
+ [ 0 0 0 0 0 2 0 0 0 0 0 0 0 -2 0 0]
3989
+ [ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0]
3990
+ [ 0 0 0 0 -1 1 1 0 0 0 0 0 0 2 2 0]
3991
+ [ 0 0 0 0 2 0 1 0 0 0 0 0 0 -8 -4 -4]
3992
+ [ 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0]
3993
+ [ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0]
3994
+ [ 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0]
3995
+ [ 0 0 0 0 0 0 0 0 -1 1 0 0 0 2 0 0]
3996
+ [ 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0]
3997
+ [ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0]
3998
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
3999
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0]
4000
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
4001
+
4002
+ .. SEEALSO::
4003
+
4004
+ :meth:`RegularSequenceRing.from_recurrence`
4005
+ """
4006
+ from itertools import chain
4007
+
4008
+ from sage.arith.srange import srange
4009
+ from sage.functions.other import floor
4010
+ from sage.matrix.constructor import Matrix
4011
+ from sage.matrix.special import block_matrix, block_diagonal_matrix, zero_matrix
4012
+ from sage.modules.free_module_element import vector
4013
+
4014
+ coefficient_ring = self.coefficient_ring
4015
+ k = self.k
4016
+ M = recurrence_rules.M
4017
+ m = recurrence_rules.m
4018
+ l = recurrence_rules.l
4019
+ ll = recurrence_rules.ll
4020
+ uu = recurrence_rules.uu
4021
+ dim = recurrence_rules.dim
4022
+ n1 = recurrence_rules.n1
4023
+ dim_without_corr = dim - n1
4024
+ coeffs = recurrence_rules.coeffs
4025
+ inhomogeneities = recurrence_rules.inhomogeneities
4026
+ ind = self.ind(M, m, ll, uu)
4027
+
4028
+ @cached_function
4029
+ def coeff(r, k):
4030
+ try:
4031
+ return coeffs[(r, k)]
4032
+ except KeyError:
4033
+ return 0
4034
+
4035
+ def entry(i, kk):
4036
+ j, d = ind[i]
4037
+ if j < M - 1:
4038
+ return int(kk == ind[(j + 1, k**j*rem + d)])
4039
+ else:
4040
+ rem_d = k**(M-1)*rem + (d % k**M)
4041
+ dd = d // k**M
4042
+ if rem_d < k**M:
4043
+ lambd = l - ind[(m, (k**m)*dd + l)]
4044
+ return coeff(rem_d, kk + lambd)
4045
+ else:
4046
+ lambd = l - ind[(m, k**m*dd + k**m + l)]
4047
+ return coeff(rem_d - k**M, kk + lambd)
4048
+
4049
+ mat = Matrix(coefficient_ring, dim_without_corr, dim_without_corr, entry)
4050
+
4051
+ if not all(S.is_trivial_zero() for S in inhomogeneities.values()):
4052
+ shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules)
4053
+ lower = floor(ll/k**M)
4054
+ upper = floor((k**(M-1) - k**m + uu)/k**M) + 1
4055
+
4056
+ def wanted_inhomogeneity(row):
4057
+ j, d = ind[row]
4058
+ if j != M - 1:
4059
+ return (None, None)
4060
+ rem_d = k**(M-1)*rem + (d % k**M)
4061
+ dd = d // k**M
4062
+ if rem_d < k**M:
4063
+ return (rem_d, dd)
4064
+ elif rem_d >= k**M:
4065
+ return (rem_d - k**M, dd + 1)
4066
+ else:
4067
+ return (None, None)
4068
+
4069
+ def left_for_inhomogeneity(wanted):
4070
+ return list(chain(*[(wanted == (r, i))*inhomogeneity.left
4071
+ for r, inhomogeneity in inhomogeneities.items()
4072
+ for i in srange(lower, upper + 1)]))
4073
+
4074
+ def matrix_row(row):
4075
+ wanted = wanted_inhomogeneity(row)
4076
+ return left_for_inhomogeneity(wanted)
4077
+
4078
+ mat_upper_right = Matrix([matrix_row(row) for row in srange(dim_without_corr)])
4079
+ mat_inhomog = block_diagonal_matrix([S.mu[rem]
4080
+ for S in shifted_inhomogeneities.values()],
4081
+ subdivide=False)
4082
+
4083
+ mat = block_matrix([[mat, mat_upper_right],
4084
+ [zero_matrix(mat_inhomog.nrows(), dim_without_corr),
4085
+ mat_inhomog]], subdivide=False)
4086
+
4087
+ dim_without_corr = mat.ncols()
4088
+ dim = dim_without_corr + n1
4089
+
4090
+ if n1 > 0 and correct_offset:
4091
+ W = Matrix(coefficient_ring, dim_without_corr, 0)
4092
+ for i in srange(n1):
4093
+ W = W.augment(
4094
+ self.v_eval_n(recurrence_rules, k*i + rem) -
4095
+ mat*self.v_eval_n(recurrence_rules, i))
4096
+
4097
+ J = Matrix(coefficient_ring, 0, n1)
4098
+ for i in srange(n1):
4099
+ J = J.stack(vector([int(j*k == i - rem) for j in srange(n1)]))
4100
+
4101
+ Z = zero_matrix(coefficient_ring, n1, dim_without_corr)
4102
+ mat = block_matrix([[mat, W], [Z, J]], subdivide=False)
4103
+
4104
+ return mat
4105
+
4106
+ def left(self, recurrence_rules):
4107
+ r"""
4108
+ Construct the vector ``left`` of the linear representation of
4109
+ recursive sequences.
4110
+
4111
+ INPUT:
4112
+
4113
+ - ``recurrence_rules`` -- a namedtuple generated by
4114
+ :meth:`parameters`; it only needs to contain a field
4115
+ ``dim`` (a positive integer)
4116
+
4117
+ OUTPUT: a vector
4118
+
4119
+ EXAMPLES::
4120
+
4121
+ sage: from collections import namedtuple
4122
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
4123
+ sage: RP = RecurrenceParser(2, ZZ)
4124
+ sage: RRD = namedtuple('recurrence_rules_dim',
4125
+ ....: ['dim', 'inhomogeneities'])
4126
+ sage: recurrence_rules = RRD(dim=5, inhomogeneities={})
4127
+ sage: RP.left(recurrence_rules)
4128
+ (1, 0, 0, 0, 0)
4129
+
4130
+ ::
4131
+
4132
+ sage: Seq2 = RegularSequenceRing(2, ZZ)
4133
+ sage: RRD = namedtuple('recurrence_rules_dim',
4134
+ ....: ['M', 'm', 'll', 'uu', 'dim', 'inhomogeneities'])
4135
+ sage: recurrence_rules = RRD(M=3, m=2, ll=0, uu=9, dim=5,
4136
+ ....: inhomogeneities={0: Seq2.one_hadamard()})
4137
+ sage: RP.left(recurrence_rules)
4138
+ (1, 0, 0, 0, 0, 0, 0, 0)
4139
+
4140
+ .. SEEALSO::
4141
+
4142
+ :meth:`RegularSequenceRing.from_recurrence`
4143
+ """
4144
+ from sage.modules.free_module_element import vector
4145
+
4146
+ dim = recurrence_rules.dim
4147
+ inhomogeneities = recurrence_rules.inhomogeneities
4148
+
4149
+ if not all(S.is_trivial_zero() for S in inhomogeneities.values()):
4150
+ shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules)
4151
+ dim += sum(shifted_inhomogeneities[i].mu[0].ncols()
4152
+ for i in shifted_inhomogeneities)
4153
+
4154
+ return vector([1] + (dim - 1)*[0])
4155
+
4156
+ def right(self, recurrence_rules):
4157
+ r"""
4158
+ Construct the vector ``right`` of the linear
4159
+ representation of the sequence induced by ``recurrence_rules``.
4160
+
4161
+ INPUT:
4162
+
4163
+ - ``recurrence_rules`` -- a namedtuple generated by
4164
+ :meth:`parameters`
4165
+
4166
+ OUTPUT: a vector
4167
+
4168
+ .. SEEALSO::
4169
+
4170
+ :meth:`RegularSequenceRing.from_recurrence`
4171
+
4172
+ TESTS:
4173
+
4174
+ Stern--Brocot Sequence::
4175
+
4176
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
4177
+ sage: RP = RecurrenceParser(2, ZZ)
4178
+ sage: var('n')
4179
+ n
4180
+ sage: function('f')
4181
+ f
4182
+ sage: SB_rules = RP.parameters(
4183
+ ....: 1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1},
4184
+ ....: {0: 0, 1: 1, 2: 1}, 0)
4185
+ sage: RP.right(SB_rules)
4186
+ (0, 1, 1)
4187
+
4188
+ Number of Unbordered Factors in the Thue--Morse Sequence::
4189
+
4190
+ sage: M, m, coeffs, initial_values = RP.parse_recurrence([
4191
+ ....: f(8*n) == 2*f(4*n),
4192
+ ....: f(8*n + 1) == f(4*n + 1),
4193
+ ....: f(8*n + 2) == f(4*n + 1) + f(4*n + 3),
4194
+ ....: f(8*n + 3) == -f(4*n + 1) + f(4*n + 2),
4195
+ ....: f(8*n + 4) == 2*f(4*n + 2),
4196
+ ....: f(8*n + 5) == f(4*n + 3),
4197
+ ....: f(8*n + 6) == -f(4*n + 1) + f(4*n + 2) + f(4*n + 3),
4198
+ ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3),
4199
+ ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2,
4200
+ ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4,
4201
+ ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4,
4202
+ ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0,
4203
+ ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n)
4204
+ sage: UB_rules = RP.parameters(
4205
+ ....: M, m, coeffs, initial_values, 3)
4206
+ sage: RP.right(UB_rules)
4207
+ (1, 1, 2, 1, 2, 2, 4, 2, 4, 6, 0, 4, 4, 1, 0, 0)
4208
+ """
4209
+ from sage.modules.free_module_element import vector
4210
+
4211
+ n1 = recurrence_rules.n1
4212
+ right = self.v_eval_n(recurrence_rules, 0)
4213
+
4214
+ if n1 >= 1:
4215
+ right = vector(list(right) + [1] + (n1 - 1)*[0])
4216
+
4217
+ return right
4218
+
4219
+ def __call__(self, *args, **kwds):
4220
+ r"""
4221
+ Construct a `k`-linear representation that fulfills the recurrence relations
4222
+ given in ``equations``.
4223
+
4224
+ This is the main method of :class:`RecurrenceParser` and
4225
+ is called by :meth:`RegularSequenceRing.from_recurrence`
4226
+ to construct a :class:`RegularSequence`.
4227
+
4228
+ INPUT:
4229
+
4230
+ All parameters are explained in the high-level method
4231
+ :meth:`RegularSequenceRing.from_recurrence`.
4232
+
4233
+ OUTPUT: a linear representation ``(left, mu, right)``
4234
+
4235
+ Many examples can be found in
4236
+ :meth:`RegularSequenceRing.from_recurrence`.
4237
+
4238
+ TESTS::
4239
+
4240
+ sage: from sage.combinat.regular_sequence import RecurrenceParser
4241
+ sage: RP = RecurrenceParser(2, ZZ)
4242
+ sage: var('n')
4243
+ n
4244
+ sage: function('f')
4245
+ f
4246
+
4247
+ sage: RP([f(2*n) == f(n), f(2*n + 1) == f(n) + f(n + 1),
4248
+ ....: f(0) == 0, f(1) == 1], f, n)
4249
+ ([
4250
+ [1 0 0] [1 1 0]
4251
+ [1 1 0] [0 1 0]
4252
+ [0 1 0], [0 1 1]
4253
+ ],
4254
+ (1, 0, 0),
4255
+ (0, 1, 1))
4256
+
4257
+ sage: RP(equations=[f(2*n) == f(n), f(2*n + 1) == f(n) + f(n + 1),
4258
+ ....: f(0) == 0, f(1) == 1], function=f, var=n)
4259
+ ([
4260
+ [1 0 0] [1 1 0]
4261
+ [1 1 0] [0 1 0]
4262
+ [0 1 0], [0 1 1]
4263
+ ],
4264
+ (1, 0, 0),
4265
+ (0, 1, 1))
4266
+
4267
+ sage: RP(1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, {0: 0, 1: 1})
4268
+ ([
4269
+ [1 0 0] [1 1 0]
4270
+ [1 1 0] [0 1 0]
4271
+ [0 1 0], [0 1 1]
4272
+ ],
4273
+ (1, 0, 0),
4274
+ (0, 1, 1))
4275
+
4276
+ sage: RP(M=1, m=0,
4277
+ ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1},
4278
+ ....: initial_values={0: 0, 1: 1})
4279
+ ([
4280
+ [1 0 0] [1 1 0]
4281
+ [1 1 0] [0 1 0]
4282
+ [0 1 0], [0 1 1]
4283
+ ],
4284
+ (1, 0, 0),
4285
+ (0, 1, 1))
4286
+ """
4287
+ from sage.arith.srange import srange
4288
+
4289
+ k = self.k
4290
+ if len(args) == 3:
4291
+ M, m, coeffs, initial_values = self.parse_recurrence(*args)
4292
+ elif len(args) == 0 and all(kwd in kwds for kwd in ['equations', 'function', 'var']):
4293
+ args = (kwds.pop('equations'),
4294
+ kwds.pop('function'),
4295
+ kwds.pop('var'))
4296
+ M, m, coeffs, initial_values = self.parse_recurrence(*args)
4297
+ elif len(args) == 4:
4298
+ M, m, coeffs, initial_values = self.parse_direct_arguments(*args)
4299
+ elif len(args) == 0 and all(kwd in kwds for kwd in ['M', 'm', 'coeffs', 'initial_values']):
4300
+ args = (kwds.pop('M'),
4301
+ kwds.pop('m'),
4302
+ kwds.pop('coeffs'),
4303
+ kwds.pop('initial_values'))
4304
+ M, m, coeffs, initial_values = self.parse_direct_arguments(*args)
4305
+ else:
4306
+ raise ValueError("Number of positional arguments must be three or four or all arguments provided as keywords.")
4307
+
4308
+ recurrence_rules = self.parameters(M, m, coeffs, initial_values, **kwds)
4309
+
4310
+ mu = [self.matrix(recurrence_rules, rem)
4311
+ for rem in srange(k)]
4312
+
4313
+ left = self.left(recurrence_rules)
4314
+ right = self.right(recurrence_rules)
4315
+
4316
+ return (mu, left, right)