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.
- passagemath_combinat/__init__.py +3 -0
- passagemath_combinat-10.6.42.dist-info/METADATA +160 -0
- passagemath_combinat-10.6.42.dist-info/RECORD +400 -0
- passagemath_combinat-10.6.42.dist-info/WHEEL +5 -0
- passagemath_combinat-10.6.42.dist-info/top_level.txt +3 -0
- passagemath_combinat.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
- passagemath_combinat.libs/libsymmetrica-81fe8739.so.3.0.0 +0 -0
- sage/algebras/affine_nil_temperley_lieb.py +263 -0
- sage/algebras/all.py +24 -0
- sage/algebras/all__sagemath_combinat.py +35 -0
- sage/algebras/askey_wilson.py +935 -0
- sage/algebras/associated_graded.py +345 -0
- sage/algebras/cellular_basis.py +350 -0
- sage/algebras/cluster_algebra.py +2766 -0
- sage/algebras/down_up_algebra.py +860 -0
- sage/algebras/free_algebra.py +1698 -0
- sage/algebras/free_algebra_element.py +345 -0
- sage/algebras/free_algebra_quotient.py +405 -0
- sage/algebras/free_algebra_quotient_element.py +295 -0
- sage/algebras/free_zinbiel_algebra.py +885 -0
- sage/algebras/hall_algebra.py +783 -0
- sage/algebras/hecke_algebras/all.py +4 -0
- sage/algebras/hecke_algebras/ariki_koike_algebra.py +1796 -0
- sage/algebras/hecke_algebras/ariki_koike_specht_modules.py +475 -0
- sage/algebras/hecke_algebras/cubic_hecke_algebra.py +3520 -0
- sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +1473 -0
- sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +1079 -0
- sage/algebras/iwahori_hecke_algebra.py +3095 -0
- sage/algebras/jordan_algebra.py +1773 -0
- sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py +113 -0
- sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py +156 -0
- sage/algebras/lie_conformal_algebras/all.py +18 -0
- sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +134 -0
- sage/algebras/lie_conformal_algebras/examples.py +43 -0
- sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py +131 -0
- sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py +139 -0
- sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py +174 -0
- sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py +167 -0
- sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py +107 -0
- sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py +135 -0
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py +353 -0
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py +236 -0
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py +78 -0
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py +328 -0
- sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py +117 -0
- sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py +86 -0
- sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py +82 -0
- sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +205 -0
- sage/algebras/nil_coxeter_algebra.py +191 -0
- sage/algebras/q_commuting_polynomials.py +673 -0
- sage/algebras/q_system.py +608 -0
- sage/algebras/quantum_clifford.py +959 -0
- sage/algebras/quantum_groups/ace_quantum_onsager.py +693 -0
- sage/algebras/quantum_groups/all.py +9 -0
- sage/algebras/quantum_groups/fock_space.py +2219 -0
- sage/algebras/quantum_groups/q_numbers.py +207 -0
- sage/algebras/quantum_groups/quantum_group_gap.py +2695 -0
- sage/algebras/quantum_groups/representations.py +591 -0
- sage/algebras/quantum_matrix_coordinate_algebra.py +1006 -0
- sage/algebras/quantum_oscillator.py +623 -0
- sage/algebras/quaternion_algebra.py +20 -0
- sage/algebras/quaternion_algebra_element.py +55 -0
- sage/algebras/rational_cherednik_algebra.py +525 -0
- sage/algebras/schur_algebra.py +670 -0
- sage/algebras/shuffle_algebra.py +1011 -0
- sage/algebras/splitting_algebra.py +779 -0
- sage/algebras/tensor_algebra.py +709 -0
- sage/algebras/yangian.py +1082 -0
- sage/algebras/yokonuma_hecke_algebra.py +1018 -0
- sage/all__sagemath_combinat.py +35 -0
- sage/combinat/SJT.py +255 -0
- sage/combinat/affine_permutation.py +2405 -0
- sage/combinat/algebraic_combinatorics.py +55 -0
- sage/combinat/all.py +53 -0
- sage/combinat/all__sagemath_combinat.py +195 -0
- sage/combinat/alternating_sign_matrix.py +2063 -0
- sage/combinat/baxter_permutations.py +346 -0
- sage/combinat/bijectionist.py +3220 -0
- sage/combinat/binary_recurrence_sequences.py +1180 -0
- sage/combinat/blob_algebra.py +685 -0
- sage/combinat/catalog_partitions.py +27 -0
- sage/combinat/chas/all.py +23 -0
- sage/combinat/chas/fsym.py +1180 -0
- sage/combinat/chas/wqsym.py +2601 -0
- sage/combinat/cluster_complex.py +326 -0
- sage/combinat/colored_permutations.py +2039 -0
- sage/combinat/colored_permutations_representations.py +964 -0
- sage/combinat/composition_signed.py +142 -0
- sage/combinat/composition_tableau.py +855 -0
- sage/combinat/constellation.py +1729 -0
- sage/combinat/core.py +751 -0
- sage/combinat/counting.py +12 -0
- sage/combinat/crystals/affine.py +742 -0
- sage/combinat/crystals/affine_factorization.py +518 -0
- sage/combinat/crystals/affinization.py +331 -0
- sage/combinat/crystals/alcove_path.py +2013 -0
- sage/combinat/crystals/all.py +22 -0
- sage/combinat/crystals/bkk_crystals.py +141 -0
- sage/combinat/crystals/catalog.py +115 -0
- sage/combinat/crystals/catalog_elementary_crystals.py +18 -0
- sage/combinat/crystals/catalog_infinity_crystals.py +33 -0
- sage/combinat/crystals/catalog_kirillov_reshetikhin.py +18 -0
- sage/combinat/crystals/crystals.py +257 -0
- sage/combinat/crystals/direct_sum.py +260 -0
- sage/combinat/crystals/elementary_crystals.py +1251 -0
- sage/combinat/crystals/fast_crystals.py +441 -0
- sage/combinat/crystals/fully_commutative_stable_grothendieck.py +1205 -0
- sage/combinat/crystals/generalized_young_walls.py +1076 -0
- sage/combinat/crystals/highest_weight_crystals.py +436 -0
- sage/combinat/crystals/induced_structure.py +695 -0
- sage/combinat/crystals/infinity_crystals.py +730 -0
- sage/combinat/crystals/kac_modules.py +863 -0
- sage/combinat/crystals/kirillov_reshetikhin.py +4196 -0
- sage/combinat/crystals/kyoto_path_model.py +497 -0
- sage/combinat/crystals/letters.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/crystals/letters.pxd +79 -0
- sage/combinat/crystals/letters.pyx +3056 -0
- sage/combinat/crystals/littelmann_path.py +1518 -0
- sage/combinat/crystals/monomial_crystals.py +1262 -0
- sage/combinat/crystals/multisegments.py +462 -0
- sage/combinat/crystals/mv_polytopes.py +467 -0
- sage/combinat/crystals/pbw_crystal.py +511 -0
- sage/combinat/crystals/pbw_datum.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/crystals/pbw_datum.pxd +4 -0
- sage/combinat/crystals/pbw_datum.pyx +487 -0
- sage/combinat/crystals/polyhedral_realization.py +372 -0
- sage/combinat/crystals/spins.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/crystals/spins.pxd +21 -0
- sage/combinat/crystals/spins.pyx +756 -0
- sage/combinat/crystals/star_crystal.py +290 -0
- sage/combinat/crystals/subcrystal.py +464 -0
- sage/combinat/crystals/tensor_product.py +1177 -0
- sage/combinat/crystals/tensor_product_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/crystals/tensor_product_element.pxd +35 -0
- sage/combinat/crystals/tensor_product_element.pyx +1870 -0
- sage/combinat/crystals/virtual_crystal.py +420 -0
- sage/combinat/cyclic_sieving_phenomenon.py +204 -0
- sage/combinat/debruijn_sequence.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/debruijn_sequence.pyx +355 -0
- sage/combinat/decorated_permutation.py +270 -0
- sage/combinat/degree_sequences.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/degree_sequences.pyx +588 -0
- sage/combinat/derangements.py +527 -0
- sage/combinat/descent_algebra.py +1008 -0
- sage/combinat/diagram.py +1551 -0
- sage/combinat/diagram_algebras.py +5886 -0
- sage/combinat/dyck_word.py +4349 -0
- sage/combinat/e_one_star.py +1623 -0
- sage/combinat/enumerated_sets.py +123 -0
- sage/combinat/expnums.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/expnums.pyx +148 -0
- sage/combinat/fast_vector_partitions.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/fast_vector_partitions.pyx +346 -0
- sage/combinat/fqsym.py +1977 -0
- sage/combinat/free_dendriform_algebra.py +954 -0
- sage/combinat/free_prelie_algebra.py +1141 -0
- sage/combinat/fully_commutative_elements.py +1077 -0
- sage/combinat/fully_packed_loop.py +1523 -0
- sage/combinat/gelfand_tsetlin_patterns.py +1409 -0
- sage/combinat/gray_codes.py +311 -0
- sage/combinat/grossman_larson_algebras.py +667 -0
- sage/combinat/growth.py +4352 -0
- sage/combinat/hall_polynomial.py +188 -0
- sage/combinat/hillman_grassl.py +866 -0
- sage/combinat/integer_matrices.py +329 -0
- sage/combinat/integer_vectors_mod_permgroup.py +1238 -0
- sage/combinat/k_tableau.py +4564 -0
- sage/combinat/kazhdan_lusztig.py +215 -0
- sage/combinat/key_polynomial.py +885 -0
- sage/combinat/knutson_tao_puzzles.py +2286 -0
- sage/combinat/lr_tableau.py +311 -0
- sage/combinat/matrices/all.py +24 -0
- sage/combinat/matrices/hadamard_matrix.py +3790 -0
- sage/combinat/matrices/latin.py +2912 -0
- sage/combinat/misc.py +401 -0
- sage/combinat/multiset_partition_into_sets_ordered.py +3541 -0
- sage/combinat/ncsf_qsym/all.py +21 -0
- sage/combinat/ncsf_qsym/combinatorics.py +317 -0
- sage/combinat/ncsf_qsym/generic_basis_code.py +1427 -0
- sage/combinat/ncsf_qsym/ncsf.py +5637 -0
- sage/combinat/ncsf_qsym/qsym.py +4053 -0
- sage/combinat/ncsf_qsym/tutorial.py +447 -0
- sage/combinat/ncsym/all.py +21 -0
- sage/combinat/ncsym/bases.py +855 -0
- sage/combinat/ncsym/dual.py +593 -0
- sage/combinat/ncsym/ncsym.py +2076 -0
- sage/combinat/necklace.py +551 -0
- sage/combinat/non_decreasing_parking_function.py +634 -0
- sage/combinat/nu_dyck_word.py +1474 -0
- sage/combinat/output.py +861 -0
- sage/combinat/parallelogram_polyomino.py +4326 -0
- sage/combinat/parking_functions.py +1602 -0
- sage/combinat/partition_algebra.py +1998 -0
- sage/combinat/partition_kleshchev.py +1982 -0
- sage/combinat/partition_shifting_algebras.py +584 -0
- sage/combinat/partition_tuple.py +3114 -0
- sage/combinat/path_tableaux/all.py +13 -0
- sage/combinat/path_tableaux/catalog.py +29 -0
- sage/combinat/path_tableaux/dyck_path.py +380 -0
- sage/combinat/path_tableaux/frieze.py +476 -0
- sage/combinat/path_tableaux/path_tableau.py +728 -0
- sage/combinat/path_tableaux/semistandard.py +510 -0
- sage/combinat/perfect_matching.py +779 -0
- sage/combinat/plane_partition.py +3300 -0
- sage/combinat/q_bernoulli.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/q_bernoulli.pyx +128 -0
- sage/combinat/quickref.py +81 -0
- sage/combinat/recognizable_series.py +2051 -0
- sage/combinat/regular_sequence.py +4316 -0
- sage/combinat/regular_sequence_bounded.py +543 -0
- sage/combinat/restricted_growth.py +81 -0
- sage/combinat/ribbon.py +20 -0
- sage/combinat/ribbon_shaped_tableau.py +489 -0
- sage/combinat/ribbon_tableau.py +1180 -0
- sage/combinat/rigged_configurations/all.py +46 -0
- sage/combinat/rigged_configurations/bij_abstract_class.py +548 -0
- sage/combinat/rigged_configurations/bij_infinity.py +370 -0
- sage/combinat/rigged_configurations/bij_type_A.py +163 -0
- sage/combinat/rigged_configurations/bij_type_A2_dual.py +338 -0
- sage/combinat/rigged_configurations/bij_type_A2_even.py +218 -0
- sage/combinat/rigged_configurations/bij_type_A2_odd.py +199 -0
- sage/combinat/rigged_configurations/bij_type_B.py +900 -0
- sage/combinat/rigged_configurations/bij_type_C.py +267 -0
- sage/combinat/rigged_configurations/bij_type_D.py +771 -0
- sage/combinat/rigged_configurations/bij_type_D_tri.py +392 -0
- sage/combinat/rigged_configurations/bij_type_D_twisted.py +576 -0
- sage/combinat/rigged_configurations/bij_type_E67.py +402 -0
- sage/combinat/rigged_configurations/bijection.py +143 -0
- sage/combinat/rigged_configurations/kleber_tree.py +1475 -0
- sage/combinat/rigged_configurations/kr_tableaux.py +1898 -0
- sage/combinat/rigged_configurations/rc_crystal.py +461 -0
- sage/combinat/rigged_configurations/rc_infinity.py +540 -0
- sage/combinat/rigged_configurations/rigged_configuration_element.py +2403 -0
- sage/combinat/rigged_configurations/rigged_configurations.py +1918 -0
- sage/combinat/rigged_configurations/rigged_partition.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/rigged_configurations/rigged_partition.pxd +15 -0
- sage/combinat/rigged_configurations/rigged_partition.pyx +680 -0
- sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py +499 -0
- sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element.py +428 -0
- sage/combinat/rsk.py +3438 -0
- sage/combinat/schubert_polynomial.py +508 -0
- sage/combinat/set_partition.py +3318 -0
- sage/combinat/set_partition_iterator.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/set_partition_iterator.pyx +136 -0
- sage/combinat/set_partition_ordered.py +1590 -0
- sage/combinat/sf/abreu_nigro.py +346 -0
- sage/combinat/sf/all.py +52 -0
- sage/combinat/sf/character.py +576 -0
- sage/combinat/sf/classical.py +319 -0
- sage/combinat/sf/dual.py +996 -0
- sage/combinat/sf/elementary.py +549 -0
- sage/combinat/sf/hall_littlewood.py +1028 -0
- sage/combinat/sf/hecke.py +336 -0
- sage/combinat/sf/homogeneous.py +464 -0
- sage/combinat/sf/jack.py +1428 -0
- sage/combinat/sf/k_dual.py +1458 -0
- sage/combinat/sf/kfpoly.py +447 -0
- sage/combinat/sf/llt.py +789 -0
- sage/combinat/sf/macdonald.py +2019 -0
- sage/combinat/sf/monomial.py +525 -0
- sage/combinat/sf/multiplicative.py +113 -0
- sage/combinat/sf/new_kschur.py +1786 -0
- sage/combinat/sf/ns_macdonald.py +964 -0
- sage/combinat/sf/orthogonal.py +246 -0
- sage/combinat/sf/orthotriang.py +355 -0
- sage/combinat/sf/powersum.py +963 -0
- sage/combinat/sf/schur.py +880 -0
- sage/combinat/sf/sf.py +1653 -0
- sage/combinat/sf/sfa.py +7053 -0
- sage/combinat/sf/symplectic.py +253 -0
- sage/combinat/sf/witt.py +721 -0
- sage/combinat/shifted_primed_tableau.py +2735 -0
- sage/combinat/shuffle.py +830 -0
- sage/combinat/sidon_sets.py +146 -0
- sage/combinat/similarity_class_type.py +1721 -0
- sage/combinat/sine_gordon.py +618 -0
- sage/combinat/six_vertex_model.py +784 -0
- sage/combinat/skew_partition.py +2053 -0
- sage/combinat/skew_tableau.py +2989 -0
- sage/combinat/sloane_functions.py +8935 -0
- sage/combinat/specht_module.py +1403 -0
- sage/combinat/species/all.py +48 -0
- sage/combinat/species/characteristic_species.py +321 -0
- sage/combinat/species/composition_species.py +273 -0
- sage/combinat/species/cycle_species.py +284 -0
- sage/combinat/species/empty_species.py +155 -0
- sage/combinat/species/functorial_composition_species.py +148 -0
- sage/combinat/species/generating_series.py +673 -0
- sage/combinat/species/library.py +148 -0
- sage/combinat/species/linear_order_species.py +169 -0
- sage/combinat/species/misc.py +83 -0
- sage/combinat/species/partition_species.py +290 -0
- sage/combinat/species/permutation_species.py +268 -0
- sage/combinat/species/product_species.py +423 -0
- sage/combinat/species/recursive_species.py +476 -0
- sage/combinat/species/set_species.py +192 -0
- sage/combinat/species/species.py +820 -0
- sage/combinat/species/structure.py +539 -0
- sage/combinat/species/subset_species.py +243 -0
- sage/combinat/species/sum_species.py +225 -0
- sage/combinat/subword.py +564 -0
- sage/combinat/subword_complex.py +2122 -0
- sage/combinat/subword_complex_c.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/subword_complex_c.pyx +119 -0
- sage/combinat/super_tableau.py +821 -0
- sage/combinat/superpartition.py +1154 -0
- sage/combinat/symmetric_group_algebra.py +3774 -0
- sage/combinat/symmetric_group_representations.py +1830 -0
- sage/combinat/t_sequences.py +877 -0
- sage/combinat/tableau.py +9506 -0
- sage/combinat/tableau_residues.py +860 -0
- sage/combinat/tableau_tuple.py +5353 -0
- sage/combinat/tiling.py +2432 -0
- sage/combinat/triangles_FHM.py +777 -0
- sage/combinat/tutorial.py +1857 -0
- sage/combinat/vector_partition.py +337 -0
- sage/combinat/words/abstract_word.py +1722 -0
- sage/combinat/words/all.py +59 -0
- sage/combinat/words/alphabet.py +268 -0
- sage/combinat/words/finite_word.py +7201 -0
- sage/combinat/words/infinite_word.py +113 -0
- sage/combinat/words/lyndon_word.py +652 -0
- sage/combinat/words/morphic.py +351 -0
- sage/combinat/words/morphism.py +3878 -0
- sage/combinat/words/paths.py +2932 -0
- sage/combinat/words/shuffle_product.py +278 -0
- sage/combinat/words/suffix_trees.py +1873 -0
- sage/combinat/words/word.py +769 -0
- sage/combinat/words/word_char.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/words/word_char.pyx +847 -0
- sage/combinat/words/word_datatypes.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/words/word_datatypes.pxd +4 -0
- sage/combinat/words/word_datatypes.pyx +1067 -0
- sage/combinat/words/word_generators.py +2026 -0
- sage/combinat/words/word_infinite_datatypes.py +1218 -0
- sage/combinat/words/word_options.py +99 -0
- sage/combinat/words/words.py +2396 -0
- sage/data_structures/all__sagemath_combinat.py +1 -0
- sage/databases/all__sagemath_combinat.py +13 -0
- sage/databases/findstat.py +4897 -0
- sage/databases/oeis.py +2058 -0
- sage/databases/sloane.py +393 -0
- sage/dynamics/all__sagemath_combinat.py +14 -0
- sage/dynamics/cellular_automata/all.py +7 -0
- sage/dynamics/cellular_automata/catalog.py +34 -0
- sage/dynamics/cellular_automata/elementary.py +612 -0
- sage/dynamics/cellular_automata/glca.py +477 -0
- sage/dynamics/cellular_automata/solitons.py +1463 -0
- sage/dynamics/finite_dynamical_system.py +1249 -0
- sage/dynamics/finite_dynamical_system_catalog.py +382 -0
- sage/games/all.py +7 -0
- sage/games/hexad.py +704 -0
- sage/games/quantumino.py +591 -0
- sage/games/sudoku.py +889 -0
- sage/games/sudoku_backtrack.cpython-314-x86_64-linux-musl.so +0 -0
- sage/games/sudoku_backtrack.pyx +189 -0
- sage/groups/all__sagemath_combinat.py +1 -0
- sage/groups/indexed_free_group.py +489 -0
- sage/libs/all__sagemath_combinat.py +6 -0
- sage/libs/lrcalc/__init__.py +1 -0
- sage/libs/lrcalc/lrcalc.py +525 -0
- sage/libs/symmetrica/__init__.py +7 -0
- sage/libs/symmetrica/all.py +101 -0
- sage/libs/symmetrica/kostka.pxi +168 -0
- sage/libs/symmetrica/part.pxi +193 -0
- sage/libs/symmetrica/plet.pxi +42 -0
- sage/libs/symmetrica/sab.pxi +196 -0
- sage/libs/symmetrica/sb.pxi +332 -0
- sage/libs/symmetrica/sc.pxi +192 -0
- sage/libs/symmetrica/schur.pxi +956 -0
- sage/libs/symmetrica/symmetrica.cpython-314-x86_64-linux-musl.so +0 -0
- sage/libs/symmetrica/symmetrica.pxi +1172 -0
- sage/libs/symmetrica/symmetrica.pyx +39 -0
- sage/monoids/all.py +13 -0
- sage/monoids/automatic_semigroup.py +1054 -0
- sage/monoids/free_abelian_monoid.py +315 -0
- sage/monoids/free_abelian_monoid_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/monoids/free_abelian_monoid_element.pxd +16 -0
- sage/monoids/free_abelian_monoid_element.pyx +397 -0
- sage/monoids/free_monoid.py +335 -0
- sage/monoids/free_monoid_element.py +431 -0
- sage/monoids/hecke_monoid.py +65 -0
- sage/monoids/string_monoid.py +817 -0
- sage/monoids/string_monoid_element.py +547 -0
- sage/monoids/string_ops.py +143 -0
- sage/monoids/trace_monoid.py +972 -0
- sage/rings/all__sagemath_combinat.py +2 -0
- sage/sat/all.py +4 -0
- sage/sat/boolean_polynomials.py +405 -0
- sage/sat/converters/__init__.py +6 -0
- sage/sat/converters/anf2cnf.py +14 -0
- sage/sat/converters/polybori.py +611 -0
- sage/sat/solvers/__init__.py +5 -0
- sage/sat/solvers/cryptominisat.py +287 -0
- sage/sat/solvers/dimacs.py +783 -0
- sage/sat/solvers/picosat.py +228 -0
- sage/sat/solvers/sat_lp.py +156 -0
- sage/sat/solvers/satsolver.cpython-314-x86_64-linux-musl.so +0 -0
- sage/sat/solvers/satsolver.pxd +3 -0
- 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)
|