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,1180 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-combinat
|
|
2
|
+
# sage.doctest: needs sage.combinat sage.modules
|
|
3
|
+
"""
|
|
4
|
+
Binary recurrence sequences
|
|
5
|
+
|
|
6
|
+
This class implements several methods relating to general linear binary
|
|
7
|
+
recurrence sequences, including a sieve to find perfect powers in integral
|
|
8
|
+
linear binary recurrence sequences.
|
|
9
|
+
|
|
10
|
+
EXAMPLES::
|
|
11
|
+
|
|
12
|
+
sage: R = BinaryRecurrenceSequence(1,1) #the Fibonacci sequence
|
|
13
|
+
sage: R(137) #the 137th term of the Fibonacci sequence
|
|
14
|
+
19134702400093278081449423917
|
|
15
|
+
sage: R(137) == fibonacci(137) # needs sage.libs.pari
|
|
16
|
+
True
|
|
17
|
+
sage: [R(i) % 4 for i in range(12)]
|
|
18
|
+
[0, 1, 1, 2, 3, 1, 0, 1, 1, 2, 3, 1]
|
|
19
|
+
sage: R.period(4) #the period of the fibonacci sequence modulo 4
|
|
20
|
+
6
|
|
21
|
+
sage: R.pthpowers(2, 10**10) # long time (7 seconds) -- in fact these are all squares, c.f. [BMS06]
|
|
22
|
+
[0, 1, 2, 12]
|
|
23
|
+
|
|
24
|
+
sage: S = BinaryRecurrenceSequence(8,1) #a Lucas sequence
|
|
25
|
+
sage: S.period(73)
|
|
26
|
+
148
|
|
27
|
+
sage: S(5) % 73 == S(5 +148) %73
|
|
28
|
+
True
|
|
29
|
+
sage: S.pthpowers(3, 10**10) # long time (3 seconds) -- provably finds the indices of all 3rd powers less than 10^10
|
|
30
|
+
[0, 1, 2]
|
|
31
|
+
|
|
32
|
+
sage: T = BinaryRecurrenceSequence(2,0,1,2)
|
|
33
|
+
sage: [T(i) for i in range(10)]
|
|
34
|
+
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
|
|
35
|
+
sage: T.is_degenerate()
|
|
36
|
+
True
|
|
37
|
+
sage: T.is_geometric()
|
|
38
|
+
True
|
|
39
|
+
sage: T.pthpowers(7, 10**30) # needs sage.symbolic
|
|
40
|
+
Traceback (most recent call last):
|
|
41
|
+
...
|
|
42
|
+
ValueError: the degenerate binary recurrence sequence is geometric or quasigeometric
|
|
43
|
+
and has many pth powers
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
AUTHORS:
|
|
47
|
+
|
|
48
|
+
- Isabel Vogt (2013): initial version
|
|
49
|
+
|
|
50
|
+
See [SV2013]_, [BMS2006]_, and [SS1983]_.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
# ****************************************************************************
|
|
54
|
+
# Copyright (C) 2013 Isabel Vogt <ivogt161@gmail.com>
|
|
55
|
+
#
|
|
56
|
+
# This program is free software: you can redistribute it and/or modify
|
|
57
|
+
# it under the terms of the GNU General Public License as published by
|
|
58
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
59
|
+
# (at your option) any later version.
|
|
60
|
+
# https://www.gnu.org/licenses/
|
|
61
|
+
# ****************************************************************************
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
from sage.structure.sage_object import SageObject
|
|
65
|
+
from sage.rings.finite_rings.integer_mod_ring import Integers
|
|
66
|
+
from sage.rings.finite_rings.finite_field_constructor import GF
|
|
67
|
+
from sage.rings.integer import Integer
|
|
68
|
+
from sage.arith.functions import lcm
|
|
69
|
+
from sage.arith.misc import is_prime, next_prime, next_prime_power, legendre_symbol
|
|
70
|
+
from sage.misc.lazy_import import lazy_import
|
|
71
|
+
from sage.misc.functional import sqrt
|
|
72
|
+
|
|
73
|
+
lazy_import("sage.functions.log", "log")
|
|
74
|
+
lazy_import("sage.rings.number_field.number_field", "QuadraticField")
|
|
75
|
+
lazy_import("sage.matrix.constructor", "matrix")
|
|
76
|
+
lazy_import("sage.modules.free_module_element", "vector")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class BinaryRecurrenceSequence(SageObject):
|
|
80
|
+
"""
|
|
81
|
+
Create a linear binary recurrence sequence defined by initial conditions
|
|
82
|
+
`u_0` and `u_1` and recurrence relation `u_{n+2} = b*u_{n+1}+c*u_n`.
|
|
83
|
+
|
|
84
|
+
INPUT:
|
|
85
|
+
|
|
86
|
+
- ``b`` -- integer; (partially determining the recurrence relation)
|
|
87
|
+
|
|
88
|
+
- ``c`` -- integer; (partially determining the recurrence relation)
|
|
89
|
+
|
|
90
|
+
- ``u0`` -- integer; (the `0`-th term of the binary recurrence sequence)
|
|
91
|
+
|
|
92
|
+
- ``u1`` -- integer; (the `1`-st term of the binary recurrence sequence)
|
|
93
|
+
|
|
94
|
+
OUTPUT: an integral linear binary recurrence sequence defined by `u_0`,
|
|
95
|
+
`u_1`, and `u_{n+2} = b u_{n+1}+c u_n`
|
|
96
|
+
|
|
97
|
+
.. SEEALSO::
|
|
98
|
+
|
|
99
|
+
:func:`fibonacci`, :func:`lucas_number1`, :func:`lucas_number2`
|
|
100
|
+
|
|
101
|
+
EXAMPLES::
|
|
102
|
+
|
|
103
|
+
sage: R = BinaryRecurrenceSequence(3,3,2,1)
|
|
104
|
+
sage: R
|
|
105
|
+
Binary recurrence sequence defined by: u_n = 3 * u_{n-1} + 3 * u_{n-2};
|
|
106
|
+
With initial conditions: u_0 = 2, and u_1 = 1
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
def __init__(self, b, c, u0=0, u1=1):
|
|
110
|
+
"""
|
|
111
|
+
See :class:`BinaryRecurrenceSequence` for full documentation.
|
|
112
|
+
|
|
113
|
+
EXAMPLES::
|
|
114
|
+
|
|
115
|
+
sage: R = BinaryRecurrenceSequence(3,3,2,1)
|
|
116
|
+
sage: R
|
|
117
|
+
Binary recurrence sequence defined by: u_n = 3 * u_{n-1} + 3 * u_{n-2};
|
|
118
|
+
With initial conditions: u_0 = 2, and u_1 = 1
|
|
119
|
+
|
|
120
|
+
sage: R = BinaryRecurrenceSequence(1,1)
|
|
121
|
+
sage: loads(R.dumps()) == R
|
|
122
|
+
True
|
|
123
|
+
"""
|
|
124
|
+
self.b = b
|
|
125
|
+
self.c = c
|
|
126
|
+
self.u0 = u0
|
|
127
|
+
self.u1 = u1
|
|
128
|
+
self._period_dict = {} # dictionary to cache the period of a sequence for future lookup
|
|
129
|
+
self._PGoodness = {} # dictionary to cache primes that are "good" by some prime power
|
|
130
|
+
self._ell = 1 # variable that keeps track of the last prime power to be used as a goodness
|
|
131
|
+
|
|
132
|
+
def __repr__(self) -> str:
|
|
133
|
+
"""
|
|
134
|
+
Give string representation of the class.
|
|
135
|
+
|
|
136
|
+
EXAMPLES::
|
|
137
|
+
|
|
138
|
+
sage: R = BinaryRecurrenceSequence(3,3,2,1)
|
|
139
|
+
sage: R
|
|
140
|
+
Binary recurrence sequence defined by: u_n = 3 * u_{n-1} + 3 * u_{n-2};
|
|
141
|
+
With initial conditions: u_0 = 2, and u_1 = 1
|
|
142
|
+
"""
|
|
143
|
+
return 'Binary recurrence sequence defined by: u_n = ' + str(self.b) + ' * u_{n-1} + ' + str(self.c) + ' * u_{n-2};\nWith initial conditions: u_0 = ' + str(self.u0) + ', and u_1 = ' + str(self.u1)
|
|
144
|
+
|
|
145
|
+
def __eq__(self, other) -> bool:
|
|
146
|
+
"""
|
|
147
|
+
Compare two binary recurrence sequences.
|
|
148
|
+
|
|
149
|
+
EXAMPLES::
|
|
150
|
+
|
|
151
|
+
sage: R = BinaryRecurrenceSequence(3,3,2,1)
|
|
152
|
+
sage: S = BinaryRecurrenceSequence(3,3,2,1)
|
|
153
|
+
sage: R == S
|
|
154
|
+
True
|
|
155
|
+
|
|
156
|
+
sage: T = BinaryRecurrenceSequence(3,3,2,2)
|
|
157
|
+
sage: R == T
|
|
158
|
+
False
|
|
159
|
+
"""
|
|
160
|
+
return (self.u0 == other.u0) and (self.u1 == other.u1) and (self.b == other.b) and (self.c == other.c)
|
|
161
|
+
|
|
162
|
+
def __call__(self, n, modulus=0):
|
|
163
|
+
"""
|
|
164
|
+
Give the `n`-th term of a binary recurrence sequence, possibly mod some modulus.
|
|
165
|
+
|
|
166
|
+
INPUT:
|
|
167
|
+
|
|
168
|
+
- ``n`` -- integer; the index of the term in the binary recurrence sequence
|
|
169
|
+
|
|
170
|
+
- ``modulus`` -- a natural number (optional -- default value is 0)
|
|
171
|
+
|
|
172
|
+
OUTPUT:
|
|
173
|
+
|
|
174
|
+
- An integer (the `n`-th term of the binary recurrence sequence modulo ``modulus``)
|
|
175
|
+
|
|
176
|
+
EXAMPLES::
|
|
177
|
+
|
|
178
|
+
sage: R = BinaryRecurrenceSequence(3,3,2,1)
|
|
179
|
+
sage: R(2)
|
|
180
|
+
9
|
|
181
|
+
sage: R(101)
|
|
182
|
+
16158686318788579168659644539538474790082623100896663971001
|
|
183
|
+
sage: R(101,12)
|
|
184
|
+
9
|
|
185
|
+
sage: R(101)%12
|
|
186
|
+
9
|
|
187
|
+
"""
|
|
188
|
+
R = Integers(modulus)
|
|
189
|
+
F = matrix(R, [[0, 1], [self.c, self.b]])
|
|
190
|
+
# F*[u_{n}, u_{n+1}]^T = [u_{n+1}, u_{n+2}]^T (T indicates transpose).
|
|
191
|
+
v = vector(R, [self.u0, self.u1])
|
|
192
|
+
return list(F**n * v)[0]
|
|
193
|
+
|
|
194
|
+
def is_degenerate(self) -> bool:
|
|
195
|
+
"""
|
|
196
|
+
Decide whether the binary recurrence sequence is degenerate.
|
|
197
|
+
|
|
198
|
+
Let `\\alpha` and `\\beta` denote the roots of the characteristic polynomial
|
|
199
|
+
`p(x) = x^2-bx -c`. Let `a = u_1-u_0\\beta/(\\beta - \\alpha)` and
|
|
200
|
+
`b = u_1-u_0\\alpha/(\\beta - \\alpha)`. The sequence is, thus, given by
|
|
201
|
+
`u_n = a \\alpha^n - b\\beta^n`. Then we say that the sequence is nondegenerate
|
|
202
|
+
if and only if `a*b*\\alpha*\\beta \\neq 0` and `\\alpha/\\beta` is not a
|
|
203
|
+
root of unity.
|
|
204
|
+
|
|
205
|
+
More concretely, there are 4 classes of degeneracy, that can all be formulated
|
|
206
|
+
in terms of the matrix `F = [[0,1], [c, b]]`.
|
|
207
|
+
|
|
208
|
+
- `F` is singular -- this corresponds to ``c`` = 0, and thus
|
|
209
|
+
`\\alpha*\\beta = 0`. This sequence is geometric after term ``u0``
|
|
210
|
+
and so we call it ``quasigeometric``
|
|
211
|
+
|
|
212
|
+
- `v = [[u_0], [u_1]]` is an eigenvector of `F` -- this corresponds to
|
|
213
|
+
a ``geometric`` sequence with `a*b = 0`
|
|
214
|
+
|
|
215
|
+
- `F` is nondiagonalizable -- this corresponds to `\\alpha = \\beta`.
|
|
216
|
+
This sequence will be the point-wise product of an arithmetic and
|
|
217
|
+
geometric sequence.
|
|
218
|
+
|
|
219
|
+
- `F^k` is scalar, for some `k>1` -- this corresponds to
|
|
220
|
+
`\\alpha/\\beta` a `k` th root of unity. This sequence is a union of
|
|
221
|
+
several geometric sequences, and so we again call it ``quasigeometric``.
|
|
222
|
+
|
|
223
|
+
EXAMPLES::
|
|
224
|
+
|
|
225
|
+
sage: S = BinaryRecurrenceSequence(0,1)
|
|
226
|
+
sage: S.is_degenerate()
|
|
227
|
+
True
|
|
228
|
+
sage: S.is_geometric()
|
|
229
|
+
False
|
|
230
|
+
sage: S.is_quasigeometric()
|
|
231
|
+
True
|
|
232
|
+
|
|
233
|
+
sage: R = BinaryRecurrenceSequence(3,-2)
|
|
234
|
+
sage: R.is_degenerate()
|
|
235
|
+
False
|
|
236
|
+
|
|
237
|
+
sage: T = BinaryRecurrenceSequence(2,-1)
|
|
238
|
+
sage: T.is_degenerate()
|
|
239
|
+
True
|
|
240
|
+
sage: T.is_arithmetic()
|
|
241
|
+
True
|
|
242
|
+
"""
|
|
243
|
+
D = self.b**2 + 4 * self.c
|
|
244
|
+
if D != 0:
|
|
245
|
+
if D.is_square():
|
|
246
|
+
A = sqrt(D)
|
|
247
|
+
else:
|
|
248
|
+
A = QuadraticField(D, 'x').gen()
|
|
249
|
+
|
|
250
|
+
aa = (self.u1 - self.u0 * (self.b + A)/2)/(A) # called `a` in Docstring
|
|
251
|
+
bb = (self.u1 - self.u0 * (self.b - A)/2)/(A) # called `b` in Docstring
|
|
252
|
+
|
|
253
|
+
# (b+A)/2 is called alpha in Docstring, (b-A)/2 is called beta in Docstring
|
|
254
|
+
|
|
255
|
+
if self.b != A:
|
|
256
|
+
if ((self.b+A)/(self.b-A))**6 == 1:
|
|
257
|
+
return True
|
|
258
|
+
else:
|
|
259
|
+
return True
|
|
260
|
+
|
|
261
|
+
return aa*bb*(self.b + A)*(self.b - A) == 0
|
|
262
|
+
|
|
263
|
+
return True
|
|
264
|
+
|
|
265
|
+
def is_geometric(self) -> bool:
|
|
266
|
+
"""
|
|
267
|
+
Decide whether the binary recurrence sequence is geometric - ie a geometric sequence.
|
|
268
|
+
|
|
269
|
+
This is a subcase of a degenerate binary recurrence sequence, for which `ab=0`, i.e.
|
|
270
|
+
`u_{n}/u_{n-1}=r` for some value of `r`.
|
|
271
|
+
|
|
272
|
+
See :meth:`is_degenerate` for a description of
|
|
273
|
+
degeneracy and definitions of `a` and `b`.
|
|
274
|
+
|
|
275
|
+
EXAMPLES::
|
|
276
|
+
|
|
277
|
+
sage: S = BinaryRecurrenceSequence(2,0,1,2)
|
|
278
|
+
sage: [S(i) for i in range(10)]
|
|
279
|
+
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
|
|
280
|
+
sage: S.is_geometric()
|
|
281
|
+
True
|
|
282
|
+
"""
|
|
283
|
+
# If [u_0, u_1]^T is an eigenvector for the incrementation matrix F = [[0,1],[c,b]], then the sequence
|
|
284
|
+
# is geometric, ie we can write u_n = a*r^n for some a and r.
|
|
285
|
+
|
|
286
|
+
# We decide if u0, u1, u2 = b*u1+c*u0 are in geometric progression by whether u1^2 = (b*u1+c*u0)*u0
|
|
287
|
+
|
|
288
|
+
return (self.u1)**2 == (self.b*self.u1 + self.c*self.u0)*self.u0
|
|
289
|
+
|
|
290
|
+
def is_quasigeometric(self) -> bool:
|
|
291
|
+
"""
|
|
292
|
+
Decide whether the binary recurrence sequence is degenerate and similar to a geometric sequence,
|
|
293
|
+
i.e. the union of multiple geometric sequences, or geometric after term ``u0``.
|
|
294
|
+
|
|
295
|
+
If `\\alpha/\\beta` is a `k` th root of unity, where `k>1`, then necessarily `k = 2, 3, 4, 6`.
|
|
296
|
+
Then `F = [[0,1],[c,b]` is diagonalizable, and `F^k = [[\\alpha^k, 0], [0,\\beta^k]]` is a diagonal
|
|
297
|
+
matrix. Thus for all values of `j` mod `k`, the `j` mod `k` terms of `u_n` form a geometric
|
|
298
|
+
series.
|
|
299
|
+
|
|
300
|
+
If `\\alpha` or `\\beta` is zero, this implies that `c=0`. This is the case when `F` is
|
|
301
|
+
singular. In this case, `u_1, u_2, u_3, ...` is geometric.
|
|
302
|
+
|
|
303
|
+
EXAMPLES::
|
|
304
|
+
|
|
305
|
+
sage: S = BinaryRecurrenceSequence(0,1)
|
|
306
|
+
sage: [S(i) for i in range(10)]
|
|
307
|
+
[0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
|
|
308
|
+
sage: S.is_quasigeometric()
|
|
309
|
+
True
|
|
310
|
+
|
|
311
|
+
sage: R = BinaryRecurrenceSequence(3,0)
|
|
312
|
+
sage: [R(i) for i in range(10)]
|
|
313
|
+
[0, 1, 3, 9, 27, 81, 243, 729, 2187, 6561]
|
|
314
|
+
sage: R.is_quasigeometric()
|
|
315
|
+
True
|
|
316
|
+
"""
|
|
317
|
+
# First test if F is singular... i.e. beta = 0
|
|
318
|
+
if self.c == 0:
|
|
319
|
+
return True
|
|
320
|
+
|
|
321
|
+
# Otherwise test if alpha/beta is a root of unity that is not 1
|
|
322
|
+
D = self.b**2 + 4 * self.c
|
|
323
|
+
if D != 0: # thus alpha/beta != 1
|
|
324
|
+
if D.is_square():
|
|
325
|
+
A = sqrt(D)
|
|
326
|
+
else:
|
|
327
|
+
A = QuadraticField(D, 'x').gen()
|
|
328
|
+
if ((self.b+A)/(self.b-A))**6 == 1:
|
|
329
|
+
return True
|
|
330
|
+
|
|
331
|
+
return False
|
|
332
|
+
|
|
333
|
+
def is_arithmetic(self) -> bool:
|
|
334
|
+
"""
|
|
335
|
+
Decide whether the sequence is degenerate and an arithmetic sequence.
|
|
336
|
+
|
|
337
|
+
The sequence is arithmetic if and only if `u_1 - u_0 = u_2 - u_1 = u_3 - u_2`.
|
|
338
|
+
|
|
339
|
+
This corresponds to the matrix `F = [[0,1],[c,b]]` being nondiagonalizable
|
|
340
|
+
and `\\alpha/\\beta = 1`.
|
|
341
|
+
|
|
342
|
+
EXAMPLES::
|
|
343
|
+
|
|
344
|
+
sage: S = BinaryRecurrenceSequence(2,-1)
|
|
345
|
+
sage: [S(i) for i in range(10)]
|
|
346
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
347
|
+
sage: S.is_arithmetic()
|
|
348
|
+
True
|
|
349
|
+
"""
|
|
350
|
+
return self(1) - self(0) == self(2) - self(1) == self(3) - self(2)
|
|
351
|
+
|
|
352
|
+
def period(self, m, *, eventual=False):
|
|
353
|
+
"""
|
|
354
|
+
Return the period of the binary recurrence sequence modulo
|
|
355
|
+
an integer ``m``.
|
|
356
|
+
|
|
357
|
+
If `n_1` is congruent to `n_2` modulo ``period(m)``, then `u_{n_1}` is
|
|
358
|
+
is congruent to `u_{n_2}` modulo ``m``.
|
|
359
|
+
|
|
360
|
+
INPUT:
|
|
361
|
+
|
|
362
|
+
- ``m`` -- integer; modulo which the period of the recurrence relation is calculated
|
|
363
|
+
|
|
364
|
+
- ``eventual`` -- boolean (default: ``False``); if ``True``, allow the
|
|
365
|
+
sequence to be eventually periodic, rather than requiring it to be
|
|
366
|
+
purely periodic. So `n_1` might not be congruent to `n_2` modulo
|
|
367
|
+
``period(m)`` unless `n_1` and `n_2` are large.
|
|
368
|
+
|
|
369
|
+
OUTPUT: integer (the period of the sequence modulo m)
|
|
370
|
+
|
|
371
|
+
EXAMPLES:
|
|
372
|
+
|
|
373
|
+
If `p = \\pm 1 \\mod 5`, then the period of the Fibonacci sequence
|
|
374
|
+
mod `p` is `p-1` (c.f. Lemma 3.3 of [BMS2006]_).
|
|
375
|
+
|
|
376
|
+
::
|
|
377
|
+
|
|
378
|
+
sage: R = BinaryRecurrenceSequence(1,1)
|
|
379
|
+
sage: R.period(31)
|
|
380
|
+
30
|
|
381
|
+
|
|
382
|
+
sage: [R(i) % 4 for i in range(12)]
|
|
383
|
+
[0, 1, 1, 2, 3, 1, 0, 1, 1, 2, 3, 1]
|
|
384
|
+
sage: R.period(4)
|
|
385
|
+
6
|
|
386
|
+
|
|
387
|
+
This function works for degenerate sequences as well.
|
|
388
|
+
|
|
389
|
+
::
|
|
390
|
+
|
|
391
|
+
sage: S = BinaryRecurrenceSequence(2,0,1,2)
|
|
392
|
+
sage: S.is_degenerate()
|
|
393
|
+
True
|
|
394
|
+
sage: S.is_geometric()
|
|
395
|
+
True
|
|
396
|
+
sage: [S(i) % 17 for i in range(16)]
|
|
397
|
+
[1, 2, 4, 8, 16, 15, 13, 9, 1, 2, 4, 8, 16, 15, 13, 9]
|
|
398
|
+
sage: S.period(17)
|
|
399
|
+
8
|
|
400
|
+
|
|
401
|
+
Letting ``eventual`` be ``True`` allows us to find the period of a
|
|
402
|
+
sequence that is not purely periodic. ::
|
|
403
|
+
|
|
404
|
+
sage: T = BinaryRecurrenceSequence(5,12,u0=0,u1=1)
|
|
405
|
+
sage: [T(n) % 10 for n in range(20)]
|
|
406
|
+
[0, 1, 5, 7, 5, 9, 5, 3, 5, 1, 5, 7, 5, 9, 5, 3, 5, 1, 5, 7]
|
|
407
|
+
sage: T.period(10)
|
|
408
|
+
Traceback (most recent call last):
|
|
409
|
+
...
|
|
410
|
+
ValueError: Binary recurrence sequence modulo 10 is not a purely
|
|
411
|
+
periodic sequence.
|
|
412
|
+
sage: T.period(10,eventual=True)
|
|
413
|
+
8
|
|
414
|
+
|
|
415
|
+
.. NOTE:: The answer is cached.
|
|
416
|
+
|
|
417
|
+
TESTS:
|
|
418
|
+
|
|
419
|
+
Verify that :issue:`38112` is fixed::
|
|
420
|
+
|
|
421
|
+
sage: T = BinaryRecurrenceSequence(3,2,u0=0,u1=1)
|
|
422
|
+
sage: [T(n) % 4 for n in range(5)]
|
|
423
|
+
[0, 1, 3, 3, 3]
|
|
424
|
+
sage: T.period(4)
|
|
425
|
+
Traceback (most recent call last):
|
|
426
|
+
...
|
|
427
|
+
ValueError: Binary recurrence sequence modulo 4 is not a purely
|
|
428
|
+
periodic sequence.
|
|
429
|
+
sage: T.period(4,eventual=True)
|
|
430
|
+
1
|
|
431
|
+
"""
|
|
432
|
+
|
|
433
|
+
# If we have already computed the period mod m, then we return the stored value.
|
|
434
|
+
|
|
435
|
+
if m in self._period_dict:
|
|
436
|
+
return self._period_dict[m]
|
|
437
|
+
|
|
438
|
+
else:
|
|
439
|
+
R = Integers(m)
|
|
440
|
+
A = matrix(R, [[0, 1], [self.c, self.b]])
|
|
441
|
+
w = vector(R, [self.u0, self.u1])
|
|
442
|
+
Fac = list(m.factor())
|
|
443
|
+
Periods = {}
|
|
444
|
+
|
|
445
|
+
if eventual is True:
|
|
446
|
+
# There are only m^2 possible pairs modulo m. Since the numbering
|
|
447
|
+
# of the sequence starts at 0, this implies that the term numbered
|
|
448
|
+
# m^2 must be in periodic part of the sequence. Hence, the
|
|
449
|
+
# sequence starting with the terms numbered m^2 and m^2 + 1 must
|
|
450
|
+
# be purely periodic.
|
|
451
|
+
an = (A**(m**2)) * w
|
|
452
|
+
return BinaryRecurrenceSequence(self.b, self.c,
|
|
453
|
+
an[0], an[1]).period(m, eventual=False)
|
|
454
|
+
|
|
455
|
+
# To compute the period mod m, we compute the least integer n such that A^n*w == w. This necessarily
|
|
456
|
+
# divides the order of A as a matrix in GL_2(Z/mZ).
|
|
457
|
+
|
|
458
|
+
# We compute the period modulo all distinct prime powers dividing m, and combine via the lcm.
|
|
459
|
+
# To compute the period mod p^e, we first compute the order mod p. Then the period mod p^e
|
|
460
|
+
# must divide p^{4e-4}*period(p), as the subgroup of matrices mod p^e, which reduce to
|
|
461
|
+
# the identity mod p is of order (p^{e-1})^4. So we compute the period mod p^e by successively
|
|
462
|
+
# multiplying the period mod p by powers of p.
|
|
463
|
+
|
|
464
|
+
for p, e in Fac:
|
|
465
|
+
# first compute the period mod p
|
|
466
|
+
if p in self._period_dict:
|
|
467
|
+
perp = self._period_dict[p]
|
|
468
|
+
else:
|
|
469
|
+
F = A.change_ring(GF(p))
|
|
470
|
+
v = w.change_ring(GF(p))
|
|
471
|
+
FF = F**(p-1)
|
|
472
|
+
p1fac = list((p-1).factor())
|
|
473
|
+
|
|
474
|
+
# The order of any matrix in GL_2(F_p) either divides p(p-1) or (p-1)(p+1).
|
|
475
|
+
# The order divides p-1 if it is diagonalizable. In any case, det(F^(p-1))=1,
|
|
476
|
+
# so if tr(F^(p-1)) = 2, then it must be triangular of the form [[1,a],[0,1]].
|
|
477
|
+
# The order of the subgroup of matrices of this form is p, so the order must divide
|
|
478
|
+
# p(p-1) -- in fact it must be a multiple of p. If this is not the case, then the
|
|
479
|
+
# order divides (p-1)(p+1). As the period divides the order of the matrix in GL_2(F_p),
|
|
480
|
+
# these conditions hold for the period as well.
|
|
481
|
+
|
|
482
|
+
# check if the order divides (p-1)
|
|
483
|
+
if FF*v == v:
|
|
484
|
+
M = p-1
|
|
485
|
+
Mfac = p1fac
|
|
486
|
+
|
|
487
|
+
# check if the trace is 2, then the order is a multiple of p dividing p*(p-1)
|
|
488
|
+
elif FF.trace() == 2:
|
|
489
|
+
M = p-1
|
|
490
|
+
Mfac = p1fac
|
|
491
|
+
F = F**p # replace F by F^p as now we only need to determine the factor dividing (p-1)
|
|
492
|
+
|
|
493
|
+
# otherwise it will divide (p+1)(p-1)
|
|
494
|
+
else:
|
|
495
|
+
M = (p+1)*(p-1)
|
|
496
|
+
p2fac = list((p+1).factor()) # factor the (p+1) and (p-1) terms separately and then combine for speed
|
|
497
|
+
Mfac_dic = {}
|
|
498
|
+
for i0, i1 in list(p1fac + p2fac):
|
|
499
|
+
if i0 not in Mfac_dic:
|
|
500
|
+
Mfac_dic[i0] = i1
|
|
501
|
+
else:
|
|
502
|
+
Mfac_dic[i0] += i1
|
|
503
|
+
Mfac = list(Mfac_dic.items())
|
|
504
|
+
|
|
505
|
+
# Now use a fast order algorithm to compute the period. We know that the period divides
|
|
506
|
+
# M = i_1*i_2*...*i_l where the i_j denote not necessarily distinct prime factors. As
|
|
507
|
+
# F^M*v == v, for each i_j, if F^(M/i_j)*v == v, then the period divides (M/i_j). After
|
|
508
|
+
# all factors have been iterated over, the result is the period mod p.
|
|
509
|
+
|
|
510
|
+
Mfac = list(Mfac)
|
|
511
|
+
|
|
512
|
+
# expand the list of prime factors so every factor is with multiplicity 1
|
|
513
|
+
C = [i0 for i0, i1 in Mfac for _ in range(i1)]
|
|
514
|
+
|
|
515
|
+
Mfac = C
|
|
516
|
+
n = M
|
|
517
|
+
for ii in Mfac:
|
|
518
|
+
b = n // ii
|
|
519
|
+
if F**b * v == v:
|
|
520
|
+
n = b
|
|
521
|
+
perp = n
|
|
522
|
+
|
|
523
|
+
# Now compute the period mod p^e by stepping up by multiples of p
|
|
524
|
+
F = A.change_ring(Integers(p**e))
|
|
525
|
+
v = w.change_ring(Integers(p**e))
|
|
526
|
+
FF = F**perp
|
|
527
|
+
if FF*v == v:
|
|
528
|
+
perpe = perp
|
|
529
|
+
else:
|
|
530
|
+
tries = 0
|
|
531
|
+
while True:
|
|
532
|
+
tries += 1
|
|
533
|
+
FF = FF**p
|
|
534
|
+
if FF*v == v:
|
|
535
|
+
perpe = perp*p**tries
|
|
536
|
+
break
|
|
537
|
+
if tries > e:
|
|
538
|
+
raise ValueError("Binary recurrence sequence " +
|
|
539
|
+
f"modulo {m} is not a purely " +
|
|
540
|
+
"periodic sequence.")
|
|
541
|
+
Periods[p] = perpe
|
|
542
|
+
|
|
543
|
+
# take the lcm of the periods mod all distinct primes dividing m
|
|
544
|
+
period = lcm(Periods.values())
|
|
545
|
+
|
|
546
|
+
self._period_dict[m] = period # cache the period mod m
|
|
547
|
+
return period
|
|
548
|
+
|
|
549
|
+
def pthpowers(self, p, Bound):
|
|
550
|
+
"""
|
|
551
|
+
Find the indices of proveably all `p`-th powers in the recurrence sequence
|
|
552
|
+
bounded by Bound.
|
|
553
|
+
|
|
554
|
+
Let `u_n` be a binary recurrence sequence. A ``p`` th power in `u_n`
|
|
555
|
+
is a solution to `u_n = y^p` for some integer `y`. There are only
|
|
556
|
+
finitely many ``p`` th powers in any recurrence sequence [SS1983]_.
|
|
557
|
+
|
|
558
|
+
INPUT:
|
|
559
|
+
|
|
560
|
+
- ``p`` -- a rational prime integer (the fixed p in `u_n = y^p`)
|
|
561
|
+
|
|
562
|
+
- ``Bound`` -- a natural number (the maximum index `n` in `u_n = y^p` that is checked)
|
|
563
|
+
|
|
564
|
+
OUTPUT:
|
|
565
|
+
|
|
566
|
+
A list of the indices of all ``p`` th powers less bounded by
|
|
567
|
+
``Bound``. If the sequence is degenerate and there are many
|
|
568
|
+
``p`` th powers, raises :exc:`ValueError`.
|
|
569
|
+
|
|
570
|
+
EXAMPLES::
|
|
571
|
+
|
|
572
|
+
sage: R = BinaryRecurrenceSequence(1,1) #the Fibonacci sequence
|
|
573
|
+
sage: R.pthpowers(2, 10**10) # long time (7 seconds) -- in fact these are all squares, c.f. [BMS2006]_
|
|
574
|
+
[0, 1, 2, 12]
|
|
575
|
+
|
|
576
|
+
sage: S = BinaryRecurrenceSequence(8,1) #a Lucas sequence
|
|
577
|
+
sage: S.pthpowers(3,10**10) # long time (3 seconds) -- provably finds the indices of all 3rd powers less than 10^10
|
|
578
|
+
[0, 1, 2]
|
|
579
|
+
|
|
580
|
+
sage: Q = BinaryRecurrenceSequence(3,3,2,1)
|
|
581
|
+
sage: Q.pthpowers(11,10**10) # long time (7.5 seconds)
|
|
582
|
+
[1]
|
|
583
|
+
|
|
584
|
+
If the sequence is degenerate, and there are no ``p`` th powers, returns `[]`. Otherwise, if
|
|
585
|
+
there are many ``p`` th powers, raises :exc:`ValueError`.
|
|
586
|
+
|
|
587
|
+
::
|
|
588
|
+
|
|
589
|
+
sage: T = BinaryRecurrenceSequence(2,0,1,2)
|
|
590
|
+
sage: T.is_degenerate()
|
|
591
|
+
True
|
|
592
|
+
sage: T.is_geometric()
|
|
593
|
+
True
|
|
594
|
+
sage: T.pthpowers(7, 10**30) # needs sage.symbolic
|
|
595
|
+
Traceback (most recent call last):
|
|
596
|
+
...
|
|
597
|
+
ValueError: the degenerate binary recurrence sequence is geometric or
|
|
598
|
+
quasigeometric and has many pth powers
|
|
599
|
+
|
|
600
|
+
sage: L = BinaryRecurrenceSequence(4,0,2,2)
|
|
601
|
+
sage: [L(i).factor() for i in range(10)]
|
|
602
|
+
[2, 2, 2^3, 2^5, 2^7, 2^9, 2^11, 2^13, 2^15, 2^17]
|
|
603
|
+
sage: L.is_quasigeometric()
|
|
604
|
+
True
|
|
605
|
+
sage: L.pthpowers(2, 10**30) # needs sage.symbolic
|
|
606
|
+
[]
|
|
607
|
+
|
|
608
|
+
.. NOTE::
|
|
609
|
+
|
|
610
|
+
This function is primarily optimized in the range where
|
|
611
|
+
``Bound`` is much larger than ``p``.
|
|
612
|
+
"""
|
|
613
|
+
# Thanks to Jesse Silliman for helpful conversations!
|
|
614
|
+
|
|
615
|
+
# Reset the dictionary of good primes, as this depends on p
|
|
616
|
+
self._PGoodness = {}
|
|
617
|
+
# Starting lower bound on good primes
|
|
618
|
+
self._ell = 1
|
|
619
|
+
|
|
620
|
+
# If the sequence is geometric, then the `n`th term is `a*r^n`. Thus the
|
|
621
|
+
# property of being a ``p`` th power is periodic mod ``p``. So there are either
|
|
622
|
+
# no ``p`` th powers if there are none in the first ``p`` terms, or many if there
|
|
623
|
+
# is at least one in the first ``p`` terms.
|
|
624
|
+
|
|
625
|
+
if self.is_geometric() or self.is_quasigeometric():
|
|
626
|
+
no_powers = True
|
|
627
|
+
for i in range(1, 6*p+1):
|
|
628
|
+
if _is_p_power(self(i), p):
|
|
629
|
+
no_powers = False
|
|
630
|
+
break
|
|
631
|
+
if no_powers:
|
|
632
|
+
if _is_p_power(self.u0, p):
|
|
633
|
+
return [0]
|
|
634
|
+
return []
|
|
635
|
+
else:
|
|
636
|
+
raise ValueError("the degenerate binary recurrence sequence is geometric or quasigeometric and has many pth powers")
|
|
637
|
+
|
|
638
|
+
# If the sequence is degenerate without being geometric or quasigeometric, there
|
|
639
|
+
# may be many ``p`` th powers or no ``p`` th powers.
|
|
640
|
+
|
|
641
|
+
elif (self.b**2+4*self.c) == 0:
|
|
642
|
+
|
|
643
|
+
# This is the case if the matrix F is not diagonalizable, ie b^2 +4c = 0, and alpha/beta = 1.
|
|
644
|
+
|
|
645
|
+
alpha = self.b/2
|
|
646
|
+
|
|
647
|
+
# In this case, u_n = u_0*alpha^n + (u_1 - u_0*alpha)*n*alpha^(n-1) = alpha^(n-1)*(u_0 +n*(u_1 - u_0*alpha)),
|
|
648
|
+
# that is, it is a geometric term (alpha^(n-1)) times an arithmetic term (u_0 + n*(u_1-u_0*alpha)).
|
|
649
|
+
|
|
650
|
+
# Look at classes n = k mod p, for k = 1,...,p.
|
|
651
|
+
|
|
652
|
+
for k in range(1, p + 1):
|
|
653
|
+
|
|
654
|
+
# The linear equation alpha^(k-1)*u_0 + (k+pm)*(alpha^(k-1)*u1 - u0*alpha^k)
|
|
655
|
+
# must thus be a pth power. This is a linear equation in m, namely, A + B*m, where
|
|
656
|
+
|
|
657
|
+
A = (alpha**(k-1)*self.u0 + k*(alpha**(k-1)*self.u1 - self.u0*alpha**k))
|
|
658
|
+
B = p*(alpha**(k-1)*self.u1 - self.u0*alpha**k)
|
|
659
|
+
|
|
660
|
+
# This linear equation represents a pth power iff A is a pth power mod B.
|
|
661
|
+
|
|
662
|
+
if _is_p_power_mod(A, p, B):
|
|
663
|
+
raise ValueError("the degenerate binary recurrence sequence has many pth powers")
|
|
664
|
+
return []
|
|
665
|
+
|
|
666
|
+
# We find ``p`` th powers using an elementary sieve. Term `u_n` is a ``p`` th
|
|
667
|
+
# power if and only if it is a ``p`` th power modulo every prime `\\ell`. This condition
|
|
668
|
+
# gives nontrivial information if ``p`` divides the order of the multiplicative group of
|
|
669
|
+
# `\\Bold(F)_{\\ell}`, i.e. if `\\ell` is ` 1 \mod{p}`, as then only `1/p` terms are ``p`` th
|
|
670
|
+
# powers modulo `\\ell``.
|
|
671
|
+
|
|
672
|
+
# Thus, given such an `\\ell`, we get a set of necessary congruences for the index modulo the
|
|
673
|
+
# the period of the sequence mod `\\ell`. Then we intersect these congruences for many primes
|
|
674
|
+
# to get a tight list modulo a growing modulus. In order to keep this step manageable, we
|
|
675
|
+
# only use primes `\\ell` that have particularly smooth periods.
|
|
676
|
+
|
|
677
|
+
# Some congruences in the list will remain as the modulus grows. If a congruence remains through
|
|
678
|
+
# 7 rounds of increasing the modulus, then we check if this corresponds to a perfect power (if
|
|
679
|
+
# it does, we add it to our list of indices corresponding to ``p`` th powers). The rest of the congruences
|
|
680
|
+
# are transient and grow with the modulus. Once the smallest of these is greater than the bound,
|
|
681
|
+
# the list of known indices corresponding to ``p`` th powers is complete.
|
|
682
|
+
|
|
683
|
+
else:
|
|
684
|
+
|
|
685
|
+
if Bound < 3 * p:
|
|
686
|
+
|
|
687
|
+
powers = []
|
|
688
|
+
ell = p + 1
|
|
689
|
+
|
|
690
|
+
while not is_prime(ell):
|
|
691
|
+
ell += p
|
|
692
|
+
|
|
693
|
+
F = GF(ell)
|
|
694
|
+
a0 = F(self.u0)
|
|
695
|
+
a1 = F(self.u1) # a0 and a1 are variables for terms in sequence
|
|
696
|
+
bf, cf = F(self.b), F(self.c)
|
|
697
|
+
|
|
698
|
+
for n in range(Bound): # n is the index of the a0
|
|
699
|
+
|
|
700
|
+
# Check whether a0 is a perfect power mod ell
|
|
701
|
+
if _is_p_power_mod(a0, p, ell):
|
|
702
|
+
# if a0 is a perfect power mod ell, check if nth term is ppower
|
|
703
|
+
if _is_p_power(self(n), p):
|
|
704
|
+
powers.append(n)
|
|
705
|
+
|
|
706
|
+
a0, a1 = a1, bf*a1 + cf*a0 # step up the variables
|
|
707
|
+
|
|
708
|
+
else:
|
|
709
|
+
|
|
710
|
+
powers = [] # documents the indices of the sequence that provably correspond to pth powers
|
|
711
|
+
cong = [0] # list of necessary congruences on the index for it to correspond to pth powers
|
|
712
|
+
Possible_count = {} # keeps track of the number of rounds a congruence lasts in cong
|
|
713
|
+
|
|
714
|
+
# These parameters are involved in how we choose primes to increase the modulus
|
|
715
|
+
qqold = 1 # we believe that we know complete information coming from primes good by qqold
|
|
716
|
+
M1 = 1 # we have congruences modulo M1, this may not be the tightest list
|
|
717
|
+
M2 = p # we want to move to have congruences mod M2
|
|
718
|
+
qq = 1 # the largest prime power divisor of M1 is qq
|
|
719
|
+
|
|
720
|
+
# This loop ups the modulus.
|
|
721
|
+
while True:
|
|
722
|
+
|
|
723
|
+
# Try to get good data mod M2
|
|
724
|
+
|
|
725
|
+
# patience of how long we should search for a "good prime"
|
|
726
|
+
patience = 0.01 * _estimated_time(lcm(M2, p * next_prime_power(qq)),
|
|
727
|
+
M1, len(cong), p)
|
|
728
|
+
tries = 0
|
|
729
|
+
|
|
730
|
+
# This loop uses primes to get a small set of congruences mod M2.
|
|
731
|
+
while True:
|
|
732
|
+
|
|
733
|
+
# only proceed if took less than patience time to find the next good prime
|
|
734
|
+
ell = _next_good_prime(p, self, qq, patience, qqold)
|
|
735
|
+
if ell:
|
|
736
|
+
|
|
737
|
+
# gather congruence data for the sequence mod ell, which will be mod period(ell) = modu
|
|
738
|
+
cong1, modu = _find_cong1(p, self, ell)
|
|
739
|
+
|
|
740
|
+
# makes a new list from cong that is now mod M = lcm(M1, modu) instead of M1
|
|
741
|
+
M = lcm(M1, modu)
|
|
742
|
+
CongNew = [k * M1 + i for k in range(M // M1)
|
|
743
|
+
for i in cong]
|
|
744
|
+
cong = set(CongNew)
|
|
745
|
+
|
|
746
|
+
M1 = M
|
|
747
|
+
|
|
748
|
+
killed_something = False # keeps track of when cong1 can rule out a congruence in cong
|
|
749
|
+
|
|
750
|
+
# CRT by hand to gain speed
|
|
751
|
+
for i in list(cong):
|
|
752
|
+
if i % modu not in cong1: # congruence in cong is inconsistent with any in cong1
|
|
753
|
+
cong.remove(i) # remove that congruence
|
|
754
|
+
killed_something = True
|
|
755
|
+
|
|
756
|
+
if M1 == M2:
|
|
757
|
+
if not killed_something:
|
|
758
|
+
tries += 1
|
|
759
|
+
if tries == 2: # try twice to rule out congruences
|
|
760
|
+
cong = list(cong)
|
|
761
|
+
qqold = qq
|
|
762
|
+
qq = next_prime_power(qq)
|
|
763
|
+
M2 = lcm(M2, p * qq)
|
|
764
|
+
break
|
|
765
|
+
|
|
766
|
+
else:
|
|
767
|
+
qq = next_prime_power(qq)
|
|
768
|
+
M2 = lcm(M2, p * qq)
|
|
769
|
+
cong = list(cong)
|
|
770
|
+
break
|
|
771
|
+
|
|
772
|
+
# Document how long each element of cong has been there
|
|
773
|
+
for i in cong:
|
|
774
|
+
if i in Possible_count:
|
|
775
|
+
Possible_count[i] += 1
|
|
776
|
+
else:
|
|
777
|
+
Possible_count[i] = 1
|
|
778
|
+
|
|
779
|
+
# Check how long each element has persisted, if it is for at least 7 cycles,
|
|
780
|
+
# then we check to see if it is actually a perfect power
|
|
781
|
+
for i, pci in Possible_count.items():
|
|
782
|
+
if pci == 7:
|
|
783
|
+
n = Integer(i)
|
|
784
|
+
if n < Bound:
|
|
785
|
+
if _is_p_power(self(n), p):
|
|
786
|
+
powers.append(n)
|
|
787
|
+
|
|
788
|
+
# check for a contradiction
|
|
789
|
+
if len(cong) > len(powers):
|
|
790
|
+
if cong[len(powers)] > Bound:
|
|
791
|
+
break
|
|
792
|
+
elif M1 > Bound:
|
|
793
|
+
break
|
|
794
|
+
|
|
795
|
+
return powers
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
def _prime_powers(N):
|
|
799
|
+
r"""
|
|
800
|
+
Find the prime powers dividing `N`.
|
|
801
|
+
|
|
802
|
+
In other words, if `N = q_1^{e_1} q_2^{e_2} \cdots q_n^{e_n}`, it returns
|
|
803
|
+
`[q_1^{e_1}, q_2^{e_2}, \ldots, q_n^{e_n}]`.
|
|
804
|
+
|
|
805
|
+
INPUT:
|
|
806
|
+
|
|
807
|
+
- ``N`` -- integer
|
|
808
|
+
|
|
809
|
+
OUTPUT: list of the prime powers dividing N
|
|
810
|
+
|
|
811
|
+
EXAMPLES::
|
|
812
|
+
|
|
813
|
+
sage: sage.combinat.binary_recurrence_sequences._prime_powers(124656)
|
|
814
|
+
[3, 16, 49, 53]
|
|
815
|
+
|
|
816
|
+
sage: sage.combinat.binary_recurrence_sequences._prime_powers(65537)
|
|
817
|
+
[65537]
|
|
818
|
+
"""
|
|
819
|
+
return sorted(i**j for i, j in N.factor())
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
def _largest_ppower_divisor(N):
|
|
823
|
+
"""
|
|
824
|
+
Find the largest prime power divisor of `N`.
|
|
825
|
+
|
|
826
|
+
INPUT:
|
|
827
|
+
|
|
828
|
+
- ``N`` -- integer
|
|
829
|
+
|
|
830
|
+
OUTPUT: the largest prime power dividing `N`
|
|
831
|
+
|
|
832
|
+
EXAMPLES::
|
|
833
|
+
|
|
834
|
+
sage: sage.combinat.binary_recurrence_sequences._largest_ppower_divisor(124656)
|
|
835
|
+
53
|
|
836
|
+
sage: sage.combinat.binary_recurrence_sequences._largest_ppower_divisor(65537)
|
|
837
|
+
65537
|
|
838
|
+
"""
|
|
839
|
+
return _prime_powers(N)[-1]
|
|
840
|
+
|
|
841
|
+
|
|
842
|
+
def _goodness(n, R, p):
|
|
843
|
+
"""
|
|
844
|
+
Return the goodness of `n` for the sequence `R` and the prime `p` -- that is the largest
|
|
845
|
+
non-`p` prime power dividing ``period(n)``.
|
|
846
|
+
|
|
847
|
+
INPUT:
|
|
848
|
+
|
|
849
|
+
- ``n`` -- an integer
|
|
850
|
+
|
|
851
|
+
- ``R`` -- an object in the class ``BinaryRecurrenceSequence``
|
|
852
|
+
|
|
853
|
+
- ``p`` -- a rational prime
|
|
854
|
+
|
|
855
|
+
OUTPUT:
|
|
856
|
+
|
|
857
|
+
- An integer which is the "goodness" of ``n``, i.e. the largest non-``p`` prime power dividing ``period(n)``.
|
|
858
|
+
|
|
859
|
+
EXAMPLES::
|
|
860
|
+
|
|
861
|
+
sage: R = BinaryRecurrenceSequence(11,2)
|
|
862
|
+
sage: sage.combinat.binary_recurrence_sequences._goodness(89,R,7)
|
|
863
|
+
11
|
|
864
|
+
|
|
865
|
+
sage: R = BinaryRecurrenceSequence(1,1)
|
|
866
|
+
sage: sage.combinat.binary_recurrence_sequences._goodness(13,R,7)
|
|
867
|
+
4
|
|
868
|
+
sage: R.period(13) #the period of R mod 13 is divisible by 7
|
|
869
|
+
28
|
|
870
|
+
"""
|
|
871
|
+
# The period of R mod ell
|
|
872
|
+
K = R.period(n)
|
|
873
|
+
return _largest_ppower_divisor(K // K.gcd(p))
|
|
874
|
+
|
|
875
|
+
|
|
876
|
+
def _next_good_prime(p, R, qq, patience, qqold):
|
|
877
|
+
r"""
|
|
878
|
+
Find the next prime `\ell` which is good by ``qq`` but not by ``qqold``, 1 mod ``p``, and for which
|
|
879
|
+
``b^2+4*c`` is a square mod `\ell`, for the sequence ``R`` if it is possible in runtime patience.
|
|
880
|
+
|
|
881
|
+
INPUT:
|
|
882
|
+
|
|
883
|
+
- ``p`` -- a prime
|
|
884
|
+
|
|
885
|
+
- ``R`` -- an object in the class ``BinaryRecurrenceSequence``
|
|
886
|
+
|
|
887
|
+
- ``qq`` -- a perfect power
|
|
888
|
+
|
|
889
|
+
- ``patience`` -- a real number
|
|
890
|
+
|
|
891
|
+
- ``qqold`` -- a perfect power less than or equal to ``qq``
|
|
892
|
+
|
|
893
|
+
OUTPUT: a prime `\ell` such that `\ell` is 1 mod `p`, `b^2+4 c` is a
|
|
894
|
+
square mod `\ell` and the period of `\ell` has ``goodness`` by ``qq`` but
|
|
895
|
+
not ``qqold``, if patience has not be surpased; otherwise ``False``
|
|
896
|
+
|
|
897
|
+
EXAMPLES::
|
|
898
|
+
|
|
899
|
+
sage: # needs sage.libs.pari
|
|
900
|
+
sage: R = BinaryRecurrenceSequence(1,1)
|
|
901
|
+
sage: sage.combinat.binary_recurrence_sequences._next_good_prime(7,R,1,100,1) #ran out of patience to search for good primes
|
|
902
|
+
False
|
|
903
|
+
sage: sage.combinat.binary_recurrence_sequences._next_good_prime(7,R,2,100,1)
|
|
904
|
+
29
|
|
905
|
+
sage: sage.combinat.binary_recurrence_sequences._next_good_prime(7,R,2,100,2) #ran out of patience, as qqold == qq, so no primes work
|
|
906
|
+
False
|
|
907
|
+
"""
|
|
908
|
+
# We are looking for pth powers in R.
|
|
909
|
+
# Our primes must be good by qq, but not qqold.
|
|
910
|
+
# We only allow patience number of iterations to find a good prime.
|
|
911
|
+
|
|
912
|
+
# The variable _ell for R keeps track of the last "good" prime returned
|
|
913
|
+
# that was not found from the dictionary _PGoodness
|
|
914
|
+
|
|
915
|
+
# First, we check to see if we have already computed the goodness of a prime that fits
|
|
916
|
+
# our requirement of being good by qq but not by qqold. This is stored in the _PGoodness
|
|
917
|
+
# dictionary.
|
|
918
|
+
|
|
919
|
+
# Then if we have, we return the smallest such prime and delete it from the list. If not, we
|
|
920
|
+
# search through patience number of primes R._ell to find one good by qq but not qqold. If it is
|
|
921
|
+
# not good by either qqold or qq, then we add this prime to R._PGoodness under its goodness.
|
|
922
|
+
|
|
923
|
+
# Possible_Primes keeps track of possible primes satisfying our goodness requirements we might return
|
|
924
|
+
# check to see if anything in R._PGoodness fits our goodness requirements
|
|
925
|
+
Possible_Primes = [item[0] for j, item in R._PGoodness.items()
|
|
926
|
+
if qqold < j <= qq and item]
|
|
927
|
+
|
|
928
|
+
# If we found good primes, we take the smallest
|
|
929
|
+
if Possible_Primes:
|
|
930
|
+
q = min(Possible_Primes)
|
|
931
|
+
n = _goodness(q, R, p)
|
|
932
|
+
del R._PGoodness[n][0] # if we are going to use it, then we delete it from R._PGoodness
|
|
933
|
+
return q
|
|
934
|
+
|
|
935
|
+
# If nothing is already stored in R._PGoodness, we start (from where we left off at R._ell) checking
|
|
936
|
+
# for good primes. We only tolerate patience number of tries before giving up.
|
|
937
|
+
else:
|
|
938
|
+
i = 0
|
|
939
|
+
while i < patience:
|
|
940
|
+
i += 1
|
|
941
|
+
R._ell = next_prime(R._ell)
|
|
942
|
+
|
|
943
|
+
# we require that R._ell is 1 mod p, so that p divides the order of the multiplicative
|
|
944
|
+
# group mod R._ell, so that not all elements of GF(R._ell) are pth powers.
|
|
945
|
+
if R._ell % p == 1:
|
|
946
|
+
|
|
947
|
+
# requiring that b^2 + 4c is a square in GF(R._ell) ensures that the period mod R._ell
|
|
948
|
+
# divides R._ell - 1
|
|
949
|
+
if legendre_symbol(R.b**2 + 4*R.c, R._ell) == 1:
|
|
950
|
+
|
|
951
|
+
N = _goodness(R._ell, R, p)
|
|
952
|
+
|
|
953
|
+
# proceed only if R._ell satisfies the goodness requirements
|
|
954
|
+
if qqold < N <= qq:
|
|
955
|
+
return R._ell
|
|
956
|
+
|
|
957
|
+
# if we do not use the prime, we store it in R._PGoodness
|
|
958
|
+
else:
|
|
959
|
+
if N in R._PGoodness:
|
|
960
|
+
R._PGoodness[N].append(R._ell)
|
|
961
|
+
else:
|
|
962
|
+
R._PGoodness[N] = [R._ell]
|
|
963
|
+
|
|
964
|
+
return False
|
|
965
|
+
|
|
966
|
+
|
|
967
|
+
def _is_p_power_mod(a, p, N):
|
|
968
|
+
"""
|
|
969
|
+
Determine if ``a`` is a ``p`` th power modulo ``N``.
|
|
970
|
+
|
|
971
|
+
By the CRT, this is equivalent to the condition that ``a`` be a ``p`` th power mod all
|
|
972
|
+
distinct prime powers dividing ``N``. For each of these, we use the strong statement of
|
|
973
|
+
Hensel's lemma to lift ``p`` th powers mod `q` or `q^2` or `q^3` to ``p`` th powers mod `q^e`.
|
|
974
|
+
|
|
975
|
+
INPUT:
|
|
976
|
+
|
|
977
|
+
- ``a`` -- integer
|
|
978
|
+
|
|
979
|
+
- ``p`` -- a rational prime number
|
|
980
|
+
|
|
981
|
+
- ``N`` -- positive integer
|
|
982
|
+
|
|
983
|
+
OUTPUT: ``True`` if `a` is a `p`-th power modulo `N`; ``False`` otherwise
|
|
984
|
+
|
|
985
|
+
EXAMPLES::
|
|
986
|
+
|
|
987
|
+
sage: sage.combinat.binary_recurrence_sequences._is_p_power_mod(2**3,7,29)
|
|
988
|
+
False
|
|
989
|
+
sage: sage.combinat.binary_recurrence_sequences._is_p_power_mod(2**3,3,29)
|
|
990
|
+
True
|
|
991
|
+
"""
|
|
992
|
+
# By the chinese remainder theorem, we can answer this question by examining whether
|
|
993
|
+
# a is a pth power mod q^e, for all distinct prime powers q^e dividing N.
|
|
994
|
+
|
|
995
|
+
for q, e in N.factor():
|
|
996
|
+
|
|
997
|
+
# If a = q^v*x, with
|
|
998
|
+
|
|
999
|
+
v = a.valuation(q)
|
|
1000
|
+
|
|
1001
|
+
# then if v>=e, a is congruent to 0 mod q^e and is thus a pth power trivially.
|
|
1002
|
+
|
|
1003
|
+
if v >= e:
|
|
1004
|
+
continue
|
|
1005
|
+
|
|
1006
|
+
# otherwise, it can only be a pth power if v is a multiple of p.
|
|
1007
|
+
if v % p:
|
|
1008
|
+
return False
|
|
1009
|
+
|
|
1010
|
+
# in this cse it is a pth power if x is a pth power mod q^(e-v), so let x = aa,
|
|
1011
|
+
# and (e-v) = ee:
|
|
1012
|
+
|
|
1013
|
+
aa = a / q**v
|
|
1014
|
+
ee = e - v
|
|
1015
|
+
|
|
1016
|
+
# The above steps are equivalent to the statement that we may assume a and qq are
|
|
1017
|
+
# relatively prime, if we replace a with aa and e with ee. Now we must determine when
|
|
1018
|
+
# aa is a pth power mod q^ee for (aa,q)=1.
|
|
1019
|
+
|
|
1020
|
+
# If q != p, then by Hensel's lemma, we may lift a pth power mod q, to a pth power
|
|
1021
|
+
# mod q^2, etc.
|
|
1022
|
+
|
|
1023
|
+
if q != p:
|
|
1024
|
+
|
|
1025
|
+
# aa is necessarily a pth power mod q if p does not divide the order of the multiplicative
|
|
1026
|
+
# group mod q, ie if q is not 1 mod p.
|
|
1027
|
+
|
|
1028
|
+
if q % p == 1:
|
|
1029
|
+
|
|
1030
|
+
# otherwise aa if a pth power mod q iff aa^(q-1)/p == 1
|
|
1031
|
+
|
|
1032
|
+
if GF(q)(aa)**((q - 1) / p) != 1:
|
|
1033
|
+
return False
|
|
1034
|
+
|
|
1035
|
+
# If q = p and ee = 1, then everything is a pth power p by Fermat's little theorem.
|
|
1036
|
+
|
|
1037
|
+
elif ee > 1:
|
|
1038
|
+
|
|
1039
|
+
# We use the strong statement of Hensel's lemma, which implies that if p is odd
|
|
1040
|
+
# and aa is a pth power mod p^2, then aa is a pth power mod any higher power of p
|
|
1041
|
+
|
|
1042
|
+
if p % 2:
|
|
1043
|
+
|
|
1044
|
+
# ZZ/(p^2)ZZ^\times is abstractly isomorphic to ZZ/(p)ZZ cross ZZ/(p-1)ZZ. then
|
|
1045
|
+
# aa is a pth power mod p^2 if (aa)^(p*(p-1)/p) == 1, ie if aa^(p-1) == 1.
|
|
1046
|
+
|
|
1047
|
+
if Integers(p**2)(aa)**(p - 1) != 1:
|
|
1048
|
+
return False
|
|
1049
|
+
|
|
1050
|
+
# Otherwise, p=2. By the strong statement of Hensel's lemma, if aa is a pth power
|
|
1051
|
+
# mod p^3, then it is a pth power mod higher powers of p. So we need only check if it
|
|
1052
|
+
# is a pth power mod p^2 and p^3.
|
|
1053
|
+
|
|
1054
|
+
elif ee == 2:
|
|
1055
|
+
|
|
1056
|
+
# all odd squares a 1 mod 4
|
|
1057
|
+
|
|
1058
|
+
if aa % 4 != 1:
|
|
1059
|
+
return False
|
|
1060
|
+
|
|
1061
|
+
# all odd squares are 1 mod 8
|
|
1062
|
+
|
|
1063
|
+
elif aa % 8 != 1:
|
|
1064
|
+
return False
|
|
1065
|
+
|
|
1066
|
+
return True
|
|
1067
|
+
|
|
1068
|
+
|
|
1069
|
+
def _estimated_time(M2, M1, length, p):
|
|
1070
|
+
"""
|
|
1071
|
+
Find the estimated time to extend congruences mod M1 to consistent congruences mod M2.
|
|
1072
|
+
|
|
1073
|
+
INPUT:
|
|
1074
|
+
|
|
1075
|
+
- ``M2`` -- integer; (the new modulus)
|
|
1076
|
+
|
|
1077
|
+
- ``M1`` -- integer; (the old modulus)
|
|
1078
|
+
|
|
1079
|
+
- ``length`` -- list (the current length of the list of congruences mod ``M1``)
|
|
1080
|
+
|
|
1081
|
+
- ``p`` -- a prime
|
|
1082
|
+
|
|
1083
|
+
OUTPUT: the estimated run time of the "CRT" step to combine consistent congruences
|
|
1084
|
+
|
|
1085
|
+
EXAMPLES::
|
|
1086
|
+
|
|
1087
|
+
sage: from sage.combinat.binary_recurrence_sequences import _estimated_time
|
|
1088
|
+
sage: _estimated_time(2**4*3**2*5*7*11*13*17, 2**4*3**2*5*7*11*13, 20, 7) # needs sage.symbolic
|
|
1089
|
+
106.211159309421
|
|
1090
|
+
"""
|
|
1091
|
+
# The heuristic run time of the CRT step to go from modulus M1 to M2
|
|
1092
|
+
|
|
1093
|
+
# length is the current length of cong
|
|
1094
|
+
|
|
1095
|
+
Q = p * log(M2) # Size of our primes.
|
|
1096
|
+
NPrimes = log(M2 / M1) / log(Q) # The number of primes
|
|
1097
|
+
|
|
1098
|
+
return (length * (Q / p)**NPrimes).n()
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
# Find the list of necessary congruences for the index n of binary recurrence
|
|
1102
|
+
# sequence R using the fact that the reduction mod ell must be a pth power
|
|
1103
|
+
def _find_cong1(p, R, ell):
|
|
1104
|
+
"""
|
|
1105
|
+
Find the list of permissible indices `n` for which `u_n = y^p` mod ``ell``.
|
|
1106
|
+
|
|
1107
|
+
INPUT:
|
|
1108
|
+
|
|
1109
|
+
- ``p`` -- a prime number
|
|
1110
|
+
|
|
1111
|
+
- ``R`` -- an object in class :class:`BinaryRecurrenceSequence`
|
|
1112
|
+
|
|
1113
|
+
- ``ell`` -- a prime number
|
|
1114
|
+
|
|
1115
|
+
OUTPUT:
|
|
1116
|
+
|
|
1117
|
+
- A list of permissible values of `n` modulo ``period(ell)`` and the integer ``period(ell)``.
|
|
1118
|
+
|
|
1119
|
+
EXAMPLES::
|
|
1120
|
+
|
|
1121
|
+
sage: R = BinaryRecurrenceSequence(1,1)
|
|
1122
|
+
sage: sage.combinat.binary_recurrence_sequences._find_cong1(7, R, 29) # needs sage.rings.finite_rings
|
|
1123
|
+
([0, 1, 2, 12, 13], 14)
|
|
1124
|
+
"""
|
|
1125
|
+
F = GF(ell)
|
|
1126
|
+
u0 = F(R.u0)
|
|
1127
|
+
u1 = F(R.u1)
|
|
1128
|
+
bf, cf = F(R.b), F(R.c)
|
|
1129
|
+
a0 = u0
|
|
1130
|
+
a1 = u1 # a0 and a1 are variables for terms in sequence
|
|
1131
|
+
|
|
1132
|
+
# The set of pth powers mod ell
|
|
1133
|
+
PPowers = set(i**p for i in F)
|
|
1134
|
+
|
|
1135
|
+
# The period of R mod ell
|
|
1136
|
+
modu = R.period(ell)
|
|
1137
|
+
|
|
1138
|
+
# cong1 keeps track of congruences mod modu for the sequence mod ell
|
|
1139
|
+
cong1 = []
|
|
1140
|
+
|
|
1141
|
+
for n in range(modu): # n is the index of the a0
|
|
1142
|
+
|
|
1143
|
+
# Check whether a0 is a perfect power mod ell
|
|
1144
|
+
if a0 in PPowers:
|
|
1145
|
+
# if a0 is a perfect power mod ell, add the index
|
|
1146
|
+
# to the list of necessary congruences
|
|
1147
|
+
cong1.append(n)
|
|
1148
|
+
|
|
1149
|
+
a0, a1 = a1, bf * a1 + cf * a0 # step up the variables
|
|
1150
|
+
|
|
1151
|
+
cong1.sort()
|
|
1152
|
+
|
|
1153
|
+
return cong1, modu
|
|
1154
|
+
|
|
1155
|
+
|
|
1156
|
+
def _is_p_power(a, p) -> bool:
|
|
1157
|
+
"""
|
|
1158
|
+
Determine whether `a` is a perfect `p`-th power.
|
|
1159
|
+
|
|
1160
|
+
INPUT:
|
|
1161
|
+
|
|
1162
|
+
- ``a`` -- integer
|
|
1163
|
+
|
|
1164
|
+
- ``p`` -- a prime number
|
|
1165
|
+
|
|
1166
|
+
OUTPUT: boolean
|
|
1167
|
+
|
|
1168
|
+
EXAMPLES::
|
|
1169
|
+
|
|
1170
|
+
sage: from sage.combinat.binary_recurrence_sequences import _is_p_power
|
|
1171
|
+
sage: _is_p_power(2**7, 7)
|
|
1172
|
+
True
|
|
1173
|
+
sage: _is_p_power(2**7*3**2, 7)
|
|
1174
|
+
False
|
|
1175
|
+
"""
|
|
1176
|
+
try:
|
|
1177
|
+
Integer(a).nth_root(p)
|
|
1178
|
+
except ValueError:
|
|
1179
|
+
return False
|
|
1180
|
+
return True
|