passagemath-objects 10.6.41__cp312-cp312-win_amd64.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_objects/__init__.py +3 -0
- passagemath_objects-10.6.41.dist-info/DELVEWHEEL +2 -0
- passagemath_objects-10.6.41.dist-info/METADATA +115 -0
- passagemath_objects-10.6.41.dist-info/RECORD +281 -0
- passagemath_objects-10.6.41.dist-info/WHEEL +5 -0
- passagemath_objects-10.6.41.dist-info/top_level.txt +3 -0
- passagemath_objects.libs/libgmp-10-79b4110c7ea2b760f16cfef97e8a8a34.dll +0 -0
- sage/all__sagemath_objects.py +46 -0
- sage/arith/all__sagemath_objects.py +5 -0
- sage/arith/long.pxd +411 -0
- sage/arith/numerical_approx.cp312-win_amd64.pyd +0 -0
- sage/arith/numerical_approx.pxd +35 -0
- sage/arith/numerical_approx.pyx +75 -0
- sage/arith/power.cp312-win_amd64.pyd +0 -0
- sage/arith/power.pxd +31 -0
- sage/arith/power.pyx +127 -0
- sage/categories/action.cp312-win_amd64.pyd +0 -0
- sage/categories/action.pxd +29 -0
- sage/categories/action.pyx +641 -0
- sage/categories/algebra_functor.py +745 -0
- sage/categories/all__sagemath_objects.py +33 -0
- sage/categories/basic.py +71 -0
- sage/categories/cartesian_product.py +295 -0
- sage/categories/category.py +3401 -0
- sage/categories/category_cy_helper.cp312-win_amd64.pyd +0 -0
- sage/categories/category_cy_helper.pxd +8 -0
- sage/categories/category_cy_helper.pyx +322 -0
- sage/categories/category_singleton.cp312-win_amd64.pyd +0 -0
- sage/categories/category_singleton.pxd +3 -0
- sage/categories/category_singleton.pyx +342 -0
- sage/categories/category_types.py +637 -0
- sage/categories/category_with_axiom.py +2885 -0
- sage/categories/covariant_functorial_construction.py +703 -0
- sage/categories/facade_sets.py +228 -0
- sage/categories/functor.cp312-win_amd64.pyd +0 -0
- sage/categories/functor.pxd +7 -0
- sage/categories/functor.pyx +691 -0
- sage/categories/homset.py +1338 -0
- sage/categories/homsets.py +364 -0
- sage/categories/isomorphic_objects.py +73 -0
- sage/categories/map.cp312-win_amd64.pyd +0 -0
- sage/categories/map.pxd +34 -0
- sage/categories/map.pyx +2112 -0
- sage/categories/morphism.cp312-win_amd64.pyd +0 -0
- sage/categories/morphism.pxd +14 -0
- sage/categories/morphism.pyx +895 -0
- sage/categories/objects.py +167 -0
- sage/categories/primer.py +1696 -0
- sage/categories/pushout.py +4834 -0
- sage/categories/quotients.py +64 -0
- sage/categories/realizations.py +200 -0
- sage/categories/sets_cat.py +3228 -0
- sage/categories/sets_with_partial_maps.py +52 -0
- sage/categories/subobjects.py +64 -0
- sage/categories/subquotients.py +21 -0
- sage/categories/with_realizations.py +311 -0
- sage/cpython/__init__.py +28 -0
- sage/cpython/_py2_random.py +619 -0
- sage/cpython/all.py +3 -0
- sage/cpython/atexit.cp312-win_amd64.pyd +0 -0
- sage/cpython/atexit.pyx +269 -0
- sage/cpython/builtin_types.cp312-win_amd64.pyd +0 -0
- sage/cpython/builtin_types.pyx +7 -0
- sage/cpython/cython_metaclass.cp312-win_amd64.pyd +0 -0
- sage/cpython/cython_metaclass.h +117 -0
- sage/cpython/cython_metaclass.pxd +3 -0
- sage/cpython/cython_metaclass.pyx +130 -0
- sage/cpython/debug.cp312-win_amd64.pyd +0 -0
- sage/cpython/debug.pyx +302 -0
- sage/cpython/dict_del_by_value.cp312-win_amd64.pyd +0 -0
- sage/cpython/dict_del_by_value.pxd +9 -0
- sage/cpython/dict_del_by_value.pyx +191 -0
- sage/cpython/dict_internal.h +245 -0
- sage/cpython/getattr.cp312-win_amd64.pyd +0 -0
- sage/cpython/getattr.pxd +9 -0
- sage/cpython/getattr.pyx +439 -0
- sage/cpython/pycore_long.h +97 -0
- sage/cpython/pycore_long.pxd +10 -0
- sage/cpython/python_debug.h +44 -0
- sage/cpython/python_debug.pxd +47 -0
- sage/cpython/pyx_visit.h +13 -0
- sage/cpython/string.cp312-win_amd64.pyd +0 -0
- sage/cpython/string.pxd +76 -0
- sage/cpython/string.pyx +34 -0
- sage/cpython/string_impl.h +60 -0
- sage/cpython/type.cp312-win_amd64.pyd +0 -0
- sage/cpython/type.pxd +2 -0
- sage/cpython/type.pyx +40 -0
- sage/cpython/wrapperdescr.pxd +67 -0
- sage/ext/all__sagemath_objects.py +3 -0
- sage/ext/ccobject.h +64 -0
- sage/ext/cplusplus.pxd +17 -0
- sage/ext/mod_int.h +30 -0
- sage/ext/mod_int.pxd +24 -0
- sage/ext/stdsage.pxd +39 -0
- sage/groups/all__sagemath_objects.py +1 -0
- sage/groups/group.cp312-win_amd64.pyd +0 -0
- sage/groups/group.pxd +14 -0
- sage/groups/group.pyx +322 -0
- sage/groups/old.cp312-win_amd64.pyd +0 -0
- sage/groups/old.pxd +14 -0
- sage/groups/old.pyx +219 -0
- sage/libs/all__sagemath_objects.py +3 -0
- sage/libs/gmp/__init__.py +1 -0
- sage/libs/gmp/all.pxd +6 -0
- sage/libs/gmp/binop.pxd +23 -0
- sage/libs/gmp/misc.pxd +8 -0
- sage/libs/gmp/mpf.pxd +88 -0
- sage/libs/gmp/mpn.pxd +57 -0
- sage/libs/gmp/mpq.pxd +57 -0
- sage/libs/gmp/mpz.pxd +202 -0
- sage/libs/gmp/pylong.cp312-win_amd64.pyd +0 -0
- sage/libs/gmp/pylong.pxd +12 -0
- sage/libs/gmp/pylong.pyx +150 -0
- sage/libs/gmp/random.pxd +25 -0
- sage/libs/gmp/randomize.pxd +59 -0
- sage/libs/gmp/types.pxd +53 -0
- sage/libs/gmpxx.pxd +19 -0
- sage/misc/abstract_method.py +276 -0
- sage/misc/all__sagemath_objects.py +43 -0
- sage/misc/bindable_class.py +253 -0
- sage/misc/c3_controlled.cp312-win_amd64.pyd +0 -0
- sage/misc/c3_controlled.pxd +2 -0
- sage/misc/c3_controlled.pyx +1402 -0
- sage/misc/cachefunc.cp312-win_amd64.pyd +0 -0
- sage/misc/cachefunc.pxd +43 -0
- sage/misc/cachefunc.pyx +3781 -0
- sage/misc/call.py +188 -0
- sage/misc/classcall_metaclass.cp312-win_amd64.pyd +0 -0
- sage/misc/classcall_metaclass.pxd +14 -0
- sage/misc/classcall_metaclass.pyx +599 -0
- sage/misc/constant_function.cp312-win_amd64.pyd +0 -0
- sage/misc/constant_function.pyx +130 -0
- sage/misc/decorators.py +747 -0
- sage/misc/fast_methods.cp312-win_amd64.pyd +0 -0
- sage/misc/fast_methods.pxd +20 -0
- sage/misc/fast_methods.pyx +351 -0
- sage/misc/flatten.py +90 -0
- sage/misc/fpickle.cp312-win_amd64.pyd +0 -0
- sage/misc/fpickle.pyx +177 -0
- sage/misc/function_mangling.cp312-win_amd64.pyd +0 -0
- sage/misc/function_mangling.pxd +11 -0
- sage/misc/function_mangling.pyx +308 -0
- sage/misc/inherit_comparison.cp312-win_amd64.pyd +0 -0
- sage/misc/inherit_comparison.pxd +5 -0
- sage/misc/inherit_comparison.pyx +105 -0
- sage/misc/instancedoc.cp312-win_amd64.pyd +0 -0
- sage/misc/instancedoc.pyx +331 -0
- sage/misc/lazy_attribute.cp312-win_amd64.pyd +0 -0
- sage/misc/lazy_attribute.pyx +607 -0
- sage/misc/lazy_format.py +135 -0
- sage/misc/lazy_import.cp312-win_amd64.pyd +0 -0
- sage/misc/lazy_import.pyx +1299 -0
- sage/misc/lazy_import_cache.py +36 -0
- sage/misc/lazy_list.cp312-win_amd64.pyd +0 -0
- sage/misc/lazy_list.pxd +19 -0
- sage/misc/lazy_list.pyx +1187 -0
- sage/misc/lazy_string.cp312-win_amd64.pyd +0 -0
- sage/misc/lazy_string.pxd +7 -0
- sage/misc/lazy_string.pyx +546 -0
- sage/misc/misc.py +1066 -0
- sage/misc/misc_c.cp312-win_amd64.pyd +0 -0
- sage/misc/misc_c.pxd +3 -0
- sage/misc/misc_c.pyx +766 -0
- sage/misc/namespace_package.py +37 -0
- sage/misc/nested_class.cp312-win_amd64.pyd +0 -0
- sage/misc/nested_class.pxd +3 -0
- sage/misc/nested_class.pyx +394 -0
- sage/misc/persist.cp312-win_amd64.pyd +0 -0
- sage/misc/persist.pyx +1251 -0
- sage/misc/prandom.py +418 -0
- sage/misc/randstate.cp312-win_amd64.pyd +0 -0
- sage/misc/randstate.pxd +30 -0
- sage/misc/randstate.pyx +1059 -0
- sage/misc/repr.py +203 -0
- sage/misc/reset.cp312-win_amd64.pyd +0 -0
- sage/misc/reset.pyx +196 -0
- sage/misc/sage_ostools.cp312-win_amd64.pyd +0 -0
- sage/misc/sage_ostools.pyx +323 -0
- sage/misc/sage_timeit.py +276 -0
- sage/misc/sage_timeit_class.cp312-win_amd64.pyd +0 -0
- sage/misc/sage_timeit_class.pyx +120 -0
- sage/misc/sage_unittest.py +637 -0
- sage/misc/sageinspect.py +2768 -0
- sage/misc/session.cp312-win_amd64.pyd +0 -0
- sage/misc/session.pyx +392 -0
- sage/misc/superseded.py +557 -0
- sage/misc/test_nested_class.py +228 -0
- sage/misc/timing.py +264 -0
- sage/misc/unknown.py +222 -0
- sage/misc/verbose.py +253 -0
- sage/misc/weak_dict.cp312-win_amd64.pyd +0 -0
- sage/misc/weak_dict.pxd +15 -0
- sage/misc/weak_dict.pyx +1231 -0
- sage/modules/all__sagemath_objects.py +1 -0
- sage/modules/module.cp312-win_amd64.pyd +0 -0
- sage/modules/module.pxd +5 -0
- sage/modules/module.pyx +329 -0
- sage/rings/all__sagemath_objects.py +3 -0
- sage/rings/integer_fake.h +22 -0
- sage/rings/integer_fake.pxd +55 -0
- sage/sets/all__sagemath_objects.py +3 -0
- sage/sets/pythonclass.cp312-win_amd64.pyd +0 -0
- sage/sets/pythonclass.pxd +9 -0
- sage/sets/pythonclass.pyx +247 -0
- sage/structure/__init__.py +13 -0
- sage/structure/all.py +30 -0
- sage/structure/category_object.cp312-win_amd64.pyd +0 -0
- sage/structure/category_object.pxd +28 -0
- sage/structure/category_object.pyx +1087 -0
- sage/structure/coerce.cp312-win_amd64.pyd +0 -0
- sage/structure/coerce.pxd +44 -0
- sage/structure/coerce.pyx +2107 -0
- sage/structure/coerce_actions.cp312-win_amd64.pyd +0 -0
- sage/structure/coerce_actions.pxd +27 -0
- sage/structure/coerce_actions.pyx +988 -0
- sage/structure/coerce_dict.cp312-win_amd64.pyd +0 -0
- sage/structure/coerce_dict.pxd +51 -0
- sage/structure/coerce_dict.pyx +1557 -0
- sage/structure/coerce_exceptions.py +23 -0
- sage/structure/coerce_maps.cp312-win_amd64.pyd +0 -0
- sage/structure/coerce_maps.pxd +28 -0
- sage/structure/coerce_maps.pyx +718 -0
- sage/structure/debug_options.cp312-win_amd64.pyd +0 -0
- sage/structure/debug_options.pxd +6 -0
- sage/structure/debug_options.pyx +54 -0
- sage/structure/dynamic_class.py +541 -0
- sage/structure/element.cp312-win_amd64.pyd +0 -0
- sage/structure/element.pxd +272 -0
- sage/structure/element.pyx +4772 -0
- sage/structure/element_wrapper.cp312-win_amd64.pyd +0 -0
- sage/structure/element_wrapper.pxd +12 -0
- sage/structure/element_wrapper.pyx +582 -0
- sage/structure/factorization.py +1422 -0
- sage/structure/factorization_integer.py +105 -0
- sage/structure/factory.cp312-win_amd64.pyd +0 -0
- sage/structure/factory.pyx +786 -0
- sage/structure/formal_sum.py +489 -0
- sage/structure/gens_py.py +73 -0
- sage/structure/global_options.py +1743 -0
- sage/structure/indexed_generators.py +863 -0
- sage/structure/list_clone.cp312-win_amd64.pyd +0 -0
- sage/structure/list_clone.pxd +65 -0
- sage/structure/list_clone.pyx +1867 -0
- sage/structure/list_clone_demo.cp312-win_amd64.pyd +0 -0
- sage/structure/list_clone_demo.pyx +248 -0
- sage/structure/list_clone_timings.py +179 -0
- sage/structure/list_clone_timings_cy.cp312-win_amd64.pyd +0 -0
- sage/structure/list_clone_timings_cy.pyx +86 -0
- sage/structure/mutability.cp312-win_amd64.pyd +0 -0
- sage/structure/mutability.pxd +21 -0
- sage/structure/mutability.pyx +348 -0
- sage/structure/nonexact.py +69 -0
- sage/structure/parent.cp312-win_amd64.pyd +0 -0
- sage/structure/parent.pxd +112 -0
- sage/structure/parent.pyx +3093 -0
- sage/structure/parent_base.cp312-win_amd64.pyd +0 -0
- sage/structure/parent_base.pxd +13 -0
- sage/structure/parent_base.pyx +44 -0
- sage/structure/parent_gens.cp312-win_amd64.pyd +0 -0
- sage/structure/parent_gens.pxd +22 -0
- sage/structure/parent_gens.pyx +377 -0
- sage/structure/parent_old.cp312-win_amd64.pyd +0 -0
- sage/structure/parent_old.pxd +25 -0
- sage/structure/parent_old.pyx +294 -0
- sage/structure/proof/__init__.py +1 -0
- sage/structure/proof/all.py +243 -0
- sage/structure/proof/proof.py +300 -0
- sage/structure/richcmp.cp312-win_amd64.pyd +0 -0
- sage/structure/richcmp.pxd +213 -0
- sage/structure/richcmp.pyx +495 -0
- sage/structure/sage_object.cp312-win_amd64.pyd +0 -0
- sage/structure/sage_object.pxd +3 -0
- sage/structure/sage_object.pyx +988 -0
- sage/structure/sage_object_test.py +19 -0
- sage/structure/sequence.py +937 -0
- sage/structure/set_factories.py +1178 -0
- sage/structure/set_factories_example.py +527 -0
- sage/structure/support_view.py +179 -0
- sage/structure/test_factory.py +56 -0
- sage/structure/unique_representation.py +1359 -0
sage/misc/lazy_list.pyx
ADDED
|
@@ -0,0 +1,1187 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-objects
|
|
2
|
+
r"""
|
|
3
|
+
Lazy lists
|
|
4
|
+
|
|
5
|
+
A lazy list is an iterator that behaves like a list and possesses a cache
|
|
6
|
+
mechanism. A lazy list is potentially infinite and speed performances of the
|
|
7
|
+
cache is comparable with Python lists. One major difference with original
|
|
8
|
+
Python list is that lazy list are immutable. The advantage is that slices
|
|
9
|
+
share memory.
|
|
10
|
+
|
|
11
|
+
EXAMPLES::
|
|
12
|
+
|
|
13
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
14
|
+
sage: P = lazy_list(Primes())
|
|
15
|
+
sage: P[100] # needs sage.libs.pari
|
|
16
|
+
547
|
|
17
|
+
sage: P[10:34] # needs sage.libs.pari
|
|
18
|
+
lazy list [31, 37, 41, ...]
|
|
19
|
+
sage: P[12:23].list() # needs sage.libs.pari
|
|
20
|
+
[41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83]
|
|
21
|
+
|
|
22
|
+
sage: f = lazy_list((i**2 - 3*i for i in range(10)))
|
|
23
|
+
sage: print(" ".join(str(i) for i in f))
|
|
24
|
+
0 -2 -2 0 4 10 18 28 40 54
|
|
25
|
+
sage: i1 = iter(f)
|
|
26
|
+
sage: i2 = iter(f)
|
|
27
|
+
sage: [next(i1), next(i1)]
|
|
28
|
+
[0, -2]
|
|
29
|
+
sage: [next(i2), next(i2)]
|
|
30
|
+
[0, -2]
|
|
31
|
+
sage: [next(i1), next(i2)]
|
|
32
|
+
[-2, -2]
|
|
33
|
+
|
|
34
|
+
It is possible to prepend a list to a lazy list::
|
|
35
|
+
|
|
36
|
+
sage: from itertools import count
|
|
37
|
+
sage: l = [3,7] + lazy_list(i**2 for i in count())
|
|
38
|
+
sage: l
|
|
39
|
+
lazy list [3, 7, 0, ...]
|
|
40
|
+
|
|
41
|
+
But, naturally, not the other way around::
|
|
42
|
+
|
|
43
|
+
sage: lazy_list(i-1 for i in count()) + [3,2,5]
|
|
44
|
+
Traceback (most recent call last):
|
|
45
|
+
...
|
|
46
|
+
TypeError: can only add list to lazy_list
|
|
47
|
+
|
|
48
|
+
You can easily create your own class inheriting from :class:`lazy_list_generic`. You
|
|
49
|
+
should call the :class:`lazy_list_generic` constructor (optionally with some
|
|
50
|
+
precomputed values for the cache) and implement the method ``_new_slice`` that
|
|
51
|
+
returns a new chunk of data at each call. Here is an example of implementation
|
|
52
|
+
of the Thue--Morse word that is obtained as the fixed point of the substitution
|
|
53
|
+
`0 \to 01` and `1 \to 10`::
|
|
54
|
+
|
|
55
|
+
sage: from sage.misc.lazy_list import lazy_list_generic
|
|
56
|
+
sage: class MyThueMorseWord(lazy_list_generic):
|
|
57
|
+
....: def __init__(self):
|
|
58
|
+
....: self.i = 1
|
|
59
|
+
....: lazy_list_generic.__init__(self, cache=[0,1])
|
|
60
|
+
....: def _new_slice(self):
|
|
61
|
+
....: letter = self.get(self.i)
|
|
62
|
+
....: self.i += 1
|
|
63
|
+
....: return [0,1] if letter == 0 else [1,0]
|
|
64
|
+
sage: w = MyThueMorseWord()
|
|
65
|
+
sage: w
|
|
66
|
+
lazy list [0, 1, 1, ...]
|
|
67
|
+
sage: all(w[i] == ZZ(i).popcount()%2 for i in range(100))
|
|
68
|
+
True
|
|
69
|
+
sage: w[:500].list() == w[:1000:2].list()
|
|
70
|
+
True
|
|
71
|
+
|
|
72
|
+
Alternatively, you can create the lazy list from an update function::
|
|
73
|
+
|
|
74
|
+
sage: def thue_morse_update(values):
|
|
75
|
+
....: n = len(values)
|
|
76
|
+
....: if n == 0:
|
|
77
|
+
....: letter = 0
|
|
78
|
+
....: else:
|
|
79
|
+
....: assert n%2 == 0
|
|
80
|
+
....: letter = values[n//2]
|
|
81
|
+
....: values.append(letter)
|
|
82
|
+
....: values.append(1-letter)
|
|
83
|
+
sage: w2 = lazy_list(update_function=thue_morse_update)
|
|
84
|
+
sage: w2
|
|
85
|
+
lazy list [0, 1, 1, ...]
|
|
86
|
+
sage: w2[:500].list() == w[:500].list()
|
|
87
|
+
True
|
|
88
|
+
|
|
89
|
+
You can also create user-defined classes (Python) and extension types (Cython)
|
|
90
|
+
inheriting from :class:`lazy_list_generic`.
|
|
91
|
+
In that case you would better implement directly the method
|
|
92
|
+
``_update_cache_up_to``. See the examples in this file with the classes
|
|
93
|
+
:class:`lazy_list_from_iterator` and :class:`lazy_list_from_function`.
|
|
94
|
+
|
|
95
|
+
Classes and Methods
|
|
96
|
+
===================
|
|
97
|
+
"""
|
|
98
|
+
# ****************************************************************************
|
|
99
|
+
# Copyright (C) 2015 Vincent Delecroix <20100.delecroix@gmail.com>
|
|
100
|
+
# Copyright (C) 2016 Daniel Krenn <dev@danielkrenn.at>
|
|
101
|
+
#
|
|
102
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
103
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
104
|
+
# the License, or (at your option) any later version.
|
|
105
|
+
# https://www.gnu.org/licenses/
|
|
106
|
+
# ****************************************************************************
|
|
107
|
+
|
|
108
|
+
cdef extern from "Python.h":
|
|
109
|
+
Py_ssize_t PY_SSIZE_T_MAX
|
|
110
|
+
|
|
111
|
+
# make a unique instance of empty lazy lists
|
|
112
|
+
cdef lazy_list_generic empty_lazy_list
|
|
113
|
+
empty_lazy_list = lazy_list_generic.__new__(lazy_list_generic)
|
|
114
|
+
empty_lazy_list.start = 0
|
|
115
|
+
empty_lazy_list.stop = 0
|
|
116
|
+
empty_lazy_list.step = 1
|
|
117
|
+
empty_lazy_list.cache = []
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def lazy_list(data=None, initial_values=None, start=None, stop=None, step=None,
|
|
121
|
+
update_function=None):
|
|
122
|
+
r"""
|
|
123
|
+
Return a lazy list.
|
|
124
|
+
|
|
125
|
+
INPUT:
|
|
126
|
+
|
|
127
|
+
- ``data`` -- data to create a lazy list from. This can be
|
|
128
|
+
|
|
129
|
+
#. a (possibly infinite) iterable,
|
|
130
|
+
#. a function (that takes as input an integer ``n`` and return
|
|
131
|
+
the ``n``-th term of the list),
|
|
132
|
+
#. or a standard Python container ``list`` or ``tuple``.
|
|
133
|
+
|
|
134
|
+
- ``initial_values`` -- the beginning of the sequence that will not be computed from
|
|
135
|
+
the ``data`` provided
|
|
136
|
+
|
|
137
|
+
- ``update_function`` -- you can also construct a lazy list from a function
|
|
138
|
+
that takes as input a list of precomputed values and updates it with some
|
|
139
|
+
more values
|
|
140
|
+
|
|
141
|
+
.. NOTE::
|
|
142
|
+
|
|
143
|
+
If you want finer tuning of the constructor you can directly instantiate
|
|
144
|
+
the classes associated to lazy lists that are
|
|
145
|
+
:class:`lazy_list_generic`, :class:`lazy_list_from_iterator`,
|
|
146
|
+
:class:`lazy_list_from_function`.
|
|
147
|
+
|
|
148
|
+
EXAMPLES:
|
|
149
|
+
|
|
150
|
+
The basic construction of lazy lists.
|
|
151
|
+
::
|
|
152
|
+
|
|
153
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
154
|
+
|
|
155
|
+
#. Iterators::
|
|
156
|
+
|
|
157
|
+
sage: from itertools import count
|
|
158
|
+
sage: lazy_list(count())
|
|
159
|
+
lazy list [0, 1, 2, ...]
|
|
160
|
+
|
|
161
|
+
#. Functions::
|
|
162
|
+
|
|
163
|
+
sage: lazy_list(lambda n: (n**2)%17)
|
|
164
|
+
lazy list [0, 1, 4, ...]
|
|
165
|
+
|
|
166
|
+
#. Plain lists::
|
|
167
|
+
|
|
168
|
+
sage: lazy_list([1,5,7,2])
|
|
169
|
+
lazy list [1, 5, 7, ...]
|
|
170
|
+
|
|
171
|
+
If a function is only defined for large values, you can provide the beginning
|
|
172
|
+
of the sequence manually::
|
|
173
|
+
|
|
174
|
+
sage: l = lazy_list(divisors, [None])
|
|
175
|
+
sage: l
|
|
176
|
+
lazy list [None, [1], [1, 2], ...]
|
|
177
|
+
|
|
178
|
+
Lazy lists behave like lists except that they are immutable::
|
|
179
|
+
|
|
180
|
+
sage: l[3::5]
|
|
181
|
+
lazy list [[1, 3], [1, 2, 4, 8], [1, 13], ...]
|
|
182
|
+
|
|
183
|
+
If your lazy list is finite, you can obtain the underlying list with the
|
|
184
|
+
method `.list()`::
|
|
185
|
+
|
|
186
|
+
sage: l[30:50:5].list()
|
|
187
|
+
[[1, 2, 3, 5, 6, 10, 15, 30],
|
|
188
|
+
[1, 5, 7, 35],
|
|
189
|
+
[1, 2, 4, 5, 8, 10, 20, 40],
|
|
190
|
+
[1, 3, 5, 9, 15, 45]]
|
|
191
|
+
|
|
192
|
+
TESTS::
|
|
193
|
+
|
|
194
|
+
sage: lazy_list()
|
|
195
|
+
lazy list []
|
|
196
|
+
sage: lazy_list(data='hey', update_function='hello')
|
|
197
|
+
Traceback (most recent call last):
|
|
198
|
+
...
|
|
199
|
+
ValueError: only one of the arguments 'data' or 'update_function'
|
|
200
|
+
can be used
|
|
201
|
+
|
|
202
|
+
Applying :func:`lazy_list` is idempotent. Thus, lazy lists created
|
|
203
|
+
from each other are unmodified::
|
|
204
|
+
|
|
205
|
+
sage: C = lazy_list(count())
|
|
206
|
+
sage: C[4]
|
|
207
|
+
4
|
|
208
|
+
sage: D = lazy_list(C)
|
|
209
|
+
sage: C is D
|
|
210
|
+
True
|
|
211
|
+
"""
|
|
212
|
+
cdef lazy_list_generic l
|
|
213
|
+
|
|
214
|
+
if data is None and update_function is None:
|
|
215
|
+
return empty_lazy_list
|
|
216
|
+
elif data is not None and update_function is not None:
|
|
217
|
+
raise ValueError("only one of the arguments 'data' or 'update_function' can be used")
|
|
218
|
+
|
|
219
|
+
if initial_values is None:
|
|
220
|
+
cache = []
|
|
221
|
+
else:
|
|
222
|
+
cache = list(initial_values)
|
|
223
|
+
|
|
224
|
+
if update_function is not None:
|
|
225
|
+
assert callable(update_function)
|
|
226
|
+
return lazy_list_from_update_function(update_function, cache)
|
|
227
|
+
|
|
228
|
+
if isinstance(data, (tuple, list)):
|
|
229
|
+
data = cache + list(data)
|
|
230
|
+
l = lazy_list_generic(data, start=0, stop=len(data), step=1)
|
|
231
|
+
elif isinstance(data, lazy_list_generic):
|
|
232
|
+
return data
|
|
233
|
+
else:
|
|
234
|
+
# the code below is not very clean
|
|
235
|
+
# we just want to differentiate on the one hand iterable (= object with a
|
|
236
|
+
# proper __iter__ method)/iterator (= object with a next method) and on the
|
|
237
|
+
# other hand callable (= object with __call__)
|
|
238
|
+
try:
|
|
239
|
+
data = iter(data)
|
|
240
|
+
except TypeError:
|
|
241
|
+
pass
|
|
242
|
+
|
|
243
|
+
from sage.misc.misc import is_iterator
|
|
244
|
+
if is_iterator(data):
|
|
245
|
+
l = lazy_list_from_iterator(iter(data), cache)
|
|
246
|
+
elif callable(data):
|
|
247
|
+
l = lazy_list_from_function(data, cache)
|
|
248
|
+
else:
|
|
249
|
+
raise ValueError("not able to build a lazy list from {}".format(type(data)))
|
|
250
|
+
|
|
251
|
+
return l
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def slice_unpickle(master, start, stop, step):
|
|
255
|
+
r"""
|
|
256
|
+
Unpickle helper.
|
|
257
|
+
|
|
258
|
+
TESTS::
|
|
259
|
+
|
|
260
|
+
sage: from sage.misc.lazy_list import slice_unpickle
|
|
261
|
+
sage: slice_unpickle(list(range(35)), 1, 3, 7) == list(range(35))[1:3:7]
|
|
262
|
+
True
|
|
263
|
+
"""
|
|
264
|
+
return master[start:stop:step]
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def lazy_list_formatter(L, name='lazy list',
|
|
268
|
+
separator=', ', more='...',
|
|
269
|
+
opening_delimiter='[', closing_delimiter=']',
|
|
270
|
+
preview=3):
|
|
271
|
+
r"""
|
|
272
|
+
Return a string representation of ``L``.
|
|
273
|
+
|
|
274
|
+
INPUT:
|
|
275
|
+
|
|
276
|
+
- ``L`` -- an iterable object
|
|
277
|
+
|
|
278
|
+
- ``name`` -- (default: ``'lazy list'``) a string appearing
|
|
279
|
+
at first position (i.e., in front of the actual values)
|
|
280
|
+
in the representation
|
|
281
|
+
|
|
282
|
+
- ``opening_delimiter`` -- (default: ``'['``) a string heading
|
|
283
|
+
the shown entries
|
|
284
|
+
|
|
285
|
+
- ``closing_delimiter`` -- (default: ``']'``) a string trailing
|
|
286
|
+
the shown entries
|
|
287
|
+
|
|
288
|
+
- ``separator`` -- (default: ``', '``) a string appearing between
|
|
289
|
+
two entries
|
|
290
|
+
|
|
291
|
+
- ``more`` -- (default: ``'...'``) a string indicating that
|
|
292
|
+
not all entries of the list are shown
|
|
293
|
+
|
|
294
|
+
- ``preview`` -- (default: ``3``) an integer specifying the number of
|
|
295
|
+
elements shown in the representation string
|
|
296
|
+
|
|
297
|
+
OUTPUT: string
|
|
298
|
+
|
|
299
|
+
EXAMPLES::
|
|
300
|
+
|
|
301
|
+
sage: from sage.misc.lazy_list import lazy_list_formatter
|
|
302
|
+
sage: lazy_list_formatter(srange(3, 1000, 5), name='list')
|
|
303
|
+
'list [3, 8, 13, ...]'
|
|
304
|
+
|
|
305
|
+
::
|
|
306
|
+
|
|
307
|
+
sage: # needs sage.libs.pari
|
|
308
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
309
|
+
sage: L = lazy_list(Primes()); L
|
|
310
|
+
lazy list [2, 3, 5, ...]
|
|
311
|
+
sage: repr(L) == lazy_list_formatter(L)
|
|
312
|
+
True
|
|
313
|
+
sage: lazy_list_formatter(L, name='primes')
|
|
314
|
+
'primes [2, 3, 5, ...]'
|
|
315
|
+
sage: lazy_list_formatter(L, opening_delimiter='(', closing_delimiter=')')
|
|
316
|
+
'lazy list (2, 3, 5, ...)'
|
|
317
|
+
sage: lazy_list_formatter(L, opening_delimiter='', closing_delimiter='')
|
|
318
|
+
'lazy list 2, 3, 5, ...'
|
|
319
|
+
sage: lazy_list_formatter(L, separator='--')
|
|
320
|
+
'lazy list [2--3--5--...]'
|
|
321
|
+
sage: lazy_list_formatter(L, more='and more')
|
|
322
|
+
'lazy list [2, 3, 5, and more]'
|
|
323
|
+
sage: lazy_list_formatter(L, preview=10)
|
|
324
|
+
'lazy list [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, ...]'
|
|
325
|
+
sage: lazy_list_formatter(L, name='primes',
|
|
326
|
+
....: opening_delimiter='', closing_delimiter='',
|
|
327
|
+
....: separator=' ', more='->', preview=7)
|
|
328
|
+
'primes 2 3 5 7 11 13 17 ->'
|
|
329
|
+
|
|
330
|
+
TESTS::
|
|
331
|
+
|
|
332
|
+
sage: from itertools import count
|
|
333
|
+
sage: lazy_list_formatter(count(), name='iterator count')
|
|
334
|
+
'iterator count [0, 1, 2, ...]'
|
|
335
|
+
"""
|
|
336
|
+
from itertools import islice
|
|
337
|
+
|
|
338
|
+
cdef str s = name
|
|
339
|
+
if s:
|
|
340
|
+
s += ' '
|
|
341
|
+
s += opening_delimiter
|
|
342
|
+
cdef list P = list(islice(L, int(preview + 1)))
|
|
343
|
+
cdef list E = list(repr(e) for e in P[:preview])
|
|
344
|
+
if len(P) > preview:
|
|
345
|
+
E.append(more)
|
|
346
|
+
s += separator.join(E)
|
|
347
|
+
s += closing_delimiter
|
|
348
|
+
return s
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
cdef class lazy_list_generic():
|
|
352
|
+
r"""
|
|
353
|
+
A lazy list.
|
|
354
|
+
|
|
355
|
+
EXAMPLES::
|
|
356
|
+
|
|
357
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
358
|
+
sage: l = lazy_list(Primes())
|
|
359
|
+
sage: l # needs sage.libs.pari
|
|
360
|
+
lazy list [2, 3, 5, ...]
|
|
361
|
+
sage: l[200] # needs sage.libs.pari
|
|
362
|
+
1229
|
|
363
|
+
"""
|
|
364
|
+
|
|
365
|
+
def __init__(self, cache=None, start=None, stop=None, step=None):
|
|
366
|
+
r"""
|
|
367
|
+
No check is performed on input and bad input can result in a Sage crash.
|
|
368
|
+
You are advised to use the function :func:`lazy_list` instead. The only
|
|
369
|
+
case where you might want to use directly this constructor is if you
|
|
370
|
+
have a list that you want to wrap (without copy) into a lazy list.
|
|
371
|
+
See in the example below.
|
|
372
|
+
|
|
373
|
+
INPUT:
|
|
374
|
+
|
|
375
|
+
- ``cache`` -- an optional list to be used as the cache. Be careful that
|
|
376
|
+
there is no copy
|
|
377
|
+
|
|
378
|
+
- ``start``, ``stop``, ``step`` -- for slices
|
|
379
|
+
|
|
380
|
+
.. NOTE::
|
|
381
|
+
|
|
382
|
+
Everywhere the constant ``PY_SSIZE_T_MAX`` plays the role of infinity
|
|
383
|
+
|
|
384
|
+
EXAMPLES::
|
|
385
|
+
|
|
386
|
+
sage: from sage.misc.lazy_list import lazy_list_generic
|
|
387
|
+
sage: l = [0,1,2]
|
|
388
|
+
sage: ll = lazy_list_generic(l, 0, 2, None)
|
|
389
|
+
sage: ll
|
|
390
|
+
lazy list [0, 1]
|
|
391
|
+
|
|
392
|
+
The above code may be dangerous since the lazy list holds a reference
|
|
393
|
+
to the initial list::
|
|
394
|
+
|
|
395
|
+
sage: l[0] = 'haha'
|
|
396
|
+
sage: ll
|
|
397
|
+
lazy list ['haha', 1]
|
|
398
|
+
"""
|
|
399
|
+
self.cache = [] if cache is None else cache
|
|
400
|
+
self.start = 0 if start is None else start
|
|
401
|
+
self.stop = PY_SSIZE_T_MAX if stop is None else stop
|
|
402
|
+
self.step = 1 if step is None else step
|
|
403
|
+
|
|
404
|
+
def list(self):
|
|
405
|
+
r"""
|
|
406
|
+
Return the list made of the elements of ``self``.
|
|
407
|
+
|
|
408
|
+
.. NOTE::
|
|
409
|
+
|
|
410
|
+
If the iterator is sufficiently large, this will build a list
|
|
411
|
+
of length ``PY_SSIZE_T_MAX`` which should be beyond the capacity of
|
|
412
|
+
your RAM!
|
|
413
|
+
|
|
414
|
+
EXAMPLES::
|
|
415
|
+
|
|
416
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
417
|
+
sage: P = lazy_list(Primes())
|
|
418
|
+
sage: P[2:143:5].list() # needs sage.libs.pari
|
|
419
|
+
[5, 19, 41, 61, 83, 107, 137, 163, 191, 223, 241, 271, 307, 337, 367,
|
|
420
|
+
397, 431, 457, 487, 521, 563, 593, 617, 647, 677, 719, 751, 787, 823]
|
|
421
|
+
sage: P = lazy_list(iter([1,2,3]))
|
|
422
|
+
sage: P.list()
|
|
423
|
+
[1, 2, 3]
|
|
424
|
+
sage: P[:100000].list()
|
|
425
|
+
[1, 2, 3]
|
|
426
|
+
sage: P[1:7:2].list()
|
|
427
|
+
[2]
|
|
428
|
+
|
|
429
|
+
TESTS:
|
|
430
|
+
|
|
431
|
+
Check that the cache is immutable::
|
|
432
|
+
|
|
433
|
+
sage: lazy = lazy_list(iter(Primes()))[:5]
|
|
434
|
+
sage: l = lazy.list(); l # needs sage.libs.pari
|
|
435
|
+
[2, 3, 5, 7, 11]
|
|
436
|
+
sage: l[0] = -1; l # needs sage.libs.pari
|
|
437
|
+
[-1, 3, 5, 7, 11]
|
|
438
|
+
sage: lazy.list() # needs sage.libs.pari
|
|
439
|
+
[2, 3, 5, 7, 11]
|
|
440
|
+
"""
|
|
441
|
+
self._fit(self.stop - self.step)
|
|
442
|
+
return self.cache[self.start:self.stop:self.step]
|
|
443
|
+
|
|
444
|
+
def _info(self):
|
|
445
|
+
r"""
|
|
446
|
+
Print information about ``self`` on standard output.
|
|
447
|
+
|
|
448
|
+
EXAMPLES::
|
|
449
|
+
|
|
450
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
451
|
+
sage: P = lazy_list(iter(Primes()))[10:21474838:4]
|
|
452
|
+
sage: P._info()
|
|
453
|
+
cache length 0
|
|
454
|
+
start 10
|
|
455
|
+
stop 21474838
|
|
456
|
+
step 4
|
|
457
|
+
sage: P[0] # needs sage.libs.pari
|
|
458
|
+
31
|
|
459
|
+
sage: P._info() # needs sage.libs.pari
|
|
460
|
+
cache length 11
|
|
461
|
+
start 10
|
|
462
|
+
stop 21474838
|
|
463
|
+
step 4
|
|
464
|
+
"""
|
|
465
|
+
print("cache length", len(self.cache))
|
|
466
|
+
print("start ", self.start)
|
|
467
|
+
print("stop ", self.stop)
|
|
468
|
+
print("step ", self.step)
|
|
469
|
+
|
|
470
|
+
def __add__(self, other):
|
|
471
|
+
r"""
|
|
472
|
+
If ``self`` is a list then return the lazy_list that consists of the
|
|
473
|
+
concatenation of ``self`` and ``other``.
|
|
474
|
+
|
|
475
|
+
TESTS::
|
|
476
|
+
|
|
477
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
478
|
+
sage: from itertools import count
|
|
479
|
+
sage: l = lazy_list(i**3 - i + 1 for i in count()); l
|
|
480
|
+
lazy list [1, 1, 7, ...]
|
|
481
|
+
sage: p = ['huit', 'douze']
|
|
482
|
+
sage: ll = p + l; ll
|
|
483
|
+
lazy list ['huit', 'douze', 1, ...]
|
|
484
|
+
sage: l[:10].list() == ll[2:12].list()
|
|
485
|
+
True
|
|
486
|
+
sage: p
|
|
487
|
+
['huit', 'douze']
|
|
488
|
+
sage: ([0,2] + lazy_list([0,1])).list()
|
|
489
|
+
[0, 2, 0, 1]
|
|
490
|
+
"""
|
|
491
|
+
if not isinstance(self, list):
|
|
492
|
+
raise TypeError("can only add list to lazy_list")
|
|
493
|
+
|
|
494
|
+
cdef lazy_list_from_iterator l = lazy_list_from_iterator.__new__(lazy_list_from_iterator)
|
|
495
|
+
l.cache = self[:]
|
|
496
|
+
l.start = 0
|
|
497
|
+
l.stop = PY_SSIZE_T_MAX
|
|
498
|
+
l.step = 1
|
|
499
|
+
l.iterator = iter(other)
|
|
500
|
+
return l
|
|
501
|
+
|
|
502
|
+
def __repr__(self):
|
|
503
|
+
r"""
|
|
504
|
+
Return a string representation.
|
|
505
|
+
|
|
506
|
+
To customize the string representation, the
|
|
507
|
+
:func:`lazy_list_formatter` can be used.
|
|
508
|
+
|
|
509
|
+
TESTS::
|
|
510
|
+
|
|
511
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
512
|
+
sage: from itertools import count
|
|
513
|
+
sage: r = lazy_list(count()); r # indirect doctest
|
|
514
|
+
lazy list [0, 1, 2, ...]
|
|
515
|
+
sage: r[:0]
|
|
516
|
+
lazy list []
|
|
517
|
+
sage: r[:1]
|
|
518
|
+
lazy list [0]
|
|
519
|
+
sage: r[:2]
|
|
520
|
+
lazy list [0, 1]
|
|
521
|
+
sage: r[:3]
|
|
522
|
+
lazy list [0, 1, 2]
|
|
523
|
+
sage: r[:4]
|
|
524
|
+
lazy list [0, 1, 2, ...]
|
|
525
|
+
sage: lazy_list([0,1])
|
|
526
|
+
lazy list [0, 1]
|
|
527
|
+
sage: lazy_list([0,1,2,3])
|
|
528
|
+
lazy list [0, 1, 2, ...]
|
|
529
|
+
"""
|
|
530
|
+
return lazy_list_formatter(self)
|
|
531
|
+
|
|
532
|
+
def __reduce__(self):
|
|
533
|
+
r"""
|
|
534
|
+
Pickling support.
|
|
535
|
+
|
|
536
|
+
EXAMPLES::
|
|
537
|
+
|
|
538
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
539
|
+
sage: m = lazy_list(iter([0, 1, 4, 9, 16, 25, 36, 49, 64, 81]))
|
|
540
|
+
sage: x = loads(dumps(m))
|
|
541
|
+
sage: y = iter(x)
|
|
542
|
+
sage: print("{} {} {}".format(next(y), next(y), next(y)))
|
|
543
|
+
0 1 4
|
|
544
|
+
sage: m2 = m[3::2]
|
|
545
|
+
sage: loads(dumps(m2))
|
|
546
|
+
lazy list [9, 25, 49, ...]
|
|
547
|
+
"""
|
|
548
|
+
if self.master is None:
|
|
549
|
+
raise NotImplementedError
|
|
550
|
+
return slice_unpickle, (self.master, self.start, self.stop, self.step)
|
|
551
|
+
|
|
552
|
+
cpdef int _fit(self, Py_ssize_t n) except -1:
|
|
553
|
+
r"""
|
|
554
|
+
Fill the cache making the term at index ``n`` available.
|
|
555
|
+
|
|
556
|
+
You can access the term at position ``n`` from the cache when it returns
|
|
557
|
+
``0``.
|
|
558
|
+
|
|
559
|
+
OUTPUT:
|
|
560
|
+
|
|
561
|
+
- ``1`` -- the lazy list is actually finite and shorter than ``n``
|
|
562
|
+
|
|
563
|
+
- ``0`` -- you can safely access the term at position ``n`` after this call
|
|
564
|
+
|
|
565
|
+
- ``-1`` -- to handle Python errors (you can ignore it in Python code)
|
|
566
|
+
|
|
567
|
+
EXAMPLES::
|
|
568
|
+
|
|
569
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
570
|
+
sage: l = lazy_list(iter([0,1,2,-34,3,2,-5,12,1,4,-18,5,-12]))[2::3]
|
|
571
|
+
sage: l._info()
|
|
572
|
+
cache length 0
|
|
573
|
+
start 2
|
|
574
|
+
stop 9223372036854775807 # 64-bit
|
|
575
|
+
stop 2147483647 # 32-bit
|
|
576
|
+
step 3
|
|
577
|
+
sage: l._fit(13)
|
|
578
|
+
1
|
|
579
|
+
sage: l._info()
|
|
580
|
+
cache length 13
|
|
581
|
+
start 2
|
|
582
|
+
stop 14
|
|
583
|
+
step 3
|
|
584
|
+
|
|
585
|
+
sage: l = lazy_list([0]*12)[1::2]
|
|
586
|
+
sage: l._fit(100)
|
|
587
|
+
1
|
|
588
|
+
sage: l._info()
|
|
589
|
+
cache length 12
|
|
590
|
+
start 1
|
|
591
|
+
stop 13
|
|
592
|
+
step 2
|
|
593
|
+
sage: l._fit(100)
|
|
594
|
+
1
|
|
595
|
+
"""
|
|
596
|
+
if n > self.stop - self.step:
|
|
597
|
+
return 1
|
|
598
|
+
|
|
599
|
+
if self._update_cache_up_to(n):
|
|
600
|
+
self.stop = min(self.stop, len(self.cache))
|
|
601
|
+
if self.master is not None:
|
|
602
|
+
self.stop = min(self.stop, self.master.stop)
|
|
603
|
+
if self.stop <= self.start:
|
|
604
|
+
self.start = self.stop = 0
|
|
605
|
+
self.step = 1
|
|
606
|
+
if (self.start - self.stop) % self.step:
|
|
607
|
+
self.stop += self.step + (self.start - self.stop) % self.step
|
|
608
|
+
return 1
|
|
609
|
+
return 0
|
|
610
|
+
|
|
611
|
+
cpdef get(self, Py_ssize_t i):
|
|
612
|
+
r"""
|
|
613
|
+
Return the element at position ``i``.
|
|
614
|
+
|
|
615
|
+
If the index is not an integer, then raise a :exc:`TypeError`. If the
|
|
616
|
+
argument is negative then raise a :exc:`ValueError`. Finally, if the
|
|
617
|
+
argument is beyond the size of that lazy list it raises a
|
|
618
|
+
:exc:`IndexError`.
|
|
619
|
+
|
|
620
|
+
EXAMPLES::
|
|
621
|
+
|
|
622
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
623
|
+
sage: from itertools import chain, repeat
|
|
624
|
+
sage: f = lazy_list(chain(iter([1,2,3]), repeat('a')))
|
|
625
|
+
sage: f.get(0)
|
|
626
|
+
1
|
|
627
|
+
sage: f.get(3)
|
|
628
|
+
'a'
|
|
629
|
+
sage: f.get(0)
|
|
630
|
+
1
|
|
631
|
+
sage: f.get(4)
|
|
632
|
+
'a'
|
|
633
|
+
|
|
634
|
+
sage: g = f[:10]
|
|
635
|
+
sage: g.get(5)
|
|
636
|
+
'a'
|
|
637
|
+
sage: g.get(10)
|
|
638
|
+
Traceback (most recent call last):
|
|
639
|
+
...
|
|
640
|
+
IndexError: lazy list index out of range
|
|
641
|
+
sage: g.get(1/2)
|
|
642
|
+
Traceback (most recent call last):
|
|
643
|
+
...
|
|
644
|
+
TypeError: unable to convert rational 1/2 to an integer
|
|
645
|
+
"""
|
|
646
|
+
if i < 0:
|
|
647
|
+
raise ValueError("indices must be nonnegative")
|
|
648
|
+
|
|
649
|
+
i = self.start + i * self.step
|
|
650
|
+
if self._fit(i):
|
|
651
|
+
raise IndexError("lazy list index out of range")
|
|
652
|
+
return self.cache[i]
|
|
653
|
+
|
|
654
|
+
def __call__(self, i):
|
|
655
|
+
r"""
|
|
656
|
+
An alias for :meth:`get`.
|
|
657
|
+
|
|
658
|
+
TESTS::
|
|
659
|
+
|
|
660
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
661
|
+
sage: from itertools import chain, repeat
|
|
662
|
+
sage: f = lazy_list(chain(iter([1,2,3]), repeat('a')))
|
|
663
|
+
sage: f(2)
|
|
664
|
+
3
|
|
665
|
+
sage: f(3)
|
|
666
|
+
'a'
|
|
667
|
+
"""
|
|
668
|
+
return self.get(i)
|
|
669
|
+
|
|
670
|
+
def __iter__(self):
|
|
671
|
+
r"""
|
|
672
|
+
Return an iterator.
|
|
673
|
+
|
|
674
|
+
TESTS::
|
|
675
|
+
|
|
676
|
+
sage: from itertools import count
|
|
677
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
678
|
+
sage: iter(lazy_list(count()))
|
|
679
|
+
<...generator object at 0x...>
|
|
680
|
+
|
|
681
|
+
::
|
|
682
|
+
|
|
683
|
+
sage: l = lazy_list(i ** 2 for i in range(5))
|
|
684
|
+
sage: list(l)
|
|
685
|
+
[0, 1, 4, 9, 16]
|
|
686
|
+
sage: l._info()
|
|
687
|
+
cache length 5
|
|
688
|
+
start 0
|
|
689
|
+
stop 5
|
|
690
|
+
step 1
|
|
691
|
+
"""
|
|
692
|
+
cdef Py_ssize_t i
|
|
693
|
+
|
|
694
|
+
i = self.start
|
|
695
|
+
while i < self.stop:
|
|
696
|
+
if self._fit(i):
|
|
697
|
+
return
|
|
698
|
+
yield self.cache[i]
|
|
699
|
+
i += self.step
|
|
700
|
+
|
|
701
|
+
def __getitem__(self, key):
|
|
702
|
+
r"""
|
|
703
|
+
Return a lazy list which shares the same cache.
|
|
704
|
+
|
|
705
|
+
EXAMPLES::
|
|
706
|
+
|
|
707
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
708
|
+
sage: f = lazy_list(iter([1,2,3]))
|
|
709
|
+
sage: f0 = f[0:]
|
|
710
|
+
sage: [f.get(0), f.get(1), f.get(2)]
|
|
711
|
+
[1, 2, 3]
|
|
712
|
+
sage: f1 = f[1:]
|
|
713
|
+
sage: [f1.get(0), f1.get(1)]
|
|
714
|
+
[2, 3]
|
|
715
|
+
sage: f2 = f[2:]
|
|
716
|
+
sage: f2.get(0)
|
|
717
|
+
3
|
|
718
|
+
sage: f3 = f[3:]
|
|
719
|
+
sage: f3.get(0)
|
|
720
|
+
Traceback (most recent call last):
|
|
721
|
+
...
|
|
722
|
+
IndexError: lazy list index out of range
|
|
723
|
+
|
|
724
|
+
sage: l = lazy_list([0]*12)[1::2]
|
|
725
|
+
sage: l[2::3]
|
|
726
|
+
lazy list [0, 0]
|
|
727
|
+
sage: l[3::2]
|
|
728
|
+
lazy list [0, 0]
|
|
729
|
+
|
|
730
|
+
A lazy list automatically adjusts the indices in order that start and
|
|
731
|
+
stop are congruent modulo step::
|
|
732
|
+
|
|
733
|
+
sage: P = lazy_list(iter(Primes()))
|
|
734
|
+
sage: P[1:12:4]._info()
|
|
735
|
+
cache length 0
|
|
736
|
+
start 1
|
|
737
|
+
stop 13
|
|
738
|
+
step 4
|
|
739
|
+
sage: P[1:13:4]._info()
|
|
740
|
+
cache length 0
|
|
741
|
+
start 1
|
|
742
|
+
stop 13
|
|
743
|
+
step 4
|
|
744
|
+
sage: P[1:14:4]._info()
|
|
745
|
+
cache length 0
|
|
746
|
+
start 1
|
|
747
|
+
stop 17
|
|
748
|
+
step 4
|
|
749
|
+
sage: Q = P[100:1042233:12]
|
|
750
|
+
sage: Q._info()
|
|
751
|
+
cache length 0
|
|
752
|
+
start 100
|
|
753
|
+
stop 1042240
|
|
754
|
+
step 12
|
|
755
|
+
sage: R = Q[233::3]
|
|
756
|
+
sage: R._info()
|
|
757
|
+
cache length 0
|
|
758
|
+
start 2896
|
|
759
|
+
stop 1042252
|
|
760
|
+
step 36
|
|
761
|
+
sage: 1042252%36 == 2896%36
|
|
762
|
+
True
|
|
763
|
+
|
|
764
|
+
We check commutation::
|
|
765
|
+
|
|
766
|
+
sage: l = lazy_list(iter(range(10000)))
|
|
767
|
+
sage: l1 = l[::2][:3001]
|
|
768
|
+
sage: l2 = l[:6002][::2]
|
|
769
|
+
sage: l1._info()
|
|
770
|
+
cache length 0
|
|
771
|
+
start 0
|
|
772
|
+
stop 6002
|
|
773
|
+
step 2
|
|
774
|
+
sage: l2._info()
|
|
775
|
+
cache length 0
|
|
776
|
+
start 0
|
|
777
|
+
stop 6002
|
|
778
|
+
step 2
|
|
779
|
+
sage: l3 = l1[13::2][:50:2]
|
|
780
|
+
sage: l4 = l1[:200][13:113:4]
|
|
781
|
+
sage: l3._info()
|
|
782
|
+
cache length 0
|
|
783
|
+
start 26
|
|
784
|
+
stop 226
|
|
785
|
+
step 8
|
|
786
|
+
sage: l4._info()
|
|
787
|
+
cache length 0
|
|
788
|
+
start 26
|
|
789
|
+
stop 226
|
|
790
|
+
step 8
|
|
791
|
+
|
|
792
|
+
Further tests::
|
|
793
|
+
|
|
794
|
+
sage: l = lazy_list(iter([0]*25))
|
|
795
|
+
sage: l[2::3][2::3][4::5]
|
|
796
|
+
lazy list []
|
|
797
|
+
sage: l[2::5][3::][1::]
|
|
798
|
+
lazy list [0]
|
|
799
|
+
sage: l[3:24:2][1::][1:7:3]
|
|
800
|
+
lazy list [0, 0]
|
|
801
|
+
sage: l[::2][2::][2::3]
|
|
802
|
+
lazy list [0, 0, 0]
|
|
803
|
+
sage: l[4:3][:] is l[18:2] # *the* empty_lazy_list
|
|
804
|
+
True
|
|
805
|
+
"""
|
|
806
|
+
if not isinstance(key, slice):
|
|
807
|
+
return self.get(key)
|
|
808
|
+
|
|
809
|
+
# the following make all terms > 0
|
|
810
|
+
cdef Py_ssize_t start, stop, step
|
|
811
|
+
start = 0 if key.start is None else key.start
|
|
812
|
+
stop = PY_SSIZE_T_MAX if key.stop is None else key.stop
|
|
813
|
+
step = 1 if key.step is None else key.step
|
|
814
|
+
|
|
815
|
+
if step == 0:
|
|
816
|
+
raise TypeError("step may not be 0")
|
|
817
|
+
if step < 0 or start < 0 or stop < 0:
|
|
818
|
+
raise ValueError("slice indices must be nonnegative")
|
|
819
|
+
|
|
820
|
+
step = step * self.step
|
|
821
|
+
start = self.start + start * self.step
|
|
822
|
+
if stop != PY_SSIZE_T_MAX:
|
|
823
|
+
stop = self.start + stop * self.step
|
|
824
|
+
if stop > self.stop:
|
|
825
|
+
stop = self.stop
|
|
826
|
+
if stop != PY_SSIZE_T_MAX and stop % step != start % step:
|
|
827
|
+
stop = stop - (stop - start) % step + step
|
|
828
|
+
|
|
829
|
+
if stop <= start:
|
|
830
|
+
return empty_lazy_list
|
|
831
|
+
|
|
832
|
+
# here we return a slice of self. That is to say, a lazy list which
|
|
833
|
+
# shares the same cache of values
|
|
834
|
+
cdef lazy_list_generic l = lazy_list_generic.__new__(lazy_list_generic)
|
|
835
|
+
l.master = self
|
|
836
|
+
l.cache = self.cache
|
|
837
|
+
l.start = start
|
|
838
|
+
l.stop = stop
|
|
839
|
+
l.step = step
|
|
840
|
+
|
|
841
|
+
return l
|
|
842
|
+
|
|
843
|
+
cpdef int _update_cache_up_to(self, Py_ssize_t i) except -1:
|
|
844
|
+
r"""
|
|
845
|
+
Update the cache up to ``i``.
|
|
846
|
+
|
|
847
|
+
This is the default implementation that calls ``_new_slice``.
|
|
848
|
+
|
|
849
|
+
OUTPUT:
|
|
850
|
+
|
|
851
|
+
- ``-1`` -- a Python error occurred
|
|
852
|
+
|
|
853
|
+
- ``0`` -- the cache has now size larger than ``i``
|
|
854
|
+
|
|
855
|
+
- ``1`` -- the lazy list is actually finite and shorter than ``i``
|
|
856
|
+
|
|
857
|
+
TESTS::
|
|
858
|
+
|
|
859
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
860
|
+
sage: L = lazy_list(Primes())[2:]
|
|
861
|
+
sage: L._update_cache_up_to(4) # needs sage.libs.pari
|
|
862
|
+
0
|
|
863
|
+
sage: L._info() # needs sage.libs.pari
|
|
864
|
+
cache length 5
|
|
865
|
+
start 2
|
|
866
|
+
stop 9223372036854775807 # 64-bit
|
|
867
|
+
stop 2147483647 # 32-bit
|
|
868
|
+
step 1
|
|
869
|
+
"""
|
|
870
|
+
if self.master is not None: # this is a slice
|
|
871
|
+
return self.master._fit(i)
|
|
872
|
+
|
|
873
|
+
cdef list l
|
|
874
|
+
while len(self.cache) <= i:
|
|
875
|
+
l = self._new_slice()
|
|
876
|
+
if not l:
|
|
877
|
+
return 1
|
|
878
|
+
self.cache.extend(l)
|
|
879
|
+
return 0
|
|
880
|
+
|
|
881
|
+
cpdef list _get_cache_(self):
|
|
882
|
+
r"""
|
|
883
|
+
Return the internal cache.
|
|
884
|
+
|
|
885
|
+
TESTS::
|
|
886
|
+
|
|
887
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
888
|
+
sage: L = lazy_list(Primes()); L # needs sage.libs.pari
|
|
889
|
+
lazy list [2, 3, 5, ...]
|
|
890
|
+
sage: L._get_cache_() # needs sage.libs.pari
|
|
891
|
+
[2, 3, 5, 7]
|
|
892
|
+
"""
|
|
893
|
+
return self.cache
|
|
894
|
+
|
|
895
|
+
|
|
896
|
+
cdef class lazy_list_from_iterator(lazy_list_generic):
|
|
897
|
+
r"""
|
|
898
|
+
Lazy list built from an iterator.
|
|
899
|
+
|
|
900
|
+
EXAMPLES::
|
|
901
|
+
|
|
902
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
903
|
+
sage: from itertools import count
|
|
904
|
+
sage: m = lazy_list(count()); m
|
|
905
|
+
lazy list [0, 1, 2, ...]
|
|
906
|
+
|
|
907
|
+
sage: m2 = lazy_list(count())[8:20551:2]
|
|
908
|
+
sage: m2
|
|
909
|
+
lazy list [8, 10, 12, ...]
|
|
910
|
+
|
|
911
|
+
sage: x = iter(m)
|
|
912
|
+
sage: [next(x), next(x), next(x)]
|
|
913
|
+
[0, 1, 2]
|
|
914
|
+
sage: y = iter(m)
|
|
915
|
+
sage: [next(y), next(y), next(y)]
|
|
916
|
+
[0, 1, 2]
|
|
917
|
+
sage: [next(x), next(y)]
|
|
918
|
+
[3, 3]
|
|
919
|
+
sage: m2 = lazy_list(iter([0, 1, 4, 9, 16]))
|
|
920
|
+
sage: loads(dumps(m2))
|
|
921
|
+
lazy list [0, 1, 4, ...]
|
|
922
|
+
"""
|
|
923
|
+
|
|
924
|
+
def __init__(self, iterator, cache=None, stop=None):
|
|
925
|
+
r"""
|
|
926
|
+
INPUT:
|
|
927
|
+
|
|
928
|
+
- ``iterator`` -- an iterator
|
|
929
|
+
|
|
930
|
+
- ``cache`` -- an optional list to be used as the cache; be careful that
|
|
931
|
+
there is no copy
|
|
932
|
+
|
|
933
|
+
- ``stop`` -- an optional stop point
|
|
934
|
+
|
|
935
|
+
TESTS::
|
|
936
|
+
|
|
937
|
+
sage: from sage.misc.lazy_list import lazy_list_from_iterator
|
|
938
|
+
sage: from itertools import count
|
|
939
|
+
sage: lazy_list_from_iterator(count())
|
|
940
|
+
lazy list [0, 1, 2, ...]
|
|
941
|
+
sage: lazy_list_from_iterator(count(), ['a'], 10)
|
|
942
|
+
lazy list ['a', 0, 1, ...]
|
|
943
|
+
sage: _._info()
|
|
944
|
+
cache length 4
|
|
945
|
+
start 0
|
|
946
|
+
stop 10
|
|
947
|
+
step 1
|
|
948
|
+
"""
|
|
949
|
+
self.iterator = iterator
|
|
950
|
+
lazy_list_generic.__init__(self, cache, None, stop, None)
|
|
951
|
+
|
|
952
|
+
cpdef int _update_cache_up_to(self, Py_ssize_t i) except -1:
|
|
953
|
+
r"""
|
|
954
|
+
Update the cache up to ``i``.
|
|
955
|
+
|
|
956
|
+
OUTPUT:
|
|
957
|
+
|
|
958
|
+
- ``-1`` -- a Python error occurred
|
|
959
|
+
|
|
960
|
+
- ``0`` -- everything went fine
|
|
961
|
+
|
|
962
|
+
- ``1`` -- the iterator stopped before ``i``
|
|
963
|
+
|
|
964
|
+
TESTS::
|
|
965
|
+
|
|
966
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
967
|
+
sage: L = lazy_list(iter(Primes()))[2:]
|
|
968
|
+
sage: L._update_cache_up_to(4) # needs sage.libs.pari
|
|
969
|
+
0
|
|
970
|
+
sage: L._info() # needs sage.libs.pari
|
|
971
|
+
cache length 5
|
|
972
|
+
start 2
|
|
973
|
+
stop 9223372036854775807 # 64-bit
|
|
974
|
+
stop 2147483647 # 32-bit
|
|
975
|
+
step 1
|
|
976
|
+
"""
|
|
977
|
+
while len(self.cache) <= i:
|
|
978
|
+
try:
|
|
979
|
+
o = next(self.iterator)
|
|
980
|
+
except StopIteration:
|
|
981
|
+
return 1
|
|
982
|
+
self.cache.append(o)
|
|
983
|
+
return 0
|
|
984
|
+
|
|
985
|
+
def __reduce__(self):
|
|
986
|
+
r"""
|
|
987
|
+
TESTS::
|
|
988
|
+
|
|
989
|
+
sage: from sage.misc.lazy_list import lazy_list_from_iterator
|
|
990
|
+
sage: loads(dumps(lazy_list_from_iterator(iter([0, 1, 4, 9, 16]))))
|
|
991
|
+
lazy list [0, 1, 4, ...]
|
|
992
|
+
sage: loads(dumps(lazy_list_from_iterator(iter([0, 1, 4, 9, 16]), ['a'])))
|
|
993
|
+
lazy list ['a', 0, 1, ...]
|
|
994
|
+
"""
|
|
995
|
+
return lazy_list_from_iterator, (self.iterator, self.cache, self.stop)
|
|
996
|
+
|
|
997
|
+
|
|
998
|
+
cdef class lazy_list_from_function(lazy_list_generic):
|
|
999
|
+
|
|
1000
|
+
def __init__(self, function, cache=None, stop=None):
|
|
1001
|
+
r"""
|
|
1002
|
+
INPUT:
|
|
1003
|
+
|
|
1004
|
+
- ``function`` -- a function that maps ``n`` to the element
|
|
1005
|
+
at position ``n`` (this function only needs to be defined for length
|
|
1006
|
+
larger than the length of the cache)
|
|
1007
|
+
|
|
1008
|
+
- ``cache`` -- an optional list to be used as the cache. Be careful that
|
|
1009
|
+
there is no copy
|
|
1010
|
+
|
|
1011
|
+
- ``stop`` -- an optional integer to specify the length of this lazy list
|
|
1012
|
+
(Otherwise it is considered infinite)
|
|
1013
|
+
|
|
1014
|
+
EXAMPLES::
|
|
1015
|
+
|
|
1016
|
+
sage: from sage.misc.lazy_list import lazy_list_from_function
|
|
1017
|
+
sage: lazy_list_from_function(euler_phi) # needs sage.libs.pari
|
|
1018
|
+
lazy list [0, 1, 1, ...]
|
|
1019
|
+
sage: lazy_list_from_function(divisors, [None])
|
|
1020
|
+
lazy list [None, [1], [1, 2], ...]
|
|
1021
|
+
|
|
1022
|
+
TESTS::
|
|
1023
|
+
|
|
1024
|
+
sage: def f(n):
|
|
1025
|
+
....: if n >= 5: raise StopIteration
|
|
1026
|
+
....: return 5 - n
|
|
1027
|
+
sage: list(lazy_list_from_function(f))
|
|
1028
|
+
[5, 4, 3, 2, 1]
|
|
1029
|
+
"""
|
|
1030
|
+
self.callable = function
|
|
1031
|
+
lazy_list_generic.__init__(self, cache)
|
|
1032
|
+
|
|
1033
|
+
cpdef int _update_cache_up_to(self, Py_ssize_t i) except -1:
|
|
1034
|
+
r"""
|
|
1035
|
+
Update the cache up to ``i``.
|
|
1036
|
+
|
|
1037
|
+
OUTPUT:
|
|
1038
|
+
|
|
1039
|
+
- ``-1`` -- a Python error occurred
|
|
1040
|
+
|
|
1041
|
+
- ``0`` -- everything went fine
|
|
1042
|
+
|
|
1043
|
+
- ``1`` -- the iterator stopped before ``i``
|
|
1044
|
+
|
|
1045
|
+
TESTS::
|
|
1046
|
+
|
|
1047
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
1048
|
+
sage: L = lazy_list(lambda x: 2*x)[2:]
|
|
1049
|
+
sage: L._update_cache_up_to(4)
|
|
1050
|
+
0
|
|
1051
|
+
sage: L._info()
|
|
1052
|
+
cache length 5
|
|
1053
|
+
start 2
|
|
1054
|
+
stop 9223372036854775807 # 64-bit
|
|
1055
|
+
stop 2147483647 # 32-bit
|
|
1056
|
+
step 1
|
|
1057
|
+
"""
|
|
1058
|
+
while len(self.cache) <= i:
|
|
1059
|
+
try:
|
|
1060
|
+
value = self.callable(len(self.cache))
|
|
1061
|
+
except StopIteration:
|
|
1062
|
+
return 1
|
|
1063
|
+
self.cache.append(value)
|
|
1064
|
+
|
|
1065
|
+
def __reduce__(self):
|
|
1066
|
+
r"""
|
|
1067
|
+
TESTS::
|
|
1068
|
+
|
|
1069
|
+
sage: from sage.misc.lazy_list import lazy_list_from_function
|
|
1070
|
+
sage: loads(dumps(lazy_list_from_function(euler_phi))) # needs sage.libs.pari
|
|
1071
|
+
lazy list [0, 1, 1, ...]
|
|
1072
|
+
sage: loads(dumps(lazy_list_from_function(divisors, [None])))
|
|
1073
|
+
lazy list [None, [1], [1, 2], ...]
|
|
1074
|
+
"""
|
|
1075
|
+
if self.start != 0 or self.step != 1:
|
|
1076
|
+
raise RuntimeError
|
|
1077
|
+
return lazy_list_from_function, (self.callable, self.cache, self.stop)
|
|
1078
|
+
|
|
1079
|
+
|
|
1080
|
+
cdef class lazy_list_from_update_function(lazy_list_generic):
|
|
1081
|
+
|
|
1082
|
+
def __init__(self, function, cache=None, stop=None):
|
|
1083
|
+
r"""
|
|
1084
|
+
INPUT:
|
|
1085
|
+
|
|
1086
|
+
- ``function`` -- a function that updates a list of precomputed values
|
|
1087
|
+
The update function should take as input a list and make it longer
|
|
1088
|
+
(using either the methods ``append`` or ``extend``). If after a call
|
|
1089
|
+
to the update function the list of values is shorter a
|
|
1090
|
+
:exc:`RuntimeError` will occur. If no value is added then the lazy list
|
|
1091
|
+
is considered finite.
|
|
1092
|
+
|
|
1093
|
+
- ``cache`` -- an optional list to be used as the cache. Be careful that
|
|
1094
|
+
there is no copy
|
|
1095
|
+
|
|
1096
|
+
- ``stop`` -- an optional integer to specify the length of this lazy list
|
|
1097
|
+
(otherwise it is considered infinite)
|
|
1098
|
+
|
|
1099
|
+
TESTS::
|
|
1100
|
+
|
|
1101
|
+
sage: from sage.misc.lazy_list import lazy_list_from_update_function
|
|
1102
|
+
sage: def update_function(values):
|
|
1103
|
+
....: n = len(values)+1
|
|
1104
|
+
....: values.extend([n]*n)
|
|
1105
|
+
sage: l = lazy_list_from_update_function(update_function)
|
|
1106
|
+
sage: l[:20].list()
|
|
1107
|
+
[1, 2, 2, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16]
|
|
1108
|
+
"""
|
|
1109
|
+
self.update_function = function
|
|
1110
|
+
lazy_list_generic.__init__(self, cache, None, stop, None)
|
|
1111
|
+
|
|
1112
|
+
cpdef int _update_cache_up_to(self, Py_ssize_t i) except -1:
|
|
1113
|
+
r"""
|
|
1114
|
+
Update the cache up to ``i``.
|
|
1115
|
+
|
|
1116
|
+
OUTPUT:
|
|
1117
|
+
|
|
1118
|
+
- ``-1`` -- a Python error occurred
|
|
1119
|
+
|
|
1120
|
+
- ``0`` -- everything went fine
|
|
1121
|
+
|
|
1122
|
+
- ``1`` -- the iterator stopped before ``i``
|
|
1123
|
+
|
|
1124
|
+
TESTS::
|
|
1125
|
+
|
|
1126
|
+
sage: from sage.misc.lazy_list import lazy_list_from_update_function
|
|
1127
|
+
sage: def update_function(values):
|
|
1128
|
+
....: n = len(values)+1
|
|
1129
|
+
....: values.extend([n]*n)
|
|
1130
|
+
sage: L = lazy_list_from_update_function(update_function)[2:]
|
|
1131
|
+
sage: L._update_cache_up_to(4)
|
|
1132
|
+
0
|
|
1133
|
+
sage: L._info()
|
|
1134
|
+
cache length 7
|
|
1135
|
+
start 2
|
|
1136
|
+
stop 9223372036854775807 # 64-bit
|
|
1137
|
+
stop 2147483647 # 32-bit
|
|
1138
|
+
step 1
|
|
1139
|
+
"""
|
|
1140
|
+
cdef Py_ssize_t l, ll
|
|
1141
|
+
l = len(self.cache)
|
|
1142
|
+
while l <= i:
|
|
1143
|
+
self.update_function(self.cache)
|
|
1144
|
+
ll = len(self.cache)
|
|
1145
|
+
if ll < l:
|
|
1146
|
+
raise RuntimeError("the update function made the cache shorter")
|
|
1147
|
+
elif l == ll:
|
|
1148
|
+
return 1
|
|
1149
|
+
l = ll
|
|
1150
|
+
return 0
|
|
1151
|
+
|
|
1152
|
+
def __reduce__(self):
|
|
1153
|
+
r"""
|
|
1154
|
+
TESTS::
|
|
1155
|
+
|
|
1156
|
+
sage: from sage.misc.lazy_list import lazy_list
|
|
1157
|
+
|
|
1158
|
+
sage: def my_update_function(values): values.append(ZZ(len(values)).is_prime())
|
|
1159
|
+
sage: l = lazy_list(update_function=my_update_function)
|
|
1160
|
+
sage: l[4]
|
|
1161
|
+
False
|
|
1162
|
+
sage: loads(dumps(l)) # not tested (works in console though)
|
|
1163
|
+
lazy list [False, False, True, ...]
|
|
1164
|
+
|
|
1165
|
+
sage: def say_hey(cache): print("hey")
|
|
1166
|
+
sage: l = lazy_list(update_function=say_hey, initial_values=range(10))
|
|
1167
|
+
sage: l._fit(10)
|
|
1168
|
+
hey
|
|
1169
|
+
1
|
|
1170
|
+
sage: l._info()
|
|
1171
|
+
cache length 10
|
|
1172
|
+
start 0
|
|
1173
|
+
stop 10
|
|
1174
|
+
step 1
|
|
1175
|
+
sage: l2 = loads(dumps(l)) # not tested
|
|
1176
|
+
sage: l2._info() # not tested
|
|
1177
|
+
sage: l2._info() # not tested
|
|
1178
|
+
cache length 10
|
|
1179
|
+
start 0
|
|
1180
|
+
stop 10
|
|
1181
|
+
step 1
|
|
1182
|
+
sage: l.list() == l2.list() # not tested
|
|
1183
|
+
True
|
|
1184
|
+
"""
|
|
1185
|
+
if self.start != 0 or self.step != 1:
|
|
1186
|
+
raise RuntimeError
|
|
1187
|
+
return lazy_list_from_update_function, (self.update_function, self.cache, self.stop)
|