passagemath-categories 10.6.32__cp314-cp314t-musllinux_1_2_aarch64.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_categories-10.6.32.dist-info/METADATA +156 -0
- passagemath_categories-10.6.32.dist-info/RECORD +719 -0
- passagemath_categories-10.6.32.dist-info/WHEEL +5 -0
- passagemath_categories-10.6.32.dist-info/top_level.txt +2 -0
- passagemath_categories.libs/libgcc_s-2d945d6c.so.1 +0 -0
- passagemath_categories.libs/libgmp-28992bcb.so.10.5.0 +0 -0
- passagemath_categories.libs/libstdc++-85f2cd6d.so.6.0.33 +0 -0
- sage/all__sagemath_categories.py +28 -0
- sage/arith/all.py +38 -0
- sage/arith/constants.pxd +27 -0
- sage/arith/functions.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/functions.pxd +4 -0
- sage/arith/functions.pyx +221 -0
- sage/arith/misc.py +6552 -0
- sage/arith/multi_modular.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/multi_modular.pxd +39 -0
- sage/arith/multi_modular.pyx +994 -0
- sage/arith/rational_reconstruction.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/rational_reconstruction.pxd +4 -0
- sage/arith/rational_reconstruction.pyx +115 -0
- sage/arith/srange.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/srange.pyx +571 -0
- sage/calculus/all__sagemath_categories.py +2 -0
- sage/calculus/functional.py +481 -0
- sage/calculus/functions.py +151 -0
- sage/categories/additive_groups.py +73 -0
- sage/categories/additive_magmas.py +1044 -0
- sage/categories/additive_monoids.py +114 -0
- sage/categories/additive_semigroups.py +184 -0
- sage/categories/affine_weyl_groups.py +238 -0
- sage/categories/algebra_ideals.py +95 -0
- sage/categories/algebra_modules.py +96 -0
- sage/categories/algebras.py +349 -0
- sage/categories/algebras_with_basis.py +377 -0
- sage/categories/all.py +160 -0
- sage/categories/aperiodic_semigroups.py +29 -0
- sage/categories/associative_algebras.py +47 -0
- sage/categories/bialgebras.py +101 -0
- sage/categories/bialgebras_with_basis.py +414 -0
- sage/categories/bimodules.py +206 -0
- sage/categories/chain_complexes.py +268 -0
- sage/categories/classical_crystals.py +480 -0
- sage/categories/coalgebras.py +405 -0
- sage/categories/coalgebras_with_basis.py +232 -0
- sage/categories/coercion_methods.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/categories/coercion_methods.pyx +52 -0
- sage/categories/commutative_additive_groups.py +104 -0
- sage/categories/commutative_additive_monoids.py +45 -0
- sage/categories/commutative_additive_semigroups.py +48 -0
- sage/categories/commutative_algebra_ideals.py +87 -0
- sage/categories/commutative_algebras.py +94 -0
- sage/categories/commutative_ring_ideals.py +58 -0
- sage/categories/commutative_rings.py +736 -0
- sage/categories/complete_discrete_valuation.py +293 -0
- sage/categories/complex_reflection_groups.py +145 -0
- sage/categories/complex_reflection_or_generalized_coxeter_groups.py +1249 -0
- sage/categories/coxeter_group_algebras.py +186 -0
- sage/categories/coxeter_groups.py +3402 -0
- sage/categories/crystals.py +2628 -0
- sage/categories/cw_complexes.py +216 -0
- sage/categories/dedekind_domains.py +137 -0
- sage/categories/discrete_valuation.py +325 -0
- sage/categories/distributive_magmas_and_additive_magmas.py +100 -0
- sage/categories/division_rings.py +114 -0
- sage/categories/domains.py +95 -0
- sage/categories/drinfeld_modules.py +789 -0
- sage/categories/dual.py +42 -0
- sage/categories/enumerated_sets.py +1146 -0
- sage/categories/euclidean_domains.py +271 -0
- sage/categories/examples/algebras_with_basis.py +102 -0
- sage/categories/examples/all.py +1 -0
- sage/categories/examples/commutative_additive_monoids.py +130 -0
- sage/categories/examples/commutative_additive_semigroups.py +199 -0
- sage/categories/examples/coxeter_groups.py +8 -0
- sage/categories/examples/crystals.py +236 -0
- sage/categories/examples/cw_complexes.py +163 -0
- sage/categories/examples/facade_sets.py +187 -0
- sage/categories/examples/filtered_algebras_with_basis.py +204 -0
- sage/categories/examples/filtered_modules_with_basis.py +154 -0
- sage/categories/examples/finite_coxeter_groups.py +252 -0
- sage/categories/examples/finite_dimensional_algebras_with_basis.py +148 -0
- sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +495 -0
- sage/categories/examples/finite_enumerated_sets.py +208 -0
- sage/categories/examples/finite_monoids.py +150 -0
- sage/categories/examples/finite_semigroups.py +190 -0
- sage/categories/examples/finite_weyl_groups.py +191 -0
- sage/categories/examples/graded_connected_hopf_algebras_with_basis.py +152 -0
- sage/categories/examples/graded_modules_with_basis.py +168 -0
- sage/categories/examples/graphs.py +122 -0
- sage/categories/examples/hopf_algebras_with_basis.py +145 -0
- sage/categories/examples/infinite_enumerated_sets.py +190 -0
- sage/categories/examples/lie_algebras.py +352 -0
- sage/categories/examples/lie_algebras_with_basis.py +196 -0
- sage/categories/examples/magmas.py +162 -0
- sage/categories/examples/manifolds.py +94 -0
- sage/categories/examples/monoids.py +144 -0
- sage/categories/examples/posets.py +178 -0
- sage/categories/examples/semigroups.py +580 -0
- sage/categories/examples/semigroups_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/categories/examples/semigroups_cython.pyx +221 -0
- sage/categories/examples/semirings.py +249 -0
- sage/categories/examples/sets_cat.py +706 -0
- sage/categories/examples/sets_with_grading.py +101 -0
- sage/categories/examples/with_realizations.py +542 -0
- sage/categories/fields.py +991 -0
- sage/categories/filtered_algebras.py +63 -0
- sage/categories/filtered_algebras_with_basis.py +548 -0
- sage/categories/filtered_hopf_algebras_with_basis.py +138 -0
- sage/categories/filtered_modules.py +210 -0
- sage/categories/filtered_modules_with_basis.py +1209 -0
- sage/categories/finite_complex_reflection_groups.py +1506 -0
- sage/categories/finite_coxeter_groups.py +1138 -0
- sage/categories/finite_crystals.py +103 -0
- sage/categories/finite_dimensional_algebras_with_basis.py +1860 -0
- sage/categories/finite_dimensional_bialgebras_with_basis.py +33 -0
- sage/categories/finite_dimensional_coalgebras_with_basis.py +33 -0
- sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py +231 -0
- sage/categories/finite_dimensional_hopf_algebras_with_basis.py +38 -0
- sage/categories/finite_dimensional_lie_algebras_with_basis.py +2774 -0
- sage/categories/finite_dimensional_modules_with_basis.py +1407 -0
- sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py +167 -0
- sage/categories/finite_dimensional_semisimple_algebras_with_basis.py +270 -0
- sage/categories/finite_enumerated_sets.py +769 -0
- sage/categories/finite_fields.py +252 -0
- sage/categories/finite_groups.py +256 -0
- sage/categories/finite_lattice_posets.py +242 -0
- sage/categories/finite_monoids.py +316 -0
- sage/categories/finite_permutation_groups.py +339 -0
- sage/categories/finite_posets.py +1994 -0
- sage/categories/finite_semigroups.py +136 -0
- sage/categories/finite_sets.py +93 -0
- sage/categories/finite_weyl_groups.py +39 -0
- sage/categories/finitely_generated_lambda_bracket_algebras.py +112 -0
- sage/categories/finitely_generated_lie_conformal_algebras.py +114 -0
- sage/categories/finitely_generated_magmas.py +57 -0
- sage/categories/finitely_generated_semigroups.py +214 -0
- sage/categories/function_fields.py +76 -0
- sage/categories/g_sets.py +77 -0
- sage/categories/gcd_domains.py +65 -0
- sage/categories/generalized_coxeter_groups.py +94 -0
- sage/categories/graded_algebras.py +85 -0
- sage/categories/graded_algebras_with_basis.py +258 -0
- sage/categories/graded_bialgebras.py +32 -0
- sage/categories/graded_bialgebras_with_basis.py +32 -0
- sage/categories/graded_coalgebras.py +65 -0
- sage/categories/graded_coalgebras_with_basis.py +51 -0
- sage/categories/graded_hopf_algebras.py +41 -0
- sage/categories/graded_hopf_algebras_with_basis.py +169 -0
- sage/categories/graded_lie_algebras.py +91 -0
- sage/categories/graded_lie_algebras_with_basis.py +44 -0
- sage/categories/graded_lie_conformal_algebras.py +74 -0
- sage/categories/graded_modules.py +133 -0
- sage/categories/graded_modules_with_basis.py +329 -0
- sage/categories/graphs.py +138 -0
- sage/categories/group_algebras.py +430 -0
- sage/categories/groupoid.py +94 -0
- sage/categories/groups.py +667 -0
- sage/categories/h_trivial_semigroups.py +64 -0
- sage/categories/hecke_modules.py +185 -0
- sage/categories/highest_weight_crystals.py +980 -0
- sage/categories/hopf_algebras.py +219 -0
- sage/categories/hopf_algebras_with_basis.py +309 -0
- sage/categories/infinite_enumerated_sets.py +115 -0
- sage/categories/integral_domains.py +203 -0
- sage/categories/j_trivial_semigroups.py +29 -0
- sage/categories/kac_moody_algebras.py +82 -0
- sage/categories/kahler_algebras.py +203 -0
- sage/categories/l_trivial_semigroups.py +63 -0
- sage/categories/lambda_bracket_algebras.py +280 -0
- sage/categories/lambda_bracket_algebras_with_basis.py +107 -0
- sage/categories/lattice_posets.py +89 -0
- sage/categories/left_modules.py +49 -0
- sage/categories/lie_algebras.py +1070 -0
- sage/categories/lie_algebras_with_basis.py +261 -0
- sage/categories/lie_conformal_algebras.py +350 -0
- sage/categories/lie_conformal_algebras_with_basis.py +147 -0
- sage/categories/lie_groups.py +73 -0
- sage/categories/loop_crystals.py +1290 -0
- sage/categories/magmas.py +1189 -0
- sage/categories/magmas_and_additive_magmas.py +149 -0
- sage/categories/magmatic_algebras.py +365 -0
- sage/categories/manifolds.py +352 -0
- sage/categories/matrix_algebras.py +40 -0
- sage/categories/metric_spaces.py +387 -0
- sage/categories/modular_abelian_varieties.py +78 -0
- sage/categories/modules.py +989 -0
- sage/categories/modules_with_basis.py +2794 -0
- sage/categories/monoid_algebras.py +38 -0
- sage/categories/monoids.py +739 -0
- sage/categories/noetherian_rings.py +87 -0
- sage/categories/number_fields.py +242 -0
- sage/categories/ore_modules.py +189 -0
- sage/categories/partially_ordered_monoids.py +49 -0
- sage/categories/permutation_groups.py +63 -0
- sage/categories/pointed_sets.py +42 -0
- sage/categories/polyhedra.py +74 -0
- sage/categories/poor_man_map.py +270 -0
- sage/categories/posets.py +722 -0
- sage/categories/principal_ideal_domains.py +270 -0
- sage/categories/quantum_group_representations.py +543 -0
- sage/categories/quotient_fields.py +728 -0
- sage/categories/r_trivial_semigroups.py +45 -0
- sage/categories/regular_crystals.py +898 -0
- sage/categories/regular_supercrystals.py +170 -0
- sage/categories/right_modules.py +49 -0
- sage/categories/ring_ideals.py +74 -0
- sage/categories/rings.py +1904 -0
- sage/categories/rngs.py +175 -0
- sage/categories/schemes.py +393 -0
- sage/categories/semigroups.py +1060 -0
- sage/categories/semirings.py +71 -0
- sage/categories/semisimple_algebras.py +114 -0
- sage/categories/sets_with_grading.py +235 -0
- sage/categories/shephard_groups.py +43 -0
- sage/categories/signed_tensor.py +120 -0
- sage/categories/simplicial_complexes.py +134 -0
- sage/categories/simplicial_sets.py +1206 -0
- sage/categories/super_algebras.py +149 -0
- sage/categories/super_algebras_with_basis.py +144 -0
- sage/categories/super_hopf_algebras_with_basis.py +126 -0
- sage/categories/super_lie_conformal_algebras.py +193 -0
- sage/categories/super_modules.py +229 -0
- sage/categories/super_modules_with_basis.py +193 -0
- sage/categories/supercommutative_algebras.py +99 -0
- sage/categories/supercrystals.py +406 -0
- sage/categories/tensor.py +110 -0
- sage/categories/topological_spaces.py +170 -0
- sage/categories/triangular_kac_moody_algebras.py +439 -0
- sage/categories/tutorial.py +58 -0
- sage/categories/unique_factorization_domains.py +318 -0
- sage/categories/unital_algebras.py +426 -0
- sage/categories/vector_bundles.py +159 -0
- sage/categories/vector_spaces.py +357 -0
- sage/categories/weyl_groups.py +853 -0
- sage/combinat/all__sagemath_categories.py +34 -0
- sage/combinat/backtrack.py +180 -0
- sage/combinat/combinat.py +2269 -0
- sage/combinat/combinat_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/combinat_cython.pxd +6 -0
- sage/combinat/combinat_cython.pyx +390 -0
- sage/combinat/combination.py +796 -0
- sage/combinat/combinatorial_map.py +416 -0
- sage/combinat/composition.py +2192 -0
- sage/combinat/dlx.py +510 -0
- sage/combinat/integer_lists/__init__.py +7 -0
- sage/combinat/integer_lists/base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/integer_lists/base.pxd +16 -0
- sage/combinat/integer_lists/base.pyx +713 -0
- sage/combinat/integer_lists/invlex.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/integer_lists/invlex.pxd +4 -0
- sage/combinat/integer_lists/invlex.pyx +1650 -0
- sage/combinat/integer_lists/lists.py +328 -0
- sage/combinat/integer_lists/nn.py +48 -0
- sage/combinat/integer_vector.py +1818 -0
- sage/combinat/integer_vector_weighted.py +413 -0
- sage/combinat/matrices/all__sagemath_categories.py +5 -0
- sage/combinat/matrices/dancing_links.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/matrices/dancing_links.pyx +1159 -0
- sage/combinat/matrices/dancing_links_c.h +380 -0
- sage/combinat/matrices/dlxcpp.py +136 -0
- sage/combinat/partition.py +10070 -0
- sage/combinat/partitions.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/partitions.pyx +743 -0
- sage/combinat/permutation.py +10168 -0
- sage/combinat/permutation_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/permutation_cython.pxd +11 -0
- sage/combinat/permutation_cython.pyx +407 -0
- sage/combinat/q_analogues.py +1090 -0
- sage/combinat/ranker.py +268 -0
- sage/combinat/subset.py +1561 -0
- sage/combinat/subsets_hereditary.py +202 -0
- sage/combinat/subsets_pairwise.py +184 -0
- sage/combinat/tools.py +63 -0
- sage/combinat/tuple.py +348 -0
- sage/data_structures/all.py +2 -0
- sage/data_structures/all__sagemath_categories.py +2 -0
- sage/data_structures/binary_matrix.pxd +138 -0
- sage/data_structures/binary_search.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/binary_search.pxd +3 -0
- sage/data_structures/binary_search.pyx +66 -0
- sage/data_structures/bitset.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/bitset.pxd +40 -0
- sage/data_structures/bitset.pyx +2385 -0
- sage/data_structures/bitset_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/bitset_base.pxd +926 -0
- sage/data_structures/bitset_base.pyx +117 -0
- sage/data_structures/bitset_intrinsics.h +487 -0
- sage/data_structures/blas_dict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/blas_dict.pxd +12 -0
- sage/data_structures/blas_dict.pyx +469 -0
- sage/data_structures/list_of_pairs.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/list_of_pairs.pxd +16 -0
- sage/data_structures/list_of_pairs.pyx +122 -0
- sage/data_structures/mutable_poset.py +3312 -0
- sage/data_structures/pairing_heap.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/pairing_heap.h +346 -0
- sage/data_structures/pairing_heap.pxd +88 -0
- sage/data_structures/pairing_heap.pyx +1464 -0
- sage/data_structures/sparse_bitset.pxd +62 -0
- sage/data_structures/stream.py +5070 -0
- sage/databases/all__sagemath_categories.py +7 -0
- sage/databases/sql_db.py +2236 -0
- sage/ext/all__sagemath_categories.py +3 -0
- sage/ext/fast_callable.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/fast_callable.pxd +4 -0
- sage/ext/fast_callable.pyx +2746 -0
- sage/ext/fast_eval.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/fast_eval.pxd +1 -0
- sage/ext/fast_eval.pyx +102 -0
- sage/ext/interpreters/__init__.py +1 -0
- sage/ext/interpreters/all__sagemath_categories.py +2 -0
- sage/ext/interpreters/wrapper_el.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_el.pxd +18 -0
- sage/ext/interpreters/wrapper_el.pyx +148 -0
- sage/ext/interpreters/wrapper_py.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_py.pxd +17 -0
- sage/ext/interpreters/wrapper_py.pyx +133 -0
- sage/functions/airy.py +937 -0
- sage/functions/all.py +97 -0
- sage/functions/bessel.py +2102 -0
- sage/functions/error.py +784 -0
- sage/functions/exp_integral.py +1529 -0
- sage/functions/gamma.py +1087 -0
- sage/functions/generalized.py +672 -0
- sage/functions/hyperbolic.py +747 -0
- sage/functions/hypergeometric.py +1156 -0
- sage/functions/jacobi.py +1705 -0
- sage/functions/log.py +1402 -0
- sage/functions/min_max.py +338 -0
- sage/functions/orthogonal_polys.py +3106 -0
- sage/functions/other.py +2303 -0
- sage/functions/piecewise.py +1505 -0
- sage/functions/prime_pi.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/functions/prime_pi.pyx +262 -0
- sage/functions/special.py +1212 -0
- sage/functions/spike_function.py +278 -0
- sage/functions/transcendental.py +690 -0
- sage/functions/trig.py +1062 -0
- sage/functions/wigner.py +726 -0
- sage/geometry/abc.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/geometry/abc.pyx +82 -0
- sage/geometry/all__sagemath_categories.py +1 -0
- sage/groups/all__sagemath_categories.py +11 -0
- sage/groups/generic.py +1733 -0
- sage/groups/groups_catalog.py +113 -0
- sage/groups/perm_gps/all__sagemath_categories.py +1 -0
- sage/groups/perm_gps/partn_ref/all.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_categories.py +1 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pxd +52 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx +906 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd +85 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx +534 -0
- sage/groups/perm_gps/partn_ref/data_structures.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/data_structures.pxd +576 -0
- sage/groups/perm_gps/partn_ref/data_structures.pyx +1792 -0
- sage/groups/perm_gps/partn_ref/double_coset.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/double_coset.pxd +45 -0
- sage/groups/perm_gps/partn_ref/double_coset.pyx +739 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.pxd +18 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.pyx +82 -0
- sage/groups/perm_gps/partn_ref/refinement_python.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_python.pxd +16 -0
- sage/groups/perm_gps/partn_ref/refinement_python.pyx +564 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.pxd +60 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.pyx +858 -0
- sage/interfaces/abc.py +140 -0
- sage/interfaces/all.py +58 -0
- sage/interfaces/all__sagemath_categories.py +1 -0
- sage/interfaces/expect.py +1643 -0
- sage/interfaces/interface.py +1682 -0
- sage/interfaces/process.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/interfaces/process.pxd +5 -0
- sage/interfaces/process.pyx +288 -0
- sage/interfaces/quit.py +167 -0
- sage/interfaces/sage0.py +604 -0
- sage/interfaces/sagespawn.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/interfaces/sagespawn.pyx +308 -0
- sage/interfaces/tab_completion.py +101 -0
- sage/misc/all__sagemath_categories.py +78 -0
- sage/misc/allocator.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/allocator.pxd +6 -0
- sage/misc/allocator.pyx +47 -0
- sage/misc/binary_tree.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/binary_tree.pxd +29 -0
- sage/misc/binary_tree.pyx +537 -0
- sage/misc/callable_dict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/callable_dict.pyx +89 -0
- sage/misc/citation.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/citation.pyx +159 -0
- sage/misc/converting_dict.py +293 -0
- sage/misc/defaults.py +129 -0
- sage/misc/derivative.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/derivative.pyx +223 -0
- sage/misc/functional.py +2005 -0
- sage/misc/html.py +589 -0
- sage/misc/latex.py +2673 -0
- sage/misc/latex_macros.py +236 -0
- sage/misc/latex_standalone.py +1833 -0
- sage/misc/map_threaded.py +38 -0
- sage/misc/mathml.py +76 -0
- sage/misc/method_decorator.py +88 -0
- sage/misc/mrange.py +755 -0
- sage/misc/multireplace.py +41 -0
- sage/misc/object_multiplexer.py +92 -0
- sage/misc/parser.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/parser.pyx +1107 -0
- sage/misc/random_testing.py +264 -0
- sage/misc/rest_index_of_methods.py +377 -0
- sage/misc/search.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/search.pxd +2 -0
- sage/misc/search.pyx +68 -0
- sage/misc/stopgap.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/stopgap.pyx +95 -0
- sage/misc/table.py +853 -0
- sage/monoids/all__sagemath_categories.py +1 -0
- sage/monoids/indexed_free_monoid.py +1071 -0
- sage/monoids/monoid.py +82 -0
- sage/numerical/all__sagemath_categories.py +1 -0
- sage/numerical/backends/all__sagemath_categories.py +1 -0
- sage/numerical/backends/generic_backend.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/numerical/backends/generic_backend.pxd +61 -0
- sage/numerical/backends/generic_backend.pyx +1893 -0
- sage/numerical/backends/generic_sdp_backend.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/numerical/backends/generic_sdp_backend.pxd +38 -0
- sage/numerical/backends/generic_sdp_backend.pyx +755 -0
- sage/parallel/all.py +6 -0
- sage/parallel/decorate.py +575 -0
- sage/parallel/map_reduce.py +1997 -0
- sage/parallel/multiprocessing_sage.py +76 -0
- sage/parallel/ncpus.py +35 -0
- sage/parallel/parallelism.py +364 -0
- sage/parallel/reference.py +47 -0
- sage/parallel/use_fork.py +333 -0
- sage/rings/abc.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/abc.pxd +31 -0
- sage/rings/abc.pyx +526 -0
- sage/rings/algebraic_closure_finite_field.py +1154 -0
- sage/rings/all__sagemath_categories.py +91 -0
- sage/rings/big_oh.py +227 -0
- sage/rings/continued_fraction.py +2754 -0
- sage/rings/continued_fraction_gosper.py +220 -0
- sage/rings/factorint.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/factorint.pyx +295 -0
- sage/rings/fast_arith.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/fast_arith.pxd +21 -0
- sage/rings/fast_arith.pyx +535 -0
- sage/rings/finite_rings/all__sagemath_categories.py +9 -0
- sage/rings/finite_rings/conway_polynomials.py +542 -0
- sage/rings/finite_rings/element_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/element_base.pxd +12 -0
- sage/rings/finite_rings/element_base.pyx +1176 -0
- sage/rings/finite_rings/finite_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/finite_field_base.pxd +7 -0
- sage/rings/finite_rings/finite_field_base.pyx +2171 -0
- sage/rings/finite_rings/finite_field_constructor.py +827 -0
- sage/rings/finite_rings/finite_field_prime_modn.py +372 -0
- sage/rings/finite_rings/galois_group.py +154 -0
- sage/rings/finite_rings/hom_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_finite_field.pxd +23 -0
- sage/rings/finite_rings/hom_finite_field.pyx +856 -0
- sage/rings/finite_rings/hom_prime_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_prime_finite_field.pxd +15 -0
- sage/rings/finite_rings/hom_prime_finite_field.pyx +164 -0
- sage/rings/finite_rings/homset.py +357 -0
- sage/rings/finite_rings/integer_mod.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/integer_mod.pxd +56 -0
- sage/rings/finite_rings/integer_mod.pyx +4586 -0
- sage/rings/finite_rings/integer_mod_limits.h +11 -0
- sage/rings/finite_rings/integer_mod_ring.py +2044 -0
- sage/rings/finite_rings/residue_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/residue_field.pxd +30 -0
- sage/rings/finite_rings/residue_field.pyx +1811 -0
- sage/rings/finite_rings/stdint.pxd +19 -0
- sage/rings/fraction_field.py +1452 -0
- sage/rings/fraction_field_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/fraction_field_element.pyx +1357 -0
- sage/rings/function_field/all.py +7 -0
- sage/rings/function_field/all__sagemath_categories.py +2 -0
- sage/rings/function_field/constructor.py +218 -0
- sage/rings/function_field/element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/element.pxd +11 -0
- sage/rings/function_field/element.pyx +1008 -0
- sage/rings/function_field/element_rational.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/element_rational.pyx +513 -0
- sage/rings/function_field/extensions.py +230 -0
- sage/rings/function_field/function_field.py +1468 -0
- sage/rings/function_field/function_field_rational.py +1005 -0
- sage/rings/function_field/ideal.py +1155 -0
- sage/rings/function_field/ideal_rational.py +629 -0
- sage/rings/function_field/jacobian_base.py +826 -0
- sage/rings/function_field/jacobian_hess.py +1053 -0
- sage/rings/function_field/jacobian_khuri_makdisi.py +1027 -0
- sage/rings/function_field/maps.py +1039 -0
- sage/rings/function_field/order.py +281 -0
- sage/rings/function_field/order_basis.py +586 -0
- sage/rings/function_field/order_rational.py +576 -0
- sage/rings/function_field/place.py +426 -0
- sage/rings/function_field/place_rational.py +181 -0
- sage/rings/generic.py +320 -0
- sage/rings/homset.py +332 -0
- sage/rings/ideal.py +1885 -0
- sage/rings/ideal_monoid.py +215 -0
- sage/rings/infinity.py +1890 -0
- sage/rings/integer.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/integer.pxd +45 -0
- sage/rings/integer.pyx +7874 -0
- sage/rings/integer_ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/integer_ring.pxd +8 -0
- sage/rings/integer_ring.pyx +1693 -0
- sage/rings/laurent_series_ring.py +931 -0
- sage/rings/laurent_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/laurent_series_ring_element.pxd +11 -0
- sage/rings/laurent_series_ring_element.pyx +1927 -0
- sage/rings/lazy_series.py +7815 -0
- sage/rings/lazy_series_ring.py +4356 -0
- sage/rings/localization.py +1043 -0
- sage/rings/morphism.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/morphism.pxd +39 -0
- sage/rings/morphism.pyx +3299 -0
- sage/rings/multi_power_series_ring.py +1145 -0
- sage/rings/multi_power_series_ring_element.py +2184 -0
- sage/rings/noncommutative_ideals.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/noncommutative_ideals.pyx +423 -0
- sage/rings/number_field/all__sagemath_categories.py +1 -0
- sage/rings/number_field/number_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/number_field/number_field_base.pxd +8 -0
- sage/rings/number_field/number_field_base.pyx +507 -0
- sage/rings/number_field/number_field_element_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/number_field/number_field_element_base.pxd +6 -0
- sage/rings/number_field/number_field_element_base.pyx +36 -0
- sage/rings/number_field/number_field_ideal.py +3550 -0
- sage/rings/padics/all__sagemath_categories.py +4 -0
- sage/rings/padics/local_generic.py +1670 -0
- sage/rings/padics/local_generic_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/padics/local_generic_element.pxd +5 -0
- sage/rings/padics/local_generic_element.pyx +1017 -0
- sage/rings/padics/misc.py +256 -0
- sage/rings/padics/padic_generic.py +1911 -0
- sage/rings/padics/pow_computer.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/padics/pow_computer.pxd +38 -0
- sage/rings/padics/pow_computer.pyx +671 -0
- sage/rings/padics/precision_error.py +24 -0
- sage/rings/polynomial/all__sagemath_categories.py +25 -0
- sage/rings/polynomial/commutative_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/commutative_polynomial.pxd +6 -0
- sage/rings/polynomial/commutative_polynomial.pyx +24 -0
- sage/rings/polynomial/cyclotomic.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/cyclotomic.pyx +404 -0
- sage/rings/polynomial/flatten.py +711 -0
- sage/rings/polynomial/ideal.py +102 -0
- sage/rings/polynomial/infinite_polynomial_element.py +1768 -0
- sage/rings/polynomial/infinite_polynomial_ring.py +1653 -0
- sage/rings/polynomial/laurent_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/laurent_polynomial.pxd +18 -0
- sage/rings/polynomial/laurent_polynomial.pyx +2190 -0
- sage/rings/polynomial/laurent_polynomial_ideal.py +590 -0
- sage/rings/polynomial/laurent_polynomial_ring.py +832 -0
- sage/rings/polynomial/laurent_polynomial_ring_base.py +708 -0
- sage/rings/polynomial/multi_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/multi_polynomial.pxd +12 -0
- sage/rings/polynomial/multi_polynomial.pyx +3082 -0
- sage/rings/polynomial/multi_polynomial_element.py +2570 -0
- sage/rings/polynomial/multi_polynomial_ideal.py +5771 -0
- sage/rings/polynomial/multi_polynomial_ring.py +947 -0
- sage/rings/polynomial/multi_polynomial_ring_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/multi_polynomial_ring_base.pxd +15 -0
- sage/rings/polynomial/multi_polynomial_ring_base.pyx +1855 -0
- sage/rings/polynomial/multi_polynomial_sequence.py +2204 -0
- sage/rings/polynomial/polydict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polydict.pxd +45 -0
- sage/rings/polynomial/polydict.pyx +2701 -0
- sage/rings/polynomial/polynomial_compiled.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_compiled.pxd +59 -0
- sage/rings/polynomial/polynomial_compiled.pyx +509 -0
- sage/rings/polynomial/polynomial_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_element.pxd +64 -0
- sage/rings/polynomial/polynomial_element.pyx +13255 -0
- sage/rings/polynomial/polynomial_element_generic.py +1637 -0
- sage/rings/polynomial/polynomial_fateman.py +97 -0
- sage/rings/polynomial/polynomial_quotient_ring.py +2465 -0
- sage/rings/polynomial/polynomial_quotient_ring_element.py +779 -0
- sage/rings/polynomial/polynomial_ring.py +3784 -0
- sage/rings/polynomial/polynomial_ring_constructor.py +1051 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.pxd +5 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.pyx +121 -0
- sage/rings/polynomial/polynomial_singular_interface.py +549 -0
- sage/rings/polynomial/symmetric_ideal.py +989 -0
- sage/rings/polynomial/symmetric_reduction.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/symmetric_reduction.pxd +8 -0
- sage/rings/polynomial/symmetric_reduction.pyx +669 -0
- sage/rings/polynomial/term_order.py +2279 -0
- sage/rings/polynomial/toy_buchberger.py +449 -0
- sage/rings/polynomial/toy_d_basis.py +387 -0
- sage/rings/polynomial/toy_variety.py +362 -0
- sage/rings/power_series_mpoly.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_mpoly.pxd +9 -0
- sage/rings/power_series_mpoly.pyx +161 -0
- sage/rings/power_series_poly.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_poly.pxd +10 -0
- sage/rings/power_series_poly.pyx +1317 -0
- sage/rings/power_series_ring.py +1441 -0
- sage/rings/power_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_ring_element.pxd +12 -0
- sage/rings/power_series_ring_element.pyx +3028 -0
- sage/rings/puiseux_series_ring.py +487 -0
- sage/rings/puiseux_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/puiseux_series_ring_element.pxd +7 -0
- sage/rings/puiseux_series_ring_element.pyx +1055 -0
- sage/rings/qqbar_decorators.py +167 -0
- sage/rings/quotient_ring.py +1598 -0
- sage/rings/quotient_ring_element.py +979 -0
- sage/rings/rational.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/rational.pxd +20 -0
- sage/rings/rational.pyx +4284 -0
- sage/rings/rational_field.py +1730 -0
- sage/rings/real_double.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/real_double.pxd +16 -0
- sage/rings/real_double.pyx +2218 -0
- sage/rings/real_lazy.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/real_lazy.pxd +30 -0
- sage/rings/real_lazy.pyx +1773 -0
- sage/rings/ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/ring.pxd +30 -0
- sage/rings/ring.pyx +850 -0
- sage/rings/semirings/all.py +3 -0
- sage/rings/semirings/non_negative_integer_semiring.py +107 -0
- sage/rings/semirings/tropical_mpolynomial.py +972 -0
- sage/rings/semirings/tropical_polynomial.py +997 -0
- sage/rings/semirings/tropical_semiring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/semirings/tropical_semiring.pyx +676 -0
- sage/rings/semirings/tropical_variety.py +1701 -0
- sage/rings/sum_of_squares.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/sum_of_squares.pxd +3 -0
- sage/rings/sum_of_squares.pyx +336 -0
- sage/rings/tests.py +504 -0
- sage/schemes/affine/affine_homset.py +508 -0
- sage/schemes/affine/affine_morphism.py +1574 -0
- sage/schemes/affine/affine_point.py +460 -0
- sage/schemes/affine/affine_rational_point.py +308 -0
- sage/schemes/affine/affine_space.py +1264 -0
- sage/schemes/affine/affine_subscheme.py +592 -0
- sage/schemes/affine/all.py +25 -0
- sage/schemes/all__sagemath_categories.py +5 -0
- sage/schemes/generic/algebraic_scheme.py +2092 -0
- sage/schemes/generic/all.py +5 -0
- sage/schemes/generic/ambient_space.py +400 -0
- sage/schemes/generic/divisor.py +465 -0
- sage/schemes/generic/divisor_group.py +313 -0
- sage/schemes/generic/glue.py +84 -0
- sage/schemes/generic/homset.py +820 -0
- sage/schemes/generic/hypersurface.py +234 -0
- sage/schemes/generic/morphism.py +2107 -0
- sage/schemes/generic/point.py +237 -0
- sage/schemes/generic/scheme.py +1190 -0
- sage/schemes/generic/spec.py +199 -0
- sage/schemes/product_projective/all.py +6 -0
- sage/schemes/product_projective/homset.py +236 -0
- sage/schemes/product_projective/morphism.py +517 -0
- sage/schemes/product_projective/point.py +568 -0
- sage/schemes/product_projective/rational_point.py +550 -0
- sage/schemes/product_projective/space.py +1301 -0
- sage/schemes/product_projective/subscheme.py +466 -0
- sage/schemes/projective/all.py +24 -0
- sage/schemes/projective/proj_bdd_height.py +453 -0
- sage/schemes/projective/projective_homset.py +718 -0
- sage/schemes/projective/projective_morphism.py +2792 -0
- sage/schemes/projective/projective_point.py +1484 -0
- sage/schemes/projective/projective_rational_point.py +569 -0
- sage/schemes/projective/projective_space.py +2571 -0
- sage/schemes/projective/projective_subscheme.py +1574 -0
- sage/sets/all.py +17 -0
- sage/sets/cartesian_product.py +376 -0
- sage/sets/condition_set.py +525 -0
- sage/sets/disjoint_set.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/disjoint_set.pxd +36 -0
- sage/sets/disjoint_set.pyx +998 -0
- sage/sets/disjoint_union_enumerated_sets.py +625 -0
- sage/sets/family.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/family.pxd +12 -0
- sage/sets/family.pyx +1556 -0
- sage/sets/finite_enumerated_set.py +406 -0
- sage/sets/finite_set_map_cy.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/finite_set_map_cy.pxd +34 -0
- sage/sets/finite_set_map_cy.pyx +708 -0
- sage/sets/finite_set_maps.py +591 -0
- sage/sets/image_set.py +448 -0
- sage/sets/integer_range.py +829 -0
- sage/sets/non_negative_integers.py +241 -0
- sage/sets/positive_integers.py +93 -0
- sage/sets/primes.py +188 -0
- sage/sets/real_set.py +2760 -0
- sage/sets/recursively_enumerated_set.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/recursively_enumerated_set.pxd +31 -0
- sage/sets/recursively_enumerated_set.pyx +2082 -0
- sage/sets/set.py +2083 -0
- sage/sets/set_from_iterator.py +1021 -0
- sage/sets/totally_ordered_finite_set.py +329 -0
- sage/symbolic/all__sagemath_categories.py +1 -0
- sage/symbolic/function.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/symbolic/function.pxd +29 -0
- sage/symbolic/function.pyx +1488 -0
- sage/symbolic/symbols.py +56 -0
- sage/tests/all__sagemath_categories.py +1 -0
- sage/tests/cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/tests/cython.pyx +37 -0
- sage/tests/stl_vector.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/tests/stl_vector.pyx +171 -0
- sage/typeset/all.py +6 -0
- sage/typeset/ascii_art.py +295 -0
- sage/typeset/character_art.py +789 -0
- sage/typeset/character_art_factory.py +572 -0
- sage/typeset/symbols.py +334 -0
- sage/typeset/unicode_art.py +183 -0
- sage/typeset/unicode_characters.py +101 -0
|
@@ -0,0 +1,2082 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-categories
|
|
2
|
+
r"""
|
|
3
|
+
Recursively Enumerated Sets
|
|
4
|
+
|
|
5
|
+
A set `S` is called recursively enumerable if there is an algorithm that
|
|
6
|
+
enumerates the members of `S`. We consider here the recursively enumerated
|
|
7
|
+
sets that are described by some ``seeds`` and a successor function
|
|
8
|
+
``successors``. The successor function may have some structure (symmetric,
|
|
9
|
+
graded, forest) or not. The elements of a set having a symmetric, graded or
|
|
10
|
+
forest structure can be enumerated uniquely without keeping all of them in
|
|
11
|
+
memory. Many kinds of iterators are provided in this module: depth first
|
|
12
|
+
search, breadth first search and elements of given depth.
|
|
13
|
+
|
|
14
|
+
See :wikipedia:`Recursively_enumerable_set`.
|
|
15
|
+
|
|
16
|
+
See the documentation of :func:`RecursivelyEnumeratedSet` below for the
|
|
17
|
+
description of the inputs.
|
|
18
|
+
|
|
19
|
+
AUTHORS:
|
|
20
|
+
|
|
21
|
+
- Sébastien Labbé, April 2014, at Sage Days 57, Cernay-la-ville
|
|
22
|
+
|
|
23
|
+
EXAMPLES:
|
|
24
|
+
|
|
25
|
+
.. RUBRIC:: No hypothesis on the structure
|
|
26
|
+
|
|
27
|
+
What we mean by "no hypothesis" is that the set is not known
|
|
28
|
+
to be a forest, symmetric, or graded. However, it may have other
|
|
29
|
+
structure, such as not containing an oriented cycle, that does not
|
|
30
|
+
help with the enumeration.
|
|
31
|
+
|
|
32
|
+
In this example, the seed is 0 and the successor function is either ``+2``
|
|
33
|
+
or ``+3``. This is the set of nonnegative linear combinations of 2 and 3::
|
|
34
|
+
|
|
35
|
+
sage: succ = lambda a:[a+2,a+3]
|
|
36
|
+
sage: C = RecursivelyEnumeratedSet([0], succ)
|
|
37
|
+
sage: C
|
|
38
|
+
A recursively enumerated set (breadth first search)
|
|
39
|
+
|
|
40
|
+
Breadth first search::
|
|
41
|
+
|
|
42
|
+
sage: it = C.breadth_first_search_iterator()
|
|
43
|
+
sage: [next(it) for _ in range(10)]
|
|
44
|
+
[0, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
45
|
+
|
|
46
|
+
Depth first search::
|
|
47
|
+
|
|
48
|
+
sage: it = C.depth_first_search_iterator()
|
|
49
|
+
sage: [next(it) for _ in range(10)]
|
|
50
|
+
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
|
|
51
|
+
|
|
52
|
+
.. RUBRIC:: Symmetric structure
|
|
53
|
+
|
|
54
|
+
The origin ``(0, 0)`` as seed and the upper, lower, left and right lattice
|
|
55
|
+
point as successor function. This function is symmetric since `p` is a
|
|
56
|
+
successor of `q` if and only if `q` is a successor or `p`::
|
|
57
|
+
|
|
58
|
+
sage: succ = lambda a: [(a[0]-1,a[1]), (a[0],a[1]-1), (a[0]+1,a[1]), (a[0],a[1]+1)]
|
|
59
|
+
sage: seeds = [(0,0)]
|
|
60
|
+
sage: C = RecursivelyEnumeratedSet(seeds, succ, structure='symmetric', enumeration='depth')
|
|
61
|
+
sage: C
|
|
62
|
+
A recursively enumerated set with a symmetric structure (depth first search)
|
|
63
|
+
|
|
64
|
+
In this case, depth first search is the default enumeration for iteration::
|
|
65
|
+
|
|
66
|
+
sage: it_depth = iter(C)
|
|
67
|
+
sage: [next(it_depth) for _ in range(10)]
|
|
68
|
+
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9)]
|
|
69
|
+
|
|
70
|
+
Breadth first search::
|
|
71
|
+
|
|
72
|
+
sage: it_breadth = C.breadth_first_search_iterator()
|
|
73
|
+
sage: [next(it_breadth) for _ in range(13)]
|
|
74
|
+
[(0, 0),
|
|
75
|
+
(-1, 0), (0, -1), (1, 0), (0, 1),
|
|
76
|
+
(-2, 0), (-1, -1), (-1, 1), (0, -2), (1, -1), (2, 0), (1, 1), (0, 2)]
|
|
77
|
+
|
|
78
|
+
Levels (elements of given depth)::
|
|
79
|
+
|
|
80
|
+
sage: sorted(C.graded_component(0))
|
|
81
|
+
[(0, 0)]
|
|
82
|
+
sage: sorted(C.graded_component(1))
|
|
83
|
+
[(-1, 0), (0, -1), (0, 1), (1, 0)]
|
|
84
|
+
sage: sorted(C.graded_component(2))
|
|
85
|
+
[(-2, 0), (-1, -1), (-1, 1), (0, -2), (0, 2), (1, -1), (1, 1), (2, 0)]
|
|
86
|
+
|
|
87
|
+
.. RUBRIC:: Graded structure
|
|
88
|
+
|
|
89
|
+
Identity permutation as seed and ``permutohedron_succ`` as successor
|
|
90
|
+
function::
|
|
91
|
+
|
|
92
|
+
sage: succ = attrcall("permutohedron_succ")
|
|
93
|
+
sage: seed = [Permutation([1..5])]
|
|
94
|
+
sage: R = RecursivelyEnumeratedSet(seed, succ, structure='graded')
|
|
95
|
+
sage: R
|
|
96
|
+
A recursively enumerated set with a graded structure (breadth first search)
|
|
97
|
+
|
|
98
|
+
Depth first search iterator::
|
|
99
|
+
|
|
100
|
+
sage: it_depth = R.depth_first_search_iterator()
|
|
101
|
+
sage: [next(it_depth) for _ in range(5)]
|
|
102
|
+
[[1, 2, 3, 4, 5],
|
|
103
|
+
[1, 2, 3, 5, 4],
|
|
104
|
+
[1, 2, 5, 3, 4],
|
|
105
|
+
[1, 2, 5, 4, 3],
|
|
106
|
+
[1, 5, 2, 4, 3]]
|
|
107
|
+
|
|
108
|
+
Breadth first search iterator::
|
|
109
|
+
|
|
110
|
+
sage: it_breadth = R.breadth_first_search_iterator()
|
|
111
|
+
sage: [next(it_breadth) for _ in range(5)]
|
|
112
|
+
[[1, 2, 3, 4, 5],
|
|
113
|
+
[2, 1, 3, 4, 5],
|
|
114
|
+
[1, 3, 2, 4, 5],
|
|
115
|
+
[1, 2, 4, 3, 5],
|
|
116
|
+
[1, 2, 3, 5, 4]]
|
|
117
|
+
|
|
118
|
+
Elements of given depth iterator::
|
|
119
|
+
|
|
120
|
+
sage: sorted(R.elements_of_depth_iterator(9))
|
|
121
|
+
[[4, 5, 3, 2, 1], [5, 3, 4, 2, 1], [5, 4, 2, 3, 1], [5, 4, 3, 1, 2]]
|
|
122
|
+
sage: list(R.elements_of_depth_iterator(10))
|
|
123
|
+
[[5, 4, 3, 2, 1]]
|
|
124
|
+
|
|
125
|
+
Graded components (set of elements of the same depth)::
|
|
126
|
+
|
|
127
|
+
sage: # needs sage.combinat
|
|
128
|
+
sage: sorted(R.graded_component(0))
|
|
129
|
+
[[1, 2, 3, 4, 5]]
|
|
130
|
+
sage: sorted(R.graded_component(1))
|
|
131
|
+
[[1, 2, 3, 5, 4], [1, 2, 4, 3, 5], [1, 3, 2, 4, 5], [2, 1, 3, 4, 5]]
|
|
132
|
+
sage: sorted(R.graded_component(9))
|
|
133
|
+
[[4, 5, 3, 2, 1], [5, 3, 4, 2, 1], [5, 4, 2, 3, 1], [5, 4, 3, 1, 2]]
|
|
134
|
+
sage: sorted(R.graded_component(10))
|
|
135
|
+
[[5, 4, 3, 2, 1]]
|
|
136
|
+
|
|
137
|
+
.. RUBRIC:: Forest structure (Example 1)
|
|
138
|
+
|
|
139
|
+
The set of words over the alphabet `\{a,b\}` can be generated from the
|
|
140
|
+
empty word by appending the letter `a` or `b` as a successor function. This set
|
|
141
|
+
has a forest structure::
|
|
142
|
+
|
|
143
|
+
sage: seeds = ['']
|
|
144
|
+
sage: succ = lambda w: [w+'a', w+'b']
|
|
145
|
+
sage: C = RecursivelyEnumeratedSet(seeds, succ, structure='forest')
|
|
146
|
+
sage: C
|
|
147
|
+
An enumerated set with a forest structure
|
|
148
|
+
|
|
149
|
+
Depth first search iterator::
|
|
150
|
+
|
|
151
|
+
sage: it = C.depth_first_search_iterator()
|
|
152
|
+
sage: [next(it) for _ in range(6)]
|
|
153
|
+
['', 'a', 'aa', 'aaa', 'aaaa', 'aaaaa']
|
|
154
|
+
|
|
155
|
+
Breadth first search iterator::
|
|
156
|
+
|
|
157
|
+
sage: it = C.breadth_first_search_iterator()
|
|
158
|
+
sage: [next(it) for _ in range(6)]
|
|
159
|
+
['', 'a', 'b', 'aa', 'ab', 'ba']
|
|
160
|
+
|
|
161
|
+
This example was provided by Florent Hivert.
|
|
162
|
+
|
|
163
|
+
How to define a set using those classes?
|
|
164
|
+
|
|
165
|
+
Only two things are necessary to define a set using a
|
|
166
|
+
:class:`RecursivelyEnumeratedSet` object (the other
|
|
167
|
+
classes being very similar):
|
|
168
|
+
|
|
169
|
+
.. MATH::
|
|
170
|
+
|
|
171
|
+
\begin{array}{ccc}
|
|
172
|
+
& \emptyset \\
|
|
173
|
+
\hfil\swarrow & \downarrow & \searrow\hfil\\
|
|
174
|
+
a & b & c \\
|
|
175
|
+
\begin{array}{ccc}
|
|
176
|
+
\swarrow & \downarrow & \searrow \\
|
|
177
|
+
aa & ab & ac \\
|
|
178
|
+
\end{array} &
|
|
179
|
+
\begin{array}{ccc}
|
|
180
|
+
\swarrow & \downarrow & \searrow \\
|
|
181
|
+
ba & bb & bc \\
|
|
182
|
+
\end{array} &
|
|
183
|
+
\begin{array}{ccc}
|
|
184
|
+
\swarrow & \downarrow & \searrow \\
|
|
185
|
+
ca & cb & cc \\
|
|
186
|
+
\end{array}
|
|
187
|
+
\end{array}
|
|
188
|
+
|
|
189
|
+
For the previous example, the two necessary pieces of information are:
|
|
190
|
+
|
|
191
|
+
- the initial element ``""``;
|
|
192
|
+
|
|
193
|
+
- the function::
|
|
194
|
+
|
|
195
|
+
lambda x: [x + letter for letter in ['a', 'b', 'c']
|
|
196
|
+
|
|
197
|
+
This would actually describe an **infinite** set, as such rules describe
|
|
198
|
+
"all words" on 3 letters. Hence, it is a good idea to replace the function by::
|
|
199
|
+
|
|
200
|
+
lambda x: [x + letter for letter in ['a', 'b', 'c']] if len(x) < 2 else []
|
|
201
|
+
|
|
202
|
+
or even::
|
|
203
|
+
|
|
204
|
+
sage: def children(x):
|
|
205
|
+
....: if len(x) < 2:
|
|
206
|
+
....: for letter in ['a', 'b', 'c']:
|
|
207
|
+
....: yield x+letter
|
|
208
|
+
|
|
209
|
+
We can then create the :class:`RecursivelyEnumeratedSet` object with either::
|
|
210
|
+
|
|
211
|
+
sage: S = RecursivelyEnumeratedSet([''],
|
|
212
|
+
....: lambda x: [x + letter for letter in ['a', 'b', 'c']]
|
|
213
|
+
....: if len(x) < 2 else [],
|
|
214
|
+
....: structure='forest', enumeration='depth',
|
|
215
|
+
....: category=FiniteEnumeratedSets())
|
|
216
|
+
sage: S.list()
|
|
217
|
+
['', 'a', 'aa', 'ab', 'ac', 'b', 'ba', 'bb', 'bc', 'c', 'ca', 'cb', 'cc']
|
|
218
|
+
|
|
219
|
+
or::
|
|
220
|
+
|
|
221
|
+
sage: S = RecursivelyEnumeratedSet([''], children,
|
|
222
|
+
....: structure='forest', enumeration='depth',
|
|
223
|
+
....: category=FiniteEnumeratedSets())
|
|
224
|
+
sage: S.list()
|
|
225
|
+
['', 'a', 'aa', 'ab', 'ac', 'b', 'ba', 'bb', 'bc', 'c', 'ca', 'cb', 'cc']
|
|
226
|
+
|
|
227
|
+
.. RUBRIC:: Forest structure (Example 2)
|
|
228
|
+
|
|
229
|
+
This example was provided by Florent Hivert.
|
|
230
|
+
|
|
231
|
+
Here is a little more involved example. We want to iterate through all
|
|
232
|
+
permutations of a given set `S`. One solution is to take elements of `S` one
|
|
233
|
+
by one and insert them at every position. So a node of the generating tree
|
|
234
|
+
contains two pieces of information:
|
|
235
|
+
|
|
236
|
+
- the list ``lst`` of already inserted element;
|
|
237
|
+
- the set ``st`` of the yet to be inserted element.
|
|
238
|
+
|
|
239
|
+
We want to generate a permutation only if ``st`` is empty (leaves on the
|
|
240
|
+
tree). Also suppose for the sake of the example, that instead of list we want
|
|
241
|
+
to generate tuples. This selection of some nodes and final mapping of a
|
|
242
|
+
function to the element is done by the ``post_process = f`` argument. The
|
|
243
|
+
convention is that the generated elements are the ``s := f(n)``, except when
|
|
244
|
+
``s`` not ``None`` when no element is generated at all. Here is the code::
|
|
245
|
+
|
|
246
|
+
sage: def children(node):
|
|
247
|
+
....: (lst, st) = node
|
|
248
|
+
....: st = set(st) # make a copy
|
|
249
|
+
....: if st:
|
|
250
|
+
....: el = st.pop()
|
|
251
|
+
....: for i in range(len(lst) + 1):
|
|
252
|
+
....: yield (lst[0:i] + [el] + lst[i:], st)
|
|
253
|
+
sage: list(children(([1,2], {3,7,9})))
|
|
254
|
+
[([9, 1, 2], {3, 7}), ([1, 9, 2], {3, 7}), ([1, 2, 9], {3, 7})]
|
|
255
|
+
sage: def post_process(node):
|
|
256
|
+
....: (l, s) = node
|
|
257
|
+
....: return tuple(l) if not s else None
|
|
258
|
+
sage: S = RecursivelyEnumeratedSet( [([], {1,3,6,8})],
|
|
259
|
+
....: children, post_process=post_process,
|
|
260
|
+
....: structure='forest', enumeration='depth',
|
|
261
|
+
....: category=FiniteEnumeratedSets())
|
|
262
|
+
sage: S.list()
|
|
263
|
+
[(6, 3, 1, 8), (3, 6, 1, 8), (3, 1, 6, 8), (3, 1, 8, 6), (6, 1, 3, 8),
|
|
264
|
+
(1, 6, 3, 8), (1, 3, 6, 8), (1, 3, 8, 6), (6, 1, 8, 3), (1, 6, 8, 3),
|
|
265
|
+
(1, 8, 6, 3), (1, 8, 3, 6), (6, 3, 8, 1), (3, 6, 8, 1), (3, 8, 6, 1),
|
|
266
|
+
(3, 8, 1, 6), (6, 8, 3, 1), (8, 6, 3, 1), (8, 3, 6, 1), (8, 3, 1, 6),
|
|
267
|
+
(6, 8, 1, 3), (8, 6, 1, 3), (8, 1, 6, 3), (8, 1, 3, 6)]
|
|
268
|
+
sage: S.cardinality()
|
|
269
|
+
24
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
# ****************************************************************************
|
|
273
|
+
# Copyright (C) 2014 Sebastien Labbe <slabqc at gmail.com>
|
|
274
|
+
#
|
|
275
|
+
# This program is free software: you can redistribute it and/or modify
|
|
276
|
+
# it under the terms of the GNU General Public License as published by
|
|
277
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
278
|
+
# (at your option) any later version.
|
|
279
|
+
# https://www.gnu.org/licenses/
|
|
280
|
+
# ****************************************************************************
|
|
281
|
+
|
|
282
|
+
from sage.structure.parent cimport Parent
|
|
283
|
+
from sage.categories.enumerated_sets import EnumeratedSets
|
|
284
|
+
from sage.misc.abstract_method import abstract_method
|
|
285
|
+
from sage.misc.prandom import randint
|
|
286
|
+
from collections import deque
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def RecursivelyEnumeratedSet(seeds, successors, structure=None,
|
|
290
|
+
enumeration=None, max_depth=float("inf"),
|
|
291
|
+
post_process=None,
|
|
292
|
+
facade=None, category=None):
|
|
293
|
+
r"""
|
|
294
|
+
Return a recursively enumerated set.
|
|
295
|
+
|
|
296
|
+
A set `S` is called recursively enumerable if there is an algorithm that
|
|
297
|
+
enumerates the members of `S`. We consider here the recursively
|
|
298
|
+
enumerated sets that are described by some ``seeds`` and a successor
|
|
299
|
+
function ``successors``.
|
|
300
|
+
|
|
301
|
+
Let `U` be a set and ``successors`` `:U \to 2^U` be a successor function
|
|
302
|
+
associating to each element of `U` a subset of `U`. Let ``seeds`` be a
|
|
303
|
+
subset of `U`. Let `S\subseteq U` be the set of elements of `U` that
|
|
304
|
+
can be reached from a seed by applying recursively the ``successors``
|
|
305
|
+
function. This class provides different kinds of iterators (breadth first,
|
|
306
|
+
depth first, elements of given depth, etc.) for the elements of `S`.
|
|
307
|
+
|
|
308
|
+
See :wikipedia:`Recursively_enumerable_set`.
|
|
309
|
+
|
|
310
|
+
INPUT:
|
|
311
|
+
|
|
312
|
+
- ``seeds`` -- list (or iterable) of hashable objects
|
|
313
|
+
- ``successors`` -- function (or callable) returning a list (or iterable) of
|
|
314
|
+
hashable objects
|
|
315
|
+
- ``structure`` -- string (default: ``None``); structure of the
|
|
316
|
+
set, possible values are:
|
|
317
|
+
|
|
318
|
+
- ``None`` -- nothing is known about the structure of the set
|
|
319
|
+
- ``'forest'`` -- if the ``successors`` function generates a *forest*, that
|
|
320
|
+
is, each element can be reached uniquely from a seed
|
|
321
|
+
- ``'graded'`` -- if the ``successors`` function is *graded*, that is, all
|
|
322
|
+
paths from a seed to a given element have equal length
|
|
323
|
+
- ``'symmetric'`` -- if the relation is *symmetric*, that is,
|
|
324
|
+
``y in successors(x)`` if and only if ``x in successors(y)``
|
|
325
|
+
|
|
326
|
+
- ``enumeration`` -- ``'depth'``, ``'breadth'``, ``'naive'`` or ``None``
|
|
327
|
+
(default: ``None``); the default enumeration for the
|
|
328
|
+
``__iter__`` function
|
|
329
|
+
- ``max_depth`` -- integer (default: ``float("inf")``); limit
|
|
330
|
+
the search to a certain depth, currently works only for breadth first
|
|
331
|
+
search
|
|
332
|
+
- ``post_process`` -- (default: ``None``) for forest only
|
|
333
|
+
- ``facade`` -- (default: ``None``)
|
|
334
|
+
- ``category`` -- (default: ``None``)
|
|
335
|
+
|
|
336
|
+
EXAMPLES:
|
|
337
|
+
|
|
338
|
+
A recursive set with no other information::
|
|
339
|
+
|
|
340
|
+
sage: f = lambda a: [a+3, a+5]
|
|
341
|
+
sage: C = RecursivelyEnumeratedSet([0], f)
|
|
342
|
+
sage: C
|
|
343
|
+
A recursively enumerated set (breadth first search)
|
|
344
|
+
sage: it = iter(C)
|
|
345
|
+
sage: [next(it) for _ in range(10)]
|
|
346
|
+
[0, 3, 5, 6, 8, 10, 9, 11, 13, 15]
|
|
347
|
+
|
|
348
|
+
A recursive set with a forest structure::
|
|
349
|
+
|
|
350
|
+
sage: f = lambda a: [2*a,2*a+1]
|
|
351
|
+
sage: C = RecursivelyEnumeratedSet([1], f, structure='forest'); C
|
|
352
|
+
An enumerated set with a forest structure
|
|
353
|
+
sage: it = C.depth_first_search_iterator()
|
|
354
|
+
sage: [next(it) for _ in range(7)]
|
|
355
|
+
[1, 2, 4, 8, 16, 32, 64]
|
|
356
|
+
sage: it = C.breadth_first_search_iterator()
|
|
357
|
+
sage: [next(it) for _ in range(7)]
|
|
358
|
+
[1, 2, 3, 4, 5, 6, 7]
|
|
359
|
+
|
|
360
|
+
A recursive set given by a symmetric relation::
|
|
361
|
+
|
|
362
|
+
sage: f = lambda a: [a-1,a+1]
|
|
363
|
+
sage: C = RecursivelyEnumeratedSet([10, 15], f, structure='symmetric')
|
|
364
|
+
sage: C
|
|
365
|
+
A recursively enumerated set with a symmetric structure (breadth first search)
|
|
366
|
+
sage: it = iter(C)
|
|
367
|
+
sage: [next(it) for _ in range(7)]
|
|
368
|
+
[10, 15, 9, 11, 14, 16, 8]
|
|
369
|
+
|
|
370
|
+
A recursive set given by a graded relation::
|
|
371
|
+
|
|
372
|
+
sage: # needs sage.symbolic
|
|
373
|
+
sage: def f(a):
|
|
374
|
+
....: return [a + 1, a + I]
|
|
375
|
+
sage: C = RecursivelyEnumeratedSet([0], f, structure='graded'); C
|
|
376
|
+
A recursively enumerated set with a graded structure (breadth first search)
|
|
377
|
+
sage: it = iter(C)
|
|
378
|
+
sage: [next(it) for _ in range(7)]
|
|
379
|
+
[0, 1, I, 2, I + 1, 2*I, 3]
|
|
380
|
+
|
|
381
|
+
.. WARNING::
|
|
382
|
+
|
|
383
|
+
If you do not set a good structure, you might obtain bad results,
|
|
384
|
+
like elements generated twice::
|
|
385
|
+
|
|
386
|
+
sage: f = lambda a: [a-1,a+1]
|
|
387
|
+
sage: C = RecursivelyEnumeratedSet([0], f, structure='graded')
|
|
388
|
+
sage: it = iter(C)
|
|
389
|
+
sage: [next(it) for _ in range(7)]
|
|
390
|
+
[0, -1, 1, -2, 0, 2, -3]
|
|
391
|
+
|
|
392
|
+
TESTS:
|
|
393
|
+
|
|
394
|
+
The successors method is an attribute::
|
|
395
|
+
|
|
396
|
+
sage: R = RecursivelyEnumeratedSet([1], lambda x: [x+1, x-1])
|
|
397
|
+
sage: R.successors(4)
|
|
398
|
+
[5, 3]
|
|
399
|
+
|
|
400
|
+
::
|
|
401
|
+
|
|
402
|
+
sage: C = RecursivelyEnumeratedSet((1, 2, 3), factor)
|
|
403
|
+
sage: C.successors
|
|
404
|
+
<function factor at ...>
|
|
405
|
+
sage: C._seeds
|
|
406
|
+
(1, 2, 3)
|
|
407
|
+
"""
|
|
408
|
+
if structure is None:
|
|
409
|
+
if enumeration is None:
|
|
410
|
+
enumeration = 'breadth'
|
|
411
|
+
return RecursivelyEnumeratedSet_generic(seeds, successors,
|
|
412
|
+
enumeration, max_depth, facade=facade, category=category)
|
|
413
|
+
if structure == 'symmetric':
|
|
414
|
+
if enumeration is None:
|
|
415
|
+
enumeration = 'breadth'
|
|
416
|
+
return RecursivelyEnumeratedSet_symmetric(seeds, successors,
|
|
417
|
+
enumeration, max_depth, facade=facade, category=category)
|
|
418
|
+
if structure == 'forest':
|
|
419
|
+
if enumeration is None:
|
|
420
|
+
enumeration = 'depth'
|
|
421
|
+
return RecursivelyEnumeratedSet_forest(roots=seeds, children=successors,
|
|
422
|
+
algorithm=enumeration, post_process=post_process,
|
|
423
|
+
facade=facade, category=category)
|
|
424
|
+
if structure == 'graded':
|
|
425
|
+
if enumeration is None:
|
|
426
|
+
enumeration = 'breadth'
|
|
427
|
+
return RecursivelyEnumeratedSet_graded(seeds, successors, enumeration,
|
|
428
|
+
max_depth, facade=facade, category=category)
|
|
429
|
+
|
|
430
|
+
raise ValueError("Unknown value for structure (={})".format(structure))
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
cdef class RecursivelyEnumeratedSet_generic(Parent):
|
|
434
|
+
r"""
|
|
435
|
+
A generic recursively enumerated set.
|
|
436
|
+
|
|
437
|
+
For more information, see :func:`RecursivelyEnumeratedSet`.
|
|
438
|
+
|
|
439
|
+
EXAMPLES::
|
|
440
|
+
|
|
441
|
+
sage: f = lambda a:[a+1]
|
|
442
|
+
|
|
443
|
+
Different structure for the sets::
|
|
444
|
+
|
|
445
|
+
sage: RecursivelyEnumeratedSet([0], f, structure=None)
|
|
446
|
+
A recursively enumerated set (breadth first search)
|
|
447
|
+
sage: RecursivelyEnumeratedSet([0], f, structure='graded')
|
|
448
|
+
A recursively enumerated set with a graded structure (breadth first search)
|
|
449
|
+
sage: RecursivelyEnumeratedSet([0], f, structure='symmetric')
|
|
450
|
+
A recursively enumerated set with a symmetric structure (breadth first search)
|
|
451
|
+
sage: RecursivelyEnumeratedSet([0], f, structure='forest')
|
|
452
|
+
An enumerated set with a forest structure
|
|
453
|
+
|
|
454
|
+
Different default enumeration algorithms::
|
|
455
|
+
|
|
456
|
+
sage: RecursivelyEnumeratedSet([0], f, enumeration='breadth')
|
|
457
|
+
A recursively enumerated set (breadth first search)
|
|
458
|
+
sage: RecursivelyEnumeratedSet([0], f, enumeration='naive')
|
|
459
|
+
A recursively enumerated set (naive search)
|
|
460
|
+
sage: RecursivelyEnumeratedSet([0], f, enumeration='depth')
|
|
461
|
+
A recursively enumerated set (depth first search)
|
|
462
|
+
"""
|
|
463
|
+
def __init__(self, seeds, successors,
|
|
464
|
+
enumeration='depth', max_depth=float("inf"),
|
|
465
|
+
post_process=None, facade=None, category=None):
|
|
466
|
+
r"""
|
|
467
|
+
TESTS::
|
|
468
|
+
|
|
469
|
+
sage: f = lambda a: [a+3, a+5]
|
|
470
|
+
sage: C = RecursivelyEnumeratedSet([0], f)
|
|
471
|
+
sage: C
|
|
472
|
+
A recursively enumerated set (breadth first search)
|
|
473
|
+
"""
|
|
474
|
+
assert enumeration in ['naive', 'depth', 'breadth'], \
|
|
475
|
+
"unknown enumeration(={})".format(enumeration)
|
|
476
|
+
|
|
477
|
+
self._seeds = seeds
|
|
478
|
+
self.successors = successors
|
|
479
|
+
self._enumeration = enumeration
|
|
480
|
+
self._max_depth = max_depth
|
|
481
|
+
|
|
482
|
+
if post_process is not None:
|
|
483
|
+
self.post_process = post_process
|
|
484
|
+
self._graded_component = None
|
|
485
|
+
Parent.__init__(self, facade=facade,
|
|
486
|
+
category=EnumeratedSets().or_subcategory(category))
|
|
487
|
+
|
|
488
|
+
def __reduce__(self):
|
|
489
|
+
r"""
|
|
490
|
+
Return a tuple of three elements:
|
|
491
|
+
|
|
492
|
+
- The function :func:`RecursivelyEnumeratedSet`
|
|
493
|
+
- Arguments for the function :func:`RecursivelyEnumeratedSet`
|
|
494
|
+
- The actual state of ``self``.
|
|
495
|
+
|
|
496
|
+
EXAMPLES::
|
|
497
|
+
|
|
498
|
+
sage: C = RecursivelyEnumeratedSet((1, 2, 3), factor)
|
|
499
|
+
sage: loads(dumps(C))
|
|
500
|
+
A recursively enumerated set (breadth first search)
|
|
501
|
+
"""
|
|
502
|
+
try:
|
|
503
|
+
pp = self.post_process
|
|
504
|
+
except AttributeError:
|
|
505
|
+
pp = None
|
|
506
|
+
|
|
507
|
+
classname = self.__class__.__name__
|
|
508
|
+
if classname.startswith('RecursivelyEnumeratedSet_graded'):
|
|
509
|
+
struct = 'graded'
|
|
510
|
+
elif classname.startswith('RecursivelyEnumeratedSet_symmetric'):
|
|
511
|
+
struct = 'symmetric'
|
|
512
|
+
elif classname.startswith('RecursivelyEnumeratedSet_forest'):
|
|
513
|
+
struct = 'forest'
|
|
514
|
+
elif classname.startswith('RecursivelyEnumeratedSet_generic'):
|
|
515
|
+
struct = None
|
|
516
|
+
|
|
517
|
+
args = (self._seeds, self.successors, struct,
|
|
518
|
+
self._enumeration, self._max_depth, pp)
|
|
519
|
+
return (RecursivelyEnumeratedSet, args, self.__getstate__())
|
|
520
|
+
|
|
521
|
+
def __getstate__(self):
|
|
522
|
+
r"""
|
|
523
|
+
Get the current state of ``self``. Used in pickling.
|
|
524
|
+
|
|
525
|
+
EXAMPLES::
|
|
526
|
+
|
|
527
|
+
sage: C = RecursivelyEnumeratedSet((1, 2, 3), factor)
|
|
528
|
+
sage: C.__getstate__()
|
|
529
|
+
(None,)
|
|
530
|
+
"""
|
|
531
|
+
return (self._graded_component, )
|
|
532
|
+
|
|
533
|
+
def __setstate__(self, l):
|
|
534
|
+
r"""
|
|
535
|
+
Set the state of ``self``. Used in pickling.
|
|
536
|
+
|
|
537
|
+
INPUT:
|
|
538
|
+
|
|
539
|
+
- ``l`` -- the state in the pickle
|
|
540
|
+
|
|
541
|
+
EXAMPLES::
|
|
542
|
+
|
|
543
|
+
sage: C = RecursivelyEnumeratedSet((1, 2, 3), factor)
|
|
544
|
+
sage: C.__setstate__(C.__getstate__())
|
|
545
|
+
"""
|
|
546
|
+
self._graded_component = l[0]
|
|
547
|
+
# Since github issue #21312, the graded component iterator is not used
|
|
548
|
+
# anymore but maybe some previously pickled object still have it
|
|
549
|
+
# self._graded_component_it = l[1]
|
|
550
|
+
|
|
551
|
+
def __len__(self):
|
|
552
|
+
"""
|
|
553
|
+
Disable ``__len__()`` from :class:`Parent` :issue:`12955`.
|
|
554
|
+
|
|
555
|
+
Because Python assumes ``__len__()`` is fast and we cannot
|
|
556
|
+
have a fast default implementation.
|
|
557
|
+
|
|
558
|
+
EXAMPLES::
|
|
559
|
+
|
|
560
|
+
sage: f = lambda a: [a+3, a+5]
|
|
561
|
+
sage: C = RecursivelyEnumeratedSet([0], f)
|
|
562
|
+
sage: len(C)
|
|
563
|
+
Traceback (most recent call last):
|
|
564
|
+
...
|
|
565
|
+
TypeError: cannot compute length of A recursively enumerated set (breadth first search)
|
|
566
|
+
"""
|
|
567
|
+
raise TypeError(f"cannot compute length of {self}")
|
|
568
|
+
|
|
569
|
+
def __iter__(self):
|
|
570
|
+
r"""
|
|
571
|
+
Iterate on the elements of ``self``.
|
|
572
|
+
|
|
573
|
+
The enumeration is done depth first or breadth first depending on
|
|
574
|
+
the value of ``self._enumeration``.
|
|
575
|
+
|
|
576
|
+
EXAMPLES::
|
|
577
|
+
|
|
578
|
+
sage: f = lambda a: [a+3, a+5]
|
|
579
|
+
sage: it_naive = iter(RecursivelyEnumeratedSet([0], f, enumeration='naive'))
|
|
580
|
+
sage: it_depth = iter(RecursivelyEnumeratedSet([0], f, enumeration='depth'))
|
|
581
|
+
sage: it_breadth = iter(RecursivelyEnumeratedSet([0], f, enumeration='breadth'))
|
|
582
|
+
sage: sorted([next(it_naive) for _ in range(10)])
|
|
583
|
+
[0, 3, 5, 6, 8, 9, 10, 11, 12, 13]
|
|
584
|
+
sage: [next(it_depth) for _ in range(10)]
|
|
585
|
+
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45]
|
|
586
|
+
sage: [next(it_breadth) for _ in range(10)]
|
|
587
|
+
[0, 3, 5, 6, 8, 10, 9, 11, 13, 15]
|
|
588
|
+
"""
|
|
589
|
+
if self._enumeration == 'naive':
|
|
590
|
+
return self.naive_search_iterator()
|
|
591
|
+
elif self._enumeration == 'breadth':
|
|
592
|
+
return self.breadth_first_search_iterator(max_depth=self._max_depth)
|
|
593
|
+
elif self._enumeration == 'depth':
|
|
594
|
+
return self.depth_first_search_iterator()
|
|
595
|
+
|
|
596
|
+
raise ValueError("unknown value for enumeration(={})".format(self._enumeration))
|
|
597
|
+
|
|
598
|
+
def __contains__(self, elt):
|
|
599
|
+
r"""
|
|
600
|
+
Return ``True`` if ``elt`` is in ``self``.
|
|
601
|
+
|
|
602
|
+
.. WARNING::
|
|
603
|
+
|
|
604
|
+
This is achieved by iterating through the elements using the
|
|
605
|
+
default enumeration until ``elt`` is found. In particular, this
|
|
606
|
+
method will never stop when ``elt`` is not in ``self`` and
|
|
607
|
+
``self`` is infinite or when ``elt`` is in ``self`` but the
|
|
608
|
+
enumeration is not appropriate.
|
|
609
|
+
|
|
610
|
+
EXAMPLES::
|
|
611
|
+
|
|
612
|
+
sage: f = lambda a:[a+3,a+5]
|
|
613
|
+
sage: R = RecursivelyEnumeratedSet([0], f)
|
|
614
|
+
sage: R
|
|
615
|
+
A recursively enumerated set (breadth first search)
|
|
616
|
+
sage: 8 in R
|
|
617
|
+
True
|
|
618
|
+
|
|
619
|
+
::
|
|
620
|
+
|
|
621
|
+
sage: R = RecursivelyEnumeratedSet([0], f, enumeration='depth')
|
|
622
|
+
sage: R
|
|
623
|
+
A recursively enumerated set (depth first search)
|
|
624
|
+
sage: it = iter(R)
|
|
625
|
+
sage: [next(it) for _ in range(6)]
|
|
626
|
+
[0, 5, 10, 15, 20, 25]
|
|
627
|
+
sage: 8 in R # (should return True) not tested: does not terminate
|
|
628
|
+
sage: 7 in R # (should return False) not tested: does not terminate
|
|
629
|
+
"""
|
|
630
|
+
return any(node == elt for node in self)
|
|
631
|
+
|
|
632
|
+
def _repr_(self):
|
|
633
|
+
r"""
|
|
634
|
+
TESTS::
|
|
635
|
+
|
|
636
|
+
sage: f = lambda x: [x-1, x+1]
|
|
637
|
+
sage: RecursivelyEnumeratedSet([1], f, structure=None)
|
|
638
|
+
A recursively enumerated set (breadth first search)
|
|
639
|
+
|
|
640
|
+
::
|
|
641
|
+
|
|
642
|
+
sage: RecursivelyEnumeratedSet([1], f, structure='graded')
|
|
643
|
+
A recursively enumerated set with a graded structure (breadth first search)
|
|
644
|
+
|
|
645
|
+
::
|
|
646
|
+
|
|
647
|
+
sage: RecursivelyEnumeratedSet([1], f, structure='symmetric')
|
|
648
|
+
A recursively enumerated set with a symmetric structure (breadth first search)
|
|
649
|
+
|
|
650
|
+
When ``max_depth`` is set::
|
|
651
|
+
|
|
652
|
+
sage: RecursivelyEnumeratedSet([1], f, structure='symmetric', max_depth=4)
|
|
653
|
+
A recursively enumerated set with a symmetric structure (breadth
|
|
654
|
+
first search) with max_depth=4
|
|
655
|
+
"""
|
|
656
|
+
L = ["A recursively enumerated set"]
|
|
657
|
+
classname = self.__class__.__name__
|
|
658
|
+
if classname.startswith('RecursivelyEnumeratedSet_graded'):
|
|
659
|
+
L.append("with a graded structure")
|
|
660
|
+
elif classname.startswith('RecursivelyEnumeratedSet_symmetric'):
|
|
661
|
+
L.append("with a symmetric structure")
|
|
662
|
+
elif classname.startswith('RecursivelyEnumeratedSet_forest'):
|
|
663
|
+
L.append("with a forest structure")
|
|
664
|
+
|
|
665
|
+
if self._enumeration in ['depth', 'breadth']:
|
|
666
|
+
L.append("({} first search)".format(self._enumeration))
|
|
667
|
+
else:
|
|
668
|
+
L.append("({} search)".format(self._enumeration))
|
|
669
|
+
|
|
670
|
+
if not self._max_depth == float('inf'):
|
|
671
|
+
L.append("with max_depth={}".format(self._max_depth))
|
|
672
|
+
return " ".join(L)
|
|
673
|
+
|
|
674
|
+
cpdef seeds(self):
|
|
675
|
+
r"""
|
|
676
|
+
Return an iterable over the seeds of ``self``.
|
|
677
|
+
|
|
678
|
+
EXAMPLES::
|
|
679
|
+
|
|
680
|
+
sage: R = RecursivelyEnumeratedSet([1], lambda x: [x + 1, x - 1])
|
|
681
|
+
sage: R.seeds()
|
|
682
|
+
[1]
|
|
683
|
+
"""
|
|
684
|
+
return self._seeds
|
|
685
|
+
|
|
686
|
+
# using this in a .pyx file makes sage crash at startup
|
|
687
|
+
# @abstract_method
|
|
688
|
+
# def successors(self, x):
|
|
689
|
+
# r"""
|
|
690
|
+
# Return the successors of the element ``x``
|
|
691
|
+
#
|
|
692
|
+
# OUTPUT:
|
|
693
|
+
#
|
|
694
|
+
# an iterable
|
|
695
|
+
#
|
|
696
|
+
# EXAMPLES::
|
|
697
|
+
#
|
|
698
|
+
# sage: R = RecursivelyEnumeratedSet([1], lambda x: [x+1, x-1])
|
|
699
|
+
# sage: R.successors(4)
|
|
700
|
+
# [5, 3]
|
|
701
|
+
# """
|
|
702
|
+
|
|
703
|
+
def graded_component_iterator(self):
|
|
704
|
+
r"""
|
|
705
|
+
Iterate over the graded components of ``self``.
|
|
706
|
+
|
|
707
|
+
A graded component is a set of elements of the same depth.
|
|
708
|
+
|
|
709
|
+
It is currently implemented only for graded or symmetric structure.
|
|
710
|
+
|
|
711
|
+
OUTPUT: an iterator of sets
|
|
712
|
+
|
|
713
|
+
EXAMPLES::
|
|
714
|
+
|
|
715
|
+
sage: f = lambda a: [a+3, a+5]
|
|
716
|
+
sage: C = RecursivelyEnumeratedSet([0], f)
|
|
717
|
+
sage: it = C.graded_component_iterator() # todo: not implemented
|
|
718
|
+
"""
|
|
719
|
+
raise NotImplementedError("graded_component_iterator method currently"
|
|
720
|
+
" implemented only for graded or symmetric structure")
|
|
721
|
+
|
|
722
|
+
cpdef graded_component(self, depth):
|
|
723
|
+
r"""
|
|
724
|
+
Return the graded component of given depth.
|
|
725
|
+
|
|
726
|
+
This method caches each lower graded component.
|
|
727
|
+
|
|
728
|
+
A graded component is a set of elements of the same depth where the
|
|
729
|
+
depth of an element is its minimal distance to a root.
|
|
730
|
+
|
|
731
|
+
It is currently implemented only for graded or symmetric structure.
|
|
732
|
+
|
|
733
|
+
INPUT:
|
|
734
|
+
|
|
735
|
+
- ``depth`` -- integer
|
|
736
|
+
|
|
737
|
+
OUTPUT: set
|
|
738
|
+
|
|
739
|
+
EXAMPLES::
|
|
740
|
+
|
|
741
|
+
sage: f = lambda a: [a+3, a+5]
|
|
742
|
+
sage: C = RecursivelyEnumeratedSet([0], f)
|
|
743
|
+
sage: C.graded_component(0)
|
|
744
|
+
Traceback (most recent call last):
|
|
745
|
+
...
|
|
746
|
+
NotImplementedError: graded_component_iterator method currently implemented only for graded or symmetric structure
|
|
747
|
+
"""
|
|
748
|
+
raise NotImplementedError("graded_component_iterator method currently"
|
|
749
|
+
" implemented only for graded or symmetric structure")
|
|
750
|
+
|
|
751
|
+
def elements_of_depth_iterator(self, depth):
|
|
752
|
+
r"""
|
|
753
|
+
Iterate over the elements of ``self`` of given depth.
|
|
754
|
+
|
|
755
|
+
An element of depth `n` can be obtained by applying the
|
|
756
|
+
successor function `n` times to a seed.
|
|
757
|
+
|
|
758
|
+
INPUT:
|
|
759
|
+
|
|
760
|
+
- ``depth`` -- integer
|
|
761
|
+
|
|
762
|
+
OUTPUT: an iterator
|
|
763
|
+
|
|
764
|
+
EXAMPLES::
|
|
765
|
+
|
|
766
|
+
sage: f = lambda a: [a-1, a+1]
|
|
767
|
+
sage: S = RecursivelyEnumeratedSet([5, 10], f, structure='symmetric')
|
|
768
|
+
sage: it = S.elements_of_depth_iterator(2)
|
|
769
|
+
sage: sorted(it)
|
|
770
|
+
[3, 7, 8, 12]
|
|
771
|
+
"""
|
|
772
|
+
return iter(self.graded_component(depth))
|
|
773
|
+
|
|
774
|
+
def breadth_first_search_iterator(self, max_depth=None):
|
|
775
|
+
r"""
|
|
776
|
+
Iterate on the elements of ``self`` (breadth first).
|
|
777
|
+
|
|
778
|
+
This code remembers every element generated.
|
|
779
|
+
|
|
780
|
+
The elements are guaranteed to be enumerated in the order in which they
|
|
781
|
+
are first visited (left-to-right traversal).
|
|
782
|
+
|
|
783
|
+
INPUT:
|
|
784
|
+
|
|
785
|
+
- ``max_depth`` -- (default: ``self._max_depth``) specifies the
|
|
786
|
+
maximal depth to which elements are computed
|
|
787
|
+
|
|
788
|
+
EXAMPLES::
|
|
789
|
+
|
|
790
|
+
sage: f = lambda a: [a+3, a+5]
|
|
791
|
+
sage: C = RecursivelyEnumeratedSet([0], f)
|
|
792
|
+
sage: it = C.breadth_first_search_iterator()
|
|
793
|
+
sage: [next(it) for _ in range(10)]
|
|
794
|
+
[0, 3, 5, 6, 8, 10, 9, 11, 13, 15]
|
|
795
|
+
"""
|
|
796
|
+
if max_depth is None:
|
|
797
|
+
max_depth = self._max_depth
|
|
798
|
+
current_level = self._seeds
|
|
799
|
+
known = set(current_level)
|
|
800
|
+
if max_depth >= 0:
|
|
801
|
+
yield from current_level
|
|
802
|
+
depth = 0
|
|
803
|
+
while current_level and depth < max_depth:
|
|
804
|
+
next_level = []
|
|
805
|
+
for x in current_level:
|
|
806
|
+
for y in self.successors(x):
|
|
807
|
+
if y is None or y in known:
|
|
808
|
+
continue
|
|
809
|
+
yield y
|
|
810
|
+
next_level.append(y)
|
|
811
|
+
known.add(y)
|
|
812
|
+
current_level = next_level
|
|
813
|
+
depth += 1
|
|
814
|
+
|
|
815
|
+
def _breadth_first_search_iterator_using_queue(self):
|
|
816
|
+
r"""
|
|
817
|
+
Iterate on the elements of ``self`` (breadth first).
|
|
818
|
+
|
|
819
|
+
This code remembers every element generated and uses python
|
|
820
|
+
queues. It is 3 times slower than the other one.
|
|
821
|
+
|
|
822
|
+
See :wikipedia:`Breadth-first_search`.
|
|
823
|
+
|
|
824
|
+
EXAMPLES::
|
|
825
|
+
|
|
826
|
+
sage: f = lambda a: [a+3, a+5]
|
|
827
|
+
sage: C = RecursivelyEnumeratedSet([0], f)
|
|
828
|
+
sage: it = C._breadth_first_search_iterator_using_queue()
|
|
829
|
+
sage: [next(it) for _ in range(10)]
|
|
830
|
+
[0, 3, 5, 6, 8, 10, 9, 11, 13, 15]
|
|
831
|
+
"""
|
|
832
|
+
cdef set known
|
|
833
|
+
known = set(self._seeds)
|
|
834
|
+
q = deque(self._seeds)
|
|
835
|
+
while q:
|
|
836
|
+
x = q.popleft()
|
|
837
|
+
yield x
|
|
838
|
+
for y in self.successors(x):
|
|
839
|
+
if y is None or y in known:
|
|
840
|
+
continue
|
|
841
|
+
q.append(y)
|
|
842
|
+
known.add(y)
|
|
843
|
+
|
|
844
|
+
def naive_search_iterator(self):
|
|
845
|
+
r"""
|
|
846
|
+
Iterate on the elements of ``self`` (in no particular order).
|
|
847
|
+
|
|
848
|
+
This code remembers every element generated.
|
|
849
|
+
|
|
850
|
+
TESTS:
|
|
851
|
+
|
|
852
|
+
We compute all the permutations of 3::
|
|
853
|
+
|
|
854
|
+
sage: # needs sage.combinat
|
|
855
|
+
sage: seeds = [Permutation([1,2,3])]
|
|
856
|
+
sage: succ = attrcall("permutohedron_succ")
|
|
857
|
+
sage: R = RecursivelyEnumeratedSet(seeds, succ)
|
|
858
|
+
sage: sorted(R.naive_search_iterator())
|
|
859
|
+
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
|
|
860
|
+
"""
|
|
861
|
+
cdef set known, todo
|
|
862
|
+
known = set(self._seeds)
|
|
863
|
+
todo = known.copy()
|
|
864
|
+
while todo:
|
|
865
|
+
x = todo.pop()
|
|
866
|
+
yield x
|
|
867
|
+
for y in self.successors(x):
|
|
868
|
+
if y is None or y in known:
|
|
869
|
+
continue
|
|
870
|
+
todo.add(y)
|
|
871
|
+
known.add(y)
|
|
872
|
+
|
|
873
|
+
def depth_first_search_iterator(self):
|
|
874
|
+
r"""
|
|
875
|
+
Iterate on the elements of ``self`` (depth first).
|
|
876
|
+
|
|
877
|
+
This code remembers every element generated.
|
|
878
|
+
|
|
879
|
+
The elements are traversed right-to-left, so the last element returned
|
|
880
|
+
by the successor function is visited first.
|
|
881
|
+
|
|
882
|
+
See :wikipedia:`Depth-first_search`.
|
|
883
|
+
|
|
884
|
+
EXAMPLES::
|
|
885
|
+
|
|
886
|
+
sage: f = lambda a: [a+3, a+5]
|
|
887
|
+
sage: C = RecursivelyEnumeratedSet([0], f)
|
|
888
|
+
sage: it = C.depth_first_search_iterator()
|
|
889
|
+
sage: [next(it) for _ in range(10)]
|
|
890
|
+
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45]
|
|
891
|
+
"""
|
|
892
|
+
cdef list stack
|
|
893
|
+
cdef set known
|
|
894
|
+
stack = list(self._seeds)
|
|
895
|
+
known = set()
|
|
896
|
+
while stack:
|
|
897
|
+
x = stack.pop()
|
|
898
|
+
if x is None or x in known:
|
|
899
|
+
continue
|
|
900
|
+
yield x
|
|
901
|
+
known.add(x)
|
|
902
|
+
for y in self.successors(x):
|
|
903
|
+
stack.append(y)
|
|
904
|
+
|
|
905
|
+
def to_digraph(self, max_depth=None, loops=True, multiedges=True):
|
|
906
|
+
r"""
|
|
907
|
+
Return the directed graph of the recursively enumerated set.
|
|
908
|
+
|
|
909
|
+
INPUT:
|
|
910
|
+
|
|
911
|
+
- ``max_depth`` -- (default: ``self._max_depth``) specifies the
|
|
912
|
+
maximal depth for which outgoing edges of elements are computed
|
|
913
|
+
- ``loops`` -- boolean (default: ``True``); option for the digraph
|
|
914
|
+
- ``multiedges`` -- boolean (default: ``True``); option of the digraph
|
|
915
|
+
|
|
916
|
+
OUTPUT: a directed graph
|
|
917
|
+
|
|
918
|
+
.. WARNING::
|
|
919
|
+
|
|
920
|
+
If the set is infinite, this will loop forever unless ``max_depth``
|
|
921
|
+
is finite.
|
|
922
|
+
|
|
923
|
+
EXAMPLES::
|
|
924
|
+
|
|
925
|
+
sage: child = lambda i: [(i+3) % 10, (i+8) % 10]
|
|
926
|
+
sage: R = RecursivelyEnumeratedSet([0], child)
|
|
927
|
+
sage: R.to_digraph() # needs sage.graphs
|
|
928
|
+
Looped multi-digraph on 10 vertices
|
|
929
|
+
|
|
930
|
+
Digraph of a recursively enumerated set with a symmetric structure of
|
|
931
|
+
infinite cardinality using ``max_depth`` argument::
|
|
932
|
+
|
|
933
|
+
sage: succ = lambda a: [(a[0]-1,a[1]), (a[0],a[1]-1), (a[0]+1,a[1]), (a[0],a[1]+1)]
|
|
934
|
+
sage: seeds = [(0,0)]
|
|
935
|
+
sage: C = RecursivelyEnumeratedSet(seeds, succ, structure='symmetric')
|
|
936
|
+
sage: C.to_digraph(max_depth=3) # needs sage.graphs
|
|
937
|
+
Looped multi-digraph on 41 vertices
|
|
938
|
+
|
|
939
|
+
The ``max_depth`` argument can be given at the creation of the set::
|
|
940
|
+
|
|
941
|
+
sage: C = RecursivelyEnumeratedSet(seeds, succ, structure='symmetric',
|
|
942
|
+
....: max_depth=2)
|
|
943
|
+
sage: C.to_digraph() # needs sage.graphs
|
|
944
|
+
Looped multi-digraph on 25 vertices
|
|
945
|
+
|
|
946
|
+
Digraph of a recursively enumerated set with a graded structure::
|
|
947
|
+
|
|
948
|
+
sage: f = lambda a: [a+1, a+I]
|
|
949
|
+
sage: C = RecursivelyEnumeratedSet([0], f, structure='graded')
|
|
950
|
+
sage: C.to_digraph(max_depth=4) # needs sage.graphs sage.symbolic
|
|
951
|
+
Looped multi-digraph on 21 vertices
|
|
952
|
+
"""
|
|
953
|
+
successors = self.successors
|
|
954
|
+
it = self.breadth_first_search_iterator(max_depth=max_depth)
|
|
955
|
+
E = [(u, v) for u in it for v in successors(u)]
|
|
956
|
+
from sage.graphs.digraph import DiGraph
|
|
957
|
+
return DiGraph(E, format='list_of_edges', loops=loops,
|
|
958
|
+
multiedges=multiedges)
|
|
959
|
+
|
|
960
|
+
|
|
961
|
+
cdef class RecursivelyEnumeratedSet_symmetric(RecursivelyEnumeratedSet_generic):
|
|
962
|
+
r"""
|
|
963
|
+
Generic tool for constructing ideals of a symmetric relation.
|
|
964
|
+
|
|
965
|
+
INPUT:
|
|
966
|
+
|
|
967
|
+
- ``seeds`` -- list (or iterable) of hashable objects
|
|
968
|
+
- ``successors`` -- function (or callable) returning a list (or iterable)
|
|
969
|
+
- ``enumeration`` -- ``'depth'``, ``'breadth'`` or ``None`` (default: ``None``)
|
|
970
|
+
- ``max_depth`` -- integer (default: ``float("inf")``)
|
|
971
|
+
|
|
972
|
+
EXAMPLES::
|
|
973
|
+
|
|
974
|
+
sage: f = lambda a: [a-1,a+1]
|
|
975
|
+
sage: C = RecursivelyEnumeratedSet([0], f, structure='symmetric')
|
|
976
|
+
sage: C
|
|
977
|
+
A recursively enumerated set with a symmetric structure (breadth first search)
|
|
978
|
+
sage: it = iter(C)
|
|
979
|
+
sage: [next(it) for _ in range(7)]
|
|
980
|
+
[0, -1, 1, -2, 2, -3, 3]
|
|
981
|
+
|
|
982
|
+
TESTS:
|
|
983
|
+
|
|
984
|
+
Do not use lambda functions for saving purposes::
|
|
985
|
+
|
|
986
|
+
sage: f = lambda a: [a-1,a+1]
|
|
987
|
+
sage: C = RecursivelyEnumeratedSet([0], f, structure='symmetric')
|
|
988
|
+
sage: loads(dumps(C))
|
|
989
|
+
Traceback (most recent call last):
|
|
990
|
+
...
|
|
991
|
+
PicklingError: ...
|
|
992
|
+
|
|
993
|
+
This works in the command line but apparently not as a doctest::
|
|
994
|
+
|
|
995
|
+
sage: def f(a): return [a-1,a+1]
|
|
996
|
+
sage: C = RecursivelyEnumeratedSet([0], f, structure='symmetric')
|
|
997
|
+
sage: loads(dumps(C))
|
|
998
|
+
Traceback (most recent call last):
|
|
999
|
+
...
|
|
1000
|
+
PicklingError: ...
|
|
1001
|
+
"""
|
|
1002
|
+
|
|
1003
|
+
def breadth_first_search_iterator(self, max_depth=None):
|
|
1004
|
+
r"""
|
|
1005
|
+
Iterate on the elements of ``self`` (breadth first).
|
|
1006
|
+
|
|
1007
|
+
This iterator makes use of the graded structure by remembering only
|
|
1008
|
+
the last two graded components since the structure is symmetric.
|
|
1009
|
+
|
|
1010
|
+
The elements are guaranteed to be enumerated in the order in which they
|
|
1011
|
+
are first visited (left-to-right traversal).
|
|
1012
|
+
|
|
1013
|
+
INPUT:
|
|
1014
|
+
|
|
1015
|
+
- ``max_depth`` -- (default: ``self._max_depth``) specifies the
|
|
1016
|
+
maximal depth to which elements are computed
|
|
1017
|
+
|
|
1018
|
+
EXAMPLES::
|
|
1019
|
+
|
|
1020
|
+
sage: f = lambda a: [(a[0]-1,a[1]), (a[0],a[1]-1), (a[0]+1,a[1]), (a[0],a[1]+1)]
|
|
1021
|
+
sage: C = RecursivelyEnumeratedSet([(0,0)], f, structure='symmetric')
|
|
1022
|
+
sage: s = list(C.breadth_first_search_iterator(max_depth=2)); s
|
|
1023
|
+
[(0, 0),
|
|
1024
|
+
(-1, 0), (0, -1), (1, 0), (0, 1),
|
|
1025
|
+
(-2, 0), (-1, -1), (-1, 1), (0, -2), (1, -1), (2, 0), (1, 1), (0, 2)]
|
|
1026
|
+
|
|
1027
|
+
This iterator is used by default for symmetric structure::
|
|
1028
|
+
|
|
1029
|
+
sage: it = iter(C)
|
|
1030
|
+
sage: s == [next(it) for _ in range(13)]
|
|
1031
|
+
True
|
|
1032
|
+
|
|
1033
|
+
TESTS:
|
|
1034
|
+
|
|
1035
|
+
Check that :issue:`28674` is fixed::
|
|
1036
|
+
|
|
1037
|
+
sage: D = RecursivelyEnumeratedSet([(0,0)], f)
|
|
1038
|
+
sage: s == list(D.breadth_first_search_iterator(max_depth=2))
|
|
1039
|
+
True
|
|
1040
|
+
"""
|
|
1041
|
+
cdef list C
|
|
1042
|
+
cdef set set_A, set_B
|
|
1043
|
+
cdef int depth
|
|
1044
|
+
if max_depth is None:
|
|
1045
|
+
max_depth = self._max_depth
|
|
1046
|
+
|
|
1047
|
+
set_A = set()
|
|
1048
|
+
B = self._seeds
|
|
1049
|
+
set_B = set(B)
|
|
1050
|
+
if max_depth >= 0:
|
|
1051
|
+
yield from B
|
|
1052
|
+
depth = 0
|
|
1053
|
+
while B and depth < max_depth:
|
|
1054
|
+
C = list()
|
|
1055
|
+
set_C = set()
|
|
1056
|
+
for x in B:
|
|
1057
|
+
for y in self.successors(x):
|
|
1058
|
+
if y is None or y in set_C or y in set_A or y in set_B:
|
|
1059
|
+
continue
|
|
1060
|
+
yield y
|
|
1061
|
+
C.append(y)
|
|
1062
|
+
set_C.add(y)
|
|
1063
|
+
set_A = set_B
|
|
1064
|
+
set_B = set_C
|
|
1065
|
+
B = C
|
|
1066
|
+
depth += 1
|
|
1067
|
+
|
|
1068
|
+
def graded_component_iterator(self):
|
|
1069
|
+
r"""
|
|
1070
|
+
Iterate over the graded components of ``self``.
|
|
1071
|
+
|
|
1072
|
+
A graded component is a set of elements of the same depth.
|
|
1073
|
+
|
|
1074
|
+
The enumeration remembers only the last two graded components
|
|
1075
|
+
generated since the structure is symmetric.
|
|
1076
|
+
|
|
1077
|
+
OUTPUT: an iterator of sets
|
|
1078
|
+
|
|
1079
|
+
EXAMPLES::
|
|
1080
|
+
|
|
1081
|
+
sage: f = lambda a: [a-1, a+1]
|
|
1082
|
+
sage: S = RecursivelyEnumeratedSet([10], f, structure='symmetric')
|
|
1083
|
+
sage: it = S.graded_component_iterator()
|
|
1084
|
+
sage: [sorted(next(it)) for _ in range(5)]
|
|
1085
|
+
[[10], [9, 11], [8, 12], [7, 13], [6, 14]]
|
|
1086
|
+
|
|
1087
|
+
Starting with two generators::
|
|
1088
|
+
|
|
1089
|
+
sage: f = lambda a: [a-1, a+1]
|
|
1090
|
+
sage: S = RecursivelyEnumeratedSet([5, 10], f, structure='symmetric')
|
|
1091
|
+
sage: it = S.graded_component_iterator()
|
|
1092
|
+
sage: [sorted(next(it)) for _ in range(5)]
|
|
1093
|
+
[[5, 10], [4, 6, 9, 11], [3, 7, 8, 12], [2, 13], [1, 14]]
|
|
1094
|
+
|
|
1095
|
+
Gaussian integers::
|
|
1096
|
+
|
|
1097
|
+
sage: # needs sage.symbolic
|
|
1098
|
+
sage: def f(a):
|
|
1099
|
+
....: return [a + 1, a + I]
|
|
1100
|
+
sage: S = RecursivelyEnumeratedSet([0], f, structure='symmetric')
|
|
1101
|
+
sage: it = S.graded_component_iterator()
|
|
1102
|
+
sage: [sorted(next(it)) for _ in range(7)]
|
|
1103
|
+
[[0],
|
|
1104
|
+
[I, 1],
|
|
1105
|
+
[2*I, I + 1, 2],
|
|
1106
|
+
[3*I, 2*I + 1, I + 2, 3],
|
|
1107
|
+
[4*I, 3*I + 1, 2*I + 2, I + 3, 4],
|
|
1108
|
+
[5*I, 4*I + 1, 3*I + 2, 2*I + 3, I + 4, 5],
|
|
1109
|
+
[6*I, 5*I + 1, 4*I + 2, 3*I + 3, 2*I + 4, I + 5, 6]]
|
|
1110
|
+
|
|
1111
|
+
TESTS:
|
|
1112
|
+
|
|
1113
|
+
Note that interrupting the computation (``KeyboardInterrupt`` for
|
|
1114
|
+
instance) breaks the iterator::
|
|
1115
|
+
|
|
1116
|
+
sage: # needs sage.symbolic
|
|
1117
|
+
sage: def f(a):
|
|
1118
|
+
....: sleep(0.05r)
|
|
1119
|
+
....: return [a - 1, a + 1]
|
|
1120
|
+
sage: C = RecursivelyEnumeratedSet([0], f, structure='symmetric')
|
|
1121
|
+
sage: it = C.graded_component_iterator()
|
|
1122
|
+
sage: next(it)
|
|
1123
|
+
{0}
|
|
1124
|
+
sage: next(it)
|
|
1125
|
+
{-1, 1}
|
|
1126
|
+
sage: from sage.doctest.util import ensure_interruptible_after
|
|
1127
|
+
sage: with ensure_interruptible_after(0.02): next(it)
|
|
1128
|
+
sage: next(it)
|
|
1129
|
+
Traceback (most recent call last):
|
|
1130
|
+
...
|
|
1131
|
+
StopIteration
|
|
1132
|
+
"""
|
|
1133
|
+
cdef set A, B
|
|
1134
|
+
A = set()
|
|
1135
|
+
B = set(self._seeds)
|
|
1136
|
+
while B:
|
|
1137
|
+
yield B
|
|
1138
|
+
A, B = B, self._get_next_graded_component(A, B)
|
|
1139
|
+
|
|
1140
|
+
cpdef graded_component(self, depth):
|
|
1141
|
+
r"""
|
|
1142
|
+
Return the graded component of given depth.
|
|
1143
|
+
|
|
1144
|
+
This method caches each lower graded component. See
|
|
1145
|
+
:meth:`graded_component_iterator` to generate each graded component
|
|
1146
|
+
without caching the previous ones.
|
|
1147
|
+
|
|
1148
|
+
A graded component is a set of elements of the same depth where the
|
|
1149
|
+
depth of an element is its minimal distance to a root.
|
|
1150
|
+
|
|
1151
|
+
INPUT:
|
|
1152
|
+
|
|
1153
|
+
- ``depth`` -- integer
|
|
1154
|
+
|
|
1155
|
+
OUTPUT: set
|
|
1156
|
+
|
|
1157
|
+
EXAMPLES::
|
|
1158
|
+
|
|
1159
|
+
sage: f = lambda a: [a-1,a+1]
|
|
1160
|
+
sage: C = RecursivelyEnumeratedSet([10, 15], f, structure='symmetric')
|
|
1161
|
+
sage: for i in range(5): sorted(C.graded_component(i))
|
|
1162
|
+
[10, 15]
|
|
1163
|
+
[9, 11, 14, 16]
|
|
1164
|
+
[8, 12, 13, 17]
|
|
1165
|
+
[7, 18]
|
|
1166
|
+
[6, 19]
|
|
1167
|
+
|
|
1168
|
+
TESTS:
|
|
1169
|
+
|
|
1170
|
+
We make sure that :issue:`21312` is fixed::
|
|
1171
|
+
|
|
1172
|
+
sage: def f(a):
|
|
1173
|
+
....: sleep(0.1r)
|
|
1174
|
+
....: return [a - 1, a + 1]
|
|
1175
|
+
sage: C = RecursivelyEnumeratedSet([0], f, structure='symmetric')
|
|
1176
|
+
sage: from sage.doctest.util import ensure_interruptible_after
|
|
1177
|
+
sage: with ensure_interruptible_after(0.45): C.graded_component(10)
|
|
1178
|
+
sage: C.graded_component(1)
|
|
1179
|
+
{-1, 1}
|
|
1180
|
+
sage: C.graded_component(2)
|
|
1181
|
+
{-2, 2}
|
|
1182
|
+
sage: C.graded_component(3)
|
|
1183
|
+
{-3, 3}
|
|
1184
|
+
sage: C.graded_component(4)
|
|
1185
|
+
{-4, 4}
|
|
1186
|
+
sage: C.graded_component(5)
|
|
1187
|
+
{-5, 5}
|
|
1188
|
+
"""
|
|
1189
|
+
cdef set A, B, C
|
|
1190
|
+
if self._graded_component is None:
|
|
1191
|
+
A = set()
|
|
1192
|
+
B = set(self._seeds)
|
|
1193
|
+
C = self._get_next_graded_component(A, B)
|
|
1194
|
+
self._graded_component = [B, C]
|
|
1195
|
+
while len(self._graded_component) <= depth:
|
|
1196
|
+
A = self._graded_component[-2]
|
|
1197
|
+
B = self._graded_component[-1]
|
|
1198
|
+
C = self._get_next_graded_component(A, B)
|
|
1199
|
+
self._graded_component.append(C)
|
|
1200
|
+
return self._graded_component[depth]
|
|
1201
|
+
|
|
1202
|
+
cdef set _get_next_graded_component(self, set A, set B):
|
|
1203
|
+
r"""
|
|
1204
|
+
Return the set of elements of depth `n+1`.
|
|
1205
|
+
|
|
1206
|
+
INPUT:
|
|
1207
|
+
|
|
1208
|
+
- ``A`` -- set, the set of elements of depth n-1
|
|
1209
|
+
- ``B`` -- set, the set of elements of depth n
|
|
1210
|
+
|
|
1211
|
+
OUTPUT: ``C``; the set of elements of depth n+1
|
|
1212
|
+
|
|
1213
|
+
.. TODO::
|
|
1214
|
+
|
|
1215
|
+
Can :class:`collections.OrderedDict` help maintain the
|
|
1216
|
+
breadth first search enumeration for each graded component?
|
|
1217
|
+
|
|
1218
|
+
EXAMPLES::
|
|
1219
|
+
|
|
1220
|
+
sage: f = lambda a: [a-1, a+1]
|
|
1221
|
+
sage: S = RecursivelyEnumeratedSet([5, 10], f, structure='symmetric')
|
|
1222
|
+
sage: it = S.graded_component_iterator()
|
|
1223
|
+
sage: [sorted(next(it)) for _ in range(3)] # indirect doctest
|
|
1224
|
+
[[5, 10], [4, 6, 9, 11], [3, 7, 8, 12]]
|
|
1225
|
+
"""
|
|
1226
|
+
cdef set C
|
|
1227
|
+
C = set()
|
|
1228
|
+
for x in B:
|
|
1229
|
+
for y in self.successors(x):
|
|
1230
|
+
if (y is None or y in A or y in B):
|
|
1231
|
+
continue
|
|
1232
|
+
C.add(y)
|
|
1233
|
+
return C
|
|
1234
|
+
|
|
1235
|
+
|
|
1236
|
+
cdef class RecursivelyEnumeratedSet_graded(RecursivelyEnumeratedSet_generic):
|
|
1237
|
+
r"""
|
|
1238
|
+
Generic tool for constructing ideals of a graded relation.
|
|
1239
|
+
|
|
1240
|
+
INPUT:
|
|
1241
|
+
|
|
1242
|
+
- ``seeds`` -- list (or iterable) of hashable objects
|
|
1243
|
+
- ``successors`` -- function (or callable) returning a list (or iterable)
|
|
1244
|
+
- ``enumeration`` -- ``'depth'``, ``'breadth'`` or ``None`` (default: ``None``)
|
|
1245
|
+
- ``max_depth`` -- integer (default: ``float("inf")``)
|
|
1246
|
+
|
|
1247
|
+
EXAMPLES::
|
|
1248
|
+
|
|
1249
|
+
sage: f = lambda a: [(a[0]+1,a[1]), (a[0],a[1]+1)]
|
|
1250
|
+
sage: C = RecursivelyEnumeratedSet([(0,0)], f, structure='graded', max_depth=3)
|
|
1251
|
+
sage: C
|
|
1252
|
+
A recursively enumerated set with a graded structure (breadth first
|
|
1253
|
+
search) with max_depth=3
|
|
1254
|
+
sage: list(C)
|
|
1255
|
+
[(0, 0),
|
|
1256
|
+
(1, 0), (0, 1),
|
|
1257
|
+
(2, 0), (1, 1), (0, 2),
|
|
1258
|
+
(3, 0), (2, 1), (1, 2), (0, 3)]
|
|
1259
|
+
"""
|
|
1260
|
+
def breadth_first_search_iterator(self, max_depth=None):
|
|
1261
|
+
r"""
|
|
1262
|
+
Iterate on the elements of ``self`` (breadth first).
|
|
1263
|
+
|
|
1264
|
+
This iterator makes use of the graded structure by remembering only
|
|
1265
|
+
the elements of the current depth.
|
|
1266
|
+
|
|
1267
|
+
The elements are guaranteed to be enumerated in the order in which they
|
|
1268
|
+
are first visited (left-to-right traversal).
|
|
1269
|
+
|
|
1270
|
+
INPUT:
|
|
1271
|
+
|
|
1272
|
+
- ``max_depth`` -- (default: ``self._max_depth``) specifies the
|
|
1273
|
+
maximal depth to which elements are computed
|
|
1274
|
+
|
|
1275
|
+
EXAMPLES::
|
|
1276
|
+
|
|
1277
|
+
sage: f = lambda a: [(a[0]+1,a[1]), (a[0],a[1]+1)]
|
|
1278
|
+
sage: C = RecursivelyEnumeratedSet([(0,0)], f, structure='graded')
|
|
1279
|
+
sage: list(C.breadth_first_search_iterator(max_depth=3))
|
|
1280
|
+
[(0, 0),
|
|
1281
|
+
(1, 0), (0, 1),
|
|
1282
|
+
(2, 0), (1, 1), (0, 2),
|
|
1283
|
+
(3, 0), (2, 1), (1, 2), (0, 3)]
|
|
1284
|
+
"""
|
|
1285
|
+
cdef list next_level
|
|
1286
|
+
cdef set set_next_level
|
|
1287
|
+
cdef int depth
|
|
1288
|
+
if max_depth is None:
|
|
1289
|
+
max_depth = self._max_depth
|
|
1290
|
+
current_level = self._seeds
|
|
1291
|
+
if max_depth >= 0:
|
|
1292
|
+
yield from current_level
|
|
1293
|
+
depth = 0
|
|
1294
|
+
while current_level and depth < max_depth:
|
|
1295
|
+
next_level = list()
|
|
1296
|
+
set_next_level = set()
|
|
1297
|
+
|
|
1298
|
+
for x in current_level:
|
|
1299
|
+
for y in self.successors(x):
|
|
1300
|
+
if y is None or y in set_next_level:
|
|
1301
|
+
continue
|
|
1302
|
+
yield y
|
|
1303
|
+
next_level.append(y)
|
|
1304
|
+
set_next_level.add(y)
|
|
1305
|
+
current_level = next_level
|
|
1306
|
+
depth += 1
|
|
1307
|
+
|
|
1308
|
+
def graded_component_iterator(self):
|
|
1309
|
+
r"""
|
|
1310
|
+
Iterate over the graded components of ``self``.
|
|
1311
|
+
|
|
1312
|
+
A graded component is a set of elements of the same depth.
|
|
1313
|
+
|
|
1314
|
+
The algorithm remembers only the current graded component generated
|
|
1315
|
+
since the structure is graded.
|
|
1316
|
+
|
|
1317
|
+
OUTPUT: an iterator of sets
|
|
1318
|
+
|
|
1319
|
+
EXAMPLES::
|
|
1320
|
+
|
|
1321
|
+
sage: f = lambda a: [(a[0]+1,a[1]), (a[0],a[1]+1)]
|
|
1322
|
+
sage: C = RecursivelyEnumeratedSet([(0,0)], f, structure='graded', max_depth=3)
|
|
1323
|
+
sage: it = C.graded_component_iterator()
|
|
1324
|
+
sage: for _ in range(4): sorted(next(it))
|
|
1325
|
+
[(0, 0)]
|
|
1326
|
+
[(0, 1), (1, 0)]
|
|
1327
|
+
[(0, 2), (1, 1), (2, 0)]
|
|
1328
|
+
[(0, 3), (1, 2), (2, 1), (3, 0)]
|
|
1329
|
+
|
|
1330
|
+
TESTS:
|
|
1331
|
+
|
|
1332
|
+
Make sure that :issue:`20225` is fixed::
|
|
1333
|
+
|
|
1334
|
+
sage: child = lambda k:[2*k,2*k+1] if k<8 else []
|
|
1335
|
+
sage: root = [0]
|
|
1336
|
+
sage: R = RecursivelyEnumeratedSet(root, child, structure='graded')
|
|
1337
|
+
sage: it = R.graded_component_iterator()
|
|
1338
|
+
sage: for _ in range(7): next(it)
|
|
1339
|
+
{0}
|
|
1340
|
+
{1}
|
|
1341
|
+
{2, 3}
|
|
1342
|
+
{4, 5, 6, 7}
|
|
1343
|
+
{8, 9, 10, 11, 12, 13, 14, 15}
|
|
1344
|
+
set()
|
|
1345
|
+
set()
|
|
1346
|
+
"""
|
|
1347
|
+
cdef set B
|
|
1348
|
+
B = set(self._seeds)
|
|
1349
|
+
while True:
|
|
1350
|
+
yield B
|
|
1351
|
+
B = self._get_next_graded_component(B)
|
|
1352
|
+
|
|
1353
|
+
cpdef graded_component(self, depth):
|
|
1354
|
+
r"""
|
|
1355
|
+
Return the graded component of given depth.
|
|
1356
|
+
|
|
1357
|
+
This method caches each lower graded component. See
|
|
1358
|
+
:meth:`graded_component_iterator` to generate each graded component
|
|
1359
|
+
without caching the previous ones.
|
|
1360
|
+
|
|
1361
|
+
A graded component is a set of elements of the same depth where the
|
|
1362
|
+
depth of an element is its minimal distance to a root.
|
|
1363
|
+
|
|
1364
|
+
INPUT:
|
|
1365
|
+
|
|
1366
|
+
- ``depth`` -- integer
|
|
1367
|
+
|
|
1368
|
+
OUTPUT: set
|
|
1369
|
+
|
|
1370
|
+
EXAMPLES::
|
|
1371
|
+
|
|
1372
|
+
sage: # needs sage.symbolic
|
|
1373
|
+
sage: def f(a):
|
|
1374
|
+
....: return [a + 1, a + I]
|
|
1375
|
+
sage: C = RecursivelyEnumeratedSet([0], f, structure='graded')
|
|
1376
|
+
sage: for i in range(5): sorted(C.graded_component(i))
|
|
1377
|
+
[0]
|
|
1378
|
+
[I, 1]
|
|
1379
|
+
[2*I, I + 1, 2]
|
|
1380
|
+
[3*I, 2*I + 1, I + 2, 3]
|
|
1381
|
+
[4*I, 3*I + 1, 2*I + 2, I + 3, 4]
|
|
1382
|
+
|
|
1383
|
+
TESTS:
|
|
1384
|
+
|
|
1385
|
+
We make sure that :issue:`21312` is fixed::
|
|
1386
|
+
|
|
1387
|
+
sage: # needs sage.symbolic
|
|
1388
|
+
sage: def f(a):
|
|
1389
|
+
....: sleep(0.1r)
|
|
1390
|
+
....: return [a + 1, a + I]
|
|
1391
|
+
sage: C = RecursivelyEnumeratedSet([0], f, structure='graded')
|
|
1392
|
+
sage: from sage.doctest.util import ensure_interruptible_after
|
|
1393
|
+
sage: with ensure_interruptible_after(0.45): C.graded_component(10)
|
|
1394
|
+
sage: C.graded_component(2)
|
|
1395
|
+
{2*I, I + 1, 2}
|
|
1396
|
+
sage: C.graded_component(3)
|
|
1397
|
+
{3*I, 2*I + 1, I + 2, 3}
|
|
1398
|
+
sage: C.graded_component(4)
|
|
1399
|
+
{4*I, 3*I + 1, 2*I + 2, I + 3, 4}
|
|
1400
|
+
"""
|
|
1401
|
+
cdef set B, C
|
|
1402
|
+
if self._graded_component is None:
|
|
1403
|
+
B = set(self._seeds)
|
|
1404
|
+
self._graded_component = [B]
|
|
1405
|
+
while len(self._graded_component) <= depth:
|
|
1406
|
+
B = self._graded_component[-1]
|
|
1407
|
+
C = self._get_next_graded_component(B)
|
|
1408
|
+
self._graded_component.append(C)
|
|
1409
|
+
return self._graded_component[depth]
|
|
1410
|
+
|
|
1411
|
+
cdef set _get_next_graded_component(self, set B):
|
|
1412
|
+
r"""
|
|
1413
|
+
Return the set of elements of depth `n+1`.
|
|
1414
|
+
|
|
1415
|
+
INPUT:
|
|
1416
|
+
|
|
1417
|
+
- ``B`` -- set, the set of elements of depth `n`
|
|
1418
|
+
|
|
1419
|
+
OUTPUT: ``C``; the set of elements of depth `n+1`
|
|
1420
|
+
|
|
1421
|
+
.. TODO::
|
|
1422
|
+
|
|
1423
|
+
Can :class:`collections.OrderedDict` help maintain the
|
|
1424
|
+
breadth first search enumeration for each graded component?
|
|
1425
|
+
|
|
1426
|
+
EXAMPLES::
|
|
1427
|
+
|
|
1428
|
+
sage: f = lambda a: [(a[0]+1,a[1]), (a[0],a[1]+1)]
|
|
1429
|
+
sage: C = RecursivelyEnumeratedSet([(0,0)], f, structure='graded')
|
|
1430
|
+
sage: it = C.graded_component_iterator()
|
|
1431
|
+
sage: [sorted(next(it)) for _ in range(2)] # indirect doctest
|
|
1432
|
+
[[(0, 0)], [(0, 1), (1, 0)]]
|
|
1433
|
+
"""
|
|
1434
|
+
cdef set C
|
|
1435
|
+
C = set()
|
|
1436
|
+
for x in B:
|
|
1437
|
+
for y in self.successors(x):
|
|
1438
|
+
if (y is None or y in B):
|
|
1439
|
+
continue
|
|
1440
|
+
C.add(y)
|
|
1441
|
+
return C
|
|
1442
|
+
|
|
1443
|
+
|
|
1444
|
+
def _imap_and_filter_none(function, iterable):
|
|
1445
|
+
r"""
|
|
1446
|
+
Return an iterator over the elements ``function(x)``, where ``x``
|
|
1447
|
+
iterates through ``iterable``, such that ``function(x)`` is not
|
|
1448
|
+
``None``.
|
|
1449
|
+
|
|
1450
|
+
EXAMPLES::
|
|
1451
|
+
|
|
1452
|
+
sage: from sage.sets.recursively_enumerated_set import _imap_and_filter_none
|
|
1453
|
+
sage: p = _imap_and_filter_none(lambda x: x if is_prime(x) else None, range(15))
|
|
1454
|
+
sage: [next(p), next(p), next(p), next(p), next(p), next(p)]
|
|
1455
|
+
[2, 3, 5, 7, 11, 13]
|
|
1456
|
+
sage: p = _imap_and_filter_none(lambda x: x + x, ['a','b','c','d','e'])
|
|
1457
|
+
sage: [next(p), next(p), next(p), next(p), next(p)]
|
|
1458
|
+
['aa', 'bb', 'cc', 'dd', 'ee']
|
|
1459
|
+
"""
|
|
1460
|
+
for x in iterable:
|
|
1461
|
+
x = function(x)
|
|
1462
|
+
if x is not None:
|
|
1463
|
+
yield x
|
|
1464
|
+
|
|
1465
|
+
|
|
1466
|
+
def search_forest_iterator(roots, children, algorithm='depth'):
|
|
1467
|
+
r"""
|
|
1468
|
+
Return an iterator on the nodes of the forest having the given
|
|
1469
|
+
roots, and where ``children(x)`` returns the children of the node ``x``
|
|
1470
|
+
of the forest. Note that every node of the tree is returned,
|
|
1471
|
+
not simply the leaves.
|
|
1472
|
+
|
|
1473
|
+
INPUT:
|
|
1474
|
+
|
|
1475
|
+
- ``roots`` -- list (or iterable)
|
|
1476
|
+
- ``children`` -- a function returning a list (or iterable)
|
|
1477
|
+
- ``algorithm`` -- ``'depth'`` or ``'breadth'`` (default: ``'depth'``)
|
|
1478
|
+
|
|
1479
|
+
EXAMPLES:
|
|
1480
|
+
|
|
1481
|
+
We construct the prefix tree of binary sequences of length at most
|
|
1482
|
+
three, and enumerate its nodes::
|
|
1483
|
+
|
|
1484
|
+
sage: from sage.sets.recursively_enumerated_set import search_forest_iterator
|
|
1485
|
+
sage: list(search_forest_iterator([[]], lambda l: [l + [0], l + [1]]
|
|
1486
|
+
....: if len(l) < 3 else []))
|
|
1487
|
+
[[], [0], [0, 0], [0, 0, 0], [0, 0, 1], [0, 1], [0, 1, 0],
|
|
1488
|
+
[0, 1, 1], [1], [1, 0], [1, 0, 0], [1, 0, 1], [1, 1], [1, 1, 0], [1, 1, 1]]
|
|
1489
|
+
|
|
1490
|
+
By default, the nodes are iterated through by depth first search.
|
|
1491
|
+
We can instead use a breadth first search (increasing depth)::
|
|
1492
|
+
|
|
1493
|
+
sage: list(search_forest_iterator([[]], lambda l: [l + [0], l + [1]]
|
|
1494
|
+
....: if len(l) < 3 else [],
|
|
1495
|
+
....: algorithm='breadth'))
|
|
1496
|
+
[[],
|
|
1497
|
+
[0], [1],
|
|
1498
|
+
[0, 0], [0, 1], [1, 0], [1, 1],
|
|
1499
|
+
[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1],
|
|
1500
|
+
[1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
|
|
1501
|
+
|
|
1502
|
+
This allows for iterating through trees of infinite depth::
|
|
1503
|
+
|
|
1504
|
+
sage: it = search_forest_iterator([[]], lambda l: [l + [0], l + [1]],
|
|
1505
|
+
....: algorithm='breadth')
|
|
1506
|
+
sage: [ next(it) for i in range(16) ]
|
|
1507
|
+
[[],
|
|
1508
|
+
[0], [1], [0, 0], [0, 1], [1, 0], [1, 1],
|
|
1509
|
+
[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1],
|
|
1510
|
+
[1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1],
|
|
1511
|
+
[0, 0, 0, 0]]
|
|
1512
|
+
|
|
1513
|
+
Here is an iterator through the prefix tree of sequences of
|
|
1514
|
+
letters in `0,1,2` without repetitions, sorted by length; the
|
|
1515
|
+
leaves are therefore permutations::
|
|
1516
|
+
|
|
1517
|
+
sage: list(search_forest_iterator([[]], lambda l: [l + [i] for i in range(3) if i not in l],
|
|
1518
|
+
....: algorithm='breadth'))
|
|
1519
|
+
[[],
|
|
1520
|
+
[0], [1], [2],
|
|
1521
|
+
[0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1],
|
|
1522
|
+
[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]
|
|
1523
|
+
"""
|
|
1524
|
+
# Little trick: the same implementation handles both depth and
|
|
1525
|
+
# breadth first search. Setting position to -1 results in a depth search
|
|
1526
|
+
# (you ask the children for the last node you met). Setting
|
|
1527
|
+
# position on 0 results in a breadth search (enumerate all the
|
|
1528
|
+
# descendants of a node before going on to the next father)
|
|
1529
|
+
position = -1 if algorithm == 'depth' else 0
|
|
1530
|
+
|
|
1531
|
+
# Invariant:
|
|
1532
|
+
# - for breadth first search: stack[i] contains an iterator over the nodes
|
|
1533
|
+
# of depth ``i`` in the tree
|
|
1534
|
+
# - for depth first search: stack[i] contains an iterator over the children
|
|
1535
|
+
# of the node at depth ``i-1`` in the current branch (assuming a virtual
|
|
1536
|
+
# father of all roots at depth ``-1``)
|
|
1537
|
+
stack = [iter(roots)]
|
|
1538
|
+
while stack:
|
|
1539
|
+
try:
|
|
1540
|
+
node = next(stack[position])
|
|
1541
|
+
except StopIteration:
|
|
1542
|
+
# If there are no more, go back up the tree
|
|
1543
|
+
# We also need to check if we've exhausted all
|
|
1544
|
+
# possibilities
|
|
1545
|
+
stack.pop(position)
|
|
1546
|
+
continue
|
|
1547
|
+
|
|
1548
|
+
yield node
|
|
1549
|
+
stack.append(iter(children(node)))
|
|
1550
|
+
|
|
1551
|
+
|
|
1552
|
+
class RecursivelyEnumeratedSet_forest(Parent):
|
|
1553
|
+
r"""
|
|
1554
|
+
The enumerated set of the nodes of the forest having the given
|
|
1555
|
+
``roots``, and where ``children(x)`` returns the children of the
|
|
1556
|
+
node ``x`` of the forest.
|
|
1557
|
+
|
|
1558
|
+
See also :class:`sage.combinat.backtrack.GenericBacktracker`,
|
|
1559
|
+
:class:`RecursivelyEnumeratedSet_graded`, and
|
|
1560
|
+
:class:`RecursivelyEnumeratedSet_symmetric`.
|
|
1561
|
+
|
|
1562
|
+
INPUT:
|
|
1563
|
+
|
|
1564
|
+
- ``roots`` -- list (or iterable)
|
|
1565
|
+
- ``children`` -- a function returning a list (or iterable, or iterator)
|
|
1566
|
+
- ``post_process`` -- a function defined over the nodes of the
|
|
1567
|
+
forest (default: no post processing)
|
|
1568
|
+
- ``algorithm`` -- ``'depth'`` or ``'breadth'`` (default: ``'depth'``)
|
|
1569
|
+
- ``category`` -- a category (default: :class:`EnumeratedSets`)
|
|
1570
|
+
|
|
1571
|
+
The option ``post_process`` allows for customizing the nodes that
|
|
1572
|
+
are actually produced. Furthermore, if ``f(x)`` returns ``None``,
|
|
1573
|
+
then ``x`` won't be output at all.
|
|
1574
|
+
|
|
1575
|
+
EXAMPLES:
|
|
1576
|
+
|
|
1577
|
+
We construct the set of all binary sequences of length at most
|
|
1578
|
+
three, and list them::
|
|
1579
|
+
|
|
1580
|
+
sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
1581
|
+
sage: S = RecursivelyEnumeratedSet_forest( [[]],
|
|
1582
|
+
....: lambda l: [l + [0], l + [1]] if len(l) < 3 else [],
|
|
1583
|
+
....: category=FiniteEnumeratedSets())
|
|
1584
|
+
sage: S.list()
|
|
1585
|
+
[[],
|
|
1586
|
+
[0], [0, 0], [0, 0, 0], [0, 0, 1], [0, 1], [0, 1, 0], [0, 1, 1],
|
|
1587
|
+
[1], [1, 0], [1, 0, 0], [1, 0, 1], [1, 1], [1, 1, 0], [1, 1, 1]]
|
|
1588
|
+
|
|
1589
|
+
``RecursivelyEnumeratedSet_forest`` needs to be explicitly told that the set is
|
|
1590
|
+
finite for the following to work::
|
|
1591
|
+
|
|
1592
|
+
sage: S.category()
|
|
1593
|
+
Category of finite enumerated sets
|
|
1594
|
+
sage: S.cardinality()
|
|
1595
|
+
15
|
|
1596
|
+
|
|
1597
|
+
We proceed with the set of all lists of letters in ``0,1,2``
|
|
1598
|
+
without repetitions, ordered by increasing length (i.e. using a
|
|
1599
|
+
breadth first search through the tree)::
|
|
1600
|
+
|
|
1601
|
+
sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
1602
|
+
sage: tb = RecursivelyEnumeratedSet_forest( [[]],
|
|
1603
|
+
....: lambda l: [l + [i] for i in range(3) if i not in l],
|
|
1604
|
+
....: algorithm = 'breadth',
|
|
1605
|
+
....: category=FiniteEnumeratedSets())
|
|
1606
|
+
sage: tb[0]
|
|
1607
|
+
[]
|
|
1608
|
+
sage: tb.cardinality()
|
|
1609
|
+
16
|
|
1610
|
+
sage: list(tb)
|
|
1611
|
+
[[],
|
|
1612
|
+
[0], [1], [2],
|
|
1613
|
+
[0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1],
|
|
1614
|
+
[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]
|
|
1615
|
+
|
|
1616
|
+
For infinite sets, this option should be set carefully to ensure
|
|
1617
|
+
that all elements are actually generated. The following example
|
|
1618
|
+
builds the set of all ordered pairs `(i,j)` of nonnegative
|
|
1619
|
+
integers such that `j\leq 1`::
|
|
1620
|
+
|
|
1621
|
+
sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
1622
|
+
sage: I = RecursivelyEnumeratedSet_forest([(0,0)],
|
|
1623
|
+
....: lambda l: [(l[0]+1, l[1]), (l[0], 1)]
|
|
1624
|
+
....: if l[1] == 0 else [(l[0], l[1]+1)])
|
|
1625
|
+
|
|
1626
|
+
With a depth first search, only the elements of the form `(i,0)`
|
|
1627
|
+
are generated::
|
|
1628
|
+
|
|
1629
|
+
sage: depth_search = I.depth_first_search_iterator()
|
|
1630
|
+
sage: [next(depth_search) for i in range(7)]
|
|
1631
|
+
[(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0)]
|
|
1632
|
+
|
|
1633
|
+
Using instead breadth first search gives the usual anti-diagonal
|
|
1634
|
+
iterator::
|
|
1635
|
+
|
|
1636
|
+
sage: breadth_search = I.breadth_first_search_iterator()
|
|
1637
|
+
sage: [next(breadth_search) for i in range(15)]
|
|
1638
|
+
[(0, 0),
|
|
1639
|
+
(1, 0), (0, 1),
|
|
1640
|
+
(2, 0), (1, 1), (0, 2),
|
|
1641
|
+
(3, 0), (2, 1), (1, 2), (0, 3),
|
|
1642
|
+
(4, 0), (3, 1), (2, 2), (1, 3), (0, 4)]
|
|
1643
|
+
|
|
1644
|
+
.. rubric:: Deriving subclasses
|
|
1645
|
+
|
|
1646
|
+
The class of a parent `A` may derive from :class:`RecursivelyEnumeratedSet_forest` so
|
|
1647
|
+
that `A` can benefit from enumeration tools. As a running example,
|
|
1648
|
+
we consider the problem of enumerating integers whose binary
|
|
1649
|
+
expansion have at most three nonzero digits. For example, `3 =
|
|
1650
|
+
2^1 + 2^0` has two nonzero digits. `15 = 2^3 + 2^2 + 2^1 + 2^0`
|
|
1651
|
+
has four nonzero digits. In fact, `15` is the smallest integer
|
|
1652
|
+
which is not in the enumerated set.
|
|
1653
|
+
|
|
1654
|
+
To achieve this, we use ``RecursivelyEnumeratedSet_forest`` to enumerate binary tuples
|
|
1655
|
+
with at most three nonzero digits, apply a post processing to
|
|
1656
|
+
recover the corresponding integers, and discard tuples finishing
|
|
1657
|
+
by zero.
|
|
1658
|
+
|
|
1659
|
+
A first approach is to pass the ``roots`` and ``children``
|
|
1660
|
+
functions as arguments to :meth:`RecursivelyEnumeratedSet_forest.__init__`::
|
|
1661
|
+
|
|
1662
|
+
sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
1663
|
+
sage: class A(UniqueRepresentation, RecursivelyEnumeratedSet_forest):
|
|
1664
|
+
....: def __init__(self):
|
|
1665
|
+
....: RecursivelyEnumeratedSet_forest.__init__(self, [()],
|
|
1666
|
+
....: lambda x: [x + (0,), x + (1,)] if sum(x) < 3 else [],
|
|
1667
|
+
....: lambda x: sum(x[i]*2^i for i in range(len(x)))
|
|
1668
|
+
....: if sum(x) != 0 and x[-1] != 0 else None,
|
|
1669
|
+
....: algorithm='breadth',
|
|
1670
|
+
....: category=InfiniteEnumeratedSets())
|
|
1671
|
+
sage: MyForest = A(); MyForest
|
|
1672
|
+
An enumerated set with a forest structure
|
|
1673
|
+
sage: MyForest.category()
|
|
1674
|
+
Category of infinite enumerated sets
|
|
1675
|
+
sage: p = iter(MyForest)
|
|
1676
|
+
sage: [next(p) for i in range(30)]
|
|
1677
|
+
[1, 2, 3, 4, 6, 5, 7, 8, 12, 10, 14, 9, 13, 11, 16, 24,
|
|
1678
|
+
20, 28, 18, 26, 22, 17, 25, 21, 19, 32, 48, 40, 56, 36]
|
|
1679
|
+
|
|
1680
|
+
An alternative approach is to implement ``roots`` and ``children``
|
|
1681
|
+
as methods of the subclass (in fact they could also be attributes
|
|
1682
|
+
of `A`). Namely, ``A.roots()`` must return an iterable containing
|
|
1683
|
+
the enumeration generators, and ``A.children(x)`` must return an
|
|
1684
|
+
iterable over the children of `x`. Optionally, `A` can have a
|
|
1685
|
+
method or attribute such that ``A.post_process(x)`` returns the
|
|
1686
|
+
desired output for the node ``x`` of the tree::
|
|
1687
|
+
|
|
1688
|
+
sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
1689
|
+
sage: class A(UniqueRepresentation, RecursivelyEnumeratedSet_forest):
|
|
1690
|
+
....: def __init__(self):
|
|
1691
|
+
....: RecursivelyEnumeratedSet_forest.__init__(self, algorithm='breadth',
|
|
1692
|
+
....: category=InfiniteEnumeratedSets())
|
|
1693
|
+
....: def roots(self):
|
|
1694
|
+
....: return [()]
|
|
1695
|
+
....: def children(self, x):
|
|
1696
|
+
....: if sum(x) < 3:
|
|
1697
|
+
....: return [x + (0,), x + (1,)]
|
|
1698
|
+
....: else:
|
|
1699
|
+
....: return []
|
|
1700
|
+
....: def post_process(self, x):
|
|
1701
|
+
....: if sum(x) == 0 or x[-1] == 0:
|
|
1702
|
+
....: return None
|
|
1703
|
+
....: else:
|
|
1704
|
+
....: return sum(x[i]*2^i for i in range(len(x)))
|
|
1705
|
+
sage: MyForest = A(); MyForest
|
|
1706
|
+
An enumerated set with a forest structure
|
|
1707
|
+
sage: MyForest.category()
|
|
1708
|
+
Category of infinite enumerated sets
|
|
1709
|
+
sage: p = iter(MyForest)
|
|
1710
|
+
sage: [next(p) for i in range(30)]
|
|
1711
|
+
[1, 2, 3, 4, 6, 5, 7, 8, 12, 10, 14, 9, 13, 11, 16, 24,
|
|
1712
|
+
20, 28, 18, 26, 22, 17, 25, 21, 19, 32, 48, 40, 56, 36]
|
|
1713
|
+
|
|
1714
|
+
.. warning::
|
|
1715
|
+
|
|
1716
|
+
A :class:`RecursivelyEnumeratedSet_forest` instance is picklable if and only if
|
|
1717
|
+
the input functions are themselves picklable. This excludes
|
|
1718
|
+
anonymous or interactively defined functions::
|
|
1719
|
+
|
|
1720
|
+
sage: def children(x):
|
|
1721
|
+
....: return [x + 1]
|
|
1722
|
+
sage: S = RecursivelyEnumeratedSet_forest([1], children, category=InfiniteEnumeratedSets())
|
|
1723
|
+
sage: dumps(S)
|
|
1724
|
+
Traceback (most recent call last):
|
|
1725
|
+
...
|
|
1726
|
+
PicklingError: Can't pickle <...function...>: attribute lookup ... failed
|
|
1727
|
+
|
|
1728
|
+
Let us now fake ``children`` being defined in a Python module::
|
|
1729
|
+
|
|
1730
|
+
sage: import __main__
|
|
1731
|
+
sage: __main__.children = children
|
|
1732
|
+
sage: S = RecursivelyEnumeratedSet_forest([1], children, category=InfiniteEnumeratedSets())
|
|
1733
|
+
sage: loads(dumps(S))
|
|
1734
|
+
An enumerated set with a forest structure
|
|
1735
|
+
"""
|
|
1736
|
+
def __init__(self, roots=None, children=None, post_process=None,
|
|
1737
|
+
algorithm='depth', facade=None, category=None):
|
|
1738
|
+
r"""
|
|
1739
|
+
TESTS::
|
|
1740
|
+
|
|
1741
|
+
sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
1742
|
+
sage: S = RecursivelyEnumeratedSet_forest(NN, lambda x: [], lambda x: x^2 if x.is_prime() else None)
|
|
1743
|
+
sage: S.category()
|
|
1744
|
+
Category of enumerated sets
|
|
1745
|
+
"""
|
|
1746
|
+
if roots is not None:
|
|
1747
|
+
self._roots = roots
|
|
1748
|
+
if children is not None:
|
|
1749
|
+
self.children = children
|
|
1750
|
+
if post_process is not None:
|
|
1751
|
+
self.post_process = post_process
|
|
1752
|
+
self._algorithm = algorithm
|
|
1753
|
+
Parent.__init__(self, facade=facade,
|
|
1754
|
+
category=EnumeratedSets().or_subcategory(category))
|
|
1755
|
+
|
|
1756
|
+
__len__ = None
|
|
1757
|
+
|
|
1758
|
+
def _repr_(self):
|
|
1759
|
+
r"""
|
|
1760
|
+
TESTS::
|
|
1761
|
+
|
|
1762
|
+
sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
1763
|
+
sage: RecursivelyEnumeratedSet_forest( [1], lambda x: [x+1])
|
|
1764
|
+
An enumerated set with a forest structure
|
|
1765
|
+
"""
|
|
1766
|
+
return "An enumerated set with a forest structure"
|
|
1767
|
+
|
|
1768
|
+
def roots(self):
|
|
1769
|
+
r"""
|
|
1770
|
+
Return an iterable over the roots of ``self``.
|
|
1771
|
+
|
|
1772
|
+
EXAMPLES::
|
|
1773
|
+
|
|
1774
|
+
sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
1775
|
+
sage: I = RecursivelyEnumeratedSet_forest([(0,0)], lambda l: [(l[0]+1, l[1]), (l[0], 1)] if l[1] == 0 else [(l[0], l[1]+1)])
|
|
1776
|
+
sage: [i for i in I.roots()]
|
|
1777
|
+
[(0, 0)]
|
|
1778
|
+
sage: I = RecursivelyEnumeratedSet_forest([(0,0),(1,1)], lambda l: [(l[0]+1, l[1]), (l[0], 1)] if l[1] == 0 else [(l[0], l[1]+1)])
|
|
1779
|
+
sage: [i for i in I.roots()]
|
|
1780
|
+
[(0, 0), (1, 1)]
|
|
1781
|
+
"""
|
|
1782
|
+
return self._roots
|
|
1783
|
+
|
|
1784
|
+
@abstract_method
|
|
1785
|
+
def children(self, x):
|
|
1786
|
+
r"""
|
|
1787
|
+
Return the children of the element ``x``.
|
|
1788
|
+
|
|
1789
|
+
The result can be a list, an iterable, an iterator, or even a
|
|
1790
|
+
generator.
|
|
1791
|
+
|
|
1792
|
+
EXAMPLES::
|
|
1793
|
+
|
|
1794
|
+
sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
1795
|
+
sage: I = RecursivelyEnumeratedSet_forest([(0,0)], lambda l: [(l[0]+1, l[1]), (l[0], 1)] if l[1] == 0 else [(l[0], l[1]+1)])
|
|
1796
|
+
sage: [i for i in I.children((0,0))]
|
|
1797
|
+
[(1, 0), (0, 1)]
|
|
1798
|
+
sage: [i for i in I.children((1,0))]
|
|
1799
|
+
[(2, 0), (1, 1)]
|
|
1800
|
+
sage: [i for i in I.children((1,1))]
|
|
1801
|
+
[(1, 2)]
|
|
1802
|
+
sage: [i for i in I.children((4,1))]
|
|
1803
|
+
[(4, 2)]
|
|
1804
|
+
sage: [i for i in I.children((4,0))]
|
|
1805
|
+
[(5, 0), (4, 1)]
|
|
1806
|
+
"""
|
|
1807
|
+
|
|
1808
|
+
def __iter__(self):
|
|
1809
|
+
r"""
|
|
1810
|
+
Return an iterator over the elements of ``self``.
|
|
1811
|
+
|
|
1812
|
+
EXAMPLES::
|
|
1813
|
+
|
|
1814
|
+
sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
1815
|
+
sage: def children(l):
|
|
1816
|
+
....: return [l + [0], l + [1]]
|
|
1817
|
+
sage: C = RecursivelyEnumeratedSet_forest(([],), children)
|
|
1818
|
+
sage: f = C.__iter__()
|
|
1819
|
+
sage: next(f)
|
|
1820
|
+
[]
|
|
1821
|
+
sage: next(f)
|
|
1822
|
+
[0]
|
|
1823
|
+
sage: next(f)
|
|
1824
|
+
[0, 0]
|
|
1825
|
+
"""
|
|
1826
|
+
iter = search_forest_iterator(self.roots(),
|
|
1827
|
+
self.children,
|
|
1828
|
+
algorithm=self._algorithm)
|
|
1829
|
+
if hasattr(self, "post_process"):
|
|
1830
|
+
iter = _imap_and_filter_none(self.post_process, iter)
|
|
1831
|
+
return iter
|
|
1832
|
+
|
|
1833
|
+
def depth_first_search_iterator(self):
|
|
1834
|
+
r"""
|
|
1835
|
+
Return a depth first search iterator over the elements of ``self``.
|
|
1836
|
+
|
|
1837
|
+
EXAMPLES::
|
|
1838
|
+
|
|
1839
|
+
sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
1840
|
+
sage: f = RecursivelyEnumeratedSet_forest([[]],
|
|
1841
|
+
....: lambda l: [l + [0], l + [1]] if len(l) < 3 else [])
|
|
1842
|
+
sage: list(f.depth_first_search_iterator())
|
|
1843
|
+
[[], [0], [0, 0], [0, 0, 0], [0, 0, 1], [0, 1], [0, 1, 0], [0, 1, 1],
|
|
1844
|
+
[1], [1, 0], [1, 0, 0], [1, 0, 1], [1, 1], [1, 1, 0], [1, 1, 1]]
|
|
1845
|
+
"""
|
|
1846
|
+
return iter(self)
|
|
1847
|
+
|
|
1848
|
+
def breadth_first_search_iterator(self):
|
|
1849
|
+
r"""
|
|
1850
|
+
Return a breadth first search iterator over the elements of ``self``.
|
|
1851
|
+
|
|
1852
|
+
EXAMPLES::
|
|
1853
|
+
|
|
1854
|
+
sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
1855
|
+
sage: f = RecursivelyEnumeratedSet_forest([[]],
|
|
1856
|
+
....: lambda l: [l+[0], l+[1]] if len(l) < 3 else [])
|
|
1857
|
+
sage: list(f.breadth_first_search_iterator())
|
|
1858
|
+
[[], [0], [1], [0, 0], [0, 1], [1, 0], [1, 1], [0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
|
|
1859
|
+
sage: S = RecursivelyEnumeratedSet_forest([(0,0)],
|
|
1860
|
+
....: lambda x : [(x[0], x[1]+1)] if x[1] != 0 else [(x[0]+1,0), (x[0],1)],
|
|
1861
|
+
....: post_process = lambda x: x if ((is_prime(x[0]) and is_prime(x[1])) and ((x[0] - x[1]) == 2)) else None)
|
|
1862
|
+
sage: p = S.breadth_first_search_iterator()
|
|
1863
|
+
sage: [next(p), next(p), next(p), next(p), next(p), next(p), next(p)]
|
|
1864
|
+
[(5, 3), (7, 5), (13, 11), (19, 17), (31, 29), (43, 41), (61, 59)]
|
|
1865
|
+
"""
|
|
1866
|
+
iter = search_forest_iterator(self.roots(), self.children, algorithm='breadth')
|
|
1867
|
+
if hasattr(self, "post_process"):
|
|
1868
|
+
iter = _imap_and_filter_none(self.post_process, iter)
|
|
1869
|
+
return iter
|
|
1870
|
+
|
|
1871
|
+
def _elements_of_depth_iterator_rec(self, depth=0):
|
|
1872
|
+
r"""
|
|
1873
|
+
Return an iterator over the elements of ``self`` of given depth.
|
|
1874
|
+
An element of depth `n` can be obtained by applying the
|
|
1875
|
+
children function `n` times from a root. This function is not affected
|
|
1876
|
+
by post processing.
|
|
1877
|
+
|
|
1878
|
+
EXAMPLES::
|
|
1879
|
+
|
|
1880
|
+
sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
1881
|
+
sage: I = RecursivelyEnumeratedSet_forest([(0,0)], lambda l: [(l[0]+1, l[1]), (l[0], 1)] if l[1] == 0 else [(l[0], l[1]+1)])
|
|
1882
|
+
sage: list(I._elements_of_depth_iterator_rec(8))
|
|
1883
|
+
[(8, 0), (7, 1), (6, 2), (5, 3), (4, 4), (3, 5), (2, 6), (1, 7), (0, 8)]
|
|
1884
|
+
sage: I = RecursivelyEnumeratedSet_forest([[]], lambda l: [l+[0], l+[1]] if len(l) < 3 else [])
|
|
1885
|
+
sage: list(I._elements_of_depth_iterator_rec(0))
|
|
1886
|
+
[[]]
|
|
1887
|
+
sage: list(I._elements_of_depth_iterator_rec(1))
|
|
1888
|
+
[[0], [1]]
|
|
1889
|
+
sage: list(I._elements_of_depth_iterator_rec(2))
|
|
1890
|
+
[[0, 0], [0, 1], [1, 0], [1, 1]]
|
|
1891
|
+
sage: list(I._elements_of_depth_iterator_rec(3))
|
|
1892
|
+
[[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
|
|
1893
|
+
sage: list(I._elements_of_depth_iterator_rec(4))
|
|
1894
|
+
[]
|
|
1895
|
+
"""
|
|
1896
|
+
if depth == 0:
|
|
1897
|
+
yield from self.roots()
|
|
1898
|
+
else:
|
|
1899
|
+
for father in self._elements_of_depth_iterator_rec(depth - 1):
|
|
1900
|
+
yield from self.children(father)
|
|
1901
|
+
|
|
1902
|
+
def elements_of_depth_iterator(self, depth=0):
|
|
1903
|
+
r"""
|
|
1904
|
+
Return an iterator over the elements of ``self`` of given depth.
|
|
1905
|
+
An element of depth `n` can be obtained by applying the
|
|
1906
|
+
children function `n` times from a root.
|
|
1907
|
+
|
|
1908
|
+
EXAMPLES::
|
|
1909
|
+
|
|
1910
|
+
sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
1911
|
+
sage: S = RecursivelyEnumeratedSet_forest([(0,0)] ,
|
|
1912
|
+
....: lambda x : [(x[0], x[1]+1)] if x[1] != 0 else [(x[0]+1,0), (x[0],1)],
|
|
1913
|
+
....: post_process = lambda x: x if ((is_prime(x[0]) and is_prime(x[1]))
|
|
1914
|
+
....: and ((x[0] - x[1]) == 2)) else None)
|
|
1915
|
+
sage: p = S.elements_of_depth_iterator(8)
|
|
1916
|
+
sage: next(p)
|
|
1917
|
+
(5, 3)
|
|
1918
|
+
sage: S = RecursivelyEnumeratedSet_forest(NN, lambda x : [],
|
|
1919
|
+
....: lambda x: x^2 if x.is_prime() else None)
|
|
1920
|
+
sage: p = S.elements_of_depth_iterator(0)
|
|
1921
|
+
sage: [next(p), next(p), next(p), next(p), next(p)]
|
|
1922
|
+
[4, 9, 25, 49, 121]
|
|
1923
|
+
"""
|
|
1924
|
+
iter = self._elements_of_depth_iterator_rec(depth)
|
|
1925
|
+
if hasattr(self, "post_process"):
|
|
1926
|
+
iter = _imap_and_filter_none(self.post_process, iter)
|
|
1927
|
+
return iter
|
|
1928
|
+
|
|
1929
|
+
def __contains__(self, elt):
|
|
1930
|
+
r"""
|
|
1931
|
+
Return ``True`` if ``elt`` is in ``self``.
|
|
1932
|
+
|
|
1933
|
+
.. warning::
|
|
1934
|
+
|
|
1935
|
+
This is achieved by iterating through the elements until
|
|
1936
|
+
``elt`` is found. In particular, this method will never
|
|
1937
|
+
stop when ``elt`` is not in ``self`` and ``self`` is
|
|
1938
|
+
infinite.
|
|
1939
|
+
|
|
1940
|
+
EXAMPLES::
|
|
1941
|
+
|
|
1942
|
+
sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
1943
|
+
sage: S = RecursivelyEnumeratedSet_forest([[]], lambda l: [l + [0], l + [1]] if len(l) < 3 else [],
|
|
1944
|
+
....: category=FiniteEnumeratedSets())
|
|
1945
|
+
sage: [4] in S
|
|
1946
|
+
False
|
|
1947
|
+
sage: [1] in S
|
|
1948
|
+
True
|
|
1949
|
+
sage: [1,1,1,1] in S
|
|
1950
|
+
False
|
|
1951
|
+
sage: all(S.__contains__(i) for i in iter(S))
|
|
1952
|
+
True
|
|
1953
|
+
sage: S = RecursivelyEnumeratedSet_forest([1], lambda x: [x + 1], category=InfiniteEnumeratedSets())
|
|
1954
|
+
sage: 1 in S
|
|
1955
|
+
True
|
|
1956
|
+
sage: 732 in S
|
|
1957
|
+
True
|
|
1958
|
+
sage: -1 in S # not tested : Will never stop
|
|
1959
|
+
|
|
1960
|
+
The algorithm uses a random enumeration of the nodes of the
|
|
1961
|
+
forest. This choice was motivated by examples in which both
|
|
1962
|
+
depth first search and breadth first search failed. The
|
|
1963
|
+
following example enumerates all ordered pairs of nonnegative
|
|
1964
|
+
integers, starting from an infinite set of roots, where each
|
|
1965
|
+
root has an infinite number of children::
|
|
1966
|
+
|
|
1967
|
+
sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest
|
|
1968
|
+
sage: S = RecursivelyEnumeratedSet_forest(
|
|
1969
|
+
....: Family(NN, lambda x: (x, 0)),
|
|
1970
|
+
....: lambda x: Family(PositiveIntegers(), lambda y: (x[0], y)) if x[1] == 0 else [])
|
|
1971
|
+
sage: p = S.depth_first_search_iterator()
|
|
1972
|
+
sage: [next(p), next(p), next(p), next(p), next(p), next(p), next(p)]
|
|
1973
|
+
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6)]
|
|
1974
|
+
sage: p = S.breadth_first_search_iterator()
|
|
1975
|
+
sage: [next(p), next(p), next(p), next(p), next(p), next(p), next(p)]
|
|
1976
|
+
[(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0)]
|
|
1977
|
+
sage: (0,0) in S
|
|
1978
|
+
True
|
|
1979
|
+
sage: (1,1) in S
|
|
1980
|
+
True
|
|
1981
|
+
sage: (10,10) in S
|
|
1982
|
+
True
|
|
1983
|
+
sage: (42,18) in S
|
|
1984
|
+
True
|
|
1985
|
+
|
|
1986
|
+
We now consider the same set of all ordered pairs of
|
|
1987
|
+
nonnegative integers but constructed in a different way. There
|
|
1988
|
+
still are infinitely many roots, but each node has a single
|
|
1989
|
+
child. From each root starts an infinite branch of breadth
|
|
1990
|
+
`1`::
|
|
1991
|
+
|
|
1992
|
+
sage: S = RecursivelyEnumeratedSet_forest(Family(NN, lambda x: (x, 0)),
|
|
1993
|
+
....: lambda x: [(x[0], x[1] + 1)])
|
|
1994
|
+
sage: p = S.depth_first_search_iterator()
|
|
1995
|
+
sage: [next(p), next(p), next(p), next(p), next(p), next(p), next(p)]
|
|
1996
|
+
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6)]
|
|
1997
|
+
sage: p = S.breadth_first_search_iterator()
|
|
1998
|
+
sage: [next(p), next(p), next(p), next(p), next(p), next(p), next(p)]
|
|
1999
|
+
[(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0)]
|
|
2000
|
+
sage: (0,0) in S
|
|
2001
|
+
True
|
|
2002
|
+
sage: (1,1) in S
|
|
2003
|
+
True
|
|
2004
|
+
sage: (10,10) in S
|
|
2005
|
+
True
|
|
2006
|
+
sage: (37,11) in S
|
|
2007
|
+
True
|
|
2008
|
+
"""
|
|
2009
|
+
stack = [iter(self.roots())]
|
|
2010
|
+
while stack:
|
|
2011
|
+
position = randint(0, len(stack) - 1)
|
|
2012
|
+
try:
|
|
2013
|
+
node = next(stack[position])
|
|
2014
|
+
except StopIteration:
|
|
2015
|
+
stack.pop(position)
|
|
2016
|
+
continue
|
|
2017
|
+
|
|
2018
|
+
if node == elt:
|
|
2019
|
+
return True
|
|
2020
|
+
stack.append(iter(self.children(node)))
|
|
2021
|
+
return False
|
|
2022
|
+
|
|
2023
|
+
def map_reduce(self, map_function=None,
|
|
2024
|
+
reduce_function=None,
|
|
2025
|
+
reduce_init=None):
|
|
2026
|
+
r"""
|
|
2027
|
+
Apply a Map/Reduce algorithm on ``self``.
|
|
2028
|
+
|
|
2029
|
+
INPUT:
|
|
2030
|
+
|
|
2031
|
+
- ``map_function`` -- a function from the element of ``self`` to some
|
|
2032
|
+
set with a reduce operation (e.g.: a monoid). The default value is
|
|
2033
|
+
the constant function ``1``.
|
|
2034
|
+
|
|
2035
|
+
- ``reduce_function`` -- the reduce function (e.g.: the addition of a
|
|
2036
|
+
monoid); the default value is ``+``
|
|
2037
|
+
|
|
2038
|
+
- ``reduce_init`` -- the initialisation of the reduction (e.g.: the
|
|
2039
|
+
neutral element of the monoid); the default value is ``0``
|
|
2040
|
+
|
|
2041
|
+
.. NOTE::
|
|
2042
|
+
|
|
2043
|
+
the effect of the default values is to compute the cardinality
|
|
2044
|
+
of ``self``.
|
|
2045
|
+
|
|
2046
|
+
EXAMPLES::
|
|
2047
|
+
|
|
2048
|
+
sage: seeds = [([i], i, i) for i in range(1, 10)]
|
|
2049
|
+
sage: def succ(t):
|
|
2050
|
+
....: list, sum, last = t
|
|
2051
|
+
....: return [(list + [i], sum + i, i) for i in range(1, last)]
|
|
2052
|
+
sage: F = RecursivelyEnumeratedSet(seeds, succ,
|
|
2053
|
+
....: structure='forest', enumeration='depth')
|
|
2054
|
+
|
|
2055
|
+
sage: # needs sage.symbolic
|
|
2056
|
+
sage: y = var('y')
|
|
2057
|
+
sage: def map_function(t):
|
|
2058
|
+
....: li, sum, _ = t
|
|
2059
|
+
....: return y ^ sum
|
|
2060
|
+
sage: def reduce_function(x, y):
|
|
2061
|
+
....: return x + y
|
|
2062
|
+
sage: F.map_reduce(map_function, reduce_function, 0)
|
|
2063
|
+
y^45 + y^44 + y^43 + 2*y^42 + 2*y^41 + 3*y^40 + 4*y^39 + 5*y^38 + 6*y^37
|
|
2064
|
+
+ 8*y^36 + 9*y^35 + 10*y^34 + 12*y^33 + 13*y^32 + 15*y^31 + 17*y^30
|
|
2065
|
+
+ 18*y^29 + 19*y^28 + 21*y^27 + 21*y^26 + 22*y^25 + 23*y^24 + 23*y^23
|
|
2066
|
+
+ 23*y^22 + 23*y^21 + 22*y^20 + 21*y^19 + 21*y^18 + 19*y^17 + 18*y^16
|
|
2067
|
+
+ 17*y^15 + 15*y^14 + 13*y^13 + 12*y^12 + 10*y^11 + 9*y^10 + 8*y^9 + 6*y^8
|
|
2068
|
+
+ 5*y^7 + 4*y^6 + 3*y^5 + 2*y^4 + 2*y^3 + y^2 + y
|
|
2069
|
+
|
|
2070
|
+
Here is an example with the default values::
|
|
2071
|
+
|
|
2072
|
+
sage: F.map_reduce()
|
|
2073
|
+
511
|
|
2074
|
+
|
|
2075
|
+
.. SEEALSO:: :mod:`sage.parallel.map_reduce`
|
|
2076
|
+
"""
|
|
2077
|
+
import sage.parallel.map_reduce
|
|
2078
|
+
return sage.parallel.map_reduce.RESetMapReduce(
|
|
2079
|
+
forest=self,
|
|
2080
|
+
map_function=map_function,
|
|
2081
|
+
reduce_function=reduce_function,
|
|
2082
|
+
reduce_init=reduce_init).run()
|