passagemath-objects 10.6.47__cp311-cp311-macosx_13_0_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. passagemath_objects/.dylibs/libgmp.10.dylib +0 -0
  2. passagemath_objects/__init__.py +3 -0
  3. passagemath_objects-10.6.47.dist-info/METADATA +115 -0
  4. passagemath_objects-10.6.47.dist-info/RECORD +280 -0
  5. passagemath_objects-10.6.47.dist-info/WHEEL +6 -0
  6. passagemath_objects-10.6.47.dist-info/top_level.txt +3 -0
  7. sage/all__sagemath_objects.py +37 -0
  8. sage/arith/all__sagemath_objects.py +5 -0
  9. sage/arith/long.pxd +411 -0
  10. sage/arith/numerical_approx.cpython-311-darwin.so +0 -0
  11. sage/arith/numerical_approx.pxd +35 -0
  12. sage/arith/numerical_approx.pyx +75 -0
  13. sage/arith/power.cpython-311-darwin.so +0 -0
  14. sage/arith/power.pxd +31 -0
  15. sage/arith/power.pyx +127 -0
  16. sage/categories/action.cpython-311-darwin.so +0 -0
  17. sage/categories/action.pxd +29 -0
  18. sage/categories/action.pyx +641 -0
  19. sage/categories/algebra_functor.py +745 -0
  20. sage/categories/all__sagemath_objects.py +33 -0
  21. sage/categories/basic.py +62 -0
  22. sage/categories/cartesian_product.py +295 -0
  23. sage/categories/category.py +3401 -0
  24. sage/categories/category_cy_helper.cpython-311-darwin.so +0 -0
  25. sage/categories/category_cy_helper.pxd +8 -0
  26. sage/categories/category_cy_helper.pyx +322 -0
  27. sage/categories/category_singleton.cpython-311-darwin.so +0 -0
  28. sage/categories/category_singleton.pxd +3 -0
  29. sage/categories/category_singleton.pyx +342 -0
  30. sage/categories/category_types.py +637 -0
  31. sage/categories/category_with_axiom.py +2876 -0
  32. sage/categories/covariant_functorial_construction.py +703 -0
  33. sage/categories/facade_sets.py +228 -0
  34. sage/categories/functor.cpython-311-darwin.so +0 -0
  35. sage/categories/functor.pxd +7 -0
  36. sage/categories/functor.pyx +691 -0
  37. sage/categories/homset.py +1338 -0
  38. sage/categories/homsets.py +364 -0
  39. sage/categories/isomorphic_objects.py +73 -0
  40. sage/categories/map.cpython-311-darwin.so +0 -0
  41. sage/categories/map.pxd +34 -0
  42. sage/categories/map.pyx +2106 -0
  43. sage/categories/morphism.cpython-311-darwin.so +0 -0
  44. sage/categories/morphism.pxd +14 -0
  45. sage/categories/morphism.pyx +895 -0
  46. sage/categories/objects.py +167 -0
  47. sage/categories/primer.py +1696 -0
  48. sage/categories/pushout.py +4834 -0
  49. sage/categories/quotients.py +64 -0
  50. sage/categories/realizations.py +200 -0
  51. sage/categories/sets_cat.py +3290 -0
  52. sage/categories/sets_with_partial_maps.py +52 -0
  53. sage/categories/subobjects.py +64 -0
  54. sage/categories/subquotients.py +21 -0
  55. sage/categories/with_realizations.py +311 -0
  56. sage/cpython/__init__.py +19 -0
  57. sage/cpython/_py2_random.py +619 -0
  58. sage/cpython/all.py +3 -0
  59. sage/cpython/atexit.cpython-311-darwin.so +0 -0
  60. sage/cpython/atexit.pyx +269 -0
  61. sage/cpython/builtin_types.cpython-311-darwin.so +0 -0
  62. sage/cpython/builtin_types.pyx +7 -0
  63. sage/cpython/cython_metaclass.cpython-311-darwin.so +0 -0
  64. sage/cpython/cython_metaclass.h +117 -0
  65. sage/cpython/cython_metaclass.pxd +3 -0
  66. sage/cpython/cython_metaclass.pyx +130 -0
  67. sage/cpython/debug.cpython-311-darwin.so +0 -0
  68. sage/cpython/debug.pyx +302 -0
  69. sage/cpython/dict_del_by_value.cpython-311-darwin.so +0 -0
  70. sage/cpython/dict_del_by_value.pxd +9 -0
  71. sage/cpython/dict_del_by_value.pyx +191 -0
  72. sage/cpython/dict_internal.h +245 -0
  73. sage/cpython/getattr.cpython-311-darwin.so +0 -0
  74. sage/cpython/getattr.pxd +9 -0
  75. sage/cpython/getattr.pyx +439 -0
  76. sage/cpython/pycore_long.h +97 -0
  77. sage/cpython/pycore_long.pxd +10 -0
  78. sage/cpython/python_debug.h +44 -0
  79. sage/cpython/python_debug.pxd +47 -0
  80. sage/cpython/pyx_visit.h +13 -0
  81. sage/cpython/string.cpython-311-darwin.so +0 -0
  82. sage/cpython/string.pxd +76 -0
  83. sage/cpython/string.pyx +34 -0
  84. sage/cpython/string_impl.h +60 -0
  85. sage/cpython/type.cpython-311-darwin.so +0 -0
  86. sage/cpython/type.pxd +2 -0
  87. sage/cpython/type.pyx +40 -0
  88. sage/cpython/wrapperdescr.pxd +67 -0
  89. sage/ext/all__sagemath_objects.py +3 -0
  90. sage/ext/ccobject.h +64 -0
  91. sage/ext/cplusplus.pxd +17 -0
  92. sage/ext/mod_int.h +30 -0
  93. sage/ext/mod_int.pxd +24 -0
  94. sage/ext/stdsage.pxd +39 -0
  95. sage/groups/all__sagemath_objects.py +1 -0
  96. sage/groups/group.cpython-311-darwin.so +0 -0
  97. sage/groups/group.pxd +14 -0
  98. sage/groups/group.pyx +322 -0
  99. sage/groups/old.cpython-311-darwin.so +0 -0
  100. sage/groups/old.pxd +14 -0
  101. sage/groups/old.pyx +219 -0
  102. sage/libs/all__sagemath_objects.py +3 -0
  103. sage/libs/gmp/__init__.py +1 -0
  104. sage/libs/gmp/all.pxd +6 -0
  105. sage/libs/gmp/binop.pxd +23 -0
  106. sage/libs/gmp/misc.pxd +8 -0
  107. sage/libs/gmp/mpf.pxd +88 -0
  108. sage/libs/gmp/mpn.pxd +57 -0
  109. sage/libs/gmp/mpq.pxd +57 -0
  110. sage/libs/gmp/mpz.pxd +202 -0
  111. sage/libs/gmp/pylong.cpython-311-darwin.so +0 -0
  112. sage/libs/gmp/pylong.pxd +12 -0
  113. sage/libs/gmp/pylong.pyx +150 -0
  114. sage/libs/gmp/random.pxd +25 -0
  115. sage/libs/gmp/randomize.pxd +59 -0
  116. sage/libs/gmp/types.pxd +53 -0
  117. sage/libs/gmpxx.pxd +19 -0
  118. sage/misc/abstract_method.py +276 -0
  119. sage/misc/all__sagemath_objects.py +43 -0
  120. sage/misc/bindable_class.py +253 -0
  121. sage/misc/c3_controlled.cpython-311-darwin.so +0 -0
  122. sage/misc/c3_controlled.pxd +2 -0
  123. sage/misc/c3_controlled.pyx +1402 -0
  124. sage/misc/cachefunc.cpython-311-darwin.so +0 -0
  125. sage/misc/cachefunc.pxd +43 -0
  126. sage/misc/cachefunc.pyx +3781 -0
  127. sage/misc/call.py +188 -0
  128. sage/misc/classcall_metaclass.cpython-311-darwin.so +0 -0
  129. sage/misc/classcall_metaclass.pxd +14 -0
  130. sage/misc/classcall_metaclass.pyx +599 -0
  131. sage/misc/constant_function.cpython-311-darwin.so +0 -0
  132. sage/misc/constant_function.pyx +130 -0
  133. sage/misc/decorators.py +747 -0
  134. sage/misc/fast_methods.cpython-311-darwin.so +0 -0
  135. sage/misc/fast_methods.pxd +20 -0
  136. sage/misc/fast_methods.pyx +351 -0
  137. sage/misc/flatten.py +90 -0
  138. sage/misc/fpickle.cpython-311-darwin.so +0 -0
  139. sage/misc/fpickle.pyx +177 -0
  140. sage/misc/function_mangling.cpython-311-darwin.so +0 -0
  141. sage/misc/function_mangling.pxd +11 -0
  142. sage/misc/function_mangling.pyx +308 -0
  143. sage/misc/inherit_comparison.cpython-311-darwin.so +0 -0
  144. sage/misc/inherit_comparison.pxd +5 -0
  145. sage/misc/inherit_comparison.pyx +105 -0
  146. sage/misc/instancedoc.cpython-311-darwin.so +0 -0
  147. sage/misc/instancedoc.pyx +331 -0
  148. sage/misc/lazy_attribute.cpython-311-darwin.so +0 -0
  149. sage/misc/lazy_attribute.pyx +607 -0
  150. sage/misc/lazy_format.py +135 -0
  151. sage/misc/lazy_import.cpython-311-darwin.so +0 -0
  152. sage/misc/lazy_import.pyx +1299 -0
  153. sage/misc/lazy_import_cache.py +36 -0
  154. sage/misc/lazy_list.cpython-311-darwin.so +0 -0
  155. sage/misc/lazy_list.pxd +19 -0
  156. sage/misc/lazy_list.pyx +1187 -0
  157. sage/misc/lazy_string.cpython-311-darwin.so +0 -0
  158. sage/misc/lazy_string.pxd +7 -0
  159. sage/misc/lazy_string.pyx +546 -0
  160. sage/misc/misc.py +1066 -0
  161. sage/misc/misc_c.cpython-311-darwin.so +0 -0
  162. sage/misc/misc_c.pxd +3 -0
  163. sage/misc/misc_c.pyx +766 -0
  164. sage/misc/namespace_package.py +37 -0
  165. sage/misc/nested_class.cpython-311-darwin.so +0 -0
  166. sage/misc/nested_class.pxd +3 -0
  167. sage/misc/nested_class.pyx +394 -0
  168. sage/misc/persist.cpython-311-darwin.so +0 -0
  169. sage/misc/persist.pyx +1251 -0
  170. sage/misc/prandom.py +418 -0
  171. sage/misc/randstate.cpython-311-darwin.so +0 -0
  172. sage/misc/randstate.pxd +30 -0
  173. sage/misc/randstate.pyx +1059 -0
  174. sage/misc/repr.py +203 -0
  175. sage/misc/reset.cpython-311-darwin.so +0 -0
  176. sage/misc/reset.pyx +196 -0
  177. sage/misc/sage_ostools.cpython-311-darwin.so +0 -0
  178. sage/misc/sage_ostools.pyx +323 -0
  179. sage/misc/sage_timeit.py +275 -0
  180. sage/misc/sage_timeit_class.cpython-311-darwin.so +0 -0
  181. sage/misc/sage_timeit_class.pyx +120 -0
  182. sage/misc/sage_unittest.py +637 -0
  183. sage/misc/sageinspect.py +2768 -0
  184. sage/misc/session.cpython-311-darwin.so +0 -0
  185. sage/misc/session.pyx +392 -0
  186. sage/misc/superseded.py +557 -0
  187. sage/misc/test_nested_class.py +228 -0
  188. sage/misc/timing.py +264 -0
  189. sage/misc/unknown.py +222 -0
  190. sage/misc/verbose.py +253 -0
  191. sage/misc/weak_dict.cpython-311-darwin.so +0 -0
  192. sage/misc/weak_dict.pxd +15 -0
  193. sage/misc/weak_dict.pyx +1231 -0
  194. sage/modules/all__sagemath_objects.py +1 -0
  195. sage/modules/module.cpython-311-darwin.so +0 -0
  196. sage/modules/module.pxd +5 -0
  197. sage/modules/module.pyx +329 -0
  198. sage/rings/all__sagemath_objects.py +3 -0
  199. sage/rings/integer_fake.h +22 -0
  200. sage/rings/integer_fake.pxd +55 -0
  201. sage/sets/all__sagemath_objects.py +3 -0
  202. sage/sets/pythonclass.cpython-311-darwin.so +0 -0
  203. sage/sets/pythonclass.pxd +9 -0
  204. sage/sets/pythonclass.pyx +247 -0
  205. sage/structure/__init__.py +4 -0
  206. sage/structure/all.py +30 -0
  207. sage/structure/category_object.cpython-311-darwin.so +0 -0
  208. sage/structure/category_object.pxd +28 -0
  209. sage/structure/category_object.pyx +1087 -0
  210. sage/structure/coerce.cpython-311-darwin.so +0 -0
  211. sage/structure/coerce.pxd +44 -0
  212. sage/structure/coerce.pyx +2107 -0
  213. sage/structure/coerce_actions.cpython-311-darwin.so +0 -0
  214. sage/structure/coerce_actions.pxd +27 -0
  215. sage/structure/coerce_actions.pyx +988 -0
  216. sage/structure/coerce_dict.cpython-311-darwin.so +0 -0
  217. sage/structure/coerce_dict.pxd +51 -0
  218. sage/structure/coerce_dict.pyx +1557 -0
  219. sage/structure/coerce_exceptions.py +23 -0
  220. sage/structure/coerce_maps.cpython-311-darwin.so +0 -0
  221. sage/structure/coerce_maps.pxd +28 -0
  222. sage/structure/coerce_maps.pyx +718 -0
  223. sage/structure/debug_options.cpython-311-darwin.so +0 -0
  224. sage/structure/debug_options.pxd +6 -0
  225. sage/structure/debug_options.pyx +54 -0
  226. sage/structure/dynamic_class.py +541 -0
  227. sage/structure/element.cpython-311-darwin.so +0 -0
  228. sage/structure/element.pxd +272 -0
  229. sage/structure/element.pyx +4772 -0
  230. sage/structure/element_wrapper.cpython-311-darwin.so +0 -0
  231. sage/structure/element_wrapper.pxd +12 -0
  232. sage/structure/element_wrapper.pyx +582 -0
  233. sage/structure/factorization.py +1422 -0
  234. sage/structure/factorization_integer.py +105 -0
  235. sage/structure/factory.cpython-311-darwin.so +0 -0
  236. sage/structure/factory.pyx +786 -0
  237. sage/structure/formal_sum.py +489 -0
  238. sage/structure/gens_py.py +73 -0
  239. sage/structure/global_options.py +1743 -0
  240. sage/structure/indexed_generators.py +863 -0
  241. sage/structure/list_clone.cpython-311-darwin.so +0 -0
  242. sage/structure/list_clone.pxd +65 -0
  243. sage/structure/list_clone.pyx +1867 -0
  244. sage/structure/list_clone_demo.cpython-311-darwin.so +0 -0
  245. sage/structure/list_clone_demo.pyx +248 -0
  246. sage/structure/list_clone_timings.py +179 -0
  247. sage/structure/list_clone_timings_cy.cpython-311-darwin.so +0 -0
  248. sage/structure/list_clone_timings_cy.pyx +86 -0
  249. sage/structure/mutability.cpython-311-darwin.so +0 -0
  250. sage/structure/mutability.pxd +21 -0
  251. sage/structure/mutability.pyx +348 -0
  252. sage/structure/nonexact.py +69 -0
  253. sage/structure/parent.cpython-311-darwin.so +0 -0
  254. sage/structure/parent.pxd +112 -0
  255. sage/structure/parent.pyx +3093 -0
  256. sage/structure/parent_base.cpython-311-darwin.so +0 -0
  257. sage/structure/parent_base.pxd +13 -0
  258. sage/structure/parent_base.pyx +44 -0
  259. sage/structure/parent_gens.cpython-311-darwin.so +0 -0
  260. sage/structure/parent_gens.pxd +22 -0
  261. sage/structure/parent_gens.pyx +377 -0
  262. sage/structure/parent_old.cpython-311-darwin.so +0 -0
  263. sage/structure/parent_old.pxd +25 -0
  264. sage/structure/parent_old.pyx +294 -0
  265. sage/structure/proof/__init__.py +1 -0
  266. sage/structure/proof/all.py +243 -0
  267. sage/structure/proof/proof.py +300 -0
  268. sage/structure/richcmp.cpython-311-darwin.so +0 -0
  269. sage/structure/richcmp.pxd +213 -0
  270. sage/structure/richcmp.pyx +495 -0
  271. sage/structure/sage_object.cpython-311-darwin.so +0 -0
  272. sage/structure/sage_object.pxd +3 -0
  273. sage/structure/sage_object.pyx +988 -0
  274. sage/structure/sage_object_test.py +19 -0
  275. sage/structure/sequence.py +937 -0
  276. sage/structure/set_factories.py +1178 -0
  277. sage/structure/set_factories_example.py +527 -0
  278. sage/structure/support_view.py +179 -0
  279. sage/structure/test_factory.py +56 -0
  280. sage/structure/unique_representation.py +1359 -0
@@ -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)