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
sage/databases/oeis.py
ADDED
|
@@ -0,0 +1,2058 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-combinat
|
|
2
|
+
r"""
|
|
3
|
+
The On-Line Encyclopedia of Integer Sequences (OEIS)
|
|
4
|
+
|
|
5
|
+
You can query the OEIS (Online Database of Integer Sequences) through Sage in
|
|
6
|
+
order to:
|
|
7
|
+
|
|
8
|
+
- identify a sequence from its first terms.
|
|
9
|
+
- obtain more terms, formulae, references, etc. for a given sequence.
|
|
10
|
+
|
|
11
|
+
EXAMPLES::
|
|
12
|
+
|
|
13
|
+
sage: oeis
|
|
14
|
+
The On-Line Encyclopedia of Integer Sequences (https://oeis.org/)
|
|
15
|
+
|
|
16
|
+
What about a sequence starting with `3, 7, 15, 1` ?
|
|
17
|
+
|
|
18
|
+
::
|
|
19
|
+
|
|
20
|
+
sage: # optional - internet
|
|
21
|
+
sage: search = oeis([3, 7, 15, 1], max_results=4); search # random
|
|
22
|
+
0: A001203: Simple continued fraction expansion of Pi.
|
|
23
|
+
1: A240698: Partial sums of divisors of n, cf. A027750.
|
|
24
|
+
2: A082495: a(n) = (2^n - 1) mod n.
|
|
25
|
+
3: A165416: Irregular array read by rows: The n-th row contains those
|
|
26
|
+
distinct positive integers that each, when written in binary,
|
|
27
|
+
occurs as a substring in binary n.
|
|
28
|
+
sage: [u.id() for u in search] # random
|
|
29
|
+
['A001203', 'A240698', 'A082495', 'A165416']
|
|
30
|
+
sage: c = search[0]; c
|
|
31
|
+
A001203: Simple continued fraction expansion of Pi.
|
|
32
|
+
|
|
33
|
+
::
|
|
34
|
+
|
|
35
|
+
sage: # optional - internet
|
|
36
|
+
sage: c.first_terms(15)
|
|
37
|
+
(3, 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1)
|
|
38
|
+
sage: c.examples()
|
|
39
|
+
0: Pi = 3.1415926535897932384...
|
|
40
|
+
1: = 3 + 1/(7 + 1/(15 + 1/(1 + 1/(292 + ...))))
|
|
41
|
+
2: = [a_0; a_1, a_2, a_3, ...] = [3; 7, 15, 1, 292, ...].
|
|
42
|
+
sage: c.comments()
|
|
43
|
+
0: The first 5821569425 terms were computed by _Eric W. Weisstein_ on Sep 18 2011.
|
|
44
|
+
1: The first 10672905501 terms were computed by _Eric W. Weisstein_ on Jul 17 2013.
|
|
45
|
+
2: The first 15000000000 terms were computed by _Eric W. Weisstein_ on Jul 27 2013.
|
|
46
|
+
3: The first 30113021586 terms were computed by _Syed Fahad_ on Apr 27 2021.
|
|
47
|
+
|
|
48
|
+
::
|
|
49
|
+
|
|
50
|
+
sage: # optional - internet
|
|
51
|
+
sage: x = c.natural_object(); type(x)
|
|
52
|
+
<class 'sage.rings.continued_fraction.ContinuedFraction_periodic'>
|
|
53
|
+
sage: x.convergents()[:7]
|
|
54
|
+
[3, 22/7, 333/106, 355/113, 103993/33102, 104348/33215, 208341/66317]
|
|
55
|
+
sage: RR(x.value())
|
|
56
|
+
3.14159265358979
|
|
57
|
+
sage: RR(x.value()) == RR(pi)
|
|
58
|
+
True
|
|
59
|
+
|
|
60
|
+
What about posets? Are they hard to count? To which other structures are they
|
|
61
|
+
related?
|
|
62
|
+
|
|
63
|
+
::
|
|
64
|
+
|
|
65
|
+
sage: # optional - internet
|
|
66
|
+
sage: [Posets(i).cardinality() for i in range(10)]
|
|
67
|
+
[1, 1, 2, 5, 16, 63, 318, 2045, 16999, 183231]
|
|
68
|
+
sage: oeis(_)
|
|
69
|
+
0: A000112: Number of partially ordered sets ("posets") with n unlabeled elements.
|
|
70
|
+
sage: p = _[0]
|
|
71
|
+
sage: 'hard' in p.keywords()
|
|
72
|
+
True
|
|
73
|
+
sage: len(p.formulas())
|
|
74
|
+
0
|
|
75
|
+
sage: len(p.first_terms())
|
|
76
|
+
17
|
|
77
|
+
sage: p.cross_references(fetch=True) # random
|
|
78
|
+
0: A000798: Number of different quasi-orders (or topologies, or transitive digraphs)
|
|
79
|
+
with n labeled elements.
|
|
80
|
+
1: A001035: Number of partially ordered sets ("posets") with n labeled elements
|
|
81
|
+
(or labeled acyclic transitive digraphs).
|
|
82
|
+
2: A001930: Number of topologies, or transitive digraphs with n unlabeled nodes.
|
|
83
|
+
3: A006057: Number of topologies on n labeled points satisfying axioms T_0-T_4.
|
|
84
|
+
4: A079263: Number of constrained mixed models with n factors.
|
|
85
|
+
5: A079265: Number of antisymmetric transitive binary relations on n unlabeled points.
|
|
86
|
+
6: A263859: Triangle read by rows: T(n,k) (n>=1, k>=0) is the number of posets
|
|
87
|
+
with n elements and rank k (or depth k+1).
|
|
88
|
+
7: A316978: Number of factorizations of n into factors > 1 with no equivalent primes.
|
|
89
|
+
8: A319559: Number of non-isomorphic T_0 set systems of weight n.
|
|
90
|
+
9: A326939: Number of T_0 sets of subsets of {1..n} that cover all n vertices.
|
|
91
|
+
10: A326943: Number of T_0 sets of subsets of {1..n} that cover all n vertices and
|
|
92
|
+
are closed under intersection.
|
|
93
|
+
...
|
|
94
|
+
|
|
95
|
+
What does the Taylor expansion of the `e^{e^x-1}` function have to do with
|
|
96
|
+
primes ?
|
|
97
|
+
|
|
98
|
+
::
|
|
99
|
+
|
|
100
|
+
sage: # optional - internet, needs sage.symbolic
|
|
101
|
+
sage: x = var('x') ; f(x) = e^(e^x - 1)
|
|
102
|
+
sage: L = [a*factorial(b) for a,b in taylor(f(x), x, 0, 20).coefficients()]; L
|
|
103
|
+
[1, 1, 2, 5, 15, 52, 203, 877, 4140, 21147, 115975, 678570, 4213597,
|
|
104
|
+
27644437, 190899322, 1382958545, 10480142147, 82864869804, 682076806159,
|
|
105
|
+
5832742205057, 51724158235372]
|
|
106
|
+
sage: oeis(L)
|
|
107
|
+
0: A000110: Bell or exponential numbers: number of ways to partition
|
|
108
|
+
a set of n labeled elements.
|
|
109
|
+
1: A292935: E.g.f.: exp(exp(-x) - 1).
|
|
110
|
+
sage: b = _[0]
|
|
111
|
+
sage: b.formulas()[0]
|
|
112
|
+
'E.g.f.: exp(exp(x) - 1).'
|
|
113
|
+
sage: [i for i in b.comments() if 'prime' in i][-1]
|
|
114
|
+
'When n is prime, ...'
|
|
115
|
+
sage: [n for n in range(2, 20) if (b(n)-2) % n == 0]
|
|
116
|
+
[2, 3, 5, 7, 11, 13, 17, 19]
|
|
117
|
+
|
|
118
|
+
.. SEEALSO::
|
|
119
|
+
|
|
120
|
+
- If you plan to do a lot of automatic searches for subsequences, you
|
|
121
|
+
should consider installing :mod:`SloaneEncyclopedia
|
|
122
|
+
<sage.databases.sloane>`, a local partial copy of the OEIS.
|
|
123
|
+
- Some infinite OEIS sequences are implemented in Sage, via the
|
|
124
|
+
:mod:`sloane_functions <sage.combinat.sloane_functions>` module.
|
|
125
|
+
|
|
126
|
+
AUTHORS:
|
|
127
|
+
|
|
128
|
+
- Thierry Monteil (2012-02-10 -- 2013-06-21): initial version.
|
|
129
|
+
- Vincent Delecroix (2014): modifies continued fractions because of :issue:`14567`
|
|
130
|
+
- Moritz Firsching (2016): modifies handling of dead sequence, see :issue:`17330`
|
|
131
|
+
- Thierry Monteil (2019): refactorization (unique representation :issue:`28480`,
|
|
132
|
+
laziness :issue:`28627`)
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
import re
|
|
136
|
+
from collections import defaultdict
|
|
137
|
+
from ssl import create_default_context as default_context
|
|
138
|
+
from urllib.parse import urlencode
|
|
139
|
+
# ****************************************************************************
|
|
140
|
+
# Copyright (C) 2012 Thierry Monteil <sage!lma.metelu.net>
|
|
141
|
+
#
|
|
142
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
143
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
144
|
+
# the License, or (at your option) any later version.
|
|
145
|
+
# https://www.gnu.org/licenses/
|
|
146
|
+
# ****************************************************************************
|
|
147
|
+
from urllib.request import urlopen, Request
|
|
148
|
+
|
|
149
|
+
from sage.version import version
|
|
150
|
+
from sage.cpython.string import bytes_to_str
|
|
151
|
+
from sage.misc.cachefunc import cached_method
|
|
152
|
+
from sage.misc.flatten import flatten
|
|
153
|
+
from sage.misc.html import HtmlFragment
|
|
154
|
+
from sage.misc.temporary_file import tmp_filename
|
|
155
|
+
from sage.misc.unknown import Unknown
|
|
156
|
+
from sage.misc.verbose import verbose
|
|
157
|
+
from sage.repl.preparse import preparse
|
|
158
|
+
from sage.rings.integer import Integer
|
|
159
|
+
from sage.structure.sage_object import SageObject
|
|
160
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
161
|
+
|
|
162
|
+
oeis_url = 'https://oeis.org/'
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _fetch(url):
|
|
166
|
+
r"""
|
|
167
|
+
Fetch the given ``url``.
|
|
168
|
+
|
|
169
|
+
INPUT:
|
|
170
|
+
|
|
171
|
+
- ``url`` -- string corresponding to the URL to be fetched
|
|
172
|
+
|
|
173
|
+
OUTPUT: string representing the fetched web page
|
|
174
|
+
|
|
175
|
+
TESTS::
|
|
176
|
+
|
|
177
|
+
sage: from sage.databases.oeis import _fetch, oeis_url # optional -- internet
|
|
178
|
+
sage: _fetch(oeis_url + 'hints.html')[-8:-1] # optional -- internet
|
|
179
|
+
'</html>'
|
|
180
|
+
"""
|
|
181
|
+
try:
|
|
182
|
+
verbose("Fetching URL %s ..." % url, caller_name='OEIS')
|
|
183
|
+
with urlopen(Request(url, headers={'User-Agent': f'SageMath/{version}'})) as f:
|
|
184
|
+
return bytes_to_str(f.read())
|
|
185
|
+
except OSError as msg:
|
|
186
|
+
raise OSError("%s\nerror fetching %s" % (msg, url))
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _urls(html_string):
|
|
190
|
+
r"""
|
|
191
|
+
Return the list of URLs contained in ``html_string``.
|
|
192
|
+
|
|
193
|
+
Only URLs provided by HTML hyperlinks (``href`` attribute of ``<a>`` tags)
|
|
194
|
+
in are returned, not text strings starting with ``http://``.
|
|
195
|
+
|
|
196
|
+
INPUT:
|
|
197
|
+
|
|
198
|
+
- ``html_string`` -- string representing some HTML code
|
|
199
|
+
|
|
200
|
+
OUTPUT: list of (string) URLs contained in ``html_string``
|
|
201
|
+
|
|
202
|
+
EXAMPLES::
|
|
203
|
+
|
|
204
|
+
sage: from sage.databases.oeis import _urls
|
|
205
|
+
sage: html = 'http://example.com is not a link, but <a href="http://sagemath.org/">sagemath</a> is'
|
|
206
|
+
sage: _urls(html)
|
|
207
|
+
['http://sagemath.org/']
|
|
208
|
+
"""
|
|
209
|
+
urls = []
|
|
210
|
+
from html.parser import HTMLParser
|
|
211
|
+
|
|
212
|
+
class MyHTMLParser(HTMLParser):
|
|
213
|
+
def handle_starttag(self, tag, attrs):
|
|
214
|
+
if tag == 'a':
|
|
215
|
+
for attr in attrs:
|
|
216
|
+
if attr[0] == 'href':
|
|
217
|
+
urls.append(attr[1])
|
|
218
|
+
MyHTMLParser().feed(html_string)
|
|
219
|
+
return urls
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def to_tuple(string):
|
|
223
|
+
"""
|
|
224
|
+
Convert a string to a tuple of integers.
|
|
225
|
+
|
|
226
|
+
EXAMPLES::
|
|
227
|
+
|
|
228
|
+
sage: from sage.databases.oeis import to_tuple
|
|
229
|
+
sage: to_tuple('12,55,273')
|
|
230
|
+
(12, 55, 273)
|
|
231
|
+
"""
|
|
232
|
+
return tuple(Integer(x) for x in string.split(",") if x)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class OEIS:
|
|
236
|
+
r"""
|
|
237
|
+
The On-Line Encyclopedia of Integer Sequences.
|
|
238
|
+
|
|
239
|
+
``OEIS`` is a class representing the On-Line Encyclopedia of Integer
|
|
240
|
+
Sequences. You can query it using its methods, but ``OEIS`` can also be
|
|
241
|
+
called directly with three arguments:
|
|
242
|
+
|
|
243
|
+
- ``query`` -- it can be:
|
|
244
|
+
|
|
245
|
+
- a string representing an OEIS ID (e.g. 'A000045').
|
|
246
|
+
- an integer representing an OEIS ID (e.g. 45).
|
|
247
|
+
- a list representing a sequence of integers.
|
|
248
|
+
- a string, representing a text search.
|
|
249
|
+
|
|
250
|
+
- ``max_results`` -- (integer, default: 30) the maximum number of
|
|
251
|
+
results to return, they are sorted according to their relevance. In
|
|
252
|
+
any cases, the OEIS website will never provide more than 100 results.
|
|
253
|
+
|
|
254
|
+
- ``first_result`` -- (integer, default: 0) allow to skip the
|
|
255
|
+
``first_result`` first results in the search, to go further.
|
|
256
|
+
This is useful if you are looking for a sequence that may appear
|
|
257
|
+
after the 100 first found sequences.
|
|
258
|
+
|
|
259
|
+
OUTPUT:
|
|
260
|
+
|
|
261
|
+
- if ``query`` is an integer or an OEIS ID (e.g. 'A000045'), returns
|
|
262
|
+
the associated OEIS sequence.
|
|
263
|
+
|
|
264
|
+
- if ``query`` is a string, returns a tuple of OEIS sequences whose
|
|
265
|
+
description corresponds to the query. Those sequences can be used
|
|
266
|
+
without the need to fetch the database again.
|
|
267
|
+
|
|
268
|
+
- if ``query`` is a list or tuple of integers, returns a tuple of
|
|
269
|
+
OEIS sequences containing it as a subsequence. Those sequences
|
|
270
|
+
can be used without the need to fetch the database again.
|
|
271
|
+
|
|
272
|
+
EXAMPLES::
|
|
273
|
+
|
|
274
|
+
sage: oeis
|
|
275
|
+
The On-Line Encyclopedia of Integer Sequences (https://oeis.org/)
|
|
276
|
+
|
|
277
|
+
A particular sequence can be called by its A-number or number::
|
|
278
|
+
|
|
279
|
+
sage: oeis('A000040') # optional -- internet
|
|
280
|
+
A000040: The prime numbers.
|
|
281
|
+
sage: oeis(45) # optional -- internet
|
|
282
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
283
|
+
|
|
284
|
+
The database can be searched by subsequence::
|
|
285
|
+
|
|
286
|
+
sage: search = oeis([1,2,3,5,8,13]); search # optional -- internet
|
|
287
|
+
0: A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
288
|
+
1: A290689: Number of transitive rooted trees with n nodes.
|
|
289
|
+
2: A027926: Triangular array T read by rows: T(n,0) = T(n,2n) = 1 for n >= 0;
|
|
290
|
+
T(n,1) = 1 for n >= 1; T(n,k) = T(n-1,k-2) + T(n-1,k-1)
|
|
291
|
+
for k = 2..2n-1, n >= 2.
|
|
292
|
+
|
|
293
|
+
sage: fibo = search[0] # optional -- internet
|
|
294
|
+
|
|
295
|
+
sage: fibo.name() # optional -- internet
|
|
296
|
+
'Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.'
|
|
297
|
+
|
|
298
|
+
sage: print(fibo.first_terms()) # optional -- internet
|
|
299
|
+
(0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597,
|
|
300
|
+
2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418,
|
|
301
|
+
317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465,
|
|
302
|
+
14930352, 24157817, 39088169, 63245986, 102334155)
|
|
303
|
+
|
|
304
|
+
sage: fibo.cross_references()[0] # optional -- internet
|
|
305
|
+
'A001622'
|
|
306
|
+
|
|
307
|
+
sage: fibo == oeis(45) # optional -- internet
|
|
308
|
+
True
|
|
309
|
+
|
|
310
|
+
sage: sfibo = oeis('A039834') # optional -- internet
|
|
311
|
+
sage: sfibo.first_terms() # optional -- internet
|
|
312
|
+
(1, 1, 0, 1, -1, 2, -3, 5, -8, 13, -21, 34, -55, 89, -144, 233,
|
|
313
|
+
-377, 610, -987, 1597, -2584, 4181, -6765, 10946, -17711, 28657,
|
|
314
|
+
-46368, 75025, -121393, 196418, -317811, 514229, -832040, 1346269,
|
|
315
|
+
-2178309, 3524578, -5702887, 9227465, -14930352, 24157817)
|
|
316
|
+
|
|
317
|
+
sage: tuple(abs(i) for i in sfibo.first_terms())[2:20] == fibo.first_terms()[:18] # optional -- internet
|
|
318
|
+
True
|
|
319
|
+
|
|
320
|
+
sage: fibo.formulas()[4] # optional -- internet
|
|
321
|
+
'F(n) = F(n-1) + F(n-2) = -(-1)^n F(-n).'
|
|
322
|
+
|
|
323
|
+
sage: fibo.comments()[6] # optional -- internet
|
|
324
|
+
"F(n+2) = number of binary sequences of length n that have no
|
|
325
|
+
consecutive 0's."
|
|
326
|
+
|
|
327
|
+
sage: fibo.links()[0] # optional -- internet
|
|
328
|
+
'https://oeis.org/A000045/b000045.txt'
|
|
329
|
+
|
|
330
|
+
The database can be searched by description::
|
|
331
|
+
|
|
332
|
+
sage: oeis('prime gap factorization', max_results=4) # random # optional -- internet
|
|
333
|
+
0: A073491: Numbers having no prime gaps in their factorization.
|
|
334
|
+
1: A073485: Product of any number of consecutive primes; squarefree numbers
|
|
335
|
+
with no gaps in their prime factorization.
|
|
336
|
+
2: A073490: Number of prime gaps in factorization of n.
|
|
337
|
+
3: A073492: Numbers having at least one prime gap in their factorization.
|
|
338
|
+
|
|
339
|
+
.. NOTE::
|
|
340
|
+
|
|
341
|
+
The following will fetch the OEIS database only once::
|
|
342
|
+
|
|
343
|
+
sage: oeis([1,2,3,5,8,13]) # optional -- internet
|
|
344
|
+
0: A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
345
|
+
1: A290689: Number of transitive rooted trees with n nodes.
|
|
346
|
+
2: A027926: Triangular array T read by rows: T(n,0) = T(n,2n) = 1 for n >= 0;
|
|
347
|
+
T(n,1) = 1 for n >= 1; T(n,k) = T(n-1,k-2) + T(n-1,k-1)
|
|
348
|
+
for k = 2..2n-1, n >= 2.
|
|
349
|
+
|
|
350
|
+
sage: oeis('A000045') # optional -- internet
|
|
351
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
352
|
+
|
|
353
|
+
Indeed, due to some caching mechanism, the sequence is not re-created
|
|
354
|
+
when called from its ID.
|
|
355
|
+
|
|
356
|
+
TESTS::
|
|
357
|
+
|
|
358
|
+
sage: oeis((1,2,5,16,61)) # optional -- internet
|
|
359
|
+
0: A000111: ...
|
|
360
|
+
sage: oeis('A000040') # optional -- internet
|
|
361
|
+
A000040: The prime numbers.
|
|
362
|
+
sage: oeis('A000045') # optional -- internet
|
|
363
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
364
|
+
"""
|
|
365
|
+
|
|
366
|
+
def __call__(self, query, max_results=3, first_result=0):
|
|
367
|
+
r"""
|
|
368
|
+
See the documentation of :class:`OEIS`.
|
|
369
|
+
|
|
370
|
+
TESTS::
|
|
371
|
+
|
|
372
|
+
sage: oeis()
|
|
373
|
+
Traceback (most recent call last):
|
|
374
|
+
...
|
|
375
|
+
TypeError: ...__call__() ...
|
|
376
|
+
"""
|
|
377
|
+
if isinstance(query, str):
|
|
378
|
+
if re.match('^A[0-9]{6}$', query):
|
|
379
|
+
return self.find_by_id(query)
|
|
380
|
+
else:
|
|
381
|
+
return self.find_by_description(query, max_results, first_result)
|
|
382
|
+
elif isinstance(query, (int, Integer)):
|
|
383
|
+
return self.find_by_id(query)
|
|
384
|
+
elif isinstance(query, (list, tuple)):
|
|
385
|
+
return self.find_by_subsequence(query, max_results, first_result)
|
|
386
|
+
|
|
387
|
+
def __repr__(self) -> str:
|
|
388
|
+
r"""
|
|
389
|
+
Return the representation of ``self``.
|
|
390
|
+
|
|
391
|
+
TESTS::
|
|
392
|
+
|
|
393
|
+
sage: oeis
|
|
394
|
+
The On-Line Encyclopedia of Integer Sequences (https://oeis.org/)
|
|
395
|
+
"""
|
|
396
|
+
return "The On-Line Encyclopedia of Integer Sequences (%s)" % oeis_url
|
|
397
|
+
|
|
398
|
+
def find_by_id(self, ident, fetch=False):
|
|
399
|
+
r"""
|
|
400
|
+
INPUT:
|
|
401
|
+
|
|
402
|
+
- ``ident`` -- string representing the A-number of the sequence
|
|
403
|
+
or an integer representing its number
|
|
404
|
+
|
|
405
|
+
- ``fetch`` -- boolean (default: ``False``); whether to force fetching the
|
|
406
|
+
content of the sequence on the internet
|
|
407
|
+
|
|
408
|
+
OUTPUT: the OEIS sequence whose A-number or number corresponds to ``ident``
|
|
409
|
+
|
|
410
|
+
EXAMPLES::
|
|
411
|
+
|
|
412
|
+
sage: oeis.find_by_id('A000040') # optional -- internet
|
|
413
|
+
A000040: The prime numbers.
|
|
414
|
+
|
|
415
|
+
sage: oeis.find_by_id(40) # optional -- internet
|
|
416
|
+
A000040: The prime numbers.
|
|
417
|
+
"""
|
|
418
|
+
sequence = OEISSequence(ident=ident)
|
|
419
|
+
if fetch:
|
|
420
|
+
sequence.online_update()
|
|
421
|
+
return sequence
|
|
422
|
+
|
|
423
|
+
def find_by_entry(self, entry):
|
|
424
|
+
r"""
|
|
425
|
+
INPUT:
|
|
426
|
+
|
|
427
|
+
- ``entry`` -- string corresponding to an entry in the internal format
|
|
428
|
+
of the OEIS
|
|
429
|
+
|
|
430
|
+
OUTPUT: the corresponding OEIS sequence
|
|
431
|
+
|
|
432
|
+
EXAMPLES::
|
|
433
|
+
|
|
434
|
+
sage: entry = '%I A262002\n%N A262002 L.g.f.: log( Sum_{n>=0} x^n/n! * Product_{k=1..n} (k^2 + 1) ).\n%K A262002 nonn'
|
|
435
|
+
sage: s = oeis.find_by_entry(entry)
|
|
436
|
+
sage: s
|
|
437
|
+
A262002: L.g.f.: log( Sum_{n>=0} x^n/n! * Product_{k=1..n} (k^2 + 1) ).
|
|
438
|
+
"""
|
|
439
|
+
ident = entry[3:10]
|
|
440
|
+
sequence = OEISSequence(ident=ident)
|
|
441
|
+
sequence._raw = entry
|
|
442
|
+
return sequence
|
|
443
|
+
|
|
444
|
+
def find_by_description(self, description, max_results=3, first_result=0):
|
|
445
|
+
r"""
|
|
446
|
+
Search for OEIS sequences corresponding to the description.
|
|
447
|
+
|
|
448
|
+
INPUT:
|
|
449
|
+
|
|
450
|
+
- ``description`` -- string; the description the searched sequences
|
|
451
|
+
|
|
452
|
+
- ``max_results`` -- (integer, default: 3) the maximum number of results
|
|
453
|
+
we want. In any case, the on-line encyclopedia will not return more
|
|
454
|
+
than 100 results.
|
|
455
|
+
|
|
456
|
+
- ``first_result`` -- (integer, default: 0) allow to skip the
|
|
457
|
+
``first_result`` first results in the search, to go further.
|
|
458
|
+
This is useful if you are looking for a sequence that may appear
|
|
459
|
+
after the 100 first found sequences.
|
|
460
|
+
|
|
461
|
+
OUTPUT:
|
|
462
|
+
|
|
463
|
+
- a tuple (with fancy formatting) of at most ``max_results`` OEIS
|
|
464
|
+
sequences. Those sequences can be used without the need to fetch the
|
|
465
|
+
database again.
|
|
466
|
+
|
|
467
|
+
EXAMPLES::
|
|
468
|
+
|
|
469
|
+
sage: oeis.find_by_description('prime gap factorization') # optional -- internet
|
|
470
|
+
0: A...: ...
|
|
471
|
+
1: A...: ...
|
|
472
|
+
2: A...: ...
|
|
473
|
+
|
|
474
|
+
sage: prime_gaps = _[2] ; prime_gaps # optional -- internet
|
|
475
|
+
A...
|
|
476
|
+
|
|
477
|
+
sage: oeis('beaver') # optional -- internet
|
|
478
|
+
0: A...: ...eaver...
|
|
479
|
+
1: A...: ...eaver...
|
|
480
|
+
2: A...: ...eaver...
|
|
481
|
+
|
|
482
|
+
sage: oeis('beaver', max_results=4, first_result=2) # optional -- internet
|
|
483
|
+
0: A...: ...eaver...
|
|
484
|
+
1: A...: ...eaver...
|
|
485
|
+
2: A...: ...eaver...
|
|
486
|
+
3: A...: ...eaver...
|
|
487
|
+
"""
|
|
488
|
+
options = {'q': description,
|
|
489
|
+
'n': str(max_results),
|
|
490
|
+
'fmt': 'text',
|
|
491
|
+
'start': str(first_result)}
|
|
492
|
+
url = oeis_url + "search?" + urlencode(options)
|
|
493
|
+
sequence_list = _fetch(url).split('\n\n')[2:-1]
|
|
494
|
+
T = [self.find_by_entry(entry=s) for s in sequence_list]
|
|
495
|
+
return FancyTuple([s for s in T if not s.is_dead()])
|
|
496
|
+
|
|
497
|
+
def find_by_subsequence(self, subsequence, max_results=3, first_result=0):
|
|
498
|
+
r"""
|
|
499
|
+
Search for OEIS sequences containing the given subsequence.
|
|
500
|
+
|
|
501
|
+
INPUT:
|
|
502
|
+
|
|
503
|
+
- ``subsequence`` -- list or tuple of integers
|
|
504
|
+
|
|
505
|
+
- ``max_results`` -- integer (default: 3); the maximum of results requested
|
|
506
|
+
|
|
507
|
+
- ``first_result`` -- integer (default: 0); allow to skip the
|
|
508
|
+
``first_result`` first results in the search, to go further.
|
|
509
|
+
This is useful if you are looking for a sequence that may appear
|
|
510
|
+
after the 100 first found sequences.
|
|
511
|
+
|
|
512
|
+
OUTPUT:
|
|
513
|
+
|
|
514
|
+
A tuple (with fancy formatting) of at most ``max_results`` OEIS
|
|
515
|
+
sequences. Those sequences can be used without the need to fetch the
|
|
516
|
+
database again.
|
|
517
|
+
|
|
518
|
+
EXAMPLES::
|
|
519
|
+
|
|
520
|
+
sage: oeis.find_by_subsequence([2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]) # optional -- internet # random
|
|
521
|
+
0: A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
522
|
+
1: A212804: Expansion of (1 - x)/(1 - x - x^2).
|
|
523
|
+
2: A020695: Pisot sequence E(2,3).
|
|
524
|
+
|
|
525
|
+
sage: fibo = _[0] ; fibo # optional -- internet
|
|
526
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
527
|
+
"""
|
|
528
|
+
subsequence = str(subsequence)[1:-1]
|
|
529
|
+
return self.find_by_description(subsequence, max_results, first_result)
|
|
530
|
+
|
|
531
|
+
def browse(self):
|
|
532
|
+
r"""
|
|
533
|
+
Open the OEIS web page in a browser.
|
|
534
|
+
|
|
535
|
+
EXAMPLES::
|
|
536
|
+
|
|
537
|
+
sage: oeis.browse() # optional -- webbrowser
|
|
538
|
+
"""
|
|
539
|
+
import webbrowser
|
|
540
|
+
webbrowser.open(oeis_url)
|
|
541
|
+
|
|
542
|
+
def _imaginary_entry(self, ident='A999999', keywords=''):
|
|
543
|
+
r"""
|
|
544
|
+
This is an imaginary entry of an OEIS sequence for offline tests.
|
|
545
|
+
|
|
546
|
+
INPUT:
|
|
547
|
+
|
|
548
|
+
- ``ident`` -- string representing the A-number of the sequence
|
|
549
|
+
|
|
550
|
+
- ``keywords`` -- string corresponding to the keyword field of the
|
|
551
|
+
sequence
|
|
552
|
+
|
|
553
|
+
OUTPUT: string representing the entry of the sequence
|
|
554
|
+
|
|
555
|
+
TESTS::
|
|
556
|
+
|
|
557
|
+
sage: oeis._imaginary_entry().split('\n')[0]
|
|
558
|
+
'%I A999999 M9999 N9999'
|
|
559
|
+
|
|
560
|
+
sage: keywords = 'simon,cussonet'
|
|
561
|
+
sage: s = oeis.find_by_entry(entry=oeis._imaginary_entry(ident='A999998', keywords=keywords))
|
|
562
|
+
sage: ','.join(s.keywords()) == keywords
|
|
563
|
+
True
|
|
564
|
+
"""
|
|
565
|
+
return ('%I ' + ident + ' M9999 N9999\n'
|
|
566
|
+
'%S ' + ident + ' 1,1,1,1,2,1,1,1,\n'
|
|
567
|
+
'%T ' + ident + ' 1,1,1,1,1,1,1,1,1,\n'
|
|
568
|
+
'%U ' + ident + ' 1,1,1,1,1,1,1,1,1\n'
|
|
569
|
+
'%N ' + ident + ' The characteristic sequence of 42 plus one, starting from 38.\n'
|
|
570
|
+
'%D ' + ident + ' Lewis Carroll, Alice\'s Adventures in Wonderland.\n'
|
|
571
|
+
'%D ' + ident + ' Lewis Carroll, The Hunting of the Snark.\n'
|
|
572
|
+
'%D ' + ident + ' Deep Thought, The Answer to the Ultimate Question of Life, The Universe, and Everything.\n'
|
|
573
|
+
'%H ' + ident + ' Wikipedia, <a href="https://en.wikipedia.org/wiki/42_(number)">42 (number)</a>\n'
|
|
574
|
+
'%H ' + ident + ' See. also <a href="https://github.com/sagemath/sage/issues/42">github issue #42</a>\n'
|
|
575
|
+
'%H ' + ident + ' Do not confuse with the sequence <a href="/A000042">A000042</a> or the sequence <a href="/A000024">A000024</a>\n'
|
|
576
|
+
'%H ' + ident + ' The string http://42.com is not a link.\n'
|
|
577
|
+
'%F ' + ident + ' For n big enough, s(n+1) - s(n) = 0.\n'
|
|
578
|
+
'%Y ' + ident + ' Related sequences are A000042 and its friend A000024.\n'
|
|
579
|
+
'%A ' + ident + ' Anonymous.\n'
|
|
580
|
+
'%O ' + ident + ' 38,4\n'
|
|
581
|
+
'%E ' + ident + ' This sequence does not contain errors.\n'
|
|
582
|
+
'%e ' + ident + ' s(42) + s(43) = 0.\n'
|
|
583
|
+
'%p ' + ident + ' Do not even try, Maple is not able to produce such a sequence.\n'
|
|
584
|
+
'%t ' + ident + ' Mathematica neither.\n'
|
|
585
|
+
'%o ' + ident + ' (Python)\n'
|
|
586
|
+
'%o ' + ident + ' def ' + ident + '(n):\n'
|
|
587
|
+
'%o ' + ident + ' assert(isinstance(n, (int, Integer))), "n must be an integer."\n'
|
|
588
|
+
'%o ' + ident + ' if n < 38:\n'
|
|
589
|
+
'%o ' + ident + ' raise ValueError("the value %s is not accepted" % str(n))\n'
|
|
590
|
+
'%o ' + ident + ' elif n == 42:\n'
|
|
591
|
+
'%o ' + ident + ' return 2\n'
|
|
592
|
+
'%o ' + ident + ' else:\n'
|
|
593
|
+
'%o ' + ident + ' return 1\n'
|
|
594
|
+
'%K ' + ident + ' ' + keywords + '\n'
|
|
595
|
+
'%C ' + ident + ' 42 is the product of the first 4 prime numbers, except 5 and perhaps 1.\n'
|
|
596
|
+
'%C ' + ident + ' Apart from that, i have no comment.')
|
|
597
|
+
|
|
598
|
+
def _imaginary_sequence(self, ident='A999999', keywords='sign,easy'):
|
|
599
|
+
r"""
|
|
600
|
+
This is the OEIS sequence corresponding to the imaginary entry.
|
|
601
|
+
Its main purpose is to allow offline doctesting.
|
|
602
|
+
|
|
603
|
+
INPUT:
|
|
604
|
+
|
|
605
|
+
- ``ident`` -- string representing the A-number of the sequence
|
|
606
|
+
|
|
607
|
+
- ``keywords`` -- string (default: ``'sign,easy'``); a list of words
|
|
608
|
+
separated by commas
|
|
609
|
+
|
|
610
|
+
OUTPUT: OEIS sequence
|
|
611
|
+
|
|
612
|
+
TESTS::
|
|
613
|
+
|
|
614
|
+
sage: s = oeis._imaginary_sequence()
|
|
615
|
+
sage: s
|
|
616
|
+
A999999: The characteristic sequence of 42 plus one, starting from 38.
|
|
617
|
+
sage: s[4]
|
|
618
|
+
2
|
|
619
|
+
sage: s(42)
|
|
620
|
+
2
|
|
621
|
+
"""
|
|
622
|
+
return self.find_by_entry(entry=self._imaginary_entry(ident=ident, keywords=keywords))
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
class OEISSequence(SageObject, UniqueRepresentation):
|
|
626
|
+
r"""
|
|
627
|
+
The class of OEIS sequences.
|
|
628
|
+
|
|
629
|
+
This class implements OEIS sequences. They are usually produced by calls to
|
|
630
|
+
the On-Line Encyclopedia of Integer Sequences, represented by the class
|
|
631
|
+
:class:`OEIS`.
|
|
632
|
+
|
|
633
|
+
.. NOTE::
|
|
634
|
+
|
|
635
|
+
Since some sequences do not start with index 0, there is a difference
|
|
636
|
+
between calling and getting item, see :meth:`__call__` for more details
|
|
637
|
+
::
|
|
638
|
+
|
|
639
|
+
sage: # optional - internet
|
|
640
|
+
sage: sfibo = oeis('A039834')
|
|
641
|
+
sage: sfibo.first_terms()[:10]
|
|
642
|
+
(1, 1, 0, 1, -1, 2, -3, 5, -8, 13)
|
|
643
|
+
sage: sfibo(-2)
|
|
644
|
+
1
|
|
645
|
+
sage: sfibo(3)
|
|
646
|
+
2
|
|
647
|
+
sage: sfibo.offsets()
|
|
648
|
+
(-2, 6)
|
|
649
|
+
sage: sfibo[0]
|
|
650
|
+
1
|
|
651
|
+
sage: sfibo[6]
|
|
652
|
+
-3
|
|
653
|
+
|
|
654
|
+
.. automethod:: __call__
|
|
655
|
+
"""
|
|
656
|
+
@staticmethod
|
|
657
|
+
def __classcall__(cls, ident):
|
|
658
|
+
r"""
|
|
659
|
+
Canonicalize the ID of the sequence into a A-number.
|
|
660
|
+
|
|
661
|
+
TESTS::
|
|
662
|
+
|
|
663
|
+
sage: oeis(45) is oeis('A000045')
|
|
664
|
+
True
|
|
665
|
+
"""
|
|
666
|
+
if not isinstance(ident, str):
|
|
667
|
+
ident = str(ident)
|
|
668
|
+
ident = 'A000000'[:-len(ident)] + ident
|
|
669
|
+
return super().__classcall__(cls, ident)
|
|
670
|
+
|
|
671
|
+
def __init__(self, ident):
|
|
672
|
+
r"""
|
|
673
|
+
Initialize an OEIS sequence.
|
|
674
|
+
|
|
675
|
+
There is no fetching of additional information about the sequence at
|
|
676
|
+
this point, only the A-number is required to construct a sequence.
|
|
677
|
+
|
|
678
|
+
INPUT:
|
|
679
|
+
|
|
680
|
+
- ``ident`` -- string representing the A-number of the sequence or an
|
|
681
|
+
integer representing its number
|
|
682
|
+
|
|
683
|
+
TESTS::
|
|
684
|
+
|
|
685
|
+
sage: sfibo = oeis('A039834')
|
|
686
|
+
|
|
687
|
+
sage: s = oeis._imaginary_sequence()
|
|
688
|
+
"""
|
|
689
|
+
self._id = ident
|
|
690
|
+
|
|
691
|
+
def online_update(self):
|
|
692
|
+
r"""
|
|
693
|
+
Fetch the online OEIS to update the informations about this sequence.
|
|
694
|
+
|
|
695
|
+
TESTS::
|
|
696
|
+
|
|
697
|
+
sage: # optional -- internet
|
|
698
|
+
sage: s = oeis._imaginary_sequence(ident='A004238')
|
|
699
|
+
sage: s
|
|
700
|
+
A004238: The characteristic sequence of 42 plus one, starting from 38.
|
|
701
|
+
sage: s.online_update()
|
|
702
|
+
sage: s
|
|
703
|
+
A004238: a(n) = 100*log(n) rounded to nearest integer.
|
|
704
|
+
"""
|
|
705
|
+
options = {'q': self._id, 'n': '1', 'fmt': 'text'}
|
|
706
|
+
url = oeis_url + "search?" + urlencode(options)
|
|
707
|
+
self._raw = _fetch(url).split('\n\n')[2]
|
|
708
|
+
try:
|
|
709
|
+
del self._fields
|
|
710
|
+
except AttributeError:
|
|
711
|
+
pass
|
|
712
|
+
|
|
713
|
+
def _field(self, key, warn=True):
|
|
714
|
+
r"""
|
|
715
|
+
Return the ``key`` field of the entry of ``self``.
|
|
716
|
+
|
|
717
|
+
This method allows to handle the ``_fields`` dictionary in a lazy way.
|
|
718
|
+
|
|
719
|
+
INPUT:
|
|
720
|
+
|
|
721
|
+
- ``warn`` -- ignored
|
|
722
|
+
|
|
723
|
+
TESTS::
|
|
724
|
+
|
|
725
|
+
sage: s = oeis._imaginary_sequence()
|
|
726
|
+
sage: s._field('C')[0]
|
|
727
|
+
'42 is the product of the first 4 prime numbers, except 5 and perhaps 1.'
|
|
728
|
+
"""
|
|
729
|
+
try:
|
|
730
|
+
return self._fields[key]
|
|
731
|
+
except AttributeError:
|
|
732
|
+
fields = defaultdict(list)
|
|
733
|
+
for line in self.raw_entry().splitlines():
|
|
734
|
+
fields[line[1]].append(line[11:])
|
|
735
|
+
self._fields = fields
|
|
736
|
+
return self._fields[key]
|
|
737
|
+
|
|
738
|
+
def id(self, format='A'):
|
|
739
|
+
r"""
|
|
740
|
+
The ID of the sequence ``self`` is the A-number that identifies
|
|
741
|
+
``self``.
|
|
742
|
+
|
|
743
|
+
INPUT:
|
|
744
|
+
|
|
745
|
+
- ``format`` -- string (default: ``'A'``)
|
|
746
|
+
|
|
747
|
+
OUTPUT:
|
|
748
|
+
|
|
749
|
+
- if ``format`` is set to 'A', returns a string of the form 'A000123'.
|
|
750
|
+
- if ``format`` is set to 'int' returns an integer of the form 123.
|
|
751
|
+
|
|
752
|
+
EXAMPLES::
|
|
753
|
+
|
|
754
|
+
sage: f = oeis(45) ; f # optional -- internet
|
|
755
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
756
|
+
|
|
757
|
+
sage: f.id() # optional -- internet
|
|
758
|
+
'A000045'
|
|
759
|
+
|
|
760
|
+
sage: f.id(format='int') # optional -- internet
|
|
761
|
+
45
|
|
762
|
+
|
|
763
|
+
TESTS::
|
|
764
|
+
|
|
765
|
+
sage: s = oeis._imaginary_sequence()
|
|
766
|
+
sage: s.id()
|
|
767
|
+
'A999999'
|
|
768
|
+
sage: s.id(format='int')
|
|
769
|
+
999999
|
|
770
|
+
"""
|
|
771
|
+
if format == 'A':
|
|
772
|
+
return self._id
|
|
773
|
+
elif format == 'int':
|
|
774
|
+
return int(self._id[1:].lstrip("0"))
|
|
775
|
+
|
|
776
|
+
def __hash__(self):
|
|
777
|
+
r"""
|
|
778
|
+
Return the hash of ``self``, which is its numerical OEIS ID.
|
|
779
|
+
|
|
780
|
+
This method allows unique representation of OEIS sequences.
|
|
781
|
+
|
|
782
|
+
OUTPUT: Python integer
|
|
783
|
+
|
|
784
|
+
EXAMPLES::
|
|
785
|
+
|
|
786
|
+
sage: s = oeis([1,2,3,5,8,13])[0] # optional -- internet
|
|
787
|
+
sage: hash(s) # optional -- internet
|
|
788
|
+
45
|
|
789
|
+
|
|
790
|
+
We have unique representation::
|
|
791
|
+
|
|
792
|
+
sage: t = oeis(45) # optional -- internet
|
|
793
|
+
sage: s is t # optional -- internet
|
|
794
|
+
True
|
|
795
|
+
sage: s == t # optional -- internet
|
|
796
|
+
True
|
|
797
|
+
|
|
798
|
+
TESTS::
|
|
799
|
+
|
|
800
|
+
sage: s = oeis._imaginary_sequence()
|
|
801
|
+
sage: s is oeis._imaginary_sequence()
|
|
802
|
+
True
|
|
803
|
+
sage: s == oeis._imaginary_sequence()
|
|
804
|
+
True
|
|
805
|
+
"""
|
|
806
|
+
return self.id(format='int')
|
|
807
|
+
|
|
808
|
+
def raw_entry(self):
|
|
809
|
+
r"""
|
|
810
|
+
Return the raw entry of the sequence ``self``, in the OEIS format.
|
|
811
|
+
|
|
812
|
+
The raw entry is fetched online if needed.
|
|
813
|
+
|
|
814
|
+
OUTPUT: string
|
|
815
|
+
|
|
816
|
+
EXAMPLES::
|
|
817
|
+
|
|
818
|
+
sage: f = oeis(45) ; f # optional -- internet
|
|
819
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
820
|
+
|
|
821
|
+
sage: print(f.raw_entry()) # optional -- internet
|
|
822
|
+
%I A000045 M0692 N0256...
|
|
823
|
+
%S A000045 0,1,1,2,3,5,8,13,21,34,55,89,144,...
|
|
824
|
+
%T A000045 10946,17711,28657,46368,...
|
|
825
|
+
...
|
|
826
|
+
|
|
827
|
+
TESTS::
|
|
828
|
+
|
|
829
|
+
sage: s = oeis._imaginary_sequence()
|
|
830
|
+
sage: s.raw_entry() == oeis._imaginary_entry(keywords='sign,easy')
|
|
831
|
+
True
|
|
832
|
+
"""
|
|
833
|
+
try:
|
|
834
|
+
return self._raw
|
|
835
|
+
except AttributeError:
|
|
836
|
+
self.online_update()
|
|
837
|
+
return self._raw
|
|
838
|
+
|
|
839
|
+
def name(self) -> str:
|
|
840
|
+
r"""
|
|
841
|
+
Return the name of the sequence ``self``.
|
|
842
|
+
|
|
843
|
+
OUTPUT: string
|
|
844
|
+
|
|
845
|
+
EXAMPLES::
|
|
846
|
+
|
|
847
|
+
sage: f = oeis(45) ; f # optional -- internet
|
|
848
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
849
|
+
|
|
850
|
+
sage: f.name() # optional -- internet
|
|
851
|
+
'Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.'
|
|
852
|
+
|
|
853
|
+
TESTS::
|
|
854
|
+
|
|
855
|
+
sage: s = oeis._imaginary_sequence()
|
|
856
|
+
sage: s.name()
|
|
857
|
+
'The characteristic sequence of 42 plus one, starting from 38.'
|
|
858
|
+
"""
|
|
859
|
+
return self._field('N')[0]
|
|
860
|
+
|
|
861
|
+
def old_IDs(self):
|
|
862
|
+
r"""
|
|
863
|
+
Return the IDs of the sequence ``self`` corresponding to ancestors of OEIS.
|
|
864
|
+
|
|
865
|
+
OUTPUT:
|
|
866
|
+
|
|
867
|
+
- a tuple of at most two strings. When the string starts with `M`, it
|
|
868
|
+
corresponds to the ID of "The Encyclopedia of Integer Sequences" of
|
|
869
|
+
1995. When the string starts with `N`, it corresponds to the ID of
|
|
870
|
+
the "Handbook of Integer Sequences" of 1973.
|
|
871
|
+
|
|
872
|
+
EXAMPLES::
|
|
873
|
+
|
|
874
|
+
sage: f = oeis(45) ; f # optional -- internet
|
|
875
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
876
|
+
|
|
877
|
+
sage: f.old_IDs() # optional -- internet
|
|
878
|
+
('M0692', 'N0256')
|
|
879
|
+
|
|
880
|
+
TESTS::
|
|
881
|
+
|
|
882
|
+
sage: s = oeis._imaginary_sequence()
|
|
883
|
+
sage: s.old_IDs()
|
|
884
|
+
('M9999', 'N9999')
|
|
885
|
+
"""
|
|
886
|
+
s = self._field('I')[0]
|
|
887
|
+
# We remove all parts after '#'
|
|
888
|
+
s = s.split('#')[0].strip()
|
|
889
|
+
if not s:
|
|
890
|
+
return ()
|
|
891
|
+
return tuple(s.split(' '))
|
|
892
|
+
|
|
893
|
+
def offsets(self):
|
|
894
|
+
r"""
|
|
895
|
+
Return the offsets of the sequence ``self``.
|
|
896
|
+
|
|
897
|
+
The first offset is the subscript of the first term in the sequence
|
|
898
|
+
``self``. When, the sequence represents the decimal expansion of a real
|
|
899
|
+
number, it corresponds to the number of digits of its integer part.
|
|
900
|
+
|
|
901
|
+
The second offset is the first term in the sequence ``self`` (starting
|
|
902
|
+
from 1) whose absolute value is greater than 1. This is set to 1 if all
|
|
903
|
+
the terms are 0 or +-1.
|
|
904
|
+
|
|
905
|
+
OUTPUT: tuple of two elements
|
|
906
|
+
|
|
907
|
+
EXAMPLES::
|
|
908
|
+
|
|
909
|
+
sage: f = oeis(45) ; f # optional -- internet
|
|
910
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
911
|
+
|
|
912
|
+
sage: f.offsets() # optional -- internet
|
|
913
|
+
(0, 4)
|
|
914
|
+
|
|
915
|
+
sage: f.first_terms()[:4] # optional -- internet
|
|
916
|
+
(0, 1, 1, 2)
|
|
917
|
+
|
|
918
|
+
TESTS::
|
|
919
|
+
|
|
920
|
+
sage: s = oeis._imaginary_sequence()
|
|
921
|
+
sage: s.offsets()
|
|
922
|
+
(38, 4)
|
|
923
|
+
"""
|
|
924
|
+
return to_tuple(self._field('O')[0])
|
|
925
|
+
|
|
926
|
+
def author(self):
|
|
927
|
+
r"""
|
|
928
|
+
Return the author of the sequence in the encyclopedia.
|
|
929
|
+
|
|
930
|
+
OUTPUT: string
|
|
931
|
+
|
|
932
|
+
EXAMPLES::
|
|
933
|
+
|
|
934
|
+
sage: f = oeis(45) ; f # optional -- internet
|
|
935
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
936
|
+
|
|
937
|
+
sage: f.author() # optional -- internet
|
|
938
|
+
'_N. J. A. Sloane_, 1964'
|
|
939
|
+
|
|
940
|
+
TESTS::
|
|
941
|
+
|
|
942
|
+
sage: s = oeis._imaginary_sequence()
|
|
943
|
+
sage: s.author()
|
|
944
|
+
'Anonymous.'
|
|
945
|
+
"""
|
|
946
|
+
return self._field('A')[0]
|
|
947
|
+
|
|
948
|
+
def keywords(self, warn=True):
|
|
949
|
+
r"""
|
|
950
|
+
Return the keywords associated to the sequence ``self``.
|
|
951
|
+
|
|
952
|
+
OUTPUT: tuple of strings
|
|
953
|
+
|
|
954
|
+
EXAMPLES::
|
|
955
|
+
|
|
956
|
+
sage: f = oeis(53) ; f # optional -- internet
|
|
957
|
+
A000053: Local stops on New York City...
|
|
958
|
+
|
|
959
|
+
sage: f.keywords() # optional -- internet
|
|
960
|
+
('nonn', 'fini', ...)
|
|
961
|
+
|
|
962
|
+
TESTS::
|
|
963
|
+
|
|
964
|
+
sage: s = oeis._imaginary_sequence()
|
|
965
|
+
sage: s.keywords()
|
|
966
|
+
('sign', 'easy')
|
|
967
|
+
|
|
968
|
+
sage: s = oeis._imaginary_sequence(ident='A999997', keywords='nonn,hard')
|
|
969
|
+
sage: s.keywords()
|
|
970
|
+
('nonn', 'hard')
|
|
971
|
+
"""
|
|
972
|
+
return tuple(self._field('K', warn=warn)[0].split(','))
|
|
973
|
+
|
|
974
|
+
def natural_object(self):
|
|
975
|
+
r"""
|
|
976
|
+
Return the natural object associated to the sequence ``self``.
|
|
977
|
+
|
|
978
|
+
OUTPUT:
|
|
979
|
+
|
|
980
|
+
- If the sequence ``self`` corresponds to the digits of a real
|
|
981
|
+
number, returns the associated real number (as an element of
|
|
982
|
+
RealLazyField()).
|
|
983
|
+
|
|
984
|
+
- If the sequence ``self`` corresponds to the convergents of a
|
|
985
|
+
continued fraction, returns the associated continued fraction.
|
|
986
|
+
|
|
987
|
+
.. WARNING::
|
|
988
|
+
|
|
989
|
+
This method forgets the fact that the returned sequence may not be
|
|
990
|
+
complete.
|
|
991
|
+
|
|
992
|
+
.. TODO::
|
|
993
|
+
|
|
994
|
+
- ask OEIS to add a keyword telling whether the sequence comes from
|
|
995
|
+
a power series, e.g. for :oeis:`A000182`
|
|
996
|
+
- discover other possible conversions.
|
|
997
|
+
|
|
998
|
+
EXAMPLES::
|
|
999
|
+
|
|
1000
|
+
sage: g = oeis("A002852"); g # optional -- internet
|
|
1001
|
+
A002852: Continued fraction for Euler's constant (or Euler-Mascheroni constant) gamma.
|
|
1002
|
+
|
|
1003
|
+
sage: x = g.natural_object(); type(x) # optional -- internet
|
|
1004
|
+
<class 'sage.rings.continued_fraction.ContinuedFraction_periodic'>
|
|
1005
|
+
|
|
1006
|
+
sage: RDF(x) == RDF(euler_gamma) # optional -- internet
|
|
1007
|
+
True
|
|
1008
|
+
|
|
1009
|
+
sage: cfg = continued_fraction(euler_gamma) # needs sage.symbolic
|
|
1010
|
+
sage: x[:90] == cfg[:90] # optional - internet # needs sage.symbolic
|
|
1011
|
+
True
|
|
1012
|
+
|
|
1013
|
+
::
|
|
1014
|
+
|
|
1015
|
+
sage: ee = oeis('A001113'); ee # optional -- internet
|
|
1016
|
+
A001113: Decimal expansion of e.
|
|
1017
|
+
|
|
1018
|
+
sage: x = ee.natural_object(); x # optional -- internet
|
|
1019
|
+
2.718281828459046?
|
|
1020
|
+
|
|
1021
|
+
sage: x.parent() # optional -- internet
|
|
1022
|
+
Real Lazy Field
|
|
1023
|
+
|
|
1024
|
+
sage: x == RR(e) # optional -- internet
|
|
1025
|
+
True
|
|
1026
|
+
|
|
1027
|
+
::
|
|
1028
|
+
|
|
1029
|
+
sage: av = oeis('A322578'); av # optional -- internet
|
|
1030
|
+
A322578: Decimal expansion ... Avogadro...
|
|
1031
|
+
|
|
1032
|
+
sage: av.natural_object() # optional -- internet
|
|
1033
|
+
6.022140760000000?e23
|
|
1034
|
+
|
|
1035
|
+
::
|
|
1036
|
+
|
|
1037
|
+
sage: fib = oeis('A000045'); fib # optional -- internet
|
|
1038
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
1039
|
+
|
|
1040
|
+
sage: x = fib.natural_object(); x.universe() # optional -- internet
|
|
1041
|
+
Non negative integer semiring
|
|
1042
|
+
|
|
1043
|
+
::
|
|
1044
|
+
|
|
1045
|
+
sage: sfib = oeis('A039834'); sfib # optional -- internet
|
|
1046
|
+
A039834: a(n+2) = -a(n+1) + a(n) (signed Fibonacci numbers) with
|
|
1047
|
+
a(-2) = a(-1) = 1; or Fibonacci numbers (A000045)
|
|
1048
|
+
extended to negative indices.
|
|
1049
|
+
|
|
1050
|
+
sage: x = sfib.natural_object(); x.universe() # optional -- internet
|
|
1051
|
+
Integer Ring
|
|
1052
|
+
|
|
1053
|
+
TESTS::
|
|
1054
|
+
|
|
1055
|
+
sage: s = oeis._imaginary_sequence(ident='A999996', keywords='nonn,cofr')
|
|
1056
|
+
sage: type(s.natural_object())
|
|
1057
|
+
<class 'sage.rings.continued_fraction.ContinuedFraction_periodic'>
|
|
1058
|
+
|
|
1059
|
+
sage: s = oeis._imaginary_sequence(ident='A999995', keywords='nonn')
|
|
1060
|
+
sage: s.natural_object().universe()
|
|
1061
|
+
Non negative integer semiring
|
|
1062
|
+
|
|
1063
|
+
sage: s = oeis._imaginary_sequence()
|
|
1064
|
+
sage: s.natural_object().universe()
|
|
1065
|
+
Integer Ring
|
|
1066
|
+
"""
|
|
1067
|
+
if 'cofr' in self.keywords() and 'frac' not in self.keywords():
|
|
1068
|
+
from sage.rings.continued_fraction import continued_fraction
|
|
1069
|
+
return continued_fraction(self.first_terms())
|
|
1070
|
+
elif 'cons' in self.keywords():
|
|
1071
|
+
offset = self.offsets()[0]
|
|
1072
|
+
terms = self.first_terms() + tuple([0] * abs(offset))
|
|
1073
|
+
from sage.rings.real_lazy import RealLazyField
|
|
1074
|
+
return RealLazyField()('0' + ''.join(map(str, terms[:offset])) + '.' + ''.join(map(str, terms[offset:])))
|
|
1075
|
+
elif 'nonn' in self.keywords():
|
|
1076
|
+
from sage.rings.semirings.non_negative_integer_semiring import NN
|
|
1077
|
+
from sage.structure.sequence import Sequence
|
|
1078
|
+
return Sequence(self.first_terms(), NN)
|
|
1079
|
+
else:
|
|
1080
|
+
from sage.rings.integer_ring import ZZ
|
|
1081
|
+
from sage.structure.sequence import Sequence
|
|
1082
|
+
return Sequence(self.first_terms(), ZZ)
|
|
1083
|
+
|
|
1084
|
+
def is_dead(self, warn_only=False) -> bool:
|
|
1085
|
+
r"""
|
|
1086
|
+
Tell whether the sequence is dead.
|
|
1087
|
+
|
|
1088
|
+
INPUT:
|
|
1089
|
+
|
|
1090
|
+
- ``warn_only`` -- ignored
|
|
1091
|
+
|
|
1092
|
+
EXAMPLES:
|
|
1093
|
+
|
|
1094
|
+
sage: s = oeis(17) # optional -- internet
|
|
1095
|
+
sage: s # optional -- internet
|
|
1096
|
+
A000017: Erroneous version of A032522.
|
|
1097
|
+
|
|
1098
|
+
TESTS::
|
|
1099
|
+
|
|
1100
|
+
sage: s.is_dead() # optional -- internet
|
|
1101
|
+
True
|
|
1102
|
+
|
|
1103
|
+
sage: t = oeis._imaginary_sequence()
|
|
1104
|
+
sage: t.is_dead()
|
|
1105
|
+
False
|
|
1106
|
+
|
|
1107
|
+
sage: u = oeis._imaginary_sequence(ident='A999994', keywords='dead')
|
|
1108
|
+
sage: u
|
|
1109
|
+
A999994: The characteristic sequence of 42 plus one, starting from 38.
|
|
1110
|
+
|
|
1111
|
+
sage: u.is_dead()
|
|
1112
|
+
True
|
|
1113
|
+
"""
|
|
1114
|
+
return 'dead' in self.keywords()
|
|
1115
|
+
|
|
1116
|
+
def is_finite(self):
|
|
1117
|
+
r"""
|
|
1118
|
+
Tell whether the sequence is finite.
|
|
1119
|
+
|
|
1120
|
+
Currently, OEIS only provides a keyword when the sequence is known to
|
|
1121
|
+
be finite. So, when this keyword is not there, we do not know whether
|
|
1122
|
+
it is infinite or not.
|
|
1123
|
+
|
|
1124
|
+
OUTPUT:
|
|
1125
|
+
|
|
1126
|
+
- ``True`` when the sequence is known to be finite.
|
|
1127
|
+
- ``Unknown`` otherwise.
|
|
1128
|
+
|
|
1129
|
+
.. TODO::
|
|
1130
|
+
|
|
1131
|
+
Ask OEIS for a keyword ensuring that a sequence is infinite.
|
|
1132
|
+
|
|
1133
|
+
EXAMPLES::
|
|
1134
|
+
|
|
1135
|
+
sage: s = oeis('A114288') ; s # optional -- internet
|
|
1136
|
+
A114288: Lexicographically earliest solution of any 9 X 9 sudoku, read by rows.
|
|
1137
|
+
|
|
1138
|
+
sage: s.is_finite() # optional -- internet
|
|
1139
|
+
True
|
|
1140
|
+
|
|
1141
|
+
::
|
|
1142
|
+
|
|
1143
|
+
sage: f = oeis(45) ; f # optional -- internet
|
|
1144
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
1145
|
+
|
|
1146
|
+
sage: f.is_finite() # optional -- internet
|
|
1147
|
+
Unknown
|
|
1148
|
+
|
|
1149
|
+
TESTS::
|
|
1150
|
+
|
|
1151
|
+
sage: s = oeis._imaginary_sequence()
|
|
1152
|
+
sage: s.is_finite()
|
|
1153
|
+
Unknown
|
|
1154
|
+
|
|
1155
|
+
sage: s = oeis._imaginary_sequence(ident='A999993', keywords='nonn,finit')
|
|
1156
|
+
sage: s.is_finite()
|
|
1157
|
+
True
|
|
1158
|
+
"""
|
|
1159
|
+
if 'finit' in self.keywords() or 'full' in self.keywords():
|
|
1160
|
+
return True
|
|
1161
|
+
else:
|
|
1162
|
+
return Unknown
|
|
1163
|
+
|
|
1164
|
+
def is_full(self):
|
|
1165
|
+
r"""
|
|
1166
|
+
Tell whether the sequence ``self`` is full, that is, if all its
|
|
1167
|
+
elements are listed in ``self.first_terms()``.
|
|
1168
|
+
|
|
1169
|
+
Currently, OEIS only provides a keyword when the sequence is known to
|
|
1170
|
+
be full. So, when this keyword is not there, we do not know whether
|
|
1171
|
+
some elements are missing or not.
|
|
1172
|
+
|
|
1173
|
+
OUTPUT:
|
|
1174
|
+
|
|
1175
|
+
- ``True`` when the sequence is known to be full.
|
|
1176
|
+
- ``Unknown`` otherwise.
|
|
1177
|
+
|
|
1178
|
+
EXAMPLES::
|
|
1179
|
+
|
|
1180
|
+
sage: s = oeis('A114288') ; s # optional -- internet
|
|
1181
|
+
A114288: Lexicographically earliest solution of any 9 X 9 sudoku, read by rows.
|
|
1182
|
+
|
|
1183
|
+
sage: s.is_full() # optional -- internet
|
|
1184
|
+
True
|
|
1185
|
+
|
|
1186
|
+
::
|
|
1187
|
+
|
|
1188
|
+
sage: f = oeis(45) ; f # optional -- internet
|
|
1189
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
1190
|
+
|
|
1191
|
+
sage: f.is_full() # optional -- internet
|
|
1192
|
+
Unknown
|
|
1193
|
+
|
|
1194
|
+
TESTS::
|
|
1195
|
+
|
|
1196
|
+
sage: s = oeis._imaginary_sequence()
|
|
1197
|
+
sage: s.is_full()
|
|
1198
|
+
Unknown
|
|
1199
|
+
|
|
1200
|
+
sage: s = oeis._imaginary_sequence(ident='A999992', keywords='nonn,full,finit')
|
|
1201
|
+
sage: s.is_full()
|
|
1202
|
+
True
|
|
1203
|
+
"""
|
|
1204
|
+
if 'full' in self.keywords():
|
|
1205
|
+
return True
|
|
1206
|
+
else:
|
|
1207
|
+
return Unknown
|
|
1208
|
+
|
|
1209
|
+
@cached_method
|
|
1210
|
+
def first_terms(self, number=None):
|
|
1211
|
+
r"""
|
|
1212
|
+
|
|
1213
|
+
INPUT:
|
|
1214
|
+
|
|
1215
|
+
- ``number`` -- integer or ``None`` (default); the number of
|
|
1216
|
+
terms returned (if less than the number of available terms). When set
|
|
1217
|
+
to ``None``, returns all the known terms.
|
|
1218
|
+
|
|
1219
|
+
OUTPUT: tuple of integers
|
|
1220
|
+
|
|
1221
|
+
EXAMPLES::
|
|
1222
|
+
|
|
1223
|
+
sage: f = oeis(45); f # optional -- internet
|
|
1224
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
1225
|
+
|
|
1226
|
+
sage: f.first_terms()[:10] # optional -- internet
|
|
1227
|
+
(0, 1, 1, 2, 3, 5, 8, 13, 21, 34)
|
|
1228
|
+
|
|
1229
|
+
Handle dead sequences, see :issue:`17330` ::
|
|
1230
|
+
|
|
1231
|
+
sage: oeis(5000).first_terms(12) # optional -- internet
|
|
1232
|
+
(1, 0, 0, 1, 1, 1, 11, 36, 92, 491, 2537)
|
|
1233
|
+
|
|
1234
|
+
TESTS::
|
|
1235
|
+
|
|
1236
|
+
sage: s = oeis._imaginary_sequence()
|
|
1237
|
+
sage: s.first_terms()
|
|
1238
|
+
(1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
|
|
1239
|
+
sage: s.first_terms(5)
|
|
1240
|
+
(1, 1, 1, 1, 2)
|
|
1241
|
+
"""
|
|
1242
|
+
fields = ['S', 'T', 'U']
|
|
1243
|
+
return to_tuple(" ".join(flatten([self._field(a) for a in fields])))[:number]
|
|
1244
|
+
|
|
1245
|
+
def _repr_(self):
|
|
1246
|
+
r"""
|
|
1247
|
+
Print the sequence number and a short summary of this sequence.
|
|
1248
|
+
|
|
1249
|
+
OUTPUT: string
|
|
1250
|
+
|
|
1251
|
+
EXAMPLES::
|
|
1252
|
+
|
|
1253
|
+
sage: f = oeis(45) # optional -- internet
|
|
1254
|
+
sage: f # optional -- internet
|
|
1255
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
1256
|
+
|
|
1257
|
+
TESTS::
|
|
1258
|
+
|
|
1259
|
+
sage: s = oeis._imaginary_sequence()
|
|
1260
|
+
sage: s
|
|
1261
|
+
A999999: The characteristic sequence of 42 plus one, starting from 38.
|
|
1262
|
+
"""
|
|
1263
|
+
return "%s: %s" % (self.id(), self.name())
|
|
1264
|
+
|
|
1265
|
+
def __call__(self, k):
|
|
1266
|
+
r"""
|
|
1267
|
+
Return the element of the sequence ``self`` with index ``k``.
|
|
1268
|
+
|
|
1269
|
+
INPUT:
|
|
1270
|
+
|
|
1271
|
+
- ``k`` -- integer
|
|
1272
|
+
|
|
1273
|
+
OUTPUT: integer
|
|
1274
|
+
|
|
1275
|
+
.. NOTE::
|
|
1276
|
+
|
|
1277
|
+
The first index of the sequence ``self`` is not necessarily zero,
|
|
1278
|
+
it depends on the first offset of ``self``. If the sequence
|
|
1279
|
+
represents the decimal expansion of a real number, the index 0
|
|
1280
|
+
corresponds to the digit right after the decimal point.
|
|
1281
|
+
|
|
1282
|
+
EXAMPLES::
|
|
1283
|
+
|
|
1284
|
+
sage: f = oeis(45) # optional -- internet
|
|
1285
|
+
sage: f.first_terms()[:10] # optional -- internet
|
|
1286
|
+
(0, 1, 1, 2, 3, 5, 8, 13, 21, 34)
|
|
1287
|
+
|
|
1288
|
+
sage: f(4) # optional -- internet
|
|
1289
|
+
3
|
|
1290
|
+
|
|
1291
|
+
::
|
|
1292
|
+
|
|
1293
|
+
sage: sfibo = oeis('A039834') # optional -- internet
|
|
1294
|
+
sage: sfibo.first_terms()[:10] # optional -- internet
|
|
1295
|
+
(1, 1, 0, 1, -1, 2, -3, 5, -8, 13)
|
|
1296
|
+
|
|
1297
|
+
sage: sfibo(-2) # optional -- internet
|
|
1298
|
+
1
|
|
1299
|
+
sage: sfibo(4) # optional -- internet
|
|
1300
|
+
-3
|
|
1301
|
+
sage: sfibo.offsets() # optional -- internet
|
|
1302
|
+
(-2, 6)
|
|
1303
|
+
|
|
1304
|
+
TESTS::
|
|
1305
|
+
|
|
1306
|
+
sage: s = oeis._imaginary_sequence()
|
|
1307
|
+
sage: s(38)
|
|
1308
|
+
1
|
|
1309
|
+
sage: s(42)
|
|
1310
|
+
2
|
|
1311
|
+
sage: s(2)
|
|
1312
|
+
Traceback (most recent call last):
|
|
1313
|
+
...
|
|
1314
|
+
ValueError: sequence A999999 is not defined (or known) for index 2
|
|
1315
|
+
"""
|
|
1316
|
+
offset = self.offsets()[0]
|
|
1317
|
+
if 'cons' in self.keywords():
|
|
1318
|
+
offset = - offset
|
|
1319
|
+
n = k - offset
|
|
1320
|
+
if not 0 <= n < len(self.first_terms()):
|
|
1321
|
+
raise ValueError("sequence %s is not defined (or known) for index %s" % (self.id(), k))
|
|
1322
|
+
return self.first_terms()[n]
|
|
1323
|
+
|
|
1324
|
+
def __getitem__(self, i):
|
|
1325
|
+
r"""
|
|
1326
|
+
Return the `i`-th element of sequence ``self``, viewed as a tuple.
|
|
1327
|
+
|
|
1328
|
+
The first element appearing in the sequence ``self``corresponds to
|
|
1329
|
+
``self[0]``. Do not confuse with calling ``self(k)``.
|
|
1330
|
+
|
|
1331
|
+
INPUT:
|
|
1332
|
+
|
|
1333
|
+
- ``i`` -- integer
|
|
1334
|
+
|
|
1335
|
+
OUTPUT: integer
|
|
1336
|
+
|
|
1337
|
+
EXAMPLES::
|
|
1338
|
+
|
|
1339
|
+
sage: sfibo = oeis('A039834') # optional -- internet
|
|
1340
|
+
sage: sfibo[8] # optional -- internet
|
|
1341
|
+
-8
|
|
1342
|
+
sage: sfibo(8) # optional -- internet
|
|
1343
|
+
-21
|
|
1344
|
+
|
|
1345
|
+
TESTS::
|
|
1346
|
+
|
|
1347
|
+
sage: s = oeis._imaginary_sequence()
|
|
1348
|
+
sage: s[2]
|
|
1349
|
+
1
|
|
1350
|
+
sage: s[4]
|
|
1351
|
+
2
|
|
1352
|
+
sage: s[38]
|
|
1353
|
+
Traceback (most recent call last):
|
|
1354
|
+
...
|
|
1355
|
+
IndexError: tuple index out of range
|
|
1356
|
+
"""
|
|
1357
|
+
return self.first_terms()[i]
|
|
1358
|
+
|
|
1359
|
+
def __iter__(self):
|
|
1360
|
+
r"""
|
|
1361
|
+
Iterate over the first terms of ``self``, and raise an error if
|
|
1362
|
+
those first terms are exhausted and the real associated sequence
|
|
1363
|
+
still have terms to produce.
|
|
1364
|
+
|
|
1365
|
+
OUTPUT: integer
|
|
1366
|
+
|
|
1367
|
+
EXAMPLES::
|
|
1368
|
+
|
|
1369
|
+
sage: p = oeis('A085823') ; p # optional -- internet
|
|
1370
|
+
A085823: Numbers in which all substrings are primes.
|
|
1371
|
+
|
|
1372
|
+
sage: for i in p: # optional -- internet
|
|
1373
|
+
....: print(i)
|
|
1374
|
+
2
|
|
1375
|
+
3
|
|
1376
|
+
5
|
|
1377
|
+
7
|
|
1378
|
+
23
|
|
1379
|
+
37
|
|
1380
|
+
53
|
|
1381
|
+
73
|
|
1382
|
+
373
|
|
1383
|
+
|
|
1384
|
+
::
|
|
1385
|
+
|
|
1386
|
+
sage: w = oeis(7540) ; w # optional -- internet
|
|
1387
|
+
A007540: Wilson primes: primes p such that (p-1)! == -1 (mod p^2).
|
|
1388
|
+
|
|
1389
|
+
sage: # optional - internet
|
|
1390
|
+
sage: i = w.__iter__()
|
|
1391
|
+
sage: next(i)
|
|
1392
|
+
5
|
|
1393
|
+
sage: next(i)
|
|
1394
|
+
13
|
|
1395
|
+
sage: next(i)
|
|
1396
|
+
563
|
|
1397
|
+
sage: next(i)
|
|
1398
|
+
Traceback (most recent call last):
|
|
1399
|
+
...
|
|
1400
|
+
LookupError: future values not provided by OEIS
|
|
1401
|
+
|
|
1402
|
+
::
|
|
1403
|
+
|
|
1404
|
+
sage: f = oeis(45) ; f # optional -- internet
|
|
1405
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
1406
|
+
|
|
1407
|
+
sage: for i in f: # optional -- internet
|
|
1408
|
+
....: print(i)
|
|
1409
|
+
Traceback (most recent call last):
|
|
1410
|
+
...
|
|
1411
|
+
LookupError: future values not provided by OEIS
|
|
1412
|
+
|
|
1413
|
+
TESTS::
|
|
1414
|
+
|
|
1415
|
+
sage: s = oeis._imaginary_sequence()
|
|
1416
|
+
sage: for i in s:
|
|
1417
|
+
....: pass
|
|
1418
|
+
Traceback (most recent call last):
|
|
1419
|
+
...
|
|
1420
|
+
LookupError: future values not provided by OEIS
|
|
1421
|
+
|
|
1422
|
+
sage: for i in s:
|
|
1423
|
+
....: if i == 2:
|
|
1424
|
+
....: print(i)
|
|
1425
|
+
....: break
|
|
1426
|
+
2
|
|
1427
|
+
|
|
1428
|
+
sage: s = oeis._imaginary_sequence(ident='A999991', keywords='sign,full')
|
|
1429
|
+
sage: for i in s: pass
|
|
1430
|
+
"""
|
|
1431
|
+
yield from self.first_terms()
|
|
1432
|
+
if self.is_full() is not True:
|
|
1433
|
+
raise LookupError("future values not provided by OEIS")
|
|
1434
|
+
|
|
1435
|
+
def references(self):
|
|
1436
|
+
r"""
|
|
1437
|
+
Return a tuple of references associated to the sequence ``self``.
|
|
1438
|
+
|
|
1439
|
+
OUTPUT:
|
|
1440
|
+
|
|
1441
|
+
- tuple of strings (with fancy formatting).
|
|
1442
|
+
|
|
1443
|
+
EXAMPLES::
|
|
1444
|
+
|
|
1445
|
+
sage: w = oeis(7540) ; w # optional -- internet
|
|
1446
|
+
A007540: Wilson primes: primes p such that (p-1)! == -1 (mod p^2).
|
|
1447
|
+
|
|
1448
|
+
sage: w.references() # optional -- internet
|
|
1449
|
+
...Albert H. Beiler, Recreations in the Theory of Numbers, Dover, NY, 1964, p. 52.
|
|
1450
|
+
...
|
|
1451
|
+
|
|
1452
|
+
TESTS::
|
|
1453
|
+
|
|
1454
|
+
sage: s = oeis._imaginary_sequence()
|
|
1455
|
+
sage: s.references()[1]
|
|
1456
|
+
'Lewis Carroll, The Hunting of the Snark.'
|
|
1457
|
+
"""
|
|
1458
|
+
return FancyTuple(self._field('D'))
|
|
1459
|
+
|
|
1460
|
+
def links(self, browse=None, format='guess'):
|
|
1461
|
+
r"""
|
|
1462
|
+
Return, display or browse links associated to the sequence ``self``.
|
|
1463
|
+
|
|
1464
|
+
INPUT:
|
|
1465
|
+
|
|
1466
|
+
- ``browse`` -- integer; a list of integers, or the word 'all'
|
|
1467
|
+
(default: ``None``) which links to open in a web browser
|
|
1468
|
+
|
|
1469
|
+
- ``format`` -- string (default: ``'guess'``); how to display the links
|
|
1470
|
+
|
|
1471
|
+
OUTPUT: tuple of strings (with fancy formatting):
|
|
1472
|
+
|
|
1473
|
+
- if ``format`` is ``url``, returns a tuple of absolute links without description.
|
|
1474
|
+
- if ``format`` is ``html``, returns nothing but prints a tuple of clickable absolute links in their context.
|
|
1475
|
+
- if ``format`` is ``guess``, adapts the output to the context (command line or notebook).
|
|
1476
|
+
- if ``format`` is ``raw``, the links as they appear in the database, relative links are not made absolute.
|
|
1477
|
+
|
|
1478
|
+
EXAMPLES::
|
|
1479
|
+
|
|
1480
|
+
sage: f = oeis(45) ; f # optional -- internet
|
|
1481
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
1482
|
+
|
|
1483
|
+
sage: f.links(format='url') # optional -- internet
|
|
1484
|
+
0: https://oeis.org/A000045/b000045.txt
|
|
1485
|
+
1: ...
|
|
1486
|
+
2: ...
|
|
1487
|
+
|
|
1488
|
+
sage: f.links(format='raw') # optional -- internet
|
|
1489
|
+
0: N. J. A. Sloane, <a href="/A000045/b000045.txt">The first 2000 Fibonacci numbers: Table of n, F(n) for n = 0..2000</a>
|
|
1490
|
+
1: ...
|
|
1491
|
+
2: ...
|
|
1492
|
+
|
|
1493
|
+
TESTS::
|
|
1494
|
+
|
|
1495
|
+
sage: s = oeis._imaginary_sequence()
|
|
1496
|
+
sage: s.links(format='raw')[2]
|
|
1497
|
+
'Do not confuse with the sequence <a href="/A000042">A000042</a> or the sequence <a href="/A000024">A000024</a>'
|
|
1498
|
+
|
|
1499
|
+
sage: s.links(format='url')[3]
|
|
1500
|
+
'https://oeis.org/A000024'
|
|
1501
|
+
|
|
1502
|
+
sage: HTML = s.links(format='html'); HTML
|
|
1503
|
+
0: Wikipedia, <a href="https://en.wikipedia.org/wiki/42_(number)">42 (number)</a>
|
|
1504
|
+
1: See. also <a href="https://github.com/sagemath/sage/issues/42">github issue #42</a>
|
|
1505
|
+
...
|
|
1506
|
+
sage: type(HTML)
|
|
1507
|
+
<class 'sage.misc.html.HtmlFragment'>
|
|
1508
|
+
"""
|
|
1509
|
+
def url_absolute(s):
|
|
1510
|
+
return re.sub(r'\"\/', '\"' + oeis_url, s)
|
|
1511
|
+
|
|
1512
|
+
if browse is None:
|
|
1513
|
+
if format == 'guess':
|
|
1514
|
+
return self.links(format='url')
|
|
1515
|
+
elif format == 'raw':
|
|
1516
|
+
return FancyTuple(self._field('H'))
|
|
1517
|
+
elif format == 'html':
|
|
1518
|
+
return HtmlFragment(FancyTuple([url_absolute(f) for f in self._field('H')]))
|
|
1519
|
+
elif format == 'url':
|
|
1520
|
+
url_list = flatten([_urls(url_absolute(string)) for string in self._field('H')])
|
|
1521
|
+
return FancyTuple(url_list)
|
|
1522
|
+
else:
|
|
1523
|
+
import webbrowser
|
|
1524
|
+
url_list = flatten([_urls(url_absolute(string)) for string in self._field('H')])
|
|
1525
|
+
if isinstance(browse, (int, Integer)):
|
|
1526
|
+
webbrowser.open(url_list[browse])
|
|
1527
|
+
elif isinstance(browse, (list, tuple)):
|
|
1528
|
+
for url_number in browse:
|
|
1529
|
+
webbrowser.open(url_list[url_number])
|
|
1530
|
+
elif browse == 'all':
|
|
1531
|
+
for url in url_list:
|
|
1532
|
+
webbrowser.open(url)
|
|
1533
|
+
|
|
1534
|
+
def formulas(self):
|
|
1535
|
+
r"""
|
|
1536
|
+
Return a tuple of formulas associated to the sequence ``self``.
|
|
1537
|
+
|
|
1538
|
+
OUTPUT:
|
|
1539
|
+
|
|
1540
|
+
- tuple of strings (with fancy formatting).
|
|
1541
|
+
|
|
1542
|
+
EXAMPLES::
|
|
1543
|
+
|
|
1544
|
+
sage: f = oeis(45) ; f # optional -- internet
|
|
1545
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
1546
|
+
|
|
1547
|
+
sage: f.formulas()[2] # optional -- internet
|
|
1548
|
+
'F(n) = ((1+sqrt(5))^n - (1-sqrt(5))^n)/(2^n*sqrt(5)).'
|
|
1549
|
+
|
|
1550
|
+
TESTS::
|
|
1551
|
+
|
|
1552
|
+
sage: s = oeis._imaginary_sequence()
|
|
1553
|
+
sage: s.formulas()
|
|
1554
|
+
0: For n big enough, s(n+1) - s(n) = 0.
|
|
1555
|
+
"""
|
|
1556
|
+
return FancyTuple(self._field('F'))
|
|
1557
|
+
|
|
1558
|
+
def cross_references(self, fetch=False):
|
|
1559
|
+
r"""
|
|
1560
|
+
Return a tuple of cross references associated to the sequence
|
|
1561
|
+
``self``.
|
|
1562
|
+
|
|
1563
|
+
INPUT:
|
|
1564
|
+
|
|
1565
|
+
- ``fetch`` -- boolean (default: ``False``)
|
|
1566
|
+
|
|
1567
|
+
OUTPUT:
|
|
1568
|
+
|
|
1569
|
+
- if ``fetch`` is ``False``, return a list of OEIS IDs (strings).
|
|
1570
|
+
- if ``fetch`` is ``True``, return a tuple of OEIS sequences.
|
|
1571
|
+
|
|
1572
|
+
EXAMPLES::
|
|
1573
|
+
|
|
1574
|
+
sage: nbalanced = oeis("A005598") ; nbalanced # optional -- internet
|
|
1575
|
+
A005598: a(n) = 1 + Sum_{i=1..n} (n-i+1)*phi(i).
|
|
1576
|
+
|
|
1577
|
+
sage: nbalanced.cross_references() # optional -- internet
|
|
1578
|
+
('A000010', 'A002088', 'A011755', 'A049695', 'A049703', 'A103116')
|
|
1579
|
+
|
|
1580
|
+
sage: nbalanced.cross_references(fetch=True) # optional -- internet
|
|
1581
|
+
0: A000010: Euler totient function phi(n): count numbers <= n and prime to n.
|
|
1582
|
+
1: A002088: Sum of totient function: a(n) = Sum_{k=1..n} phi(k), cf. A000010.
|
|
1583
|
+
2: A011755: a(n) = Sum_{k=1..n} k*phi(k).
|
|
1584
|
+
3: A049695: Array T read by diagonals; T(i,j) is the number of nonnegative
|
|
1585
|
+
slopes of lines determined by 2 lattice points in
|
|
1586
|
+
[ 0,i ] X [ 0,j ] if i > 0; T(0,j)=1 if j > 0; T(0,0)=0.
|
|
1587
|
+
4: A049703: a(0) = 0; for n>0, a(n) = A005598(n)/2.
|
|
1588
|
+
5: A103116: a(n) = Sum_{i=1..n} (n-i+1)*phi(i).
|
|
1589
|
+
|
|
1590
|
+
sage: phi = _[3] # optional -- internet
|
|
1591
|
+
|
|
1592
|
+
TESTS::
|
|
1593
|
+
|
|
1594
|
+
sage: s = oeis._imaginary_sequence()
|
|
1595
|
+
sage: s.cross_references()
|
|
1596
|
+
('A000042', 'A000024')
|
|
1597
|
+
"""
|
|
1598
|
+
ref_list = re.findall('A[0-9]{6}', " ".join(self._field('Y')))
|
|
1599
|
+
if fetch:
|
|
1600
|
+
T = [oeis.find_by_id(r) for r in ref_list]
|
|
1601
|
+
return FancyTuple([s for s in T if not s.is_dead()])
|
|
1602
|
+
return tuple(ref_list)
|
|
1603
|
+
|
|
1604
|
+
def extensions_or_errors(self):
|
|
1605
|
+
r"""
|
|
1606
|
+
Return a tuple of extensions or errors associated to the
|
|
1607
|
+
sequence ``self``.
|
|
1608
|
+
|
|
1609
|
+
OUTPUT:
|
|
1610
|
+
|
|
1611
|
+
- tuple of strings (with fancy formatting).
|
|
1612
|
+
|
|
1613
|
+
EXAMPLES::
|
|
1614
|
+
|
|
1615
|
+
sage: sfibo = oeis('A039834'); sfibo # optional -- internet
|
|
1616
|
+
A039834: a(n+2) = -a(n+1) + a(n) (signed Fibonacci numbers) with
|
|
1617
|
+
a(-2) = a(-1) = 1; or Fibonacci numbers (A000045) extended
|
|
1618
|
+
to negative indices.
|
|
1619
|
+
|
|
1620
|
+
sage: sfibo.extensions_or_errors()[0] # optional -- internet
|
|
1621
|
+
'Signs corrected by _Len Smiley_ and _N. J. A. Sloane_'
|
|
1622
|
+
|
|
1623
|
+
TESTS::
|
|
1624
|
+
|
|
1625
|
+
sage: s = oeis._imaginary_sequence()
|
|
1626
|
+
sage: s.extensions_or_errors()
|
|
1627
|
+
0: This sequence does not contain errors.
|
|
1628
|
+
"""
|
|
1629
|
+
return FancyTuple(self._field('E'))
|
|
1630
|
+
|
|
1631
|
+
def examples(self):
|
|
1632
|
+
r"""
|
|
1633
|
+
Return a tuple of examples associated to the sequence ``self``.
|
|
1634
|
+
|
|
1635
|
+
OUTPUT:
|
|
1636
|
+
|
|
1637
|
+
- tuple of strings (with fancy formatting).
|
|
1638
|
+
|
|
1639
|
+
EXAMPLES::
|
|
1640
|
+
|
|
1641
|
+
sage: c = oeis(1203); c # optional -- internet
|
|
1642
|
+
A001203: Simple continued fraction expansion of Pi.
|
|
1643
|
+
|
|
1644
|
+
sage: c.examples() # optional -- internet
|
|
1645
|
+
0: Pi = 3.1415926535897932384...
|
|
1646
|
+
1: = 3 + 1/(7 + 1/(15 + 1/(1 + 1/(292 + ...))))
|
|
1647
|
+
2: = [a_0; a_1, a_2, a_3, ...] = [3; 7, 15, 1, 292, ...].
|
|
1648
|
+
|
|
1649
|
+
TESTS::
|
|
1650
|
+
|
|
1651
|
+
sage: s = oeis._imaginary_sequence()
|
|
1652
|
+
sage: s.examples()
|
|
1653
|
+
0: s(42) + s(43) = 0.
|
|
1654
|
+
"""
|
|
1655
|
+
return FancyTuple(self._field('e'))
|
|
1656
|
+
|
|
1657
|
+
def comments(self):
|
|
1658
|
+
r"""
|
|
1659
|
+
Return a tuple of comments associated to the sequence ``self``.
|
|
1660
|
+
|
|
1661
|
+
OUTPUT:
|
|
1662
|
+
|
|
1663
|
+
- tuple of strings (with fancy formatting).
|
|
1664
|
+
|
|
1665
|
+
EXAMPLES::
|
|
1666
|
+
|
|
1667
|
+
sage: f = oeis(45); f # optional -- internet
|
|
1668
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
1669
|
+
|
|
1670
|
+
sage: f.comments()[:8] # optional -- internet
|
|
1671
|
+
0: D. E. Knuth writes...
|
|
1672
|
+
1: In keeping with historical accounts...
|
|
1673
|
+
2: Susantha Goonatilake writes...
|
|
1674
|
+
3: Also sometimes called Hemachandra numbers.
|
|
1675
|
+
4: Also sometimes called Lamé's sequence.
|
|
1676
|
+
5: ...
|
|
1677
|
+
6: F(n+2) = number of binary sequences of length n that have no consecutive 0's.
|
|
1678
|
+
7: F(n+2) = number of subsets of {1,2,...,n} that contain no consecutive integers.
|
|
1679
|
+
|
|
1680
|
+
TESTS::
|
|
1681
|
+
|
|
1682
|
+
sage: s = oeis._imaginary_sequence()
|
|
1683
|
+
sage: s.comments()
|
|
1684
|
+
0: 42 is the product of the first 4 prime numbers, except 5 and perhaps 1.
|
|
1685
|
+
1: Apart from that, i have no comment.
|
|
1686
|
+
"""
|
|
1687
|
+
return FancyTuple(self._field('C'))
|
|
1688
|
+
|
|
1689
|
+
def url(self):
|
|
1690
|
+
r"""
|
|
1691
|
+
Return the URL of the page associated to the sequence ``self``.
|
|
1692
|
+
|
|
1693
|
+
OUTPUT: string
|
|
1694
|
+
|
|
1695
|
+
EXAMPLES::
|
|
1696
|
+
|
|
1697
|
+
sage: f = oeis(45); f # optional -- internet
|
|
1698
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
1699
|
+
|
|
1700
|
+
sage: f.url() # optional -- internet
|
|
1701
|
+
'https://oeis.org/A000045'
|
|
1702
|
+
|
|
1703
|
+
TESTS::
|
|
1704
|
+
|
|
1705
|
+
sage: s = oeis._imaginary_sequence()
|
|
1706
|
+
sage: s.url()
|
|
1707
|
+
'https://oeis.org/A999999'
|
|
1708
|
+
"""
|
|
1709
|
+
return oeis_url + self.id()
|
|
1710
|
+
|
|
1711
|
+
def browse(self):
|
|
1712
|
+
r"""
|
|
1713
|
+
Open the OEIS web page associated to the sequence ``self`` in a browser.
|
|
1714
|
+
|
|
1715
|
+
EXAMPLES::
|
|
1716
|
+
|
|
1717
|
+
sage: f = oeis(45); f # optional -- internet webbrowser
|
|
1718
|
+
A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
|
|
1719
|
+
|
|
1720
|
+
sage: f.browse() # optional -- internet webbrowser
|
|
1721
|
+
|
|
1722
|
+
TESTS::
|
|
1723
|
+
|
|
1724
|
+
sage: s = oeis._imaginary_sequence() # optional -- webbrowser
|
|
1725
|
+
sage: s.browse() # optional -- webbrowser
|
|
1726
|
+
"""
|
|
1727
|
+
import webbrowser
|
|
1728
|
+
webbrowser.open(self.url())
|
|
1729
|
+
|
|
1730
|
+
def show(self):
|
|
1731
|
+
r"""
|
|
1732
|
+
Display most available information about the sequence ``self``.
|
|
1733
|
+
|
|
1734
|
+
EXAMPLES::
|
|
1735
|
+
|
|
1736
|
+
sage: s = oeis(12345) # optional -- internet
|
|
1737
|
+
sage: s.show() # optional -- internet
|
|
1738
|
+
ID
|
|
1739
|
+
A012345
|
|
1740
|
+
<BLANKLINE>
|
|
1741
|
+
NAME
|
|
1742
|
+
Coefficients in the expansion sinh(arcsin(x)*arcsin(x)) = 2*x^2/2!+8*x^4/4!+248*x^6/6!+11328*x^8/8!+...
|
|
1743
|
+
<BLANKLINE>
|
|
1744
|
+
FIRST TERMS
|
|
1745
|
+
(2, 8, 248, 11328, 849312, 94857600, 14819214720, 3091936512000, 831657655349760, 280473756197529600, 115967597965430077440, 57712257892456911912960, 34039765801079493369569280)
|
|
1746
|
+
<BLANKLINE>
|
|
1747
|
+
LINKS
|
|
1748
|
+
0: https://oeis.org/A012345/b012345.txt
|
|
1749
|
+
<BLANKLINE>
|
|
1750
|
+
FORMULAS
|
|
1751
|
+
...
|
|
1752
|
+
OFFSETS
|
|
1753
|
+
(0, 1)
|
|
1754
|
+
<BLANKLINE>
|
|
1755
|
+
URL
|
|
1756
|
+
https://oeis.org/A012345
|
|
1757
|
+
<BLANKLINE>
|
|
1758
|
+
AUTHOR
|
|
1759
|
+
Patrick Demichel (patrick.demichel(AT)hp.com)
|
|
1760
|
+
<BLANKLINE>
|
|
1761
|
+
|
|
1762
|
+
TESTS::
|
|
1763
|
+
|
|
1764
|
+
sage: s = oeis._imaginary_sequence()
|
|
1765
|
+
sage: s.show()
|
|
1766
|
+
ID
|
|
1767
|
+
A999999
|
|
1768
|
+
<BLANKLINE>
|
|
1769
|
+
NAME
|
|
1770
|
+
The characteristic sequence of 42 plus ...
|
|
1771
|
+
FIRST TERMS
|
|
1772
|
+
(1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
|
|
1773
|
+
<BLANKLINE>
|
|
1774
|
+
COMMENTS
|
|
1775
|
+
0: 42 is the product of the first 4 prime numbers, except ...
|
|
1776
|
+
1: Apart from that, i have no comment.
|
|
1777
|
+
...
|
|
1778
|
+
"""
|
|
1779
|
+
for s in ['id', 'name', 'first_terms', 'comments', 'references',
|
|
1780
|
+
'links', 'formulas', 'examples', 'cross_references',
|
|
1781
|
+
'programs', 'keywords', 'offsets', 'url', 'old_IDs',
|
|
1782
|
+
'author', 'extensions_or_errors']:
|
|
1783
|
+
result = getattr(self, s)()
|
|
1784
|
+
if result != '' and result != ('',) and result != ():
|
|
1785
|
+
print(re.sub('_', ' ', s).upper())
|
|
1786
|
+
print(str(result) + '\n')
|
|
1787
|
+
|
|
1788
|
+
def programs(self, language='all', preparsing=True, keep_comments=False):
|
|
1789
|
+
r"""
|
|
1790
|
+
Return programs for the sequence ``self`` in the given ``language``.
|
|
1791
|
+
|
|
1792
|
+
INPUT:
|
|
1793
|
+
|
|
1794
|
+
- ``language`` -- string (default: ``'all'``); the chosen language.
|
|
1795
|
+
Possible values are 'all' for the full list, or
|
|
1796
|
+
any language name, for example 'sage', 'maple', 'mathematica', etc.
|
|
1797
|
+
|
|
1798
|
+
Some further optional input is specific to sage code treatment:
|
|
1799
|
+
|
|
1800
|
+
- ``preparsing`` -- boolean (default: ``True``); whether to preparse
|
|
1801
|
+
sage code
|
|
1802
|
+
- ``keep_comments`` -- boolean (default: ``False``); whether to keep
|
|
1803
|
+
comments in sage code
|
|
1804
|
+
|
|
1805
|
+
OUTPUT:
|
|
1806
|
+
|
|
1807
|
+
If ``language`` is ``'all'``, this returns a sorted list of pairs
|
|
1808
|
+
(language, code), where every language can appear several times.
|
|
1809
|
+
|
|
1810
|
+
Otherwise, this returns a list of programs in the ``language``,
|
|
1811
|
+
each program being a tuple of strings (with fancy formatting).
|
|
1812
|
+
|
|
1813
|
+
EXAMPLES::
|
|
1814
|
+
|
|
1815
|
+
sage: ee = oeis.find_by_id('A00260') # optional -- internet
|
|
1816
|
+
sage: ee.programs('pari')[0] # optional -- internet
|
|
1817
|
+
0: {a(n) = binomial(...)};...
|
|
1818
|
+
|
|
1819
|
+
sage: G = oeis.find_by_id('A27642') # optional -- internet
|
|
1820
|
+
sage: G.programs('all') # optional -- internet
|
|
1821
|
+
[('haskell', ...),
|
|
1822
|
+
('magma', ...),
|
|
1823
|
+
...
|
|
1824
|
+
('python', ...),
|
|
1825
|
+
('sage', ...)]
|
|
1826
|
+
|
|
1827
|
+
TESTS::
|
|
1828
|
+
|
|
1829
|
+
sage: s = oeis._imaginary_sequence()
|
|
1830
|
+
sage: s.programs()
|
|
1831
|
+
[('maple', ...),
|
|
1832
|
+
('mathematica', ...),
|
|
1833
|
+
('python',
|
|
1834
|
+
0: def A999999(n):
|
|
1835
|
+
1: assert(isinstance(n, (int, Integer))), "n must be an integer."
|
|
1836
|
+
2: if n < 38:
|
|
1837
|
+
3: raise ValueError("the value %s is not accepted" % str(n))
|
|
1838
|
+
4: elif n == 42:
|
|
1839
|
+
5: return 2
|
|
1840
|
+
6: else:
|
|
1841
|
+
7: return 1)]
|
|
1842
|
+
|
|
1843
|
+
sage: s.programs('maple')[0]
|
|
1844
|
+
0: Do not even try, Maple is not able to produce such a sequence.
|
|
1845
|
+
|
|
1846
|
+
sage: s.programs('mathematica')[0]
|
|
1847
|
+
0: Mathematica neither.
|
|
1848
|
+
"""
|
|
1849
|
+
language = language.lower()
|
|
1850
|
+
if language == "maple":
|
|
1851
|
+
return [FancyTuple(self._field('p'))]
|
|
1852
|
+
elif language == "mathematica":
|
|
1853
|
+
return [FancyTuple(self._field('t'))]
|
|
1854
|
+
if language == 'sagemath':
|
|
1855
|
+
language = 'sage'
|
|
1856
|
+
if language == 'all':
|
|
1857
|
+
table = (('maple', FancyTuple(self._field('p'))),
|
|
1858
|
+
('mathematica', FancyTuple(self._field('t'))))
|
|
1859
|
+
table = [(lang, code) for lang, code in table if code]
|
|
1860
|
+
else:
|
|
1861
|
+
table = []
|
|
1862
|
+
|
|
1863
|
+
known_langs = ['sage', 'python', 'scheme']
|
|
1864
|
+
|
|
1865
|
+
def is_starting_line(line):
|
|
1866
|
+
"""
|
|
1867
|
+
Help to split the big OEIS code block into blocks by language.
|
|
1868
|
+
|
|
1869
|
+
This returns ``None`` if ``line`` is not a starting line.
|
|
1870
|
+
"""
|
|
1871
|
+
if not line.startswith('('):
|
|
1872
|
+
return None
|
|
1873
|
+
if ')' not in line:
|
|
1874
|
+
return None
|
|
1875
|
+
end = line.index(')')
|
|
1876
|
+
language = line[1:end].lower() # normalise the language names
|
|
1877
|
+
if '(' in language:
|
|
1878
|
+
return None
|
|
1879
|
+
for special in known_langs:
|
|
1880
|
+
if special in language:
|
|
1881
|
+
language = special
|
|
1882
|
+
if ' ' in language: # get rid of language versions
|
|
1883
|
+
language = language.split(' ')[0]
|
|
1884
|
+
if language == 'c#' or language == 'c++':
|
|
1885
|
+
language = 'c'
|
|
1886
|
+
if language.isalnum():
|
|
1887
|
+
return (language, end)
|
|
1888
|
+
return None
|
|
1889
|
+
|
|
1890
|
+
def filter_sage(lines):
|
|
1891
|
+
"""
|
|
1892
|
+
Remove comments and preparse if required, only for sage code.
|
|
1893
|
+
|
|
1894
|
+
This is an iterator.
|
|
1895
|
+
"""
|
|
1896
|
+
for line in lines:
|
|
1897
|
+
if keep_comments or not line.strip().startswith('#'):
|
|
1898
|
+
if preparsing:
|
|
1899
|
+
yield preparse(line)
|
|
1900
|
+
else:
|
|
1901
|
+
yield line
|
|
1902
|
+
|
|
1903
|
+
def flush_to_table(language, code_lines):
|
|
1904
|
+
"""
|
|
1905
|
+
Put a list of code lines into the appropriate box of the table.
|
|
1906
|
+
|
|
1907
|
+
With special treatment for sage code blocks.
|
|
1908
|
+
"""
|
|
1909
|
+
if language == 'sage':
|
|
1910
|
+
table.append((language, FancyTuple(filter_sage(code_lines))))
|
|
1911
|
+
elif language is not None:
|
|
1912
|
+
table.append((language, FancyTuple(code_lines)))
|
|
1913
|
+
|
|
1914
|
+
programs = FancyTuple(self._field('o'))
|
|
1915
|
+
code_lines = []
|
|
1916
|
+
old_language = None
|
|
1917
|
+
for line in programs:
|
|
1918
|
+
new_language = is_starting_line(line)
|
|
1919
|
+
if new_language is not None:
|
|
1920
|
+
# flush the stock of code lines if any
|
|
1921
|
+
flush_to_table(old_language, code_lines)
|
|
1922
|
+
# start new stock of code lines
|
|
1923
|
+
old_language, end = new_language
|
|
1924
|
+
rest = line[end + 1:].strip()
|
|
1925
|
+
code_lines = [rest] if rest else []
|
|
1926
|
+
else:
|
|
1927
|
+
code_lines.append(line)
|
|
1928
|
+
flush_to_table(old_language, code_lines)
|
|
1929
|
+
|
|
1930
|
+
if language == 'all':
|
|
1931
|
+
return sorted(table)
|
|
1932
|
+
return sorted(prog for la, prog in table if la == language)
|
|
1933
|
+
|
|
1934
|
+
def test_compile_sage_code(self):
|
|
1935
|
+
"""
|
|
1936
|
+
Try to compile the extracted sage code, if there is any.
|
|
1937
|
+
|
|
1938
|
+
If there are several sage code fields, they are all considered.
|
|
1939
|
+
|
|
1940
|
+
Dead sequences are considered to compile correctly by default.
|
|
1941
|
+
|
|
1942
|
+
This returns ``True`` if the code compiles, and raises an error
|
|
1943
|
+
otherwise.
|
|
1944
|
+
|
|
1945
|
+
EXAMPLES:
|
|
1946
|
+
|
|
1947
|
+
One correct sequence::
|
|
1948
|
+
|
|
1949
|
+
sage: s = oeis.find_by_id('A027642') # optional -- internet
|
|
1950
|
+
sage: s.test_compile_sage_code() # optional -- internet
|
|
1951
|
+
True
|
|
1952
|
+
|
|
1953
|
+
One dead sequence::
|
|
1954
|
+
|
|
1955
|
+
sage: s = oeis.find_by_id('A000154') # optional -- internet
|
|
1956
|
+
sage: s.test_compile_sage_code() # optional -- internet
|
|
1957
|
+
True
|
|
1958
|
+
"""
|
|
1959
|
+
if self.is_dead():
|
|
1960
|
+
return True
|
|
1961
|
+
filt = self.programs(language='sage')
|
|
1962
|
+
if filt:
|
|
1963
|
+
for v in filt:
|
|
1964
|
+
tp = tmp_filename(ext='.sage')
|
|
1965
|
+
_ = compile('\n'.join(v), tp, 'exec')
|
|
1966
|
+
return True
|
|
1967
|
+
|
|
1968
|
+
|
|
1969
|
+
class FancyTuple(tuple):
|
|
1970
|
+
r"""
|
|
1971
|
+
This class inherits from ``tuple``, it allows to nicely print tuples whose
|
|
1972
|
+
elements have a one line representation.
|
|
1973
|
+
|
|
1974
|
+
EXAMPLES::
|
|
1975
|
+
|
|
1976
|
+
sage: from sage.databases.oeis import FancyTuple
|
|
1977
|
+
sage: t = FancyTuple(['zero', 'one', 'two', 'three', 4]); t
|
|
1978
|
+
0: zero
|
|
1979
|
+
1: one
|
|
1980
|
+
2: two
|
|
1981
|
+
3: three
|
|
1982
|
+
4: 4
|
|
1983
|
+
|
|
1984
|
+
sage: t[2]
|
|
1985
|
+
'two'
|
|
1986
|
+
"""
|
|
1987
|
+
def __repr__(self):
|
|
1988
|
+
r"""
|
|
1989
|
+
Print the tuple with one value per line, where each line
|
|
1990
|
+
begins with the index of the value in ``self``.
|
|
1991
|
+
|
|
1992
|
+
EXAMPLES::
|
|
1993
|
+
|
|
1994
|
+
sage: from sage.databases.oeis import FancyTuple
|
|
1995
|
+
sage: t = FancyTuple(['zero', 'one', 'two', 'three', 4]); t
|
|
1996
|
+
0: zero
|
|
1997
|
+
1: one
|
|
1998
|
+
2: two
|
|
1999
|
+
3: three
|
|
2000
|
+
4: 4
|
|
2001
|
+
|
|
2002
|
+
sage: t = FancyTuple(['Français', 'Español', '中文']); t
|
|
2003
|
+
0: Français
|
|
2004
|
+
1: Español
|
|
2005
|
+
2: 中文
|
|
2006
|
+
"""
|
|
2007
|
+
length = len(str(len(self) - 1))
|
|
2008
|
+
return '\n'.join('{0:>{1}}: {2}'.format(i, length, item) for i, item in enumerate(self))
|
|
2009
|
+
|
|
2010
|
+
def __getslice__(self, i, j):
|
|
2011
|
+
r"""
|
|
2012
|
+
The slice of a FancyTuple remains a FancyTuple.
|
|
2013
|
+
|
|
2014
|
+
EXAMPLES::
|
|
2015
|
+
|
|
2016
|
+
sage: from sage.databases.oeis import FancyTuple
|
|
2017
|
+
sage: t = FancyTuple(['zero', 'one', 'two', 'three', 4])
|
|
2018
|
+
sage: t[-2:]
|
|
2019
|
+
0: three
|
|
2020
|
+
1: 4
|
|
2021
|
+
|
|
2022
|
+
TESTS::
|
|
2023
|
+
|
|
2024
|
+
sage: t = ('é', 'è', 'à', 'ç')
|
|
2025
|
+
sage: FancyTuple(t)[2:4]
|
|
2026
|
+
0: à
|
|
2027
|
+
1: ç
|
|
2028
|
+
"""
|
|
2029
|
+
return self.__getitem__(slice(i, j))
|
|
2030
|
+
|
|
2031
|
+
def __getitem__(self, x):
|
|
2032
|
+
r"""
|
|
2033
|
+
If ``x`` is a slice return the corresponding sub FancyTuple,
|
|
2034
|
+
else return the ``x``-th item of ``self``.
|
|
2035
|
+
|
|
2036
|
+
TESTS::
|
|
2037
|
+
|
|
2038
|
+
sage: from sage.databases.oeis import FancyTuple
|
|
2039
|
+
sage: t = ('é', 'è', 'à', 'ç')
|
|
2040
|
+
sage: ft = FancyTuple(t)
|
|
2041
|
+
sage: ft[0] == 'é'
|
|
2042
|
+
True
|
|
2043
|
+
sage: ft[-1] == 'ç'
|
|
2044
|
+
True
|
|
2045
|
+
|
|
2046
|
+
Check that :issue:`26997` is fixed::
|
|
2047
|
+
|
|
2048
|
+
sage: FancyTuple([[1,2,3],(4,5,6)])
|
|
2049
|
+
0: [1, 2, 3]
|
|
2050
|
+
1: (4, 5, 6)
|
|
2051
|
+
"""
|
|
2052
|
+
res = tuple.__getitem__(self, x)
|
|
2053
|
+
if isinstance(x, slice):
|
|
2054
|
+
res = FancyTuple(res)
|
|
2055
|
+
return res
|
|
2056
|
+
|
|
2057
|
+
|
|
2058
|
+
oeis = OEIS()
|