passagemath-symbolics 10.6.43__cp314-cp314t-musllinux_1_2_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of passagemath-symbolics might be problematic. Click here for more details.

Files changed (171) hide show
  1. passagemath_symbolics/__init__.py +3 -0
  2. passagemath_symbolics-10.6.43.dist-info/METADATA +187 -0
  3. passagemath_symbolics-10.6.43.dist-info/RECORD +171 -0
  4. passagemath_symbolics-10.6.43.dist-info/WHEEL +5 -0
  5. passagemath_symbolics-10.6.43.dist-info/top_level.txt +3 -0
  6. sage/all__sagemath_symbolics.py +17 -0
  7. sage/calculus/all.py +14 -0
  8. sage/calculus/calculus.py +2826 -0
  9. sage/calculus/desolvers.py +1866 -0
  10. sage/calculus/predefined.py +51 -0
  11. sage/calculus/tests.py +225 -0
  12. sage/calculus/var.cpython-314t-x86_64-linux-musl.so +0 -0
  13. sage/calculus/var.pyx +401 -0
  14. sage/dynamics/all__sagemath_symbolics.py +6 -0
  15. sage/dynamics/complex_dynamics/all.py +5 -0
  16. sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
  17. sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-314t-x86_64-linux-musl.so +0 -0
  18. sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1035 -0
  19. sage/ext/all__sagemath_symbolics.py +1 -0
  20. sage/ext_data/kenzo/CP2.txt +45 -0
  21. sage/ext_data/kenzo/CP3.txt +349 -0
  22. sage/ext_data/kenzo/CP4.txt +4774 -0
  23. sage/ext_data/kenzo/README.txt +49 -0
  24. sage/ext_data/kenzo/S4.txt +20 -0
  25. sage/ext_data/magma/latex/latex.m +1021 -0
  26. sage/ext_data/magma/latex/latex.spec +1 -0
  27. sage/ext_data/magma/sage/basic.m +356 -0
  28. sage/ext_data/magma/sage/sage.spec +1 -0
  29. sage/ext_data/magma/spec +9 -0
  30. sage/geometry/all__sagemath_symbolics.py +8 -0
  31. sage/geometry/hyperbolic_space/all.py +5 -0
  32. sage/geometry/hyperbolic_space/hyperbolic_coercion.py +743 -0
  33. sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
  34. sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2409 -0
  35. sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
  36. sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1082 -0
  37. sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
  38. sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
  39. sage/geometry/riemannian_manifolds/all.py +7 -0
  40. sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
  41. sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
  42. sage/interfaces/all__sagemath_symbolics.py +1 -0
  43. sage/interfaces/magma.py +3017 -0
  44. sage/interfaces/magma_free.py +92 -0
  45. sage/interfaces/maple.py +1397 -0
  46. sage/interfaces/mathematica.py +1345 -0
  47. sage/interfaces/mathics.py +1312 -0
  48. sage/interfaces/sympy.py +1398 -0
  49. sage/interfaces/sympy_wrapper.py +197 -0
  50. sage/interfaces/tides.py +938 -0
  51. sage/libs/all__sagemath_symbolics.py +6 -0
  52. sage/manifolds/all.py +7 -0
  53. sage/manifolds/calculus_method.py +555 -0
  54. sage/manifolds/catalog.py +437 -0
  55. sage/manifolds/chart.py +4019 -0
  56. sage/manifolds/chart_func.py +3419 -0
  57. sage/manifolds/continuous_map.py +2183 -0
  58. sage/manifolds/continuous_map_image.py +155 -0
  59. sage/manifolds/differentiable/affine_connection.py +2475 -0
  60. sage/manifolds/differentiable/all.py +1 -0
  61. sage/manifolds/differentiable/automorphismfield.py +1383 -0
  62. sage/manifolds/differentiable/automorphismfield_group.py +604 -0
  63. sage/manifolds/differentiable/bundle_connection.py +1445 -0
  64. sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
  65. sage/manifolds/differentiable/chart.py +1241 -0
  66. sage/manifolds/differentiable/curve.py +1028 -0
  67. sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
  68. sage/manifolds/differentiable/degenerate.py +559 -0
  69. sage/manifolds/differentiable/degenerate_submanifold.py +1671 -0
  70. sage/manifolds/differentiable/diff_form.py +1658 -0
  71. sage/manifolds/differentiable/diff_form_module.py +1062 -0
  72. sage/manifolds/differentiable/diff_map.py +1315 -0
  73. sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
  74. sage/manifolds/differentiable/examples/all.py +1 -0
  75. sage/manifolds/differentiable/examples/euclidean.py +2517 -0
  76. sage/manifolds/differentiable/examples/real_line.py +897 -0
  77. sage/manifolds/differentiable/examples/sphere.py +1186 -0
  78. sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
  79. sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
  80. sage/manifolds/differentiable/integrated_curve.py +4035 -0
  81. sage/manifolds/differentiable/levi_civita_connection.py +841 -0
  82. sage/manifolds/differentiable/manifold.py +4254 -0
  83. sage/manifolds/differentiable/manifold_homset.py +1826 -0
  84. sage/manifolds/differentiable/metric.py +3032 -0
  85. sage/manifolds/differentiable/mixed_form.py +1507 -0
  86. sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
  87. sage/manifolds/differentiable/multivector_module.py +800 -0
  88. sage/manifolds/differentiable/multivectorfield.py +1520 -0
  89. sage/manifolds/differentiable/poisson_tensor.py +268 -0
  90. sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
  91. sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
  92. sage/manifolds/differentiable/scalarfield.py +1343 -0
  93. sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
  94. sage/manifolds/differentiable/symplectic_form.py +910 -0
  95. sage/manifolds/differentiable/symplectic_form_test.py +220 -0
  96. sage/manifolds/differentiable/tangent_space.py +412 -0
  97. sage/manifolds/differentiable/tangent_vector.py +616 -0
  98. sage/manifolds/differentiable/tensorfield.py +4665 -0
  99. sage/manifolds/differentiable/tensorfield_module.py +963 -0
  100. sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
  101. sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
  102. sage/manifolds/differentiable/vector_bundle.py +1728 -0
  103. sage/manifolds/differentiable/vectorfield.py +1717 -0
  104. sage/manifolds/differentiable/vectorfield_module.py +2445 -0
  105. sage/manifolds/differentiable/vectorframe.py +1832 -0
  106. sage/manifolds/family.py +270 -0
  107. sage/manifolds/local_frame.py +1490 -0
  108. sage/manifolds/manifold.py +3090 -0
  109. sage/manifolds/manifold_homset.py +452 -0
  110. sage/manifolds/operators.py +359 -0
  111. sage/manifolds/point.py +994 -0
  112. sage/manifolds/scalarfield.py +3718 -0
  113. sage/manifolds/scalarfield_algebra.py +629 -0
  114. sage/manifolds/section.py +3111 -0
  115. sage/manifolds/section_module.py +831 -0
  116. sage/manifolds/structure.py +229 -0
  117. sage/manifolds/subset.py +2764 -0
  118. sage/manifolds/subsets/all.py +1 -0
  119. sage/manifolds/subsets/closure.py +131 -0
  120. sage/manifolds/subsets/pullback.py +885 -0
  121. sage/manifolds/topological_submanifold.py +891 -0
  122. sage/manifolds/trivialization.py +733 -0
  123. sage/manifolds/utilities.py +1348 -0
  124. sage/manifolds/vector_bundle.py +1342 -0
  125. sage/manifolds/vector_bundle_fiber.py +332 -0
  126. sage/manifolds/vector_bundle_fiber_element.py +111 -0
  127. sage/matrix/all__sagemath_symbolics.py +1 -0
  128. sage/matrix/matrix_symbolic_dense.cpython-314t-x86_64-linux-musl.so +0 -0
  129. sage/matrix/matrix_symbolic_dense.pxd +6 -0
  130. sage/matrix/matrix_symbolic_dense.pyx +1022 -0
  131. sage/matrix/matrix_symbolic_sparse.cpython-314t-x86_64-linux-musl.so +0 -0
  132. sage/matrix/matrix_symbolic_sparse.pxd +6 -0
  133. sage/matrix/matrix_symbolic_sparse.pyx +1029 -0
  134. sage/modules/all__sagemath_symbolics.py +1 -0
  135. sage/modules/vector_callable_symbolic_dense.py +105 -0
  136. sage/modules/vector_symbolic_dense.py +116 -0
  137. sage/modules/vector_symbolic_sparse.py +118 -0
  138. sage/rings/all__sagemath_symbolics.py +4 -0
  139. sage/rings/asymptotic/all.py +6 -0
  140. sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
  141. sage/rings/asymptotic/asymptotic_ring.py +4858 -0
  142. sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4153 -0
  143. sage/rings/asymptotic/growth_group.py +5373 -0
  144. sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
  145. sage/rings/asymptotic/term_monoid.py +5237 -0
  146. sage/rings/function_field/all__sagemath_symbolics.py +2 -0
  147. sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
  148. sage/symbolic/all.py +15 -0
  149. sage/symbolic/assumptions.py +985 -0
  150. sage/symbolic/benchmark.py +93 -0
  151. sage/symbolic/callable.py +459 -0
  152. sage/symbolic/complexity_measures.py +35 -0
  153. sage/symbolic/constants.py +1287 -0
  154. sage/symbolic/expression_conversion_algebraic.py +310 -0
  155. sage/symbolic/expression_conversion_sympy.py +317 -0
  156. sage/symbolic/expression_conversions.py +1713 -0
  157. sage/symbolic/function_factory.py +355 -0
  158. sage/symbolic/integration/all.py +1 -0
  159. sage/symbolic/integration/external.py +270 -0
  160. sage/symbolic/integration/integral.py +1115 -0
  161. sage/symbolic/maxima_wrapper.py +162 -0
  162. sage/symbolic/operators.py +267 -0
  163. sage/symbolic/random_tests.py +462 -0
  164. sage/symbolic/relation.py +1907 -0
  165. sage/symbolic/ring.cpython-314t-x86_64-linux-musl.so +0 -0
  166. sage/symbolic/ring.pxd +5 -0
  167. sage/symbolic/ring.pyx +1396 -0
  168. sage/symbolic/subring.py +1025 -0
  169. sage/symbolic/symengine.py +19 -0
  170. sage/symbolic/tests.py +40 -0
  171. sage/symbolic/units.py +1470 -0
@@ -0,0 +1,4858 @@
1
+ # sage_setup: distribution = sagemath-symbolics
2
+ # sage.doctest: needs sage.graphs
3
+ r"""
4
+ Asymptotic Ring
5
+
6
+ This module provides a ring (called :class:`AsymptoticRing`) for
7
+ computations with :wikipedia:`asymptotic expansions <Asymptotic_expansion>`.
8
+
9
+
10
+ .. _asymptotic_ring_definition:
11
+
12
+ (Informal) Definition
13
+ =====================
14
+
15
+ An asymptotic expansion is a sum such as
16
+
17
+ .. MATH::
18
+
19
+ 5z^3 + 4z^2 + O(z)
20
+
21
+ as `z \to \infty` or
22
+
23
+ .. MATH::
24
+
25
+ 3x^{42}y^2 + 7x^3y^3 + O(x^2) + O(y)
26
+
27
+ as `x` and `y` tend to `\infty`. It is a truncated series (after a
28
+ finite number of terms), which approximates a function.
29
+
30
+ The summands of the asymptotic expansions are partially ordered. In
31
+ this module these summands are the following:
32
+
33
+ - Exact terms `c\cdot g` with a coefficient `c` and an element `g` of
34
+ a growth group (:ref:`see below <asymptotic_ring_growth>`).
35
+
36
+ - `O`-terms `O(g)` (see :wikipedia:`Big O notation <Big_O_notation>`;
37
+ also called *Bachmann--Landau notation*) for a growth group
38
+ element `g` (:ref:`again see below <asymptotic_ring_growth>`).
39
+
40
+ See
41
+ :wikipedia:`the Wikipedia article on asymptotic expansions <Asymptotic_expansion>`
42
+ for more details.
43
+ Further examples of such elements can be found :ref:`here <asymptotic_ring_intro>`.
44
+
45
+
46
+ .. _asymptotic_ring_growth:
47
+
48
+ Growth Groups and Elements
49
+ --------------------------
50
+
51
+ The elements of a :doc:`growth group <growth_group>` are equipped with
52
+ a partial order and usually contain a variable. Examples---the order
53
+ is described below these examples---are
54
+
55
+ - elements of the form `z^q` for some integer or rational `q`
56
+ (growth groups with :ref:`description strings <growth_group_description>`
57
+ ``z^ZZ`` or ``z^QQ``),
58
+
59
+ - elements of the form `\log(z)^q` for some integer or rational `q`
60
+ (growth groups ``log(z)^ZZ`` or ``log(z)^QQ``),
61
+
62
+ - elements of the form `a^z` for some
63
+ rational `a` (growth group ``QQ^z``), or
64
+
65
+ - more sophisticated constructions like products
66
+ `x^r \cdot \log(x)^s \cdot a^y \cdot y^q`
67
+ (this corresponds to an element of the growth group
68
+ ``x^QQ * log(x)^ZZ * QQ^y * y^QQ``).
69
+
70
+ The order in all these examples is induced by the magnitude of the
71
+ elements as `x`, `y`, or `z` (independently) tend to `\infty`. For
72
+ elements only using the variable `z` this means that `g_1 \leq g_2` if
73
+
74
+ .. MATH::
75
+
76
+ \lim_{z\to\infty} \frac{g_1}{g_2} \leq 1.
77
+
78
+ .. NOTE::
79
+
80
+ Asymptotic rings where the variable tend to some value distinct from
81
+ `\infty` are not yet implemented.
82
+
83
+ To find out more about
84
+
85
+ - growth groups,
86
+
87
+ - on how they are created and
88
+
89
+ - about the above used *descriptions strings*
90
+
91
+ see the top of the module :doc:`growth group <growth_group>`.
92
+
93
+
94
+ .. _asymptotic_ring_intro:
95
+
96
+ Introductory Examples
97
+ =====================
98
+
99
+ We start this series of examples by defining two asymptotic rings.
100
+
101
+
102
+ Two Rings
103
+ ---------
104
+
105
+ A Univariate Asymptotic Ring
106
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
107
+
108
+ First, we construct the following (very simple) asymptotic ring in the variable `z`::
109
+
110
+ sage: A.<z> = AsymptoticRing(growth_group='z^QQ', coefficient_ring=ZZ); A
111
+ Asymptotic Ring <z^QQ> over Integer Ring
112
+
113
+ A typical element of this ring is
114
+ ::
115
+
116
+ sage: A.an_element()
117
+ z^(3/2) + O(z^(1/2))
118
+
119
+ This element consists of two summands: the exact term with coefficient
120
+ `1` and growth `z^{3/2}` and the `O`-term `O(z^{1/2})`. Note that the
121
+ growth of `z^{3/2}` is larger than the growth of `z^{1/2}` as
122
+ `z\to\infty`, thus this expansion cannot be simplified (which would
123
+ be done automatically, see below).
124
+
125
+ Elements can be constructed via the generator `z` and the function
126
+ :func:`~sage.rings.big_oh.O`, for example
127
+
128
+ ::
129
+
130
+ sage: 4*z^2 + O(z)
131
+ 4*z^2 + O(z)
132
+
133
+ A Multivariate Asymptotic Ring
134
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
135
+
136
+ Next, we construct a more sophisticated asymptotic ring in the
137
+ variables `x` and `y` by
138
+ ::
139
+
140
+ sage: B.<x, y> = AsymptoticRing(growth_group='x^QQ * log(x)^ZZ * (QQ_+)^y * y^QQ', coefficient_ring=QQ); B
141
+ Asymptotic Ring <x^QQ * log(x)^ZZ * QQ^y * y^QQ> over Rational Field
142
+
143
+ Again, we can look at a typical (nontrivial) element::
144
+
145
+ sage: B.an_element()
146
+ 1/8*x^(3/2)*log(x)^3*(1/8)^y*y^(3/2) + O(x^(1/2)*log(x)*(1/2)^y*y^(1/2))
147
+
148
+ Again, elements can be created using the generators `x` and `y`, as well as
149
+ the function :func:`~sage.rings.big_oh.O`::
150
+
151
+ sage: log(x)*y/42 + O(1/2^y)
152
+ 1/42*log(x)*y + O((1/2)^y)
153
+
154
+ Arithmetical Operations
155
+ -----------------------
156
+
157
+ In this section we explain how to perform various arithmetical
158
+ operations with the elements of the asymptotic rings constructed
159
+ above.
160
+
161
+
162
+ The Ring Operations Plus and Times
163
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
164
+
165
+ We start our calculations in the ring
166
+ ::
167
+
168
+ sage: A
169
+ Asymptotic Ring <z^QQ> over Integer Ring
170
+
171
+ Of course, we can perform the usual ring operations `+` and `*`::
172
+
173
+ sage: z^2 + 3*z*(1-z)
174
+ -2*z^2 + 3*z
175
+ sage: (3*z + 2)^3
176
+ 27*z^3 + 54*z^2 + 36*z + 8
177
+
178
+ In addition to that, special powers---our growth group ``z^QQ`` allows
179
+ the exponents to be out of `\QQ`---can also be computed::
180
+
181
+ sage: (z^(5/2)+z^(1/7)) * z^(-1/5)
182
+ z^(23/10) + z^(-2/35)
183
+
184
+ The central concepts of computations with asymptotic expansions is
185
+ that the `O`-notation can be used. For example, we have
186
+ ::
187
+
188
+ sage: z^3 + z^2 + z + O(z^2)
189
+ z^3 + O(z^2)
190
+
191
+ where the result is simplified automatically. A more sophisticated example is
192
+ ::
193
+
194
+ sage: (z+2*z^2+3*z^3+4*z^4) * (O(z)+z^2)
195
+ 4*z^6 + O(z^5)
196
+
197
+
198
+ Division
199
+ ^^^^^^^^
200
+
201
+ The asymptotic expansions support division. For example, we can
202
+ expand `1/(z-1)` to a geometric series::
203
+
204
+ sage: 1 / (z-1)
205
+ z^(-1) + z^(-2) + z^(-3) + z^(-4) + ... + z^(-20) + O(z^(-21))
206
+
207
+ A default precision (parameter ``default_prec`` of
208
+ :class:`AsymptoticRing`) is predefined. Thus, only the first `20`
209
+ summands are calculated. However, if we only want the first `5` exact
210
+ terms, we cut of the rest by using
211
+ ::
212
+
213
+ sage: (1 / (z-1)).truncate(5)
214
+ z^(-1) + z^(-2) + z^(-3) + z^(-4) + z^(-5) + O(z^(-6))
215
+
216
+ or
217
+
218
+ ::
219
+
220
+ sage: 1 / (z-1) + O(z^(-6))
221
+ z^(-1) + z^(-2) + z^(-3) + z^(-4) + z^(-5) + O(z^(-6))
222
+
223
+ Of course, we can work with more complicated expansions as well::
224
+
225
+ sage: (4*z+1) / (z^3+z^2+z+O(z^0))
226
+ 4*z^(-2) - 3*z^(-3) - z^(-4) + O(z^(-5))
227
+
228
+ Not all elements are invertible, for instance,
229
+
230
+ ::
231
+
232
+ sage: 1 / O(z)
233
+ Traceback (most recent call last):
234
+ ...
235
+ ZeroDivisionError: Cannot invert O(z).
236
+
237
+ is not invertible, since it includes `0`.
238
+
239
+
240
+ Powers, Exponentials and Logarithms
241
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
242
+
243
+ It works as simple as it can be; just use the usual operators ``^``,
244
+ ``exp`` and ``log``. For example, we obtain the usual series expansion
245
+ of the logarithm
246
+ ::
247
+
248
+ sage: -log(1-1/z)
249
+ z^(-1) + 1/2*z^(-2) + 1/3*z^(-3) + ... + O(z^(-21))
250
+
251
+ as `z \to \infty`.
252
+
253
+ Similarly, we can apply the exponential function of an asymptotic expansion::
254
+
255
+ sage: exp(1/z)
256
+ 1 + z^(-1) + 1/2*z^(-2) + 1/6*z^(-3) + 1/24*z^(-4) + ... + O(z^(-20))
257
+
258
+ Arbitrary powers work as well; for example, we have
259
+ ::
260
+
261
+ sage: (1 + 1/z + O(1/z^5))^(1 + 1/z)
262
+ 1 + z^(-1) + z^(-2) + 1/2*z^(-3) + 1/3*z^(-4) + O(z^(-5))
263
+
264
+
265
+ Multivariate Arithmetic
266
+ ^^^^^^^^^^^^^^^^^^^^^^^
267
+
268
+ Now let us move on to arithmetic in the multivariate ring
269
+
270
+ ::
271
+
272
+ sage: B
273
+ Asymptotic Ring <x^QQ * log(x)^ZZ * QQ^y * y^QQ> over Rational Field
274
+
275
+ .. TODO::
276
+
277
+ write this part
278
+
279
+
280
+ More Examples
281
+ =============
282
+
283
+
284
+ The mathematical constant e as a limit
285
+ --------------------------------------
286
+
287
+ The base of the natural logarithm `e` satisfies the equation
288
+
289
+ .. MATH::
290
+
291
+ e = \lim_{n\to\infty} \left(1+\frac{1}{n}\right)^n
292
+
293
+ By using asymptotic expansions, we obtain the more precise result
294
+ ::
295
+
296
+ sage: E.<n> = AsymptoticRing(growth_group='n^ZZ', coefficient_ring=SR, default_prec=5); E
297
+ Asymptotic Ring <n^ZZ> over Symbolic Ring
298
+ sage: (1 + 1/n)^n
299
+ e - 1/2*e*n^(-1) + 11/24*e*n^(-2) - 7/16*e*n^(-3) + 2447/5760*e*n^(-4) + O(n^(-5))
300
+
301
+
302
+ Selected Technical Details
303
+ ==========================
304
+
305
+
306
+ Coercions and Functorial Constructions
307
+ --------------------------------------
308
+
309
+ The :class:`AsymptoticRing` fully supports
310
+ `coercion <../../../../coercion/index.html>`_. For example, the coefficient ring is automatically extended when needed::
311
+
312
+ sage: A
313
+ Asymptotic Ring <z^QQ> over Integer Ring
314
+ sage: (z + 1/2).parent()
315
+ Asymptotic Ring <z^QQ> over Rational Field
316
+
317
+ Here, the coefficient ring was extended to allow `1/2` as a
318
+ coefficient. Another example is
319
+ ::
320
+
321
+ sage: C.<c> = AsymptoticRing(growth_group='c^ZZ', coefficient_ring=ZZ['e'])
322
+ sage: C.an_element()
323
+ e^3*c^3 + O(c)
324
+ sage: C.an_element() / 7
325
+ 1/7*e^3*c^3 + O(c)
326
+
327
+ Here the result's coefficient ring is the newly found
328
+ ::
329
+
330
+ sage: (C.an_element() / 7).parent()
331
+ Asymptotic Ring <c^ZZ> over
332
+ Univariate Polynomial Ring in e over Rational Field
333
+
334
+ Not only the coefficient ring can be extended, but the growth group as
335
+ well. For example, we can add/multiply elements of the asymptotic
336
+ rings ``A`` and ``C`` to get an expansion of new asymptotic ring::
337
+
338
+ sage: r = c*z + c/2 + O(z); r
339
+ c*z + 1/2*c + O(z)
340
+ sage: r.parent()
341
+ Asymptotic Ring <c^ZZ * z^QQ> over
342
+ Univariate Polynomial Ring in e over Rational Field
343
+
344
+
345
+ Data Structures
346
+ ---------------
347
+
348
+ The summands of an
349
+ :class:`asymptotic expansion <AsymptoticExpansion>` are wrapped
350
+ :doc:`growth group elements <growth_group>`.
351
+ This wrapping is done by the
352
+ :doc:`term monoid module <term_monoid>`.
353
+ However, inside an
354
+ :class:`asymptotic expansion <AsymptoticExpansion>` these summands
355
+ (terms) are stored together with their growth-relationship, i.e., each
356
+ summand knows its direct predecessors and successors. As a data
357
+ structure a special poset (namely a
358
+ :mod:`mutable poset <sage.data_structures.mutable_poset>`)
359
+ is used. We can have a look at this::
360
+
361
+ sage: b = x^3*y + x^2*y + x*y^2 + O(x) + O(y)
362
+ sage: print(b.summands.repr_full(reverse=True))
363
+ poset(x*y^2, x^3*y, x^2*y, O(x), O(y))
364
+ +-- oo
365
+ | +-- no successors
366
+ | +-- predecessors: x*y^2, x^3*y
367
+ +-- x*y^2
368
+ | +-- successors: oo
369
+ | +-- predecessors: O(x), O(y)
370
+ +-- x^3*y
371
+ | +-- successors: oo
372
+ | +-- predecessors: x^2*y
373
+ +-- x^2*y
374
+ | +-- successors: x^3*y
375
+ | +-- predecessors: O(x), O(y)
376
+ +-- O(x)
377
+ | +-- successors: x*y^2, x^2*y
378
+ | +-- predecessors: null
379
+ +-- O(y)
380
+ | +-- successors: x*y^2, x^2*y
381
+ | +-- predecessors: null
382
+ +-- null
383
+ | +-- successors: O(x), O(y)
384
+ | +-- no predecessors
385
+
386
+
387
+ Various
388
+ =======
389
+
390
+ AUTHORS:
391
+
392
+ - Benjamin Hackl (2015)
393
+ - Daniel Krenn (2015)
394
+ - Clemens Heuberger (2016)
395
+
396
+ ACKNOWLEDGEMENT:
397
+
398
+ - Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the
399
+ Austrian Science Fund (FWF): P 24644-N26.
400
+
401
+ - Benjamin Hackl is supported by the Google Summer of Code 2015.
402
+
403
+
404
+ Classes and Methods
405
+ ===================
406
+ """
407
+
408
+ # *****************************************************************************
409
+ # Copyright (C) 2015 Benjamin Hackl <benjamin.hackl@aau.at>
410
+ # 2015 Daniel Krenn <dev@danielkrenn.at>
411
+ #
412
+ # This program is free software: you can redistribute it and/or modify
413
+ # it under the terms of the GNU General Public License as published by
414
+ # the Free Software Foundation, either version 2 of the License, or
415
+ # (at your option) any later version.
416
+ # https://www.gnu.org/licenses/
417
+ # *****************************************************************************
418
+
419
+ import sage.rings.abc
420
+
421
+ from sage.categories.pushout import ConstructionFunctor
422
+ from sage.misc.defaults import series_precision
423
+ from sage.misc.lazy_import import lazy_import
424
+ from sage.rings.real_mpfi import RIF
425
+ from sage.structure.element import CommutativeAlgebraElement
426
+ from sage.structure.parent import Parent
427
+ from sage.structure.unique_representation import UniqueRepresentation
428
+
429
+ from .misc import WithLocals
430
+
431
+ lazy_import('sage.rings.lazy_series_ring', 'LazyPowerSeriesRing')
432
+ lazy_import('sage.rings.polynomial.multi_polynomial_ring_base', 'MPolynomialRing_base')
433
+ lazy_import('sage.rings.polynomial.polynomial_ring', 'PolynomialRing_generic')
434
+ lazy_import('sage.rings.power_series_ring', 'PowerSeriesRing_generic')
435
+ lazy_import('sage.symbolic.ring', 'SymbolicRing')
436
+
437
+
438
+ class NoConvergenceError(RuntimeError):
439
+ r"""
440
+ A special :python:`RuntimeError<library/exceptions.html#exceptions.RuntimeError>`
441
+ which is raised when an algorithm does not converge/stop.
442
+ """
443
+
444
+
445
+ class AsymptoticExpansion(CommutativeAlgebraElement):
446
+ r"""
447
+ Class for asymptotic expansions, i.e., the elements of an
448
+ :class:`AsymptoticRing`.
449
+
450
+ INPUT:
451
+
452
+ - ``parent`` -- the parent of the asymptotic expansion
453
+
454
+ - ``summands`` -- the summands as a
455
+ :class:`~sage.data_structures.mutable_poset.MutablePoset`, which
456
+ represents the underlying structure
457
+
458
+ - ``simplify`` -- boolean (default: ``True``); it controls
459
+ automatic simplification (absorption) of the asymptotic expansion
460
+
461
+ - ``convert`` -- boolean (default: ``True``); if set, then the
462
+ ``summands`` are converted to the asymptotic ring (the parent of this
463
+ expansion). If not, then the summands are taken as they are. In
464
+ that case, the caller must ensure that the parent of the terms is
465
+ set correctly.
466
+
467
+ EXAMPLES:
468
+
469
+ There are several ways to create asymptotic expansions; usually
470
+ this is done by using the corresponding :class:`asymptotic rings <AsymptoticRing>`::
471
+
472
+ sage: R_x.<x> = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R_x
473
+ Asymptotic Ring <x^QQ> over Rational Field
474
+ sage: R_y.<y> = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=ZZ); R_y
475
+ Asymptotic Ring <y^ZZ> over Integer Ring
476
+
477
+ At this point, `x` and `y` are already asymptotic expansions::
478
+
479
+ sage: type(x)
480
+ <class 'sage.rings.asymptotic.asymptotic_ring.AsymptoticRing_with_category.element_class'>
481
+
482
+ The usual ring operations, but allowing rational exponents (growth
483
+ group ``x^QQ``) can be performed::
484
+
485
+ sage: x^2 + 3*(x - x^(2/5))
486
+ x^2 + 3*x - 3*x^(2/5)
487
+ sage: (3*x^(1/3) + 2)^3
488
+ 27*x + 54*x^(2/3) + 36*x^(1/3) + 8
489
+
490
+ One of the central ideas behind computing with asymptotic
491
+ expansions is that the `O`-notation (see
492
+ :wikipedia:`Big_O_notation`) can be used. For example, we have::
493
+
494
+ sage: (x+2*x^2+3*x^3+4*x^4) * (O(x)+x^2)
495
+ 4*x^6 + O(x^5)
496
+
497
+ In particular, :func:`~sage.rings.big_oh.O` can be used to
498
+ construct the asymptotic expansions. With the help of the
499
+ :meth:`summands`, we can also have a look at the inner structure
500
+ of an asymptotic expansion::
501
+
502
+ sage: expr1 = x + 2*x^2 + 3*x^3 + 4*x^4; expr2 = O(x) + x^2
503
+ sage: print(expr1.summands.repr_full())
504
+ poset(x, 2*x^2, 3*x^3, 4*x^4)
505
+ +-- null
506
+ | +-- no predecessors
507
+ | +-- successors: x
508
+ +-- x
509
+ | +-- predecessors: null
510
+ | +-- successors: 2*x^2
511
+ +-- 2*x^2
512
+ | +-- predecessors: x
513
+ | +-- successors: 3*x^3
514
+ +-- 3*x^3
515
+ | +-- predecessors: 2*x^2
516
+ | +-- successors: 4*x^4
517
+ +-- 4*x^4
518
+ | +-- predecessors: 3*x^3
519
+ | +-- successors: oo
520
+ +-- oo
521
+ | +-- predecessors: 4*x^4
522
+ | +-- no successors
523
+ sage: print(expr2.summands.repr_full())
524
+ poset(O(x), x^2)
525
+ +-- null
526
+ | +-- no predecessors
527
+ | +-- successors: O(x)
528
+ +-- O(x)
529
+ | +-- predecessors: null
530
+ | +-- successors: x^2
531
+ +-- x^2
532
+ | +-- predecessors: O(x)
533
+ | +-- successors: oo
534
+ +-- oo
535
+ | +-- predecessors: x^2
536
+ | +-- no successors
537
+ sage: print((expr1 * expr2).summands.repr_full())
538
+ poset(O(x^5), 4*x^6)
539
+ +-- null
540
+ | +-- no predecessors
541
+ | +-- successors: O(x^5)
542
+ +-- O(x^5)
543
+ | +-- predecessors: null
544
+ | +-- successors: 4*x^6
545
+ +-- 4*x^6
546
+ | +-- predecessors: O(x^5)
547
+ | +-- successors: oo
548
+ +-- oo
549
+ | +-- predecessors: 4*x^6
550
+ | +-- no successors
551
+
552
+ In addition to the monomial growth elements from above, we can
553
+ also compute with logarithmic terms (simply by constructing the
554
+ appropriate growth group)::
555
+
556
+ sage: R_log = AsymptoticRing(growth_group='log(x)^QQ', coefficient_ring=QQ)
557
+ sage: lx = R_log(log(SR.var('x')))
558
+ sage: (O(lx) + lx^3)^4
559
+ log(x)^12 + O(log(x)^10)
560
+
561
+ .. SEEALSO::
562
+
563
+ :doc:`growth_group`,
564
+ :doc:`term_monoid`,
565
+ :mod:`~sage.data_structures.mutable_poset`.
566
+ """
567
+ def __init__(self, parent, summands, simplify=True, convert=True):
568
+ r"""
569
+ See :class:`AsymptoticExpansion` for more information.
570
+
571
+ TESTS::
572
+
573
+ sage: R_x.<x> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
574
+ sage: R_y.<y> = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=ZZ)
575
+ sage: R_x is R_y
576
+ False
577
+ sage: ex1 = x + 2*x^2 + 3*x^3 + 4*x^4 + 5*x^5
578
+ sage: ex2 = x + O(R_x(1))
579
+ sage: ex1 * ex2
580
+ 5*x^6 + O(x^5)
581
+
582
+ ::
583
+
584
+ sage: from sage.rings.asymptotic.growth_group import GrowthGroup
585
+ sage: from sage.rings.asymptotic.term_monoid import DefaultTermMonoidFactory as TermMonoid
586
+ sage: G = GrowthGroup('x^ZZ'); x = G.gen()
587
+ sage: OT = TermMonoid('O', G, ZZ); ET = TermMonoid('exact', G, ZZ)
588
+ sage: R = AsymptoticRing(G, ZZ)
589
+ sage: lst = [ET(x, coefficient=1), ET(x^2, coefficient=2), OT(x^3), ET(x^4, coefficient=4)]
590
+ sage: expr = R(lst, simplify=False); expr # indirect doctest
591
+ 4*x^4 + O(x^3) + 2*x^2 + x
592
+ sage: print(expr.summands.repr_full())
593
+ poset(x, 2*x^2, O(x^3), 4*x^4)
594
+ +-- null
595
+ | +-- no predecessors
596
+ | +-- successors: x
597
+ +-- x
598
+ | +-- predecessors: null
599
+ | +-- successors: 2*x^2
600
+ +-- 2*x^2
601
+ | +-- predecessors: x
602
+ | +-- successors: O(x^3)
603
+ +-- O(x^3)
604
+ | +-- predecessors: 2*x^2
605
+ | +-- successors: 4*x^4
606
+ +-- 4*x^4
607
+ | +-- predecessors: O(x^3)
608
+ | +-- successors: oo
609
+ +-- oo
610
+ | +-- predecessors: 4*x^4
611
+ | +-- no successors
612
+ sage: expr._simplify_(); expr
613
+ 4*x^4 + O(x^3)
614
+ sage: print(expr.summands.repr_full())
615
+ poset(O(x^3), 4*x^4)
616
+ +-- null
617
+ | +-- no predecessors
618
+ | +-- successors: O(x^3)
619
+ +-- O(x^3)
620
+ | +-- predecessors: null
621
+ | +-- successors: 4*x^4
622
+ +-- 4*x^4
623
+ | +-- predecessors: O(x^3)
624
+ | +-- successors: oo
625
+ +-- oo
626
+ | +-- predecessors: 4*x^4
627
+ | +-- no successors
628
+ sage: R(lst, simplify=True) # indirect doctest
629
+ 4*x^4 + O(x^3)
630
+
631
+ ::
632
+
633
+ sage: R.<x> = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ)
634
+ sage: e = R(x^2 + O(x))
635
+ sage: from sage.rings.asymptotic.asymptotic_ring import AsymptoticExpansion
636
+ sage: S = AsymptoticRing(growth_group='x^QQ', coefficient_ring=ZZ)
637
+ sage: for s in AsymptoticExpansion(S, e.summands).summands.elements_topological():
638
+ ....: print(s.parent())
639
+ O-Term Monoid x^QQ with implicit coefficients in Integer Ring
640
+ Exact Term Monoid x^QQ with coefficients in Integer Ring
641
+ sage: for s in AsymptoticExpansion(S, e.summands,
642
+ ....: convert=False).summands.elements_topological():
643
+ ....: print(s.parent())
644
+ O-Term Monoid x^QQ with implicit coefficients in Rational Field
645
+ Exact Term Monoid x^QQ with coefficients in Rational Field
646
+
647
+ ::
648
+
649
+ sage: AsymptoticExpansion(S, R(1/2).summands)
650
+ Traceback (most recent call last):
651
+ ...
652
+ ValueError: Cannot include 1/2 with parent
653
+ Exact Term Monoid x^QQ with coefficients in Rational Field in
654
+ Asymptotic Ring <x^QQ> over Integer Ring
655
+ > *previous* ValueError: Cannot create ExactTerm(1)
656
+ since given coefficient 1/2 is not valid in
657
+ Exact Term Monoid x^QQ with coefficients in Integer Ring.
658
+ >> *previous* TypeError: no conversion of this rational to integer
659
+
660
+ Check :issue:`19921`::
661
+
662
+ sage: CR.<Z> = QQ['Z']
663
+ sage: CR_mod = CR.quotient((Z^2 - 1)*CR)
664
+ sage: R.<x> = AsymptoticRing(growth_group='x^NN', coefficient_ring=CR)
665
+ sage: R_mod = R.change_parameter(coefficient_ring=CR_mod)
666
+ sage: e = 1 + x*(Z^2-1)
667
+ sage: R_mod(e)
668
+ 1
669
+
670
+ Check that :issue:`19999` is resolved::
671
+
672
+ sage: A.<x> = AsymptoticRing('(QQ_+)^x * x^QQ * UU^x', QQ)
673
+ sage: 1 + (-1)^x + 2^x + (-2)^x
674
+ 2^x + 2^x*(-1)^x + (-1)^x + 1
675
+
676
+ sage: A.<x> = AsymptoticRing('QQ^x * x^QQ', QQ)
677
+ sage: 1 + (-1)^x + 2^x + (-2)^x
678
+ 2^x + 2^x*(-1)^x + (-1)^x + 1
679
+ """
680
+ super().__init__(parent=parent)
681
+
682
+ from sage.data_structures.mutable_poset import MutablePoset
683
+ if not isinstance(summands, MutablePoset):
684
+ raise TypeError('Summands %s are not in a mutable poset as expected '
685
+ 'when creating an element of %s.' % (summands, parent))
686
+
687
+ if convert:
688
+ from .misc import combine_exceptions
689
+ from .term_monoid import ZeroCoefficientError
690
+
691
+ def convert_terms(element):
692
+ T = self.parent().term_monoid(element.parent())
693
+ try:
694
+ return T(element)
695
+ except ZeroCoefficientError:
696
+ return None
697
+ except (ValueError, TypeError) as e:
698
+ raise combine_exceptions(
699
+ ValueError('Cannot include %s with parent %s in %s' %
700
+ (element, element.parent(), parent)), e)
701
+ new_summands = summands.copy()
702
+ new_summands.map(convert_terms, topological=True, reverse=True)
703
+ self._summands_ = new_summands
704
+ else:
705
+ self._summands_ = summands
706
+
707
+ if simplify:
708
+ self._simplify_()
709
+
710
+ @property
711
+ def summands(self):
712
+ r"""
713
+ The summands of this asymptotic expansion stored in the
714
+ underlying data structure (a
715
+ :class:`~sage.data_structures.mutable_poset.MutablePoset`).
716
+
717
+ EXAMPLES::
718
+
719
+ sage: R.<x> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
720
+ sage: expr = 7*x^12 + x^5 + O(x^3)
721
+ sage: expr.summands
722
+ poset(O(x^3), x^5, 7*x^12)
723
+
724
+ .. SEEALSO::
725
+
726
+ :class:`sage.data_structures.mutable_poset.MutablePoset`
727
+ """
728
+ return self._summands_
729
+
730
+ def __hash__(self):
731
+ r"""
732
+ A hash value for this element.
733
+
734
+ .. WARNING::
735
+
736
+ This hash value uses the string representation and might not be
737
+ always right.
738
+
739
+ TESTS::
740
+
741
+ sage: R_log = AsymptoticRing(growth_group='log(x)^QQ', coefficient_ring=QQ)
742
+ sage: lx = R_log(log(SR.var('x')))
743
+ sage: elt = (O(lx) + lx^3)^4
744
+ sage: hash(elt) # random
745
+ -4395085054568712393
746
+ """
747
+ return hash(str(self))
748
+
749
+ def __bool__(self) -> bool:
750
+ r"""
751
+ Return whether this asymptotic expansion is not identically zero.
752
+
753
+ OUTPUT: boolean
754
+
755
+ TESTS::
756
+
757
+ sage: R.<x> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
758
+ sage: bool(R(0)) # indirect doctest
759
+ False
760
+ sage: bool(x) # indirect doctest
761
+ True
762
+ sage: bool(7*x^12 + x^5 + O(x^3)) # indirect doctest
763
+ True
764
+ """
765
+ return bool(self._summands_)
766
+
767
+ def __eq__(self, other) -> bool:
768
+ r"""
769
+ Return whether this asymptotic expansion is equal to ``other``.
770
+
771
+ INPUT:
772
+
773
+ - ``other`` -- an object
774
+
775
+ OUTPUT: boolean
776
+
777
+ .. NOTE::
778
+
779
+ This function uses the coercion model to find a common
780
+ parent for the two operands.
781
+
782
+ EXAMPLES::
783
+
784
+ sage: R.<x> = AsymptoticRing('x^ZZ', QQ)
785
+ sage: (1 + 2*x + 3*x^2) == (3*x^2 + 2*x + 1) # indirect doctest
786
+ True
787
+ sage: O(x) == O(x)
788
+ False
789
+
790
+ TESTS::
791
+
792
+ sage: x == None
793
+ False
794
+
795
+ ::
796
+
797
+ sage: x == 'x'
798
+ False
799
+ """
800
+ if other is None:
801
+ return False
802
+ try:
803
+ return not bool(self - other)
804
+ except (TypeError, ValueError):
805
+ return False
806
+
807
+ def __ne__(self, other) -> bool:
808
+ r"""
809
+ Return whether this asymptotic expansion is not equal to ``other``.
810
+
811
+ INPUT:
812
+
813
+ - ``other`` -- an object
814
+
815
+ OUTPUT: boolean
816
+
817
+ .. NOTE::
818
+
819
+ This function uses the coercion model to find a common
820
+ parent for the two operands.
821
+
822
+ EXAMPLES::
823
+
824
+ sage: R.<x> = AsymptoticRing('x^ZZ', QQ)
825
+ sage: (1 + 2*x + 3*x^2) != (3*x^2 + 2*x + 1) # indirect doctest
826
+ False
827
+ sage: O(x) != O(x)
828
+ True
829
+
830
+ TESTS::
831
+
832
+ sage: x != None
833
+ True
834
+ """
835
+ return not self == other
836
+
837
+ def has_same_summands(self, other) -> bool:
838
+ r"""
839
+ Return whether this asymptotic expansion and ``other`` have the
840
+ same summands.
841
+
842
+ INPUT:
843
+
844
+ - ``other`` -- an asymptotic expansion
845
+
846
+ OUTPUT: boolean
847
+
848
+ .. NOTE::
849
+
850
+ While for example ``O(x) == O(x)`` yields ``False``,
851
+ these expansions *do* have the same summands and this method
852
+ returns ``True``.
853
+
854
+ Moreover, this method uses the coercion model in order to
855
+ find a common parent for this asymptotic expansion and
856
+ ``other``.
857
+
858
+ EXAMPLES::
859
+
860
+ sage: R_ZZ.<x_ZZ> = AsymptoticRing('x^ZZ', ZZ)
861
+ sage: R_QQ.<x_QQ> = AsymptoticRing('x^ZZ', QQ)
862
+ sage: sum(x_ZZ^k for k in range(5)) == sum(x_QQ^k for k in range(5)) # indirect doctest
863
+ True
864
+ sage: O(x_ZZ) == O(x_QQ)
865
+ False
866
+
867
+ TESTS::
868
+
869
+ sage: x_ZZ.has_same_summands(None)
870
+ False
871
+ """
872
+ if other is None:
873
+ return False
874
+ from sage.structure.element import have_same_parent
875
+ if have_same_parent(self, other):
876
+ return self._has_same_summands_(other)
877
+
878
+ from sage.structure.element import get_coercion_model
879
+ return get_coercion_model().bin_op(self, other,
880
+ lambda self, other:
881
+ self._has_same_summands_(other))
882
+
883
+ def _has_same_summands_(self, other) -> bool:
884
+ r"""
885
+ Return whether this :class:`AsymptoticExpansion` has the same
886
+ summands as ``other``.
887
+
888
+ INPUT:
889
+
890
+ - ``other`` -- an :class:`AsymptoticExpansion`
891
+
892
+ OUTPUT: boolean
893
+
894
+ .. NOTE::
895
+
896
+ This method compares two :class:`AsymptoticExpansion`
897
+ with the same parent.
898
+
899
+ EXAMPLES::
900
+
901
+ sage: R.<x> = AsymptoticRing('x^ZZ', QQ)
902
+ sage: O(x).has_same_summands(O(x))
903
+ True
904
+ sage: (1 + x + 2*x^2).has_same_summands(2*x^2 + O(x)) # indirect doctest
905
+ False
906
+ """
907
+ if len(self.summands) != len(other.summands):
908
+ return False
909
+ return all(s == o for s, o in
910
+ zip(self.summands.elements_topological(),
911
+ other.summands.elements_topological()))
912
+
913
+ def _simplify_(self):
914
+ r"""
915
+ Simplify this asymptotic expansion.
916
+
917
+ OUTPUT: nothing, but modifies this asymptotic expansion
918
+
919
+ .. NOTE::
920
+
921
+ This method is usually called during initialization of
922
+ this asymptotic expansion.
923
+
924
+ .. NOTE::
925
+
926
+ This asymptotic expansion is simplified by letting
927
+ `O`-terms that are included in this expansion absorb all
928
+ terms with smaller growth.
929
+
930
+ TESTS::
931
+
932
+ sage: from sage.rings.asymptotic.growth_group import GrowthGroup
933
+ sage: from sage.rings.asymptotic.term_monoid import DefaultTermMonoidFactory as TermMonoid
934
+ sage: G = GrowthGroup('x^ZZ')
935
+ sage: OT = TermMonoid('O', G, ZZ); ET = TermMonoid('exact', G, ZZ)
936
+ sage: R = AsymptoticRing(G, ZZ)
937
+ sage: lst = [ET(x, coefficient=1), ET(x^2, coefficient=2), OT(x^3), ET(x^4, coefficient=4)]
938
+ sage: expr = R(lst, simplify=False); expr # indirect doctest
939
+ 4*x^4 + O(x^3) + 2*x^2 + x
940
+ sage: expr._simplify_(); expr
941
+ 4*x^4 + O(x^3)
942
+ sage: R(lst) # indirect doctest
943
+ 4*x^4 + O(x^3)
944
+ """
945
+ self._summands_.merge(reverse=True)
946
+
947
+ def _repr_(self, latex=False):
948
+ r"""
949
+ A representation string for this asymptotic expansion.
950
+
951
+ INPUT:
952
+
953
+ - ``latex`` -- boolean (default: ``False``); if set, then
954
+ LaTeX-output is returned
955
+
956
+ OUTPUT: string
957
+
958
+ EXAMPLES::
959
+
960
+ sage: R.<x> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
961
+ sage: (5*x^2+12*x) * (x^3+O(x)) # indirect doctest
962
+ 5*x^5 + 12*x^4 + O(x^3)
963
+ sage: (5*x^2-12*x) * (x^3+O(x)) # indirect doctest
964
+ 5*x^5 - 12*x^4 + O(x^3)
965
+ """
966
+ if latex:
967
+ from sage.misc.latex import latex as latex_repr
968
+ f = latex_repr
969
+ else:
970
+ f = repr
971
+ s = ' + '.join(f(elem) for elem in
972
+ self.summands.elements_topological(reverse=True,
973
+ key=repr))
974
+ s = s.replace('+ -', '- ')
975
+ if not s:
976
+ return '0'
977
+ return s
978
+
979
+ def _latex_(self):
980
+ r"""
981
+ A LaTeX-representation string for this asymptotic expansion.
982
+
983
+ OUTPUT: string
984
+
985
+ TESTS::
986
+
987
+ sage: R.<x> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
988
+ sage: latex((5*x^2+12*x) * (x^3+O(x))) # indirect doctest
989
+ 5 x^{5} + 12 x^{4} + O\!\left(x^{3}\right)
990
+ sage: latex((5*x^2-12*x) * (x^3+O(x))) # indirect doctest
991
+ 5 x^{5} - 12 x^{4} + O\!\left(x^{3}\right)
992
+ """
993
+ return self._repr_(latex=True)
994
+
995
+ def show(self):
996
+ r"""
997
+ Pretty-print this asymptotic expansion.
998
+
999
+ OUTPUT:
1000
+
1001
+ Nothing, the representation is printed directly on the
1002
+ screen.
1003
+
1004
+ EXAMPLES::
1005
+
1006
+ sage: A.<x> = AsymptoticRing('QQ^x * x^QQ * log(x)^QQ', SR.subring(no_variables=True))
1007
+ sage: (pi/2 * 5^x * x^(42/17) - sqrt(euler_gamma) * log(x)^(-7/8)).show()
1008
+ 1/2*pi*5^x*x^(42/17) - sqrt(euler_gamma)*log(x)^(-7/8)
1009
+
1010
+ TESTS::
1011
+
1012
+ sage: A.<x> = AsymptoticRing('(e^x)^QQ * x^QQ', SR.subring(no_variables=True))
1013
+ sage: (zeta(3) * (e^x)^(-1/2) * x^42).show()
1014
+ zeta(3)*(e^x)^(-1/2)*x^42
1015
+ """
1016
+ from sage.repl.rich_output.pretty_print import pretty_print
1017
+ pretty_print(self)
1018
+
1019
+ def monomial_coefficient(self, monomial):
1020
+ r"""
1021
+ Return the coefficient in the base ring of the given monomial
1022
+ in this expansion.
1023
+
1024
+ INPUT:
1025
+
1026
+ - ``monomial`` -- a monomial element which can be converted
1027
+ into the asymptotic ring of this element
1028
+
1029
+ OUTPUT: an element of the coefficient ring
1030
+
1031
+ EXAMPLES::
1032
+
1033
+ sage: R.<m, n> = AsymptoticRing("m^QQ*n^QQ", QQ)
1034
+ sage: ae = 13 + 42/n + 2/n/m + O(n^-2)
1035
+ sage: ae.monomial_coefficient(1/n)
1036
+ 42
1037
+ sage: ae.monomial_coefficient(1/n^3)
1038
+ 0
1039
+ sage: R.<n> = AsymptoticRing("n^QQ", ZZ)
1040
+ sage: ae.monomial_coefficient(1/n)
1041
+ 42
1042
+ sage: ae.monomial_coefficient(1)
1043
+ 13
1044
+
1045
+ TESTS:
1046
+
1047
+ Conversion of ``monomial`` the parent of this element must be
1048
+ possible::
1049
+
1050
+ sage: R.<m> = AsymptoticRing("m^QQ", QQ)
1051
+ sage: S.<n> = AsymptoticRing("n^QQ", QQ)
1052
+ sage: m.monomial_coefficient(n)
1053
+ Traceback (most recent call last):
1054
+ ...
1055
+ ValueError: Cannot include n with parent Exact Term Monoid
1056
+ n^QQ with coefficients in Rational Field in Asymptotic Ring
1057
+ <m^QQ> over Rational Field
1058
+ > *previous* ValueError: Growth n is not valid in
1059
+ Exact Term Monoid m^QQ with coefficients in Rational Field.
1060
+ >> *previous* ValueError: n is not in Growth Group m^QQ.
1061
+
1062
+ Only monomials are allowed::
1063
+
1064
+ sage: R.<n> = AsymptoticRing("n^QQ", QQ)
1065
+ sage: (n + 4).monomial_coefficient(n + 5)
1066
+ Traceback (most recent call last):
1067
+ ...
1068
+ ValueError: n + 5 not a monomial
1069
+ sage: n.monomial_coefficient(0)
1070
+ Traceback (most recent call last):
1071
+ ...
1072
+ ValueError: 0 not a monomial
1073
+
1074
+ Cannot extract the coefficient of an O term::
1075
+
1076
+ sage: O(n).monomial_coefficient(n)
1077
+ Traceback (most recent call last):
1078
+ ...
1079
+ AttributeError: 'OTermMonoid_with_category.element_class' object has no attribute 'coefficient'...
1080
+
1081
+ The ``monomial`` must be exact::
1082
+
1083
+ sage: n.monomial_coefficient(O(n))
1084
+ Traceback (most recent call last):
1085
+ ...
1086
+ ValueError: non-exact monomial O(n)
1087
+ """
1088
+ monomial = self.parent()(monomial)
1089
+ if not monomial.is_exact():
1090
+ raise ValueError("non-exact monomial {}".format(monomial))
1091
+
1092
+ if len(monomial.summands) != 1:
1093
+ raise ValueError("{} not a monomial".format(monomial))
1094
+
1095
+ monomial_growth = next(monomial.summands.elements()).growth
1096
+ try:
1097
+ return self.summands.element(monomial_growth).coefficient
1098
+ except KeyError:
1099
+ return self.parent().coefficient_ring(0)
1100
+
1101
+ def _add_(self, other):
1102
+ r"""
1103
+ Add ``other`` to this asymptotic expansion.
1104
+
1105
+ INPUT:
1106
+
1107
+ - ``other`` -- an :class:`AsymptoticExpansion`
1108
+
1109
+ OUTPUT: the sum as an :class:`AsymptoticExpansion`
1110
+
1111
+ EXAMPLES::
1112
+
1113
+ sage: R.<x> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
1114
+ sage: expr1 = x^123; expr2 = x^321
1115
+ sage: expr1._add_(expr2)
1116
+ x^321 + x^123
1117
+ sage: expr1 + expr2 # indirect doctest
1118
+ x^321 + x^123
1119
+
1120
+ If an `O`-term is added to an asymptotic expansion, then
1121
+ the `O`-term absorbs everything it can::
1122
+
1123
+ sage: x^123 + x^321 + O(x^555) # indirect doctest
1124
+ O(x^555)
1125
+
1126
+ TESTS::
1127
+
1128
+ sage: x + O(x)
1129
+ O(x)
1130
+ sage: O(x) + x
1131
+ O(x)
1132
+ """
1133
+ return self.parent()(self.summands.union(other.summands),
1134
+ simplify=True, convert=False)
1135
+
1136
+ def _sub_(self, other):
1137
+ r"""
1138
+ Subtract ``other`` from this asymptotic expansion.
1139
+
1140
+ INPUT:
1141
+
1142
+ - ``other`` -- an :class:`AsymptoticExpansion`
1143
+
1144
+ OUTPUT: the difference as an :class:`AsymptoticExpansion`
1145
+
1146
+ .. NOTE::
1147
+
1148
+ Subtraction of two asymptotic expansions is implemented
1149
+ by means of addition: `e_1 - e_2 = e_1 + (-1)\cdot e_2`.
1150
+
1151
+ EXAMPLES::
1152
+
1153
+ sage: R.<x> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
1154
+ sage: expr1 = x^123; expr2 = x^321
1155
+ sage: expr1 - expr2 # indirect doctest
1156
+ -x^321 + x^123
1157
+ sage: O(x) - O(x)
1158
+ O(x)
1159
+ """
1160
+ return self + self.parent().coefficient_ring(-1) * other
1161
+
1162
+ def _mul_term_(self, term):
1163
+ r"""
1164
+ Helper method: multiply this asymptotic expansion by the
1165
+ asymptotic term ``term``.
1166
+
1167
+ INPUT:
1168
+
1169
+ - ``term`` -- an asymptotic term (see :doc:`term_monoid`)
1170
+
1171
+ OUTPUT: the product as an :class:`AsymptoticExpansion`
1172
+
1173
+ TESTS::
1174
+
1175
+ sage: from sage.rings.asymptotic.term_monoid import OTermMonoid
1176
+ sage: from sage.rings.asymptotic.term_monoid import DefaultTermMonoidFactory as TermMonoid
1177
+
1178
+ sage: R.<x> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
1179
+ sage: T = OTermMonoid(TermMonoid, R.growth_group, ZZ)
1180
+ sage: expr = 10*x^2 + O(x)
1181
+ sage: t = T(R.growth_group.gen())
1182
+ sage: expr._mul_term_(t)
1183
+ O(x^3)
1184
+ """
1185
+ simplify = not term.is_exact()
1186
+ return self.parent()(self.summands.mapped(lambda element: term * element),
1187
+ simplify=simplify, convert=False)
1188
+
1189
+ def _mul_(self, other):
1190
+ r"""
1191
+ Multiply this asymptotic expansion by another asymptotic expansion ``other``.
1192
+
1193
+ INPUT:
1194
+
1195
+ - ``other`` -- an :class:`AsymptoticExpansion`
1196
+
1197
+ OUTPUT: the product as an :class:`AsymptoticExpansion`
1198
+
1199
+ EXAMPLES::
1200
+
1201
+ sage: R.<x> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
1202
+ sage: ex1 = 5*x^12
1203
+ sage: ex2 = x^3 + O(x)
1204
+ sage: ex1 * ex2 # indirect doctest
1205
+ 5*x^15 + O(x^13)
1206
+
1207
+ .. TODO::
1208
+
1209
+ The current implementation is the standard long
1210
+ multiplication. More efficient variants like Karatsuba
1211
+ multiplication, or methods that exploit the structure
1212
+ of the underlying poset shall be implemented at a later
1213
+ point.
1214
+
1215
+ TESTS::
1216
+
1217
+ sage: R(1) * R(0)
1218
+ 0
1219
+ sage: _.parent()
1220
+ Asymptotic Ring <x^ZZ> over Integer Ring
1221
+ """
1222
+ return sum(iter(self._mul_term_(term_other) for
1223
+ term_other in other.summands.elements()),
1224
+ self.parent().zero())
1225
+
1226
+ def _lmul_(self, other):
1227
+ r"""
1228
+ Multiply this asymptotic expansion by an element ``other`` of its
1229
+ coefficient ring.
1230
+
1231
+ INPUT:
1232
+
1233
+ - ``other`` -- an element of the coefficient ring
1234
+
1235
+ OUTPUT: an :class:`AsymptoticExpansion`
1236
+
1237
+ TESTS::
1238
+
1239
+ sage: A.<a> = AsymptoticRing(growth_group='QQ^a * a^QQ * log(a)^QQ', coefficient_ring=ZZ)
1240
+ sage: 2*a # indirect doctest
1241
+ 2*a
1242
+ """
1243
+ if other.is_zero():
1244
+ return self.parent().zero()
1245
+
1246
+ E = self.parent().term_monoid('exact')
1247
+ e = E(self.parent().growth_group.one(), coefficient=other)
1248
+ return self._mul_term_(e)
1249
+
1250
+ def _div_(self, other):
1251
+ r"""
1252
+ Divide this element through ``other``.
1253
+
1254
+ INPUT:
1255
+
1256
+ - ``other`` -- an asymptotic expansion
1257
+
1258
+ OUTPUT: an asymptotic expansion
1259
+
1260
+ EXAMPLES::
1261
+
1262
+ sage: R.<x> = AsymptoticRing('x^ZZ', QQ, default_prec=5)
1263
+ sage: 1/x^42
1264
+ x^(-42)
1265
+ sage: (1 + 4*x) / (x + 2*x^2)
1266
+ 2*x^(-1) - 1/2*x^(-2) + 1/4*x^(-3) - 1/8*x^(-4) + 1/16*x^(-5) + O(x^(-6))
1267
+ sage: x / O(x)
1268
+ Traceback (most recent call last):
1269
+ ...
1270
+ ZeroDivisionError: Cannot invert O(x).
1271
+
1272
+ TESTS:
1273
+
1274
+ See :issue:`19521`::
1275
+
1276
+ sage: A.<n> = AsymptoticRing('n^ZZ', SR.subring(no_variables=True))
1277
+ sage: (A.one() / 1).parent()
1278
+ Asymptotic Ring <n^ZZ> over Symbolic Constants Subring
1279
+ """
1280
+ return self * ~other
1281
+
1282
+ def __invert__(self, precision=None):
1283
+ r"""
1284
+ Return the multiplicative inverse of this element.
1285
+
1286
+ INPUT:
1287
+
1288
+ - ``precision`` -- the precision used for truncating the
1289
+ expansion. If ``None`` (default value) is used, the
1290
+ default precision of the parent is used.
1291
+
1292
+ OUTPUT: an asymptotic expansion
1293
+
1294
+ .. WARNING::
1295
+
1296
+ Due to truncation of infinite expansions, the element
1297
+ returned by this method might not fulfill
1298
+ ``el * ~el == 1``.
1299
+
1300
+ .. TODO::
1301
+
1302
+ As soon as `L`-terms are implemented, this
1303
+ implementation has to be adapted as well in order to
1304
+ yield correct results.
1305
+
1306
+ EXAMPLES::
1307
+
1308
+ sage: R.<x> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ, default_prec=4)
1309
+ sage: ~x
1310
+ x^(-1)
1311
+ sage: ~(x^42)
1312
+ x^(-42)
1313
+ sage: ex = ~(1 + x); ex
1314
+ x^(-1) - x^(-2) + x^(-3) - x^(-4) + O(x^(-5))
1315
+ sage: ex * (1+x)
1316
+ 1 + O(x^(-4))
1317
+ sage: ~(1 + O(1/x))
1318
+ 1 + O(x^(-1))
1319
+
1320
+ TESTS::
1321
+
1322
+ sage: A.<a> = AsymptoticRing(growth_group='a^ZZ', coefficient_ring=ZZ)
1323
+ sage: (1 / a).parent()
1324
+ Asymptotic Ring <a^ZZ> over Rational Field
1325
+ sage: (a / 2).parent()
1326
+ Asymptotic Ring <a^ZZ> over Rational Field
1327
+
1328
+ ::
1329
+
1330
+ sage: ~A(0)
1331
+ Traceback (most recent call last):
1332
+ ...
1333
+ ZeroDivisionError: Cannot invert 0 in
1334
+ Asymptotic Ring <a^ZZ> over Integer Ring.
1335
+
1336
+ ::
1337
+
1338
+ sage: B.<s, t> = AsymptoticRing(growth_group='s^ZZ * t^ZZ', coefficient_ring=QQ)
1339
+ sage: ~(s + t)
1340
+ Traceback (most recent call last):
1341
+ ...
1342
+ ValueError: Cannot determine main term of s + t since there
1343
+ are several maximal elements s, t.
1344
+ """
1345
+ if not self.summands:
1346
+ raise ZeroDivisionError(
1347
+ 'Cannot invert {} in {}.'.format(self, self.parent()))
1348
+
1349
+ (imax_elem, x) = self._main_term_relative_error_(return_inverse_main_term=True)
1350
+ one = x.parent().one()
1351
+
1352
+ if x:
1353
+ import itertools
1354
+ result = AsymptoticExpansion._power_series_(
1355
+ coefficients=itertools.repeat(one),
1356
+ start=one,
1357
+ ratio=-x,
1358
+ ratio_start=one,
1359
+ precision=precision)
1360
+ else:
1361
+ result = one
1362
+
1363
+ return result._mul_term_(imax_elem)
1364
+
1365
+ invert = __invert__
1366
+
1367
+ def truncate(self, precision=None):
1368
+ r"""
1369
+ Truncate this asymptotic expansion.
1370
+
1371
+ INPUT:
1372
+
1373
+ - ``precision`` -- positive integer or ``None``. Number of
1374
+ summands that are kept. If ``None`` (default value) is
1375
+ given, then ``default_prec`` from the parent is used.
1376
+
1377
+ OUTPUT: an asymptotic expansion
1378
+
1379
+ .. NOTE::
1380
+
1381
+ For example, truncating an asymptotic expansion with
1382
+ ``precision=20`` does not yield an expansion with exactly 20
1383
+ summands! Rather than that, it keeps the 20 summands
1384
+ with the largest growth, and adds appropriate
1385
+ `O`-Terms.
1386
+
1387
+ EXAMPLES::
1388
+
1389
+ sage: R.<x> = AsymptoticRing('x^ZZ', QQ)
1390
+ sage: ex = sum(x^k for k in range(5)); ex
1391
+ x^4 + x^3 + x^2 + x + 1
1392
+ sage: ex.truncate(precision=2)
1393
+ x^4 + x^3 + O(x^2)
1394
+ sage: ex.truncate(precision=0)
1395
+ O(x^4)
1396
+ sage: ex.truncate()
1397
+ x^4 + x^3 + x^2 + x + 1
1398
+ """
1399
+ if precision is None:
1400
+ precision = self.parent().default_prec
1401
+
1402
+ if len(self.summands) <= precision:
1403
+ return self
1404
+
1405
+ summands = self.summands.copy()
1406
+
1407
+ def convert_terms(element):
1408
+ if convert_terms.count < precision:
1409
+ convert_terms.count += 1
1410
+ return element
1411
+ T = self.parent().term_monoid('O')
1412
+ return T(element)
1413
+ convert_terms.count = 0
1414
+ summands.map(convert_terms, topological=True, reverse=True)
1415
+ return self.parent()(summands, simplify=True, convert=False)
1416
+
1417
+ def exact_part(self):
1418
+ r"""
1419
+ Return the expansion consisting of all exact terms of this
1420
+ expansion.
1421
+
1422
+ OUTPUT: an asymptotic expansion
1423
+
1424
+ EXAMPLES::
1425
+
1426
+ sage: R.<x> = AsymptoticRing('x^QQ * log(x)^QQ', QQ)
1427
+ sage: (x^2 + O(x)).exact_part()
1428
+ x^2
1429
+ sage: (x + log(x)/2 + O(log(x)/x)).exact_part()
1430
+ x + 1/2*log(x)
1431
+
1432
+ TESTS::
1433
+
1434
+ sage: R.<x, y> = AsymptoticRing('x^QQ * y^QQ', QQ)
1435
+ sage: (x + y + O(1/(x*y))).exact_part()
1436
+ x + y
1437
+ sage: O(x).exact_part()
1438
+ 0
1439
+ """
1440
+ exact_terms = self.summands.copy()
1441
+ for term in self.summands.elements_topological():
1442
+ if not term.is_exact():
1443
+ exact_terms.remove(term.growth)
1444
+
1445
+ return self.parent(exact_terms)
1446
+
1447
+ def error_part(self):
1448
+ r"""
1449
+ Return the expansion consisting of all error terms of this
1450
+ expansion.
1451
+
1452
+ OUTPUT: an asymptotic expansion
1453
+
1454
+ EXAMPLES::
1455
+
1456
+ sage: R.<x,y> = AsymptoticRing('x^QQ * log(x)^QQ * y^QQ', QQ)
1457
+ sage: (x*log(x) + y^2 + O(x) + O(y)).error_part()
1458
+ O(x) + O(y)
1459
+ """
1460
+ parent = self.parent()
1461
+ return sum((parent(term)
1462
+ for term in self.summands.elements_topological()
1463
+ if not term.is_exact()),
1464
+ parent.zero())
1465
+
1466
+ def __pow__(self, exponent, precision=None):
1467
+ r"""
1468
+ Calculate the power of this asymptotic expansion to the given ``exponent``.
1469
+
1470
+ INPUT:
1471
+
1472
+ - ``exponent`` -- an element
1473
+
1474
+ - ``precision`` -- the precision used for truncating the
1475
+ expansion. If ``None`` (default value) is used, the
1476
+ default precision of the parent is used.
1477
+
1478
+ OUTPUT: an asymptotic expansion
1479
+
1480
+ EXAMPLES::
1481
+
1482
+ sage: Q.<x> = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ)
1483
+ sage: x^(1/7)
1484
+ x^(1/7)
1485
+ sage: (x^(1/2) + O(x^0))^15
1486
+ x^(15/2) + O(x^7)
1487
+
1488
+ ::
1489
+
1490
+ sage: Z.<y> = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=ZZ)
1491
+ sage: y^(1/7)
1492
+ y^(1/7)
1493
+ sage: _.parent()
1494
+ Asymptotic Ring <y^QQ> over Rational Field
1495
+ sage: (y^2 + O(y))^(1/2)
1496
+ y + O(1)
1497
+ sage: (y^2 + O(y))^(-2)
1498
+ y^(-4) + O(y^(-5))
1499
+ sage: (1 + 1/y + O(1/y^3))^pi
1500
+ 1 + pi*y^(-1) + (1/2*pi*(pi - 1))*y^(-2) + O(y^(-3))
1501
+
1502
+ ::
1503
+
1504
+ sage: B.<z> = AsymptoticRing(growth_group='z^QQ * log(z)^QQ', coefficient_ring=QQ)
1505
+ sage: (z^2 + O(z))^(1/2)
1506
+ z + O(1)
1507
+
1508
+ ::
1509
+
1510
+ sage: A.<x> = AsymptoticRing('QQ^x * x^SR * log(x)^ZZ', QQ)
1511
+ sage: x * 2^x
1512
+ 2^x*x
1513
+ sage: 5^x * 2^x
1514
+ 10^x
1515
+ sage: 2^log(x)
1516
+ x^(log(2))
1517
+ sage: 2^(x + 1/x)
1518
+ 2^x + log(2)*2^x*x^(-1) + 1/2*log(2)^2*2^x*x^(-2) + ... + O(2^x*x^(-20))
1519
+ sage: _.parent()
1520
+ Asymptotic Ring <QQ^x * x^SR * log(x)^QQ * Signs^x> over Symbolic Ring
1521
+
1522
+ ::
1523
+
1524
+ sage: C.<c> = AsymptoticRing(growth_group='QQ^c * c^QQ', coefficient_ring=QQ, default_prec=5)
1525
+ sage: (3 + 1/c^2)^c
1526
+ 3^c + 1/3*3^c*c^(-1) + 1/18*3^c*c^(-2) - 4/81*3^c*c^(-3)
1527
+ - 35/1944*3^c*c^(-4) + O(3^c*c^(-5))
1528
+ sage: _.parent()
1529
+ Asymptotic Ring <QQ^c * c^QQ * Signs^c> over Rational Field
1530
+ sage: (2 + (1/3)^c)^c
1531
+ 2^c + 1/2*(2/3)^c*c + 1/8*(2/9)^c*c^2 - 1/8*(2/9)^c*c
1532
+ + 1/48*(2/27)^c*c^3 + O((2/27)^c*c^2)
1533
+ sage: _.parent()
1534
+ Asymptotic Ring <QQ^c * c^QQ * Signs^c> over Rational Field
1535
+
1536
+ TESTS:
1537
+
1538
+ See :issue:`19110`::
1539
+
1540
+ sage: O(x)^(-1)
1541
+ Traceback (most recent call last):
1542
+ ...
1543
+ ZeroDivisionError: Cannot take O(x) to exponent -1.
1544
+ > *previous* ZeroDivisionError: rational division by zero
1545
+
1546
+ ::
1547
+
1548
+ sage: B.<z> = AsymptoticRing(growth_group='z^QQ * log(z)^QQ', coefficient_ring=QQ, default_prec=5)
1549
+ sage: z^(1+1/z)
1550
+ z + log(z) + 1/2*z^(-1)*log(z)^2 + 1/6*z^(-2)*log(z)^3 +
1551
+ 1/24*z^(-3)*log(z)^4 + O(z^(-4)*log(z)^5)
1552
+ sage: _.parent()
1553
+ Asymptotic Ring <z^QQ * log(z)^QQ> over Rational Field
1554
+
1555
+ ::
1556
+
1557
+ sage: B(0)^(-7)
1558
+ Traceback (most recent call last):
1559
+ ...
1560
+ ZeroDivisionError: Cannot take 0 to the negative exponent -7.
1561
+ sage: B(0)^SR.var('a')
1562
+ Traceback (most recent call last):
1563
+ ...
1564
+ NotImplementedError: Taking 0 to the exponent a not implemented.
1565
+
1566
+ ::
1567
+
1568
+ sage: C.<s, t> = AsymptoticRing(growth_group='s^QQ * t^QQ', coefficient_ring=QQ)
1569
+ sage: (s + t)^s
1570
+ Traceback (most recent call last):
1571
+ ...
1572
+ ValueError: Cannot take s + t to the exponent s.
1573
+ > *previous* ValueError: Cannot determine main term of s + t
1574
+ since there are several maximal elements s, t.
1575
+
1576
+ Check that :issue:`19945` is fixed::
1577
+
1578
+ sage: A.<n> = AsymptoticRing('QQ^n * n^QQ', ZZ)
1579
+ sage: (1/2)^n
1580
+ (1/2)^n
1581
+
1582
+ Check that :issue:`19946` is fixed::
1583
+
1584
+ sage: assume(SR.an_element() > 0)
1585
+ sage: A.<n> = AsymptoticRing('QQ^n * n^QQ', SR)
1586
+ sage: e = 2^n; e
1587
+ 2^n
1588
+ sage: e.parent()
1589
+ Asymptotic Ring <SR^n * n^QQ * Signs^n> over Symbolic Ring
1590
+ sage: e = A(e); e
1591
+ 2^n
1592
+ sage: e.parent()
1593
+ Asymptotic Ring <QQ^n * n^QQ * Signs^n> over Symbolic Ring
1594
+ sage: forget()
1595
+
1596
+ :issue:`22120`::
1597
+
1598
+ sage: A.<w> = AsymptoticRing('w^QQbar', QQ)
1599
+ sage: w^QQbar(sqrt(2))
1600
+ w^(1.414213562373095?)
1601
+ """
1602
+ from .misc import strip_symbolic
1603
+ exponent = strip_symbolic(exponent)
1604
+
1605
+ if not self.summands:
1606
+ if exponent == 0:
1607
+ return self.parent().one()
1608
+ elif exponent > 0:
1609
+ return self.parent().zero()
1610
+ elif exponent < 0:
1611
+ raise ZeroDivisionError('Cannot take %s to the negative exponent %s.' %
1612
+ (self, exponent))
1613
+ else:
1614
+ raise NotImplementedError('Taking %s to the exponent %s not implemented.' %
1615
+ (self, exponent))
1616
+
1617
+ elif exponent == 0:
1618
+ return self.parent().one()
1619
+
1620
+ elif exponent == 1:
1621
+ return self
1622
+
1623
+ elif len(self.summands) == 1:
1624
+ element = next(self.summands.elements())
1625
+ if isinstance(exponent, AsymptoticExpansion) and element.is_constant():
1626
+
1627
+ return exponent.rpow(base=element.coefficient, precision=precision)
1628
+ try:
1629
+ return self.parent()._create_element_in_extension_(
1630
+ element ** exponent, element.parent())
1631
+ except (ArithmeticError, TypeError, ValueError):
1632
+ if not isinstance(exponent, AsymptoticExpansion):
1633
+ raise
1634
+
1635
+ from sage.rings.integer_ring import ZZ
1636
+ try:
1637
+ exponent = ZZ(exponent)
1638
+ except (TypeError, ValueError):
1639
+ pass
1640
+ else:
1641
+ return super().__pow__(exponent)
1642
+
1643
+ from sage.rings.rational_field import QQ
1644
+ try:
1645
+ exponent = QQ(exponent)
1646
+ except (TypeError, ValueError):
1647
+ pass
1648
+ else:
1649
+ return self.__pow_number__(exponent, precision=precision)
1650
+
1651
+ from sage.structure.element import Expression
1652
+ if isinstance(exponent, Expression) and exponent.is_constant():
1653
+ return self.__pow_number__(exponent, precision=precision)
1654
+
1655
+ if isinstance(exponent, AsymptoticExpansion) and len(self.summands) != 1:
1656
+ try:
1657
+ return self.__pow_number__(exponent, precision=precision,
1658
+ check_convergence=True)
1659
+ except NoConvergenceError:
1660
+ pass
1661
+
1662
+ try:
1663
+ return (exponent * self.log(precision=precision)).exp(precision=precision)
1664
+ except (TypeError, ValueError, ZeroDivisionError) as e:
1665
+ from .misc import combine_exceptions
1666
+ raise combine_exceptions(
1667
+ ValueError('Cannot take %s to the exponent %s.' % (self, exponent)), e)
1668
+
1669
+ pow = __pow__
1670
+
1671
+ def __pow_number__(self, exponent, precision=None, check_convergence=False):
1672
+ r"""
1673
+ Return the power of this asymptotic expansion to some
1674
+ number (``exponent``).
1675
+
1676
+ Let `m` be the maximal element of this asymptotic expansion
1677
+ and `r` the remaining summands. This method calculates
1678
+
1679
+ .. MATH::
1680
+
1681
+ (m + r)^{\mathit{exponent}}
1682
+ = m^{\mathit{exponent}} \sum_{k=0}^K
1683
+ \binom{\mathit{exponent}}{k} (r/m)^k
1684
+
1685
+ where `K` is chosen such that adding an additional summand
1686
+ does not change the result.
1687
+
1688
+ INPUT:
1689
+
1690
+ - ``exponent`` -- a numerical value (e.g. integer, rational)
1691
+ or other constant
1692
+
1693
+ - ``precision`` -- nonnegative integer
1694
+
1695
+ - ``check_convergence`` -- boolean (default: ``False``); if set,
1696
+ then an additional check on the input is performed to ensure
1697
+ that the calculated sum converges
1698
+
1699
+ OUTPUT: an asymptotic expansion
1700
+
1701
+ .. SEEALSO::
1702
+
1703
+ :meth:`pow`
1704
+
1705
+ TESTS::
1706
+
1707
+ sage: R.<x> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
1708
+ sage: (1 + x).__pow_number__(4)
1709
+ x^4 + 4*x^3 + 6*x^2 + 4*x + 1
1710
+ sage: _.parent()
1711
+ Asymptotic Ring <x^ZZ> over Rational Field
1712
+ sage: (x + 1).__pow_number__(1/2, precision=5)
1713
+ x^(1/2) + 1/2*x^(-1/2) - 1/8*x^(-3/2) + 1/16*x^(-5/2)
1714
+ - 5/128*x^(-7/2) + O(x^(-9/2))
1715
+ sage: _.parent()
1716
+ Asymptotic Ring <x^QQ> over Rational Field
1717
+ sage: (8 + 1/x).__pow_number__(1/3, precision=5)
1718
+ 2 + 1/12*x^(-1) - 1/288*x^(-2) + 5/20736*x^(-3)
1719
+ - 5/248832*x^(-4) + O(x^(-5))
1720
+ sage: _.parent()
1721
+ Asymptotic Ring <x^QQ> over Rational Field
1722
+
1723
+ ::
1724
+
1725
+ sage: R(0).__pow_number__(-3/2)
1726
+ Traceback (most recent call last):
1727
+ ...
1728
+ ZeroDivisionError: Cannot take 0 to the negative exponent -3/2.
1729
+ sage: R(0).__pow_number__(RIF(-1,1))
1730
+ Traceback (most recent call last):
1731
+ ...
1732
+ ValueError: Possible division by zero, since sign of
1733
+ the exponent 0.? cannot be determined.
1734
+ sage: R(0)^0
1735
+ 1
1736
+
1737
+ ::
1738
+
1739
+ sage: A.<a, b> = AsymptoticRing(growth_group='a^ZZ * b^ZZ', coefficient_ring=QQ)
1740
+ sage: (a + b).__pow_number__(3/2)
1741
+ Traceback (most recent call last):
1742
+ ...
1743
+ ValueError: Cannot determine main term of a + b since
1744
+ there are several maximal elements a, b.
1745
+
1746
+ ::
1747
+
1748
+ sage: S.<s> = AsymptoticRing(growth_group='QQ^s * s^ZZ', coefficient_ring=QQ)
1749
+ sage: (2 + 2/s^2).__pow_number__(s, precision=7)
1750
+ 2^s + 2^s*s^(-1) + 1/2*2^s*s^(-2) - 1/3*2^s*s^(-3)
1751
+ - 11/24*2^s*s^(-4) + 11/120*2^s*s^(-5)
1752
+ + 271/720*2^s*s^(-6) + O(2^s*s^(-7))
1753
+ sage: _.parent()
1754
+ Asymptotic Ring <QQ^s * s^QQ * Signs^s> over Rational Field
1755
+
1756
+ sage: S.<s> = AsymptoticRing(growth_group='(QQ_+)^s * s^ZZ', coefficient_ring=QQ)
1757
+ sage: (2 + 2/s^2).__pow_number__(s, precision=7)
1758
+ 2^s + 2^s*s^(-1) + 1/2*2^s*s^(-2) - 1/3*2^s*s^(-3)
1759
+ - 11/24*2^s*s^(-4) + 11/120*2^s*s^(-5)
1760
+ + 271/720*2^s*s^(-6) + O(2^s*s^(-7))
1761
+ sage: _.parent()
1762
+ Asymptotic Ring <QQ^s * s^QQ> over Rational Field
1763
+ """
1764
+ if not self.summands:
1765
+ if exponent > 0:
1766
+ return self.parent().zero()
1767
+ elif exponent.is_zero():
1768
+ return self.parent().one()
1769
+ elif exponent < 0:
1770
+ raise ZeroDivisionError(
1771
+ 'Cannot take {} to the negative '
1772
+ 'exponent {}.'.format(self, exponent))
1773
+ else:
1774
+ raise ValueError(
1775
+ 'Possible division by zero, since sign of the exponent '
1776
+ '{} cannot be determined.'.format(exponent))
1777
+
1778
+ elif len(self.summands) == 1:
1779
+ element = next(self.summands.elements())
1780
+ return self.parent()._create_element_in_extension_(
1781
+ element**exponent, element.parent())
1782
+
1783
+ try:
1784
+ (max_elem, x) = self._main_term_relative_error_()
1785
+ except ValueError:
1786
+ if check_convergence:
1787
+ raise NoConvergenceError
1788
+ raise
1789
+
1790
+ if check_convergence:
1791
+ if not (x * exponent).is_little_o_of_one():
1792
+ raise NoConvergenceError
1793
+
1794
+ pmax = self.parent()(max_elem)**exponent
1795
+
1796
+ import itertools
1797
+
1798
+ def binomials(a):
1799
+ P = a.parent()
1800
+ a = a + 1
1801
+ f = P(1)
1802
+ for k in itertools.count(1):
1803
+ k = P(k)
1804
+ b = a - k
1805
+ if b == 0:
1806
+ return
1807
+ f *= b / k
1808
+ yield f
1809
+
1810
+ one = x.parent().one()
1811
+
1812
+ result = AsymptoticExpansion._power_series_(
1813
+ coefficients=binomials(exponent),
1814
+ start=one,
1815
+ ratio=x,
1816
+ ratio_start=one,
1817
+ precision=precision)
1818
+
1819
+ return result * pmax
1820
+
1821
+ def sqrt(self, precision=None):
1822
+ r"""
1823
+ Return the square root of this asymptotic expansion.
1824
+
1825
+ INPUT:
1826
+
1827
+ - ``precision`` -- the precision used for truncating the
1828
+ expansion. If ``None`` (default value) is used, the
1829
+ default precision of the parent is used.
1830
+
1831
+ OUTPUT: an asymptotic expansion
1832
+
1833
+ EXAMPLES::
1834
+
1835
+ sage: A.<s> = AsymptoticRing(growth_group='s^QQ', coefficient_ring=QQ)
1836
+ sage: s.sqrt()
1837
+ s^(1/2)
1838
+ sage: a = (1 + 1/s).sqrt(precision=6); a
1839
+ 1 + 1/2*s^(-1) - 1/8*s^(-2) + 1/16*s^(-3)
1840
+ - 5/128*s^(-4) + 7/256*s^(-5) + O(s^(-6))
1841
+
1842
+ .. SEEALSO::
1843
+
1844
+ :meth:`pow`, :meth:`rpow`, :meth:`exp`.
1845
+
1846
+ TESTS::
1847
+
1848
+ sage: P.<p> = PowerSeriesRing(QQ, default_prec=6)
1849
+ sage: bool(SR(a.exact_part()).subs(s=1/x) -
1850
+ ....: SR((1+p).sqrt().polynomial()).subs(p=x) == 0)
1851
+ True
1852
+ """
1853
+ from sage.rings.rational_field import QQ
1854
+ return self.pow(QQ((1, 2)), precision=precision)
1855
+
1856
+ def O(self):
1857
+ r"""
1858
+ Convert all terms in this asymptotic expansion to `O`-terms.
1859
+
1860
+ OUTPUT: an asymptotic expansion
1861
+
1862
+ EXAMPLES::
1863
+
1864
+ sage: AR.<x> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
1865
+ sage: O(x)
1866
+ O(x)
1867
+ sage: type(O(x))
1868
+ <class 'sage.rings.asymptotic.asymptotic_ring.AsymptoticRing_with_category.element_class'>
1869
+ sage: expr = 42*x^42 + x^10 + O(x^2); expr
1870
+ 42*x^42 + x^10 + O(x^2)
1871
+ sage: expr.O()
1872
+ O(x^42)
1873
+ sage: (2*x).O()
1874
+ O(x)
1875
+
1876
+ .. SEEALSO::
1877
+
1878
+ :func:`sage.rings.power_series_ring.PowerSeriesRing`,
1879
+ :func:`sage.rings.laurent_series_ring.LaurentSeriesRing`.
1880
+
1881
+ TESTS::
1882
+
1883
+ sage: AR(0).O()
1884
+ Traceback (most recent call last):
1885
+ ...
1886
+ NotImplementedOZero: got O(0)
1887
+ The error term O(0) means 0 for sufficiently large x.
1888
+ """
1889
+ if not self.summands:
1890
+ from .misc import NotImplementedOZero
1891
+ raise NotImplementedOZero(self.parent(), exact_part=self.parent().zero())
1892
+ return sum(self.parent().create_summand('O', growth=element)
1893
+ for element in self.summands.maximal_elements())
1894
+
1895
+ def log(self, base=None, precision=None, locals=None):
1896
+ r"""
1897
+ The logarithm of this asymptotic expansion.
1898
+
1899
+ INPUT:
1900
+
1901
+ - ``base`` -- the base of the logarithm. If ``None``
1902
+ (default value) is used, the natural logarithm is taken.
1903
+
1904
+ - ``precision`` -- the precision used for truncating the
1905
+ expansion. If ``None`` (default value) is used, the
1906
+ default precision of the parent is used.
1907
+
1908
+ - ``locals`` -- dictionary which may contain the following keys and values:
1909
+
1910
+ - ``'log'`` -- value: a function. If not used, then the usual
1911
+ :class:`log <sage.functions.log.Function_log>` is taken.
1912
+
1913
+ OUTPUT: an asymptotic expansion
1914
+
1915
+ .. NOTE::
1916
+
1917
+ Computing the logarithm of an asymptotic expansion
1918
+ is possible if and only if there is exactly one maximal
1919
+ summand in the expansion.
1920
+
1921
+ ALGORITHM:
1922
+
1923
+ If the expansion has more than one summand,
1924
+ the asymptotic expansion for `\log(1+t)` as `t` tends to `0`
1925
+ is used.
1926
+
1927
+ .. TODO::
1928
+
1929
+ As soon as `L`-terms are implemented, this
1930
+ implementation has to be adapted as well in order to
1931
+ yield correct results.
1932
+
1933
+ EXAMPLES::
1934
+
1935
+ sage: R.<x> = AsymptoticRing(growth_group='x^ZZ * log(x)^ZZ', coefficient_ring=QQ)
1936
+ sage: log(x)
1937
+ log(x)
1938
+ sage: log(x^2)
1939
+ 2*log(x)
1940
+ sage: log(x-1)
1941
+ log(x) - x^(-1) - 1/2*x^(-2) - 1/3*x^(-3) - ... + O(x^(-21))
1942
+
1943
+ The coefficient ring is automatically extended if needed::
1944
+
1945
+ sage: R.<x> = AsymptoticRing(growth_group='x^ZZ * log(x)^ZZ', coefficient_ring=ZZ, default_prec=3)
1946
+ sage: (49*x^3-1).log()
1947
+ 3*log(x) + 2*log(7) - 1/49*x^(-3) - 1/4802*x^(-6) ... + O(x^(-12))
1948
+ sage: _.parent()
1949
+ Asymptotic Ring <x^ZZ * log(x)^ZZ> over Symbolic Ring
1950
+
1951
+ If one wants to avoid this extending to the Symbolic Ring, then
1952
+ the following helps::
1953
+
1954
+ sage: L.<log7> = ZZ[]
1955
+ sage: def mylog(z, base=None):
1956
+ ....: try:
1957
+ ....: if ZZ(z).is_power_of(7):
1958
+ ....: return log(ZZ(z), 7) * log7
1959
+ ....: except (TypeError, ValueError):
1960
+ ....: pass
1961
+ ....: return log(z, base)
1962
+ sage: R.<x> = AsymptoticRing(growth_group='x^ZZ * log(x)^ZZ', coefficient_ring=L, default_prec=3)
1963
+ sage: (49*x^3-1).log(locals={'log': mylog})
1964
+ 3*log(x) + 2*log7 - 1/49*x^(-3) - 1/4802*x^(-6) ... + O(x^(-12))
1965
+
1966
+ A ``log``-function can also be specified to always be used with the
1967
+ asymptotic ring::
1968
+
1969
+ sage: R.<x> = AsymptoticRing(growth_group='x^ZZ * log(x)^ZZ', coefficient_ring=L, default_prec=3, locals={'log': mylog})
1970
+ sage: log(49*x^3-1)
1971
+ 3*log(x) + 2*log7 - 1/49*x^(-3) - 1/4802*x^(-6) - 1/352947*x^(-9) + O(x^(-12))
1972
+
1973
+ TESTS::
1974
+
1975
+ sage: R.<x> = AsymptoticRing(growth_group='x^ZZ * log(x)^ZZ', coefficient_ring=QQ)
1976
+ sage: log(R(1))
1977
+ 0
1978
+ sage: log(R(0))
1979
+ Traceback (most recent call last):
1980
+ ...
1981
+ ArithmeticError: Cannot compute log(0) in
1982
+ Asymptotic Ring <x^ZZ * log(x)^ZZ> over Rational Field.
1983
+ sage: C.<s, t> = AsymptoticRing(growth_group='s^ZZ * t^ZZ', coefficient_ring=QQ)
1984
+ sage: log(s + t)
1985
+ Traceback (most recent call last):
1986
+ ...
1987
+ ValueError: Cannot determine main term of s + t since
1988
+ there are several maximal elements s, t.
1989
+ """
1990
+ P = self.parent()
1991
+ locals = P.locals(locals)
1992
+ log = locals['log']
1993
+
1994
+ if not self.summands:
1995
+ raise ArithmeticError('Cannot compute log(0) in %s.' % (self.parent(),))
1996
+
1997
+ elif len(self.summands) == 1:
1998
+ if self.is_one():
1999
+ return P.zero()
2000
+ element = next(self.summands.elements())
2001
+ return sum(P._create_element_in_extension_(l, element.parent())
2002
+ for l in element.log_term(base=base,
2003
+ locals=locals))
2004
+
2005
+ (max_elem, x) = self._main_term_relative_error_()
2006
+ geom = -x
2007
+
2008
+ from sage.rings.integer_ring import ZZ
2009
+ import itertools
2010
+
2011
+ result = - AsymptoticExpansion._power_series_(
2012
+ coefficients=iter(1 / ZZ(k)
2013
+ for k in itertools.count(2)),
2014
+ start=geom,
2015
+ ratio=geom,
2016
+ ratio_start=geom,
2017
+ precision=precision)
2018
+
2019
+ if base:
2020
+ result = result / log(base)
2021
+
2022
+ result += x.parent()(max_elem).log(base=base, locals=locals)
2023
+
2024
+ return result
2025
+
2026
+ def is_exact(self) -> bool:
2027
+ r"""
2028
+ Return whether all terms of this expansion are exact.
2029
+
2030
+ OUTPUT: boolean
2031
+
2032
+ EXAMPLES::
2033
+
2034
+ sage: A.<x> = AsymptoticRing('x^QQ * log(x)^QQ', QQ)
2035
+ sage: (x^2 + O(x)).is_exact()
2036
+ False
2037
+ sage: (x^2 - x).is_exact()
2038
+ True
2039
+
2040
+ TESTS::
2041
+
2042
+ sage: A(0).is_exact()
2043
+ True
2044
+ sage: A.one().is_exact()
2045
+ True
2046
+ """
2047
+ return all(T.is_exact() for T in self.summands)
2048
+
2049
+ def is_little_o_of_one(self) -> bool:
2050
+ r"""
2051
+ Return whether this expansion is of order `o(1)`.
2052
+
2053
+ OUTPUT: boolean
2054
+
2055
+ EXAMPLES::
2056
+
2057
+ sage: A.<x> = AsymptoticRing('x^ZZ * log(x)^ZZ', QQ)
2058
+ sage: (x^4 * log(x)^(-2) + x^(-4) * log(x)^2).is_little_o_of_one()
2059
+ False
2060
+ sage: (x^(-1) * log(x)^1234 + x^(-2) + O(x^(-3))).is_little_o_of_one()
2061
+ True
2062
+ sage: (log(x) - log(x-1)).is_little_o_of_one()
2063
+ True
2064
+
2065
+ ::
2066
+
2067
+ sage: A.<x, y> = AsymptoticRing('x^QQ * y^QQ * log(y)^ZZ', QQ)
2068
+ sage: (x^(-1/16) * y^32 + x^32 * y^(-1/16)).is_little_o_of_one()
2069
+ False
2070
+ sage: (x^(-1) * y^(-3) + x^(-3) * y^(-1)).is_little_o_of_one()
2071
+ True
2072
+ sage: (x^(-1) * y / log(y)).is_little_o_of_one()
2073
+ False
2074
+ sage: (log(y-1)/log(y) - 1).is_little_o_of_one()
2075
+ True
2076
+
2077
+ .. SEEALSO::
2078
+
2079
+ :meth:`limit`
2080
+ """
2081
+ return all(term.is_little_o_of_one() for term in self.summands.maximal_elements())
2082
+
2083
+ def rpow(self, base, precision=None, locals=None):
2084
+ r"""
2085
+ Return the power of ``base`` to this asymptotic expansion.
2086
+
2087
+ INPUT:
2088
+
2089
+ - ``base`` -- an element or ``'e'``
2090
+
2091
+ - ``precision`` -- the precision used for truncating the
2092
+ expansion. If ``None`` (default value) is used, the
2093
+ default precision of the parent is used.
2094
+
2095
+ - ``locals`` -- dictionary which may contain the following keys and values:
2096
+
2097
+ - ``'log'`` -- value: a function. If not used, then the usual
2098
+ :class:`log <sage.functions.log.Function_log>` is taken.
2099
+
2100
+ OUTPUT: an asymptotic expansion
2101
+
2102
+ EXAMPLES::
2103
+
2104
+ sage: A.<x> = AsymptoticRing('x^ZZ', QQ)
2105
+ sage: (1/x).rpow('e', precision=5)
2106
+ 1 + x^(-1) + 1/2*x^(-2) + 1/6*x^(-3) + 1/24*x^(-4) + O(x^(-5))
2107
+
2108
+ TESTS::
2109
+
2110
+ sage: assume(SR.an_element() > 0)
2111
+ sage: y = SR.var('y')
2112
+ sage: x.rpow(y)
2113
+ Traceback (most recent call last):
2114
+ ...
2115
+ ArithmeticError: Cannot construct y^x in Growth Group x^ZZ
2116
+ > *previous* TypeError: unsupported operand parent(s) for *:
2117
+ 'Growth Group x^ZZ' and 'Growth Group SR^x * Arg_SR^x'
2118
+ sage: assume(y > 0)
2119
+ sage: x.rpow(y)
2120
+ Traceback (most recent call last):
2121
+ ...
2122
+ ArithmeticError: Cannot construct y^x in Growth Group x^ZZ
2123
+ > *previous* TypeError: unsupported operand parent(s) for *:
2124
+ 'Growth Group x^ZZ' and 'Growth Group SR^x'
2125
+ sage: forget()
2126
+
2127
+ Check that :issue:`19946` is fixed::
2128
+
2129
+ sage: A.<n> = AsymptoticRing('(QQ_+)^n * n^QQ', SR)
2130
+ sage: n.rpow(2)
2131
+ 2^n
2132
+ sage: _.parent()
2133
+ Asymptotic Ring <QQ^n * n^QQ> over Symbolic Ring
2134
+ """
2135
+ if isinstance(base, AsymptoticExpansion):
2136
+ return base.__pow__(self, precision=precision)
2137
+
2138
+ P = self.parent()
2139
+
2140
+ # first: remove terms from a copy of this term such that a
2141
+ # term in o(1) remains
2142
+
2143
+ expr_o = self.summands.copy()
2144
+ large_terms = []
2145
+ for term in self.summands.elements_topological():
2146
+ if not term.is_little_o_of_one():
2147
+ large_terms.append(term)
2148
+ expr_o.remove(term.growth)
2149
+
2150
+ expr_o = P(expr_o)
2151
+
2152
+ # next: try to take the exponential function of the large elements
2153
+
2154
+ try:
2155
+ large_result = P.prod(
2156
+ P._create_element_in_extension_(term.rpow(base),
2157
+ term.parent())
2158
+ for term in large_terms)
2159
+ except (TypeError, ValueError) as e:
2160
+ from .misc import combine_exceptions
2161
+ raise combine_exceptions(
2162
+ ValueError('Cannot construct the power of %s to the '
2163
+ 'exponent %s in %s.' %
2164
+ (base, self, self.parent())), e)
2165
+
2166
+ # then: expand expr_o
2167
+
2168
+ if not expr_o:
2169
+ return large_result
2170
+
2171
+ if base == 'e':
2172
+ geom = expr_o
2173
+ else:
2174
+ log = self.parent().locals(locals)['log']
2175
+ geom = expr_o * log(base)
2176
+ P = geom.parent()
2177
+
2178
+ from sage.rings.integer_ring import ZZ
2179
+ import itertools
2180
+
2181
+ def inverted_factorials():
2182
+ f = ZZ.one()
2183
+ for k in itertools.count(1):
2184
+ f /= ZZ(k)
2185
+ yield f
2186
+
2187
+ result = AsymptoticExpansion._power_series_(
2188
+ coefficients=inverted_factorials(),
2189
+ start=P.one(),
2190
+ ratio=geom,
2191
+ ratio_start=P.one(),
2192
+ precision=precision)
2193
+
2194
+ return result * large_result
2195
+
2196
+ def _main_term_relative_error_(self, return_inverse_main_term=False):
2197
+ r"""
2198
+ Split this asymptotic expansion into `m(1+x)` with `x=o(1)`.
2199
+
2200
+ INPUT:
2201
+
2202
+ - ``return_inverse_main_term`` -- boolean (default: ``False``);
2203
+ if set, then the pair `(m^{-1},x)` is returned instead of `(m,x)`
2204
+
2205
+ OUTPUT:
2206
+
2207
+ A pair (``m``, ``x``) consisting of
2208
+ a :mod:`term <sage.rings.asymptotic.term_monoid>` ``m`` and
2209
+ an :class:`asymptotic expansion <AsymptoticExpansion>` ``x``.
2210
+
2211
+ EXAMPLES::
2212
+
2213
+ sage: R.<n> = AsymptoticRing('n^ZZ', QQ)
2214
+ sage: ex = 2*n^2 + n + O(1/n)
2215
+ sage: (m, x) = ex._main_term_relative_error_()
2216
+ sage: m
2217
+ 2*n^2
2218
+ sage: x
2219
+ 1/2*n^(-1) + O(n^(-3))
2220
+ sage: ex = 2*n^2 + n
2221
+ sage: (m, x) = ex._main_term_relative_error_()
2222
+ sage: m
2223
+ 2*n^2
2224
+ sage: x
2225
+ 1/2*n^(-1)
2226
+ sage: ex._main_term_relative_error_(return_inverse_main_term=True)
2227
+ (1/2*n^(-2), 1/2*n^(-1))
2228
+ sage: R(0)._main_term_relative_error_()
2229
+ Traceback (most recent call last):
2230
+ ...
2231
+ ArithmeticError: Cannot determine main term of 0.
2232
+
2233
+ TESTS::
2234
+
2235
+ sage: R.<m, n> = AsymptoticRing('n^ZZ*m^ZZ', QQ)
2236
+ sage: (m + n)._main_term_relative_error_()
2237
+ Traceback (most recent call last):
2238
+ ...
2239
+ ValueError: Cannot determine main term of m + n since
2240
+ there are several maximal elements m, n.
2241
+ """
2242
+ if not self.summands:
2243
+ raise ArithmeticError("Cannot determine main term of 0.")
2244
+
2245
+ max_elem = tuple(self.summands.maximal_elements())
2246
+ if len(max_elem) != 1:
2247
+ raise ValueError('Cannot determine main term of {} since there '
2248
+ 'are several maximal elements {}.'.format(
2249
+ self, ', '.join(str(e) for e in
2250
+ sorted(max_elem, key=str))))
2251
+ max_elem = max_elem[0]
2252
+
2253
+ imax_elem = ~max_elem
2254
+ if imax_elem.parent() is max_elem.parent():
2255
+ new_self = self
2256
+ else:
2257
+ new_self = self.parent()._create_element_in_extension_(
2258
+ imax_elem, max_elem.parent()).parent()(self)
2259
+
2260
+ one = new_self.parent().one()
2261
+ x = - one + new_self._mul_term_(imax_elem)
2262
+
2263
+ if return_inverse_main_term:
2264
+ return (imax_elem, x)
2265
+ else:
2266
+ return (max_elem, x)
2267
+
2268
+ @staticmethod
2269
+ def _power_series_(coefficients, start, ratio, ratio_start, precision):
2270
+ r"""
2271
+ Return a taylor series.
2272
+
2273
+ Let `c_k` be determined by the ``coefficients`` and set
2274
+
2275
+ .. MATH::
2276
+
2277
+ s_k = c_k \cdot \mathit{ratio\_start} \cdot \mathit{ratio}^k.
2278
+
2279
+ The result is
2280
+
2281
+ .. MATH::
2282
+
2283
+ \mathit{start} + \sum_{k=1}^K s_k
2284
+
2285
+ where `K` is chosen such that adding `s_{K+1}` does not change
2286
+ the result.
2287
+
2288
+ INPUT:
2289
+
2290
+ - ``coefficients`` -- an iterator
2291
+
2292
+ - ``start`` -- an asymptotic expansion
2293
+
2294
+ - ``ratio`` -- an asymptotic expansion
2295
+
2296
+ - ``ratio_start`` -- an asymptotic expansion
2297
+
2298
+ - ``precision`` -- nonnegative integer; all intermediate
2299
+ results are truncated to this precision
2300
+
2301
+ OUTPUT: an asymptotic expansion
2302
+
2303
+ TESTS::
2304
+
2305
+ sage: from sage.rings.asymptotic.asymptotic_ring import AsymptoticExpansion
2306
+ sage: from itertools import count
2307
+ sage: A.<g> = AsymptoticRing('g^ZZ', QQ)
2308
+ sage: AsymptoticExpansion._power_series_(
2309
+ ....: coefficients=iter(ZZ(k) for k in count(1)),
2310
+ ....: start=A(42),
2311
+ ....: ratio=1/g,
2312
+ ....: ratio_start=A(5),
2313
+ ....: precision=4)
2314
+ 42 + 5*g^(-1) + 10*g^(-2) + 15*g^(-3) + O(g^(-4))
2315
+ sage: AsymptoticExpansion._power_series_(
2316
+ ....: coefficients=iter(ZZ(k) for k in count(1)),
2317
+ ....: start=A(42),
2318
+ ....: ratio=1/g+O(1/g^2),
2319
+ ....: ratio_start=A(5),
2320
+ ....: precision=4)
2321
+ 42 + 5*g^(-1) + O(g^(-2))
2322
+ sage: AsymptoticExpansion._power_series_(
2323
+ ....: coefficients=iter(ZZ(k) for k in count(1)),
2324
+ ....: start=A(42),
2325
+ ....: ratio=1/g+O(1/g^2),
2326
+ ....: ratio_start=A(5),
2327
+ ....: precision=1000000)
2328
+ 42 + 5*g^(-1) + O(g^(-2))
2329
+ """
2330
+ result = start
2331
+ g = ratio_start
2332
+ for c in coefficients:
2333
+ g *= ratio
2334
+ new_result = (result + c * g).truncate(precision=precision)
2335
+ if new_result.has_same_summands(result):
2336
+ break
2337
+ result = new_result
2338
+ return result
2339
+
2340
+ def exp(self, precision=None):
2341
+ r"""
2342
+ Return the exponential of (i.e., the power of `e` to) this asymptotic expansion.
2343
+
2344
+ INPUT:
2345
+
2346
+ - ``precision`` -- the precision used for truncating the
2347
+ expansion. If ``None`` (default value) is used, the
2348
+ default precision of the parent is used.
2349
+
2350
+ OUTPUT: an asymptotic expansion
2351
+
2352
+ .. NOTE::
2353
+
2354
+ The exponential function of this expansion can only be
2355
+ computed exactly if the respective growth element can be
2356
+ constructed in the underlying growth group.
2357
+
2358
+ ALGORITHM:
2359
+
2360
+ If the corresponding growth can be constructed, return
2361
+ the exact exponential function. Otherwise, if this term
2362
+ is `o(1)`, try to expand the series and truncate
2363
+ according to the given precision.
2364
+
2365
+ .. TODO::
2366
+
2367
+ As soon as `L`-terms are implemented, this
2368
+ implementation has to be adapted as well in order to
2369
+ yield correct results.
2370
+
2371
+ EXAMPLES::
2372
+
2373
+ sage: A.<x> = AsymptoticRing('(e^x)^ZZ * x^ZZ * log(x)^ZZ', SR)
2374
+ sage: exp(x)
2375
+ e^x
2376
+ sage: exp(2*x)
2377
+ (e^x)^2
2378
+ sage: exp(x + log(x))
2379
+ e^x*x
2380
+
2381
+ ::
2382
+
2383
+ sage: (x^(-1)).exp(precision=7)
2384
+ 1 + x^(-1) + 1/2*x^(-2) + 1/6*x^(-3) + ... + O(x^(-7))
2385
+
2386
+ TESTS::
2387
+
2388
+ sage: A.<x> = AsymptoticRing('(e^x)^ZZ * x^QQ * log(x)^QQ', SR)
2389
+ sage: exp(log(x))
2390
+ x
2391
+ sage: log(exp(x))
2392
+ x
2393
+
2394
+ ::
2395
+
2396
+ sage: exp(x+1)
2397
+ e*e^x
2398
+
2399
+ See :issue:`19521`::
2400
+
2401
+ sage: A.<n> = AsymptoticRing('n^ZZ', SR.subring(no_variables=True))
2402
+ sage: exp(O(n^(-3))).parent()
2403
+ Asymptotic Ring <n^ZZ> over Symbolic Constants Subring
2404
+ """
2405
+ return self.rpow('e', precision=precision)
2406
+
2407
+ def subs(self, rules=None, domain=None, **kwds):
2408
+ r"""
2409
+ Substitute the given ``rules`` in this asymptotic expansion.
2410
+
2411
+ INPUT:
2412
+
2413
+ - ``rules`` -- dictionary
2414
+
2415
+ - ``kwds`` -- keyword arguments will be added to the
2416
+ substitution ``rules``
2417
+
2418
+ - ``domain`` -- (default: ``None``) a parent. The neutral
2419
+ elements `0` and `1` (rules for the keys ``'_zero_'`` and
2420
+ ``'_one_'``, see note box below) are taken out of this
2421
+ domain. If ``None``, then this is determined automatically.
2422
+
2423
+ OUTPUT: an object
2424
+
2425
+ .. NOTE::
2426
+
2427
+ The neutral element of the asymptotic ring is replaced by
2428
+ the value to the key ``'_zero_'``; the neutral element of
2429
+ the growth group is replaced by the value to the key
2430
+ ``'_one_'``.
2431
+
2432
+ EXAMPLES::
2433
+
2434
+ sage: A.<x> = AsymptoticRing(growth_group='(e^x)^QQ * x^ZZ * log(x)^ZZ', coefficient_ring=QQ, default_prec=5)
2435
+
2436
+ ::
2437
+
2438
+ sage: (e^x * x^2 + log(x)).subs(x=SR('s'))
2439
+ s^2*e^s + log(s)
2440
+ sage: _.parent()
2441
+ Symbolic Ring
2442
+
2443
+ ::
2444
+
2445
+ sage: (x^3 + x + log(x)).subs(x=x+5).truncate(5)
2446
+ x^3 + 15*x^2 + 76*x + log(x) + 130 + O(x^(-1))
2447
+ sage: _.parent()
2448
+ Asymptotic Ring <(e^x)^QQ * x^ZZ * log(x)^ZZ> over Rational Field
2449
+
2450
+ ::
2451
+
2452
+ sage: (e^x * x^2 + log(x)).subs(x=2*x)
2453
+ 4*(e^x)^2*x^2 + log(x) + log(2)
2454
+ sage: _.parent()
2455
+ Asymptotic Ring <(e^x)^QQ * x^QQ * log(x)^QQ> over Symbolic Ring
2456
+
2457
+ ::
2458
+
2459
+ sage: (x^2 + log(x)).subs(x=4*x+2).truncate(5)
2460
+ 16*x^2 + 16*x + log(x) + 2*log(2) + 4 + 1/2*x^(-1) + O(x^(-2))
2461
+ sage: _.parent()
2462
+ Asymptotic Ring <(e^x)^QQ * x^ZZ * log(x)^ZZ> over Symbolic Ring
2463
+
2464
+ ::
2465
+
2466
+ sage: (e^x * x^2 + log(x)).subs(x=RIF(pi))
2467
+ 229.534211738584?
2468
+ sage: _.parent()
2469
+ Real Interval Field with 53 bits of precision
2470
+
2471
+ .. SEEALSO::
2472
+
2473
+ :meth:`sage.symbolic.expression.Expression.subs`
2474
+
2475
+ TESTS::
2476
+
2477
+ sage: x.subs({'y': -1})
2478
+ Traceback (most recent call last):
2479
+ ...
2480
+ ValueError: Cannot substitute y in x since it is not a generator of
2481
+ Asymptotic Ring <(e^x)^QQ * x^ZZ * log(x)^ZZ> over Rational Field.
2482
+ sage: B.<u, v, w> = AsymptoticRing(growth_group='u^QQ * v^QQ * w^QQ', coefficient_ring=QQ)
2483
+ sage: (1/u).subs({'u': 0})
2484
+ Traceback (most recent call last):
2485
+ ...
2486
+ TypeError: Cannot apply the substitution rules {u: 0} on u^(-1) in
2487
+ Asymptotic Ring <u^QQ * v^QQ * w^QQ> over Rational Field.
2488
+ > *previous* ZeroDivisionError: Cannot substitute in u^(-1) in
2489
+ Asymptotic Ring <u^QQ * v^QQ * w^QQ> over Rational Field.
2490
+ >> *previous* ZeroDivisionError: Cannot substitute in u^(-1) in
2491
+ Exact Term Monoid u^QQ * v^QQ * w^QQ with coefficients in Rational Field.
2492
+ >...> *previous* ZeroDivisionError: Cannot substitute in u^(-1) in
2493
+ Growth Group u^QQ * v^QQ * w^QQ.
2494
+ >...> *previous* ZeroDivisionError: Cannot substitute in u^(-1) in
2495
+ Growth Group u^QQ.
2496
+ >...> *previous* ZeroDivisionError: rational division by zero
2497
+ sage: (1/u).subs({'u': 0, 'v': SR.var('v')})
2498
+ Traceback (most recent call last):
2499
+ ...
2500
+ TypeError: Cannot apply the substitution rules {u: 0, v: v} on u^(-1) in
2501
+ Asymptotic Ring <u^QQ * v^QQ * w^QQ> over Rational Field.
2502
+ > *previous* ZeroDivisionError: Cannot substitute in u^(-1) in
2503
+ Asymptotic Ring <u^QQ * v^QQ * w^QQ> over Rational Field.
2504
+ >> *previous* ZeroDivisionError: Cannot substitute in u^(-1) in
2505
+ Exact Term Monoid u^QQ * v^QQ * w^QQ with coefficients in Rational Field.
2506
+ >...> *previous* ZeroDivisionError: Cannot substitute in u^(-1) in
2507
+ Growth Group u^QQ * v^QQ * w^QQ.
2508
+ >...> *previous* ZeroDivisionError: Cannot substitute in u^(-1) in
2509
+ Growth Group u^QQ.
2510
+ >...> *previous* ZeroDivisionError: rational division by zero
2511
+
2512
+ ::
2513
+
2514
+ sage: u.subs({u: 0, 'v': SR.var('v')})
2515
+ 0
2516
+ sage: v.subs({u: 0, 'v': SR.var('v')})
2517
+ v
2518
+ sage: _.parent()
2519
+ Symbolic Ring
2520
+
2521
+ ::
2522
+
2523
+ sage: u.subs({SR.var('u'): -1})
2524
+ Traceback (most recent call last):
2525
+ ...
2526
+ TypeError: Cannot substitute u in u since it is neither an
2527
+ asymptotic expansion nor a string
2528
+ (but a <class 'sage.symbolic.expression.Expression'>).
2529
+
2530
+ ::
2531
+
2532
+ sage: u.subs({u: 1, 'u': 1})
2533
+ 1
2534
+ sage: u.subs({u: 1}, u=1)
2535
+ 1
2536
+ sage: u.subs({u: 1, 'u': 2})
2537
+ Traceback (most recent call last):
2538
+ ...
2539
+ ValueError: Cannot substitute in u: duplicate key u.
2540
+ sage: u.subs({u: 1}, u=3)
2541
+ Traceback (most recent call last):
2542
+ ...
2543
+ ValueError: Cannot substitute in u: duplicate key u.
2544
+
2545
+ ::
2546
+
2547
+ sage: B(0).subs({'_zero_': None}) is None
2548
+ True
2549
+ sage: B(1).subs({'_one_': AA(1)}).parent() is AA
2550
+ True
2551
+
2552
+ ::
2553
+
2554
+ sage: Asy.<n> = AsymptoticRing('n^QQ', RBF)
2555
+ sage: asy = n^(2/3) + 1/3*n^(1/3)
2556
+ sage: asy.subs(n=RBF(10))
2557
+ [5.359733730290...]
2558
+ """
2559
+ # check if nothing to do
2560
+ if not rules and not kwds:
2561
+ return self
2562
+
2563
+ # init and process keyword arguments
2564
+ gens = self.parent().gens()
2565
+ locals = kwds or {}
2566
+
2567
+ # update with rules
2568
+ if isinstance(rules, dict):
2569
+ for k, v in rules.items():
2570
+ if not isinstance(k, str) and k not in gens:
2571
+ raise TypeError('Cannot substitute %s in %s '
2572
+ 'since it is neither an '
2573
+ 'asymptotic expansion '
2574
+ 'nor a string (but a %s).' %
2575
+ (k, self, type(k)))
2576
+ k = str(k)
2577
+ if k in locals and locals[k] != v:
2578
+ raise ValueError('Cannot substitute in %s: '
2579
+ 'duplicate key %s.' % (self, k))
2580
+ locals[k] = v
2581
+ elif rules is not None:
2582
+ raise TypeError('Substitution rules %s have to be a dictionary.' %
2583
+ (rules,))
2584
+
2585
+ # fill up missing rules
2586
+ gens_str = tuple(str(g)
2587
+ for g in self.parent().growth_group.gens_monomial())
2588
+ for sg, g in zip(gens_str, gens):
2589
+ locals.setdefault(sg, g)
2590
+
2591
+ # check if all keys are generators
2592
+ for k in locals:
2593
+ sk = str(k)
2594
+ if sk not in gens_str and not sk.startswith('_'):
2595
+ raise ValueError('Cannot substitute %s in %s '
2596
+ 'since it is not a generator of %s.' %
2597
+ (k, self, self.parent()))
2598
+
2599
+ # determine 0 and 1
2600
+ if domain is None and \
2601
+ ('_zero_' not in locals or '_one_' not in locals):
2602
+ P = self.parent()
2603
+ for sg in gens_str:
2604
+ G = locals[sg].parent()
2605
+ if G is not P:
2606
+ domain = G
2607
+ break
2608
+ else:
2609
+ domain = P
2610
+ locals.setdefault('_zero_', domain.zero())
2611
+ locals.setdefault('_one_', domain.one())
2612
+
2613
+ # do the actual substitution
2614
+ try:
2615
+ return self._substitute_(locals)
2616
+ except (ArithmeticError, TypeError, ValueError) as e:
2617
+ from .misc import combine_exceptions
2618
+ rules = '{' + ', '.join(
2619
+ '%s: %s' % (k, v)
2620
+ for k, v in sorted(locals.items(),
2621
+ key=lambda k: str(k[0]))
2622
+ if not k.startswith('_') and
2623
+ not any(k == sg and v is g for sg, g in zip(gens_str, gens))
2624
+ ) + '}'
2625
+ raise combine_exceptions(
2626
+ TypeError('Cannot apply the substitution rules %s on %s '
2627
+ 'in %s.' % (rules, self, self.parent())), e)
2628
+
2629
+ def _substitute_(self, rules):
2630
+ r"""
2631
+ Substitute the given ``rules`` in this asymptotic expansion.
2632
+
2633
+ INPUT:
2634
+
2635
+ - ``rules`` -- dictionary. The neutral element of the asymptotic ring
2636
+ is replaced by the value to key ``'_zero_'``.
2637
+
2638
+ OUTPUT: an object
2639
+
2640
+ TESTS::
2641
+
2642
+ sage: A.<z> = AsymptoticRing(growth_group='z^QQ', coefficient_ring=QQ)
2643
+ sage: z._substitute_({'z': SR.var('a')})
2644
+ a
2645
+ sage: _.parent()
2646
+ Symbolic Ring
2647
+ sage: A(0)._substitute_({'_zero_': 'zero'})
2648
+ 'zero'
2649
+ sage: (1/z)._substitute_({'z': 4})
2650
+ 1/4
2651
+ sage: _.parent()
2652
+ Rational Field
2653
+ sage: (1/z)._substitute_({'z': 0})
2654
+ Traceback (most recent call last):
2655
+ ...
2656
+ ZeroDivisionError: Cannot substitute in z^(-1) in
2657
+ Asymptotic Ring <z^QQ> over Rational Field.
2658
+ > *previous* ZeroDivisionError: Cannot substitute in z^(-1) in
2659
+ Exact Term Monoid z^QQ with coefficients in Rational Field.
2660
+ >> *previous* ZeroDivisionError: Cannot substitute in z^(-1) in
2661
+ Growth Group z^QQ.
2662
+ >...> *previous* ZeroDivisionError: rational division by zero
2663
+ """
2664
+ if not self.summands:
2665
+ return rules['_zero_']
2666
+ from sage.symbolic.operators import add_vararg
2667
+ try:
2668
+ return add_vararg(
2669
+ *tuple(s._substitute_(rules)
2670
+ for s in self.summands.elements_topological()))
2671
+ except (ArithmeticError, TypeError, ValueError) as e:
2672
+ from .misc import substitute_raise_exception
2673
+ substitute_raise_exception(self, e)
2674
+
2675
+ def compare_with_values(self, variable, function, values,
2676
+ rescaled=True, ring=RIF):
2677
+ """
2678
+ Compute the (rescaled) difference between this asymptotic
2679
+ expansion and the given values.
2680
+
2681
+ INPUT:
2682
+
2683
+ - ``variable`` -- an asymptotic expansion or a string
2684
+
2685
+ - ``function`` -- a callable or symbolic expression giving the
2686
+ comparison values
2687
+
2688
+ - ``values`` -- list or iterable of values where the comparison
2689
+ shall be carried out
2690
+
2691
+ - ``rescaled`` -- boolean (default: ``True``); determines whether
2692
+ the difference is divided by the error term of the asymptotic
2693
+ expansion
2694
+
2695
+ - ``ring`` -- (default: ``RIF``) the parent into which the
2696
+ difference is converted
2697
+
2698
+ OUTPUT:
2699
+
2700
+ A list of pairs containing comparison points and (rescaled)
2701
+ difference values.
2702
+
2703
+ EXAMPLES::
2704
+
2705
+ sage: assume(SR.an_element() > 0)
2706
+ sage: A.<n> = AsymptoticRing('QQ^n * n^ZZ', SR)
2707
+ sage: catalan = binomial(2*x, x)/(x+1)
2708
+ sage: expansion = 4^n*(1/sqrt(pi)*n^(-3/2)
2709
+ ....: - 9/8/sqrt(pi)*n^(-5/2)
2710
+ ....: + 145/128/sqrt(pi)*n^(-7/2) + O(n^(-9/2)))
2711
+ sage: expansion.compare_with_values(n, catalan, srange(5, 10))
2712
+ [(5, 0.5303924444775?),
2713
+ (6, 0.5455279498787?),
2714
+ (7, 0.556880411050?),
2715
+ (8, 0.565710587724?),
2716
+ (9, 0.572775029098?)]
2717
+ sage: expansion.exact_part().compare_with_values(n, catalan, [5, 10, 20])
2718
+ Traceback (most recent call last):
2719
+ ...
2720
+ NotImplementedError: exactly one error term required
2721
+ sage: expansion.exact_part().compare_with_values(n, catalan, [5, 10, 20], rescaled=False)
2722
+ [(5, 0.3886263699387?), (10, 19.1842458318?), (20, 931314.63637?)]
2723
+ sage: expansion.compare_with_values(n, catalan, [5, 10, 20], rescaled=False, ring=SR)
2724
+ [(5, 168/5*sqrt(5)/sqrt(pi) - 42),
2725
+ (10, 1178112/125*sqrt(10)/sqrt(pi) - 16796),
2726
+ (20, 650486218752/125*sqrt(5)/sqrt(pi) - 6564120420)]
2727
+
2728
+ Instead of a symbolic expression, a callable function can
2729
+ be specified as well::
2730
+
2731
+ sage: A.<n> = AsymptoticRing('n^ZZ * log(n)^ZZ', SR)
2732
+ sage: def H(n):
2733
+ ....: return sum(1/k for k in srange(1, n+1))
2734
+ sage: H_expansion = (log(n) + euler_gamma + 1/(2*n)
2735
+ ....: - 1/(12*n^2) + O(n^-4))
2736
+ sage: H_expansion.compare_with_values(n, H, srange(25, 30)) # rel tol 1e-6
2737
+ [(25, -0.008326995?),
2738
+ (26, -0.008327472?),
2739
+ (27, -0.008327898?),
2740
+ (28, -0.00832828?),
2741
+ (29, -0.00832862?)]
2742
+ sage: forget()
2743
+
2744
+ .. SEEALSO::
2745
+
2746
+ :meth:`plot_comparison`
2747
+
2748
+ TESTS::
2749
+
2750
+ sage: A.<x, y> = AsymptoticRing('x^ZZ*y^ZZ', QQ)
2751
+ sage: expansion = x^2 + O(x) + O(y)
2752
+ sage: expansion.compare_with_values(y, lambda z: z^2, srange(20, 30))
2753
+ Traceback (most recent call last):
2754
+ ....
2755
+ NotImplementedError: exactly one error term required
2756
+ sage: expansion = x^2
2757
+ sage: expansion.compare_with_values(y, lambda z: z^2, srange(20, 30))
2758
+ Traceback (most recent call last):
2759
+ ....
2760
+ NotImplementedError: exactly one error term required
2761
+ sage: expansion = x^2 + O(x)
2762
+ sage: expansion.compare_with_values(y, lambda z: z^2, srange(20, 30))
2763
+ Traceback (most recent call last):
2764
+ ....
2765
+ NameError: name 'x' is not defined
2766
+ sage: expansion.compare_with_values(x, lambda z: z^2, srange(20, 30))
2767
+ [(20, 0), (21, 0), ..., (29, 0)]
2768
+ sage: expansion.compare_with_values(x, SR('x*y'), srange(20, 30))
2769
+ Traceback (most recent call last):
2770
+ ....
2771
+ NotImplementedError: expression x*y has more than one variable
2772
+
2773
+ ::
2774
+
2775
+ sage: A.<n> = AsymptoticRing('n^ZZ', RBF)
2776
+ sage: asy = (1 - 1/n + 1/n^2)/3 + O(1/n^3)
2777
+ sage: asy.compare_with_values('n', lambda k: 1/(3+3/k), srange(5,10))
2778
+ [(5, 0.2777...), (6, 0.28571...), (7, 0.29166...), (8, 0.29629...),
2779
+ (9, 0.30000...)]
2780
+ sage: basy = asy.exact_part() + 1/3*A.B(asy.error_part())
2781
+ doctest:warning
2782
+ ...
2783
+ FutureWarning: This class/method/function is marked as experimental.
2784
+ It, its functionality or its interface might change without a formal deprecation.
2785
+ See https://github.com/sagemath/sage/issues/31922 for details.
2786
+ sage: basy.compare_with_values('n', lambda k: 1/(3+3/k), [2^k for k in srange(8)])
2787
+ [(1, 0.500...), (2, 0.666...), (4, 0.800...), (8, 0.888...),
2788
+ (16, 0.941...), (32, 0.969...), (64, 0.984...), (128, 0.992...)]
2789
+ """
2790
+ from .term_monoid import OTerm, BTerm
2791
+ from sage.rings.integer_ring import ZZ
2792
+
2793
+ if hasattr(function, 'variables'):
2794
+ expr = function
2795
+ vars = expr.variables()
2796
+ if len(vars) > 1:
2797
+ raise NotImplementedError("expression {} has more than one "
2798
+ "variable".format(expr))
2799
+ elif len(vars) == 1:
2800
+ v = vars[0]
2801
+
2802
+ def function(arg):
2803
+ return expr.subs({v: arg})
2804
+ else:
2805
+ def function(arg):
2806
+ return expr
2807
+
2808
+ main = self.exact_part()
2809
+
2810
+ if rescaled:
2811
+ error = self.error_part()
2812
+ error_terms = list(error.summands)
2813
+ if len(error_terms) != 1:
2814
+ raise NotImplementedError("exactly one error term required")
2815
+ if isinstance(error_terms[0], OTerm):
2816
+ error_coeff = ZZ.one()
2817
+ elif isinstance(error_terms[0], BTerm):
2818
+ error_coeff = error_terms[0].coefficient
2819
+ else:
2820
+ raise NotImplementedError(f"unsupported error term: {error}")
2821
+ error_growth = error_terms[0].growth
2822
+ points = [(k, ring((main.subs({variable: k}) - function(k)) /
2823
+ (error_coeff * error_growth._substitute_(
2824
+ {str(variable): k, '_one_': ZZ.one()}))))
2825
+ for k in values]
2826
+ else:
2827
+ points = [(k, ring(main.subs({variable: k}) - function(k)))
2828
+ for k in values]
2829
+
2830
+ return points
2831
+
2832
+ def plot_comparison(self, variable, function, values, rescaled=True,
2833
+ ring=RIF, relative_tolerance=0.025, **kwargs):
2834
+ r"""
2835
+ Plot the (rescaled) difference between this asymptotic
2836
+ expansion and the given values.
2837
+
2838
+ INPUT:
2839
+
2840
+ - ``variable`` -- an asymptotic expansion or a string
2841
+
2842
+ - ``function`` -- a callable or symbolic expression giving the
2843
+ comparison values
2844
+
2845
+ - ``values`` -- list or iterable of values where the comparison
2846
+ shall be carried out
2847
+
2848
+ - ``rescaled`` -- boolean (default: ``True``); determines whether
2849
+ the difference is divided by the error term of the asymptotic
2850
+ expansion
2851
+
2852
+ - ``ring`` -- (default: ``RIF``) the parent into which the
2853
+ difference is converted
2854
+
2855
+ - ``relative_tolerance`` -- (default: ``0.025``) raise error
2856
+ when relative error exceeds this tolerance
2857
+
2858
+ Other keyword arguments are passed to :func:`list_plot`.
2859
+
2860
+ OUTPUT: a graphics object
2861
+
2862
+ .. NOTE::
2863
+
2864
+ If rescaled (i.e. divided by the error term), the output
2865
+ should be bounded.
2866
+
2867
+ This method is mainly meant to have an easily usable
2868
+ plausibility check for asymptotic expansion created in
2869
+ some way.
2870
+
2871
+ EXAMPLES:
2872
+
2873
+ We want to check the quality of the asymptotic expansion of
2874
+ the harmonic numbers::
2875
+
2876
+ sage: A.<n> = AsymptoticRing('n^ZZ * log(n)^ZZ', SR)
2877
+ sage: def H(n):
2878
+ ....: return sum(1/k for k in srange(1, n+1))
2879
+ sage: H_expansion = (log(n) + euler_gamma + 1/(2*n)
2880
+ ....: - 1/(12*n^2) + O(n^-4))
2881
+ sage: H_expansion.plot_comparison(n, H, srange(1, 30))
2882
+ Graphics object consisting of 1 graphics primitive
2883
+
2884
+ Alternatively, the unscaled (absolute) difference can be
2885
+ plotted as well::
2886
+
2887
+ sage: H_expansion.plot_comparison(n, H, srange(1, 30),
2888
+ ....: rescaled=False)
2889
+ Graphics object consisting of 1 graphics primitive
2890
+
2891
+ Additional keywords are passed to :func:`list_plot`::
2892
+
2893
+ sage: H_expansion.plot_comparison(n, H, srange(1, 30),
2894
+ ....: plotjoined=True, marker='o',
2895
+ ....: color='green')
2896
+ Graphics object consisting of 1 graphics primitive
2897
+
2898
+ .. SEEALSO::
2899
+
2900
+ :meth:`compare_with_values`
2901
+
2902
+ TESTS::
2903
+
2904
+ sage: H_expansion.plot_comparison(n, H, [600])
2905
+ Traceback (most recent call last):
2906
+ ...
2907
+ ValueError: Numerical noise is too high, the comparison is inaccurate
2908
+ sage: H_expansion.plot_comparison(n, H, [600], relative_tolerance=2)
2909
+ Graphics object consisting of 1 graphics primitive
2910
+ """
2911
+ from sage.plot.plot import list_plot
2912
+ points = self.compare_with_values(variable, function,
2913
+ values, rescaled=rescaled, ring=ring)
2914
+
2915
+ if isinstance(ring, sage.rings.abc.RealIntervalField):
2916
+ if not all(p[1].relative_diameter() <= relative_tolerance for p in points):
2917
+ raise ValueError('Numerical noise is too high, the '
2918
+ 'comparison is inaccurate')
2919
+
2920
+ # RIFs cannot be plotted, they need to be converted to RR
2921
+ # (see #15011).
2922
+ points = [(p[0], p[1].center()) for p in points]
2923
+
2924
+ return list_plot(points, **kwargs)
2925
+
2926
+ def symbolic_expression(self, R=None):
2927
+ r"""
2928
+ Return this asymptotic expansion as a symbolic expression.
2929
+
2930
+ INPUT:
2931
+
2932
+ - ``R`` -- (a subring of) the symbolic ring or ``None``.
2933
+ The output will be an element of ``R``. If ``None``,
2934
+ then the symbolic ring is used.
2935
+
2936
+ OUTPUT: a symbolic expression
2937
+
2938
+ EXAMPLES::
2939
+
2940
+ sage: A.<x, y, z> = AsymptoticRing(growth_group='x^ZZ * y^QQ * log(y)^QQ * (QQ_+)^z * z^QQ', coefficient_ring=QQ)
2941
+ sage: SR(A.an_element()) # indirect doctest
2942
+ 1/8*(1/8)^z*x^3*y^(3/2)*z^(3/2)*log(y)^(3/2) +
2943
+ Order((1/2)^z*x*sqrt(y)*sqrt(z)*sqrt(log(y)))
2944
+
2945
+ sage: A.<x, y, z> = AsymptoticRing(growth_group='x^ZZ * y^QQ * log(y)^QQ * (QQ_+)^z * z^QQ', coefficient_ring=QQ)
2946
+ sage: SR(A.an_element()) # indirect doctest
2947
+ 1/8*(1/8)^z*x^3*y^(3/2)*z^(3/2)*log(y)^(3/2) +
2948
+ Order((1/2)^z*x*sqrt(y)*sqrt(z)*sqrt(log(y)))
2949
+
2950
+ TESTS::
2951
+
2952
+ sage: a = A.an_element(); a
2953
+ 1/8*x^3*y^(3/2)*log(y)^(3/2)*(1/8)^z*z^(3/2) +
2954
+ O(x*y^(1/2)*log(y)^(1/2)*(1/2)^z*z^(1/2))
2955
+ sage: a.symbolic_expression()
2956
+ 1/8*(1/8)^z*x^3*y^(3/2)*z^(3/2)*log(y)^(3/2) +
2957
+ Order((1/2)^z*x*sqrt(y)*sqrt(z)*sqrt(log(y)))
2958
+ sage: _.parent()
2959
+ Symbolic Ring
2960
+
2961
+ ::
2962
+
2963
+ sage: from sage.symbolic.ring import SymbolicRing
2964
+ sage: class MySymbolicRing(SymbolicRing):
2965
+ ....: pass
2966
+ sage: mySR = MySymbolicRing()
2967
+ sage: a.symbolic_expression(mySR).parent() is mySR
2968
+ True
2969
+ """
2970
+ if R is None:
2971
+ from sage.symbolic.ring import SR
2972
+ R = SR
2973
+
2974
+ return self.substitute({g: R(R.var(str(g)))
2975
+ for g in self.parent().gens()},
2976
+ domain=R)
2977
+
2978
+ _symbolic_ = symbolic_expression # will be used by SR._element_constructor_
2979
+
2980
+ def map_coefficients(self, f, new_coefficient_ring=None):
2981
+ r"""
2982
+ Return the asymptotic expansion obtained by applying ``f`` to
2983
+ each coefficient of this asymptotic expansion.
2984
+
2985
+ INPUT:
2986
+
2987
+ - ``f`` -- a callable; a coefficient `c` will be mapped to `f(c)`
2988
+
2989
+ - ``new_coefficient_ring`` -- (default: ``None``) a ring
2990
+
2991
+ OUTPUT: an asymptotic expansion
2992
+
2993
+ EXAMPLES::
2994
+
2995
+ sage: A.<n> = AsymptoticRing(growth_group='n^ZZ', coefficient_ring=ZZ)
2996
+ sage: a = n^4 + 2*n^3 + 3*n^2 + O(n)
2997
+ sage: a.map_coefficients(lambda c: c+1)
2998
+ 2*n^4 + 3*n^3 + 4*n^2 + O(n)
2999
+ sage: a.map_coefficients(lambda c: c-2)
3000
+ -n^4 + n^2 + O(n)
3001
+
3002
+ TESTS::
3003
+
3004
+ sage: a.map_coefficients(lambda c: 1/c, new_coefficient_ring=QQ)
3005
+ n^4 + 1/2*n^3 + 1/3*n^2 + O(n)
3006
+ sage: _.parent()
3007
+ Asymptotic Ring <n^ZZ> over Rational Field
3008
+ sage: a.map_coefficients(lambda c: 1/c)
3009
+ Traceback (most recent call last):
3010
+ ...
3011
+ ValueError: Cannot create ExactTerm(n^3) since
3012
+ given coefficient 1/2 is not valid in
3013
+ Exact Term Monoid n^ZZ with coefficients in Integer Ring.
3014
+ > *previous* TypeError: no conversion of this rational to integer
3015
+ """
3016
+ def mapping(term):
3017
+ T = term.parent().change_parameter(
3018
+ coefficient_ring=new_coefficient_ring)
3019
+ if hasattr(term, 'coefficient'):
3020
+ c = f(term.coefficient)
3021
+ if c.is_zero():
3022
+ return None
3023
+ return T(term.growth, coefficient=c)
3024
+ else:
3025
+ return T(term.growth)
3026
+
3027
+ P = self.parent().change_parameter(coefficient_ring=new_coefficient_ring)
3028
+ S = self.summands.copy()
3029
+ S.map(mapping)
3030
+ return P(S, simplify=False, convert=False)
3031
+
3032
+ def factorial(self):
3033
+ r"""
3034
+ Return the factorial of this asymptotic expansion.
3035
+
3036
+ OUTPUT: an asymptotic expansion
3037
+
3038
+ EXAMPLES::
3039
+
3040
+ sage: A.<n> = AsymptoticRing(growth_group='n^ZZ * log(n)^ZZ', coefficient_ring=ZZ, default_prec=5)
3041
+ sage: n.factorial()
3042
+ sqrt(2)*sqrt(pi)*e^(n*log(n))*(e^n)^(-1)*n^(1/2)
3043
+ + 1/12*sqrt(2)*sqrt(pi)*e^(n*log(n))*(e^n)^(-1)*n^(-1/2)
3044
+ + 1/288*sqrt(2)*sqrt(pi)*e^(n*log(n))*(e^n)^(-1)*n^(-3/2)
3045
+ + O(e^(n*log(n))*(e^n)^(-1)*n^(-5/2))
3046
+ sage: _.parent()
3047
+ Asymptotic Ring <(e^(n*log(n)))^QQ * (e^n)^QQ * n^QQ * log(n)^QQ>
3048
+ over Symbolic Constants Subring
3049
+
3050
+ :wikipedia:`Catalan numbers <Catalan_number>`
3051
+ `\frac{1}{n+1}\binom{2n}{n}`::
3052
+
3053
+ sage: (2*n).factorial() / n.factorial()^2 / (n+1) # long time
3054
+ 1/sqrt(pi)*(e^n)^(2*log(2))*n^(-3/2)
3055
+ - 9/8/sqrt(pi)*(e^n)^(2*log(2))*n^(-5/2)
3056
+ + 145/128/sqrt(pi)*(e^n)^(2*log(2))*n^(-7/2)
3057
+ + O((e^n)^(2*log(2))*n^(-9/2))
3058
+
3059
+ Note that this method substitutes the asymptotic expansion into
3060
+ Stirling's formula. This substitution has to be possible which is
3061
+ not always guaranteed::
3062
+
3063
+ sage: S.<s> = AsymptoticRing(growth_group='s^QQ * log(s)^QQ', coefficient_ring=QQ, default_prec=4)
3064
+ sage: log(s).factorial()
3065
+ Traceback (most recent call last):
3066
+ ...
3067
+ TypeError: Cannot apply the substitution rules {s: log(s)} on
3068
+ sqrt(2)*sqrt(pi)*e^(s*log(s))*(e^s)^(-1)*s^(1/2)
3069
+ + O(e^(s*log(s))*(e^s)^(-1)*s^(-1/2)) in
3070
+ Asymptotic Ring <(e^(s*log(s)))^QQ * (e^s)^QQ * s^QQ * log(s)^QQ>
3071
+ over Symbolic Constants Subring.
3072
+ ...
3073
+
3074
+ .. SEEALSO::
3075
+
3076
+ :meth:`~sage.rings.asymptotic.asymptotic_expansion_generators.AsymptoticExpansionGenerators.Stirling`
3077
+
3078
+ TESTS::
3079
+
3080
+ sage: A.<m> = AsymptoticRing(growth_group='m^ZZ * log(m)^ZZ', coefficient_ring=QQ, default_prec=5)
3081
+ sage: m.factorial()
3082
+ sqrt(2)*sqrt(pi)*e^(m*log(m))*(e^m)^(-1)*m^(1/2)
3083
+ + 1/12*sqrt(2)*sqrt(pi)*e^(m*log(m))*(e^m)^(-1)*m^(-1/2)
3084
+ + 1/288*sqrt(2)*sqrt(pi)*e^(m*log(m))*(e^m)^(-1)*m^(-3/2)
3085
+ + O(e^(m*log(m))*(e^m)^(-1)*m^(-5/2))
3086
+
3087
+ ::
3088
+
3089
+ sage: A(1/2).factorial()
3090
+ 1/2*sqrt(pi)
3091
+ sage: _.parent()
3092
+ Asymptotic Ring <m^ZZ * log(m)^ZZ> over Symbolic Ring
3093
+
3094
+ ::
3095
+
3096
+ sage: B.<a, b> = AsymptoticRing('a^ZZ * b^ZZ', QQ, default_prec=3)
3097
+ sage: b.factorial()
3098
+ O(e^(b*log(b))*(e^b)^(-1)*b^(1/2))
3099
+ sage: (a*b).factorial()
3100
+ Traceback (most recent call last):
3101
+ ...
3102
+ ValueError: Cannot build the factorial of a*b
3103
+ since it is not univariate.
3104
+ """
3105
+ vars = self.variable_names()
3106
+
3107
+ if len(vars) == 0:
3108
+ if self.is_zero():
3109
+ return self.parent().one()
3110
+ assert len(self.summands) == 1
3111
+ element = next(self.summands.elements())
3112
+ return self.parent()._create_element_in_extension_(
3113
+ element._factorial_(), element.parent())
3114
+
3115
+ if len(vars) == 1:
3116
+ from .asymptotic_expansion_generators import \
3117
+ asymptotic_expansions
3118
+ var = vars[0]
3119
+ S = asymptotic_expansions.Stirling(
3120
+ var, precision=self.parent().default_prec)
3121
+ from sage.structure.element import get_coercion_model
3122
+ cm = get_coercion_model()
3123
+ P = cm.common_parent(self, S)
3124
+ return S.subs({var: P.coerce(self)})
3125
+
3126
+ else:
3127
+ raise ValueError(
3128
+ 'Cannot build the factorial of {} since it is not '
3129
+ 'univariate.'.format(self))
3130
+
3131
+ def variable_names(self):
3132
+ r"""
3133
+ Return the names of the variables of this asymptotic expansion.
3134
+
3135
+ OUTPUT: a tuple of strings
3136
+
3137
+ EXAMPLES::
3138
+
3139
+ sage: A.<m, n> = AsymptoticRing('QQ^m * m^QQ * n^ZZ * log(n)^ZZ', QQ)
3140
+ sage: (4*2^m*m^4*log(n)).variable_names()
3141
+ ('m', 'n')
3142
+ sage: (4*2^m*m^4).variable_names()
3143
+ ('m',)
3144
+ sage: (4*log(n)).variable_names()
3145
+ ('n',)
3146
+ sage: (4*m^3).variable_names()
3147
+ ('m',)
3148
+ sage: (4*m^0).variable_names()
3149
+ ()
3150
+ sage: (4*2^m*m^4 + log(n)).variable_names()
3151
+ ('m', 'n')
3152
+ sage: (2^m + m^4 + log(n)).variable_names()
3153
+ ('m', 'n')
3154
+ sage: (2^m + m^4).variable_names()
3155
+ ('m',)
3156
+ """
3157
+ vars = sorted(sum(iter(s.variable_names()
3158
+ for s in self.summands),
3159
+ tuple()))
3160
+ from itertools import groupby
3161
+ return tuple(v for v, _ in groupby(vars))
3162
+
3163
+ def _singularity_analysis_(self, var, zeta, precision=None):
3164
+ r"""
3165
+ Return the asymptotic growth of the coefficients of some
3166
+ generating function having this singular expansion around `\zeta`.
3167
+
3168
+ INPUT:
3169
+
3170
+ - ``var`` -- string; the variable for the growth of the coefficients,
3171
+ or the generator of an asymptotic ring
3172
+
3173
+ - ``zeta`` -- location of the singularity
3174
+
3175
+ - ``precision`` -- (default: ``None``) integer; if ``None``, then
3176
+ the default precision of the parent of this expansion is used
3177
+
3178
+ OUTPUT: an asymptotic expansion in ``var``
3179
+
3180
+ EXAMPLES::
3181
+
3182
+ sage: C.<T> = AsymptoticRing('T^QQ', QQ)
3183
+ sage: ex = 2 - 2*T^(-1/2) + 2*T^(-1) - 2*T^(-3/2) + O(T^(-2))
3184
+ sage: ex._singularity_analysis_('n', 1/4, precision=2)
3185
+ 1/sqrt(pi)*4^n*n^(-3/2) - 9/8/sqrt(pi)*4^n*n^(-5/2) + O(4^n*n^(-3))
3186
+
3187
+ The parameter ``var`` can also be the generator of an asymptotic
3188
+ ring::
3189
+
3190
+ sage: A.<n> = AsymptoticRing('n^QQ', QQ)
3191
+ sage: ex._singularity_analysis_(n, 1/4, precision=2)
3192
+ 1/sqrt(pi)*4^n*n^(-3/2) - 9/8/sqrt(pi)*4^n*n^(-5/2) + O(4^n*n^(-3))
3193
+
3194
+ If the parameter ``precision`` is omitted, the default precision
3195
+ of the parent of this expansion is used. ::
3196
+
3197
+ sage: C.<T> = AsymptoticRing('T^QQ', QQ, default_prec=1)
3198
+ sage: ex = 2 - 2*T^(-1/2) + 2*T^(-1) - 2*T^(-3/2) + O(T^(-2))
3199
+ sage: ex._singularity_analysis_('n', 1/4)
3200
+ 1/sqrt(pi)*4^n*n^(-3/2) + O(4^n*n^(-5/2))
3201
+
3202
+ .. SEEALSO::
3203
+
3204
+ :meth:`AsymptoticRing.coefficients_of_generating_function`
3205
+
3206
+ .. WARNING::
3207
+
3208
+ Once singular expansions around points other than infinity
3209
+ are implemented (:issue:`20050`), this method will be
3210
+ renamed to ``singularity_analysis``, the parameter
3211
+ ``zeta`` will be dropped (as it will be part of the
3212
+ singular expansion) and expansions around infinity will no
3213
+ longer be accepted.
3214
+
3215
+ TESTS::
3216
+
3217
+ sage: C.<T> = AsymptoticRing('T^QQ', QQ)
3218
+ sage: (1/T)._singularity_analysis_('n', 1)
3219
+ Traceback (most recent call last):
3220
+ ...
3221
+ NotImplementedOZero: got O(0)
3222
+ The error term O(0) means 0 for sufficiently large n.
3223
+ """
3224
+ from .misc import NotImplementedOZero
3225
+ OZeroEncountered = False
3226
+
3227
+ if precision is None:
3228
+ precision = self.parent().default_prec
3229
+
3230
+ result = 0
3231
+ for s in self.summands:
3232
+ try:
3233
+ contribution = s._singularity_analysis_(
3234
+ var=var, zeta=zeta,
3235
+ precision=precision)
3236
+ except NotImplementedOZero as ozero:
3237
+ OZeroEncountered = True
3238
+ result += ozero.exact_part
3239
+ else:
3240
+ result += contribution
3241
+
3242
+ if OZeroEncountered and (isinstance(result, int) and result == 0
3243
+ or result.is_exact()):
3244
+ raise NotImplementedOZero(var=var, exact_part=result)
3245
+ return result
3246
+
3247
+ def limit(self):
3248
+ """
3249
+ Compute the limit of this asymptotic expansion.
3250
+
3251
+ OUTPUT: an element of the coefficient ring
3252
+
3253
+ EXAMPLES::
3254
+
3255
+ sage: A.<s> = AsymptoticRing("s^ZZ", SR, default_prec=3)
3256
+ sage: (3 + 1/s + O(1/s^2)).limit()
3257
+ 3
3258
+ sage: ((1+1/s)^s).limit()
3259
+ e
3260
+ sage: (1/s).limit()
3261
+ 0
3262
+ sage: (s + 3 + 1/s + O(1/s^2)).limit()
3263
+ Traceback (most recent call last):
3264
+ ...
3265
+ ValueError: Cannot determine limit of s + 3 + s^(-1) + O(s^(-2))
3266
+ sage: (O(s^0)).limit()
3267
+ Traceback (most recent call last):
3268
+ ...
3269
+ ValueError: Cannot determine limit of O(1)
3270
+
3271
+ .. SEEALSO::
3272
+
3273
+ :meth:`is_little_o_of_one`
3274
+ """
3275
+ non_o_one_terms = [term for term in self.summands
3276
+ if not term.is_little_o_of_one()]
3277
+ if not non_o_one_terms:
3278
+ return self.parent().base_ring()(0)
3279
+
3280
+ if (
3281
+ len(non_o_one_terms) == 1
3282
+ and non_o_one_terms[0].growth.is_one()
3283
+ and non_o_one_terms[0].is_exact()
3284
+ ):
3285
+ return non_o_one_terms[0].coefficient
3286
+
3287
+ raise ValueError(f"Cannot determine limit of {self}")
3288
+
3289
+ def B(self, valid_from=0):
3290
+ r"""
3291
+ Convert all terms in this asymptotic expansion to `B`-terms.
3292
+
3293
+ INPUT:
3294
+
3295
+ - ``valid_from`` -- dictionary mapping variable names to lower bounds
3296
+ for the corresponding variable. The bound implied by this term is valid when
3297
+ all variables are at least their corresponding lower bound. If a number
3298
+ is passed to ``valid_from``, then the lower bounds for all variables of
3299
+ the asymptotic expansion are set to this number
3300
+
3301
+ OUTPUT: an asymptotic expansion
3302
+
3303
+ EXAMPLES::
3304
+
3305
+ sage: AR.<x, z> = AsymptoticRing(growth_group='x^ZZ * z^ZZ', coefficient_ring=ZZ)
3306
+ sage: AR.B(2*x^2, {x: 10}) # indirect doctest
3307
+ B(2*x^2, x >= 10)
3308
+ sage: expr = 42*x^42 + x^10 + AR.B(x^2, 20); expr # indirect doctest
3309
+ 42*x^42 + x^10 + B(x^2, x >= 20, z >= 20)
3310
+ sage: type(AR.B(x, 10)) # indirect doctest
3311
+ <class 'sage.rings.asymptotic.asymptotic_ring.AsymptoticRing_with_category.element_class'>
3312
+ sage: 2*z^3 + AR.B(5*z^2, {z: 20}) # indirect doctest
3313
+ 2*z^3 + B(5*z^2, z >= 20)
3314
+ sage: (2*x).B({x: 20})
3315
+ B(2*x, x >= 20)
3316
+ sage: AR.B(4*x^2*z^3, valid_from=10) # indirect doctest
3317
+ B(4*x^2*z^3, x >= 10, z >= 10)
3318
+ sage: AR.B(42*x^2) # indirect doctest
3319
+ B(42*x^2, x >= 0, z >= 0)
3320
+
3321
+ TESTS::
3322
+ sage: AR(0).B(20) # indirect doctest
3323
+ Traceback (most recent call last):
3324
+ ...
3325
+ NotImplementedBZero: got B(0)
3326
+ The error term B(0) means 0 for sufficiently large x, z.
3327
+ """
3328
+ if not self.summands:
3329
+ from .misc import NotImplementedBZero
3330
+ raise NotImplementedBZero(self.parent(), exact_part=self.parent().zero())
3331
+ return sum(self.parent().create_summand('B', growth=element, valid_from=valid_from)
3332
+ for element in self.summands.elements())
3333
+
3334
+
3335
+ class AsymptoticRing(Parent, UniqueRepresentation, WithLocals):
3336
+ r"""
3337
+ A ring consisting of :class:`asymptotic expansions <AsymptoticExpansion>`.
3338
+
3339
+ INPUT:
3340
+
3341
+ - ``growth_group`` -- either a partially ordered group (see
3342
+ :doc:`growth_group`) or a string
3343
+ describing such a growth group (see
3344
+ :class:`~sage.rings.asymptotic.growth_group.GrowthGroupFactory`).
3345
+
3346
+ - ``coefficient_ring`` -- the ring which contains the
3347
+ coefficients of the expansions
3348
+
3349
+ - ``default_prec`` -- positive integer; this is the number of
3350
+ summands that are kept before truncating an infinite series
3351
+
3352
+ - ``category`` -- the category of the parent can be specified
3353
+ in order to broaden the base structure. It has to be a
3354
+ subcategory of ``Category of rings``. This is also the default
3355
+ category if ``None`` is specified.
3356
+
3357
+ - ``term_monoid_factory`` -- a :class:`~sage.rings.asymptotic.term_monoid.TermMonoidFactory`.
3358
+ If ``None``, then :class:`~sage.rings.asymptotic.term_monoid.DefaultTermMonoidFactory`
3359
+ is used.
3360
+
3361
+ - ``locals`` -- dictionary which may contain the following keys and values:
3362
+
3363
+ - ``'log'`` -- value: a function. If not given, then the usual
3364
+ :class:`log <sage.functions.log.Function_log>` is taken.
3365
+ (See also :meth:`AsymptoticExpansion.log`.)
3366
+
3367
+ EXAMPLES:
3368
+
3369
+ We begin with the construction of an asymptotic ring in various
3370
+ ways. First, we simply pass a string specifying the underlying
3371
+ growth group::
3372
+
3373
+ sage: R1_x.<x> = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R1_x
3374
+ Asymptotic Ring <x^QQ> over Rational Field
3375
+ sage: x
3376
+ x
3377
+
3378
+ This is equivalent to the following code, which explicitly
3379
+ specifies the underlying growth group::
3380
+
3381
+ sage: from sage.rings.asymptotic.growth_group import GrowthGroup
3382
+ sage: G_QQ = GrowthGroup('x^QQ')
3383
+ sage: R2_x.<x> = AsymptoticRing(growth_group=G_QQ, coefficient_ring=QQ); R2_x
3384
+ Asymptotic Ring <x^QQ> over Rational Field
3385
+
3386
+ Of course, the coefficient ring of the asymptotic ring and the
3387
+ base ring of the underlying growth group do not need to
3388
+ coincide::
3389
+
3390
+ sage: R_ZZ_x.<x> = AsymptoticRing(growth_group='x^QQ', coefficient_ring=ZZ); R_ZZ_x
3391
+ Asymptotic Ring <x^QQ> over Integer Ring
3392
+
3393
+ Note, we can also create and use logarithmic growth groups::
3394
+
3395
+ sage: R_log = AsymptoticRing(growth_group='log(x)^ZZ', coefficient_ring=QQ); R_log
3396
+ Asymptotic Ring <log(x)^ZZ> over Rational Field
3397
+
3398
+ Other growth groups are available. See :doc:`asymptotic_ring` for
3399
+ more examples.
3400
+
3401
+ Below there are some technical details.
3402
+
3403
+ According to the conventions for parents, uniqueness is ensured::
3404
+
3405
+ sage: R1_x is R2_x
3406
+ True
3407
+
3408
+ Furthermore, the coercion framework is also involved. Coercion
3409
+ between two asymptotic rings is possible (given that the
3410
+ underlying growth groups and coefficient rings are chosen
3411
+ appropriately)::
3412
+
3413
+ sage: R1_x.has_coerce_map_from(R_ZZ_x)
3414
+ True
3415
+
3416
+ Additionally, for the sake of convenience, the coefficient ring
3417
+ also coerces into the asymptotic ring (representing constant
3418
+ quantities)::
3419
+
3420
+ sage: R1_x.has_coerce_map_from(QQ)
3421
+ True
3422
+
3423
+ It is possible to customize the terms in an asymptotic expansion::
3424
+
3425
+ sage: from sage.rings.asymptotic.term_monoid import ExactTermMonoid, OTermMonoid
3426
+ sage: from sage.rings.asymptotic.term_monoid import TermMonoidFactory
3427
+ sage: class MyExactTermMonoid(ExactTermMonoid):
3428
+ ....: pass
3429
+ sage: class MyOTermMonoid(OTermMonoid):
3430
+ ....: pass
3431
+ sage: MyTermMonoid = TermMonoidFactory('MyTermMonoid',
3432
+ ....: exact_term_monoid_class=MyExactTermMonoid,
3433
+ ....: O_term_monoid_class=MyOTermMonoid)
3434
+ sage: G = GrowthGroup('x^ZZ')
3435
+ sage: A.<n> = AsymptoticRing(growth_group=G, coefficient_ring=QQ, term_monoid_factory=MyTermMonoid)
3436
+ sage: a = A.an_element(); a
3437
+ 1/8*x^3 + O(x)
3438
+ sage: for t in a.summands.elements_topological(reverse=True):
3439
+ ....: print(t, type(t))
3440
+ 1/8*x^3 <class '__main__.MyExactTermMonoid_with_category.element_class'>
3441
+ O(x) <class '__main__.MyOTermMonoid_with_category.element_class'>
3442
+
3443
+ TESTS::
3444
+
3445
+ sage: from sage.rings.asymptotic.asymptotic_ring import AsymptoticRing as AR_class
3446
+ sage: class AR(AR_class):
3447
+ ....: class Element(AR_class.Element):
3448
+ ....: __eq__ = AR_class.Element.has_same_summands
3449
+ sage: A = AR(growth_group='z^QQ', coefficient_ring=QQ)
3450
+ sage: from itertools import islice
3451
+ sage: TestSuite(A).run( # not tested # long time # see #19424
3452
+ ....: verbose=True,
3453
+ ....: elements=tuple(islice(A.some_elements(), int(10))),
3454
+ ....: skip=('_test_some_elements', # to many elements
3455
+ ....: '_test_distributivity')) # due to cancellations: O(z) != O(z^2)
3456
+ """
3457
+
3458
+ # enable the category framework for elements
3459
+ Element = AsymptoticExpansion
3460
+
3461
+ @staticmethod
3462
+ def __classcall__(cls, growth_group=None, coefficient_ring=None,
3463
+ names=None, category=None, default_prec=None,
3464
+ term_monoid_factory=None,
3465
+ locals=None):
3466
+ r"""
3467
+ Normalize the input in order to ensure a unique
3468
+ representation of the parent.
3469
+
3470
+ For more information see :class:`AsymptoticRing`.
3471
+
3472
+ EXAMPLES:
3473
+
3474
+ ``__classcall__`` unifies the input to the constructor of
3475
+ :class:`AsymptoticRing` such that the instances generated
3476
+ are unique. Also, this enables the use of the generation
3477
+ framework::
3478
+
3479
+ sage: from sage.rings.asymptotic.growth_group import GrowthGroup
3480
+ sage: MG = GrowthGroup('x^ZZ')
3481
+ sage: AR1 = AsymptoticRing(growth_group=MG, coefficient_ring=ZZ)
3482
+ sage: AR2.<x> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
3483
+ sage: AR1 is AR2
3484
+ True
3485
+
3486
+ The bracket notation can only be used if the growth group
3487
+ has a generator::
3488
+
3489
+ sage: AR.<lx> = AsymptoticRing(growth_group='log(x)^ZZ', coefficient_ring=ZZ)
3490
+ Traceback (most recent call last):
3491
+ ...
3492
+ ValueError: Growth Group log(x)^ZZ does not provide any
3493
+ generators but name 'lx' given.
3494
+
3495
+ The names of the generators have to agree with the names used in
3496
+ the growth group except for univariate rings::
3497
+
3498
+ sage: A.<icecream> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ); A
3499
+ Asymptotic Ring <x^ZZ> over Integer Ring
3500
+ sage: icecream
3501
+ x
3502
+ sage: A.<x, y> = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ); A
3503
+ Asymptotic Ring <x^ZZ * y^ZZ> over Integer Ring
3504
+ sage: A.<y, x> = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ)
3505
+ Traceback (most recent call last):
3506
+ ...
3507
+ ValueError: Names 'y', 'x' do not coincide with
3508
+ generators 'x', 'y' of Growth Group x^ZZ * y^ZZ.
3509
+ sage: A.<a, b> = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ)
3510
+ Traceback (most recent call last):
3511
+ ...
3512
+ ValueError: Names 'a', 'b' do not coincide with
3513
+ generators 'x', 'y' of Growth Group x^ZZ * y^ZZ.
3514
+ sage: A.<x, b> = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ)
3515
+ Traceback (most recent call last):
3516
+ ...
3517
+ ValueError: Names 'x', 'b' do not coincide with
3518
+ generators 'x', 'y' of Growth Group x^ZZ * y^ZZ.
3519
+ sage: A.<x> = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ)
3520
+ Traceback (most recent call last):
3521
+ ...
3522
+ ValueError: Name 'x' do not coincide with
3523
+ generators 'x', 'y' of Growth Group x^ZZ * y^ZZ.
3524
+ sage: A.<x, y, z> = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=ZZ)
3525
+ Traceback (most recent call last):
3526
+ ...
3527
+ ValueError: Names 'x', 'y', 'z' do not coincide with
3528
+ generators 'x', 'y' of Growth Group x^ZZ * y^ZZ.
3529
+
3530
+ TESTS::
3531
+
3532
+ sage: AsymptoticRing(growth_group=None, coefficient_ring=ZZ)
3533
+ Traceback (most recent call last):
3534
+ ...
3535
+ ValueError: Growth group not specified. Cannot continue.
3536
+ sage: AsymptoticRing(growth_group='x^ZZ', coefficient_ring=None)
3537
+ Traceback (most recent call last):
3538
+ ...
3539
+ ValueError: Coefficient ring not specified. Cannot continue.
3540
+ sage: AsymptoticRing(growth_group='x^ZZ', coefficient_ring='icecream')
3541
+ Traceback (most recent call last):
3542
+ ...
3543
+ ValueError: icecream is not a ring. Cannot continue.
3544
+
3545
+ ::
3546
+
3547
+ sage: A.<x> = AsymptoticRing(growth_group='x^QQ', coefficient_ring=ZZ)
3548
+ sage: from sage.rings.asymptotic.term_monoid import DefaultTermMonoidFactory
3549
+ sage: A.term_monoid_factory is DefaultTermMonoidFactory
3550
+ True
3551
+ """
3552
+ from sage.categories.sets_cat import Sets
3553
+ from sage.categories.rings import Rings
3554
+
3555
+ Sets_parent_class = Sets().parent_class
3556
+ while issubclass(cls, Sets_parent_class):
3557
+ cls = cls.__base__
3558
+
3559
+ if isinstance(growth_group, str):
3560
+ from .growth_group import GrowthGroup
3561
+ growth_group = GrowthGroup(growth_group)
3562
+
3563
+ if growth_group is None:
3564
+ raise ValueError('Growth group not specified. Cannot continue.')
3565
+
3566
+ if coefficient_ring is None:
3567
+ raise ValueError('Coefficient ring not specified. Cannot continue.')
3568
+ if coefficient_ring not in Rings():
3569
+ raise ValueError('%s is not a ring. Cannot continue.' % (coefficient_ring,))
3570
+
3571
+ strgens = tuple(str(g) for g in growth_group.gens_monomial())
3572
+
3573
+ def format_names(N):
3574
+ return ('s ' if len(N) != 1 else ' ') + ', '.join("'%s'" % n for n in N)
3575
+ if names and not strgens:
3576
+ raise ValueError('%s does not provide any generators but name%s given.' %
3577
+ (growth_group, format_names(names)))
3578
+ elif names is not None and len(names) == 1 and len(strgens) == 1:
3579
+ pass
3580
+ elif names is not None and names != strgens:
3581
+ raise ValueError('Name%s do not coincide with generator%s of %s.' %
3582
+ (format_names(names), format_names(strgens), growth_group))
3583
+
3584
+ if category is None:
3585
+ from sage.categories.commutative_algebras import CommutativeAlgebras
3586
+ from sage.categories.rings import Rings
3587
+ category = CommutativeAlgebras(Rings())
3588
+
3589
+ if default_prec is None:
3590
+ default_prec = series_precision()
3591
+
3592
+ if term_monoid_factory is None:
3593
+ from .term_monoid import DefaultTermMonoidFactory
3594
+ term_monoid_factory = DefaultTermMonoidFactory
3595
+
3596
+ if locals is not None:
3597
+ locals = cls._convert_locals_(locals)
3598
+
3599
+ return super().__classcall__(cls, growth_group, coefficient_ring,
3600
+ category=category,
3601
+ default_prec=default_prec,
3602
+ term_monoid_factory=term_monoid_factory,
3603
+ locals=locals)
3604
+
3605
+ def __init__(self, growth_group, coefficient_ring,
3606
+ category, default_prec,
3607
+ term_monoid_factory, locals):
3608
+ r"""
3609
+ See :class:`AsymptoticRing` for more information.
3610
+
3611
+ TESTS::
3612
+
3613
+ sage: R1 = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ); R1
3614
+ Asymptotic Ring <x^ZZ> over Integer Ring
3615
+ sage: R2.<x> = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); R2
3616
+ Asymptotic Ring <x^QQ> over Rational Field
3617
+ sage: R1 is R2
3618
+ False
3619
+
3620
+ ::
3621
+
3622
+ sage: R3 = AsymptoticRing('x^ZZ')
3623
+ Traceback (most recent call last):
3624
+ ...
3625
+ ValueError: Coefficient ring not specified. Cannot continue.
3626
+ """
3627
+ self._coefficient_ring_ = coefficient_ring
3628
+ self._growth_group_ = growth_group
3629
+ self._default_prec_ = default_prec
3630
+ self._term_monoid_factory_ = term_monoid_factory
3631
+ self._locals_ = locals
3632
+ super().__init__(base=coefficient_ring,
3633
+ category=category)
3634
+
3635
+ @property
3636
+ def growth_group(self):
3637
+ r"""
3638
+ The growth group of this asymptotic ring.
3639
+
3640
+ EXAMPLES::
3641
+
3642
+ sage: AR = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
3643
+ sage: AR.growth_group
3644
+ Growth Group x^ZZ
3645
+
3646
+ .. SEEALSO::
3647
+
3648
+ :doc:`growth_group`
3649
+ """
3650
+ return self._growth_group_
3651
+
3652
+ @property
3653
+ def coefficient_ring(self):
3654
+ r"""
3655
+ The coefficient ring of this asymptotic ring.
3656
+
3657
+ EXAMPLES::
3658
+
3659
+ sage: AR = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
3660
+ sage: AR.coefficient_ring
3661
+ Integer Ring
3662
+ """
3663
+ return self._coefficient_ring_
3664
+
3665
+ @property
3666
+ def default_prec(self):
3667
+ r"""
3668
+ The default precision of this asymptotic ring.
3669
+
3670
+ This is the parameter used to determine how many summands
3671
+ are kept before truncating an infinite series (which occur
3672
+ when inverting asymptotic expansions).
3673
+
3674
+ EXAMPLES::
3675
+
3676
+ sage: AR = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
3677
+ sage: AR.default_prec
3678
+ 20
3679
+ sage: AR = AsymptoticRing('x^ZZ', ZZ, default_prec=123)
3680
+ sage: AR.default_prec
3681
+ 123
3682
+ """
3683
+ return self._default_prec_
3684
+
3685
+ @property
3686
+ def term_monoid_factory(self):
3687
+ r"""
3688
+ The term monoid factory of this asymptotic ring.
3689
+
3690
+ EXAMPLES::
3691
+
3692
+ sage: AR = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
3693
+ sage: AR.term_monoid_factory
3694
+ Term Monoid Factory 'sage.rings.asymptotic.term_monoid.DefaultTermMonoidFactory'
3695
+
3696
+ .. SEEALSO::
3697
+
3698
+ :doc:`term_monoid`
3699
+ """
3700
+ return self._term_monoid_factory_
3701
+
3702
+ def term_monoid(self, type):
3703
+ r"""
3704
+ Return the term monoid of this asymptotic ring of specified ``type``.
3705
+
3706
+ INPUT:
3707
+
3708
+ - ``type`` -- ``'O'`` or ``'exact'``, or an instance of an existing
3709
+ term monoid.
3710
+ See :class:`~sage.rings.asymptotic.term_monoid.TermMonoidFactory`
3711
+ for more details.
3712
+
3713
+ OUTPUT:
3714
+
3715
+ A term monoid object derived from
3716
+ :class:`~sage.rings.asymptotic.term_monoid.GenericTermMonoid`.
3717
+
3718
+ EXAMPLES::
3719
+
3720
+ sage: AR = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
3721
+ sage: AR.term_monoid('exact')
3722
+ Exact Term Monoid x^ZZ with coefficients in Integer Ring
3723
+ sage: AR.term_monoid('O')
3724
+ O-Term Monoid x^ZZ with implicit coefficients in Integer Ring
3725
+ sage: AR.term_monoid(AR.term_monoid('exact'))
3726
+ Exact Term Monoid x^ZZ with coefficients in Integer Ring
3727
+ """
3728
+ TermMonoid = self.term_monoid_factory
3729
+ return TermMonoid(type, asymptotic_ring=self)
3730
+
3731
+ def change_parameter(self, **kwds):
3732
+ r"""
3733
+ Return an asymptotic ring with a change in one or more of the given parameters.
3734
+
3735
+ INPUT:
3736
+
3737
+ - ``growth_group`` -- (default: ``None``) the new growth group
3738
+
3739
+ - ``coefficient_ring`` -- (default: ``None``) the new coefficient ring
3740
+
3741
+ - ``category`` -- (default: ``None``) the new category
3742
+
3743
+ - ``default_prec`` -- (default: ``None``) the new default precision
3744
+
3745
+ OUTPUT: an asymptotic ring
3746
+
3747
+ EXAMPLES::
3748
+
3749
+ sage: A = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
3750
+ sage: A.change_parameter(coefficient_ring=QQ)
3751
+ Asymptotic Ring <x^ZZ> over Rational Field
3752
+
3753
+ TESTS::
3754
+
3755
+ sage: A.change_parameter(coefficient_ring=ZZ) is A
3756
+ True
3757
+ sage: A.change_parameter(coefficient_ring=None) is A
3758
+ True
3759
+ """
3760
+ parameters = ('growth_group', 'coefficient_ring', 'default_prec',
3761
+ 'term_monoid_factory')
3762
+ values = {}
3763
+ category = self.category()
3764
+ values['category'] = category
3765
+ locals = self._locals_
3766
+ values['locals'] = locals
3767
+ for parameter in parameters:
3768
+ default = getattr(self, parameter)
3769
+ values[parameter] = kwds.get(parameter, default)
3770
+ if values[parameter] is None:
3771
+ values[parameter] = default
3772
+ if isinstance(values['growth_group'], str):
3773
+ from .growth_group import GrowthGroup
3774
+ values['growth_group'] = GrowthGroup(values['growth_group'])
3775
+ if all(values[parameter] is getattr(self, parameter)
3776
+ for parameter in parameters) and values['category'] is category and values['locals'] is locals:
3777
+ return self
3778
+ return self._underlying_class()(**values)
3779
+
3780
+ @staticmethod
3781
+ def _create_empty_summands_():
3782
+ r"""
3783
+ Create an empty data structure suitable for storing and working
3784
+ with summands.
3785
+
3786
+ OUTPUT: a :class:`~sage.data_structures.mutable_poset.MutablePoset`
3787
+
3788
+ TESTS::
3789
+
3790
+ sage: AsymptoticRing._create_empty_summands_()
3791
+ poset()
3792
+ """
3793
+ from sage.data_structures.mutable_poset import MutablePoset
3794
+ from .term_monoid import can_absorb, absorption
3795
+ return MutablePoset(key=lambda element: element.growth,
3796
+ can_merge=can_absorb,
3797
+ merge=absorption)
3798
+
3799
+ def _create_element_in_extension_(self, term, old_term_parent=None):
3800
+ r"""
3801
+ Create an element in an extension of this asymptotic ring which
3802
+ is chosen according to the input.
3803
+
3804
+ INPUT:
3805
+
3806
+ - ``term`` -- the element data
3807
+
3808
+ - ``old_term_parent`` -- the parent of ``term`` is compared to this
3809
+ parent. If both are the same or ``old_parent`` is ``None``,
3810
+ then the result is an expansion in this (``self``) asymptotic ring.
3811
+
3812
+ OUTPUT: an element
3813
+
3814
+ EXAMPLES::
3815
+
3816
+ sage: A = AsymptoticRing('z^ZZ', ZZ)
3817
+ sage: a = next(A.an_element().summands.elements_topological())
3818
+ sage: B = AsymptoticRing('z^QQ', QQ)
3819
+ sage: b = next(B.an_element().summands.elements_topological())
3820
+ sage: c = A._create_element_in_extension_(a, a.parent())
3821
+ sage: next(c.summands.elements_topological()).parent()
3822
+ O-Term Monoid z^ZZ with implicit coefficients in Integer Ring
3823
+ sage: c = A._create_element_in_extension_(b, a.parent())
3824
+ sage: next(c.summands.elements_topological()).parent()
3825
+ O-Term Monoid z^QQ with implicit coefficients in Rational Field
3826
+
3827
+ TESTS::
3828
+
3829
+ sage: c = A._create_element_in_extension_(b, None)
3830
+ sage: next(c.summands.elements_topological()).parent()
3831
+ O-Term Monoid z^QQ with implicit coefficients in Rational Field
3832
+ """
3833
+ if old_term_parent is None or term.parent() is old_term_parent:
3834
+ parent = self
3835
+ else:
3836
+ # Insert an 'if' here once terms can have different
3837
+ # coefficient rings, as this will be for L-terms.
3838
+ parent = self.change_parameter(
3839
+ growth_group=term.parent().growth_group,
3840
+ coefficient_ring=term.parent().coefficient_ring)
3841
+ return parent(term, simplify=False, convert=False)
3842
+
3843
+ def _element_constructor_(self, data, simplify=True, convert=True):
3844
+ r"""
3845
+ Convert a given object to this asymptotic ring.
3846
+
3847
+ INPUT:
3848
+
3849
+ - ``data`` -- an object representing the element to be
3850
+ initialized
3851
+
3852
+ - ``simplify`` -- boolean (default: ``True``); if set, then the constructed
3853
+ element is simplified (terms are absorbed) automatically
3854
+
3855
+ - ``convert`` -- boolean (default: ``True``); passed on to the element
3856
+ constructor. If set, then the ``summands`` are converted to
3857
+ the asymptotic ring (the parent of this expansion). If not,
3858
+ then the summands are taken as they are. In that case, the
3859
+ caller must ensure that the parent of the terms is set
3860
+ correctly.
3861
+
3862
+ OUTPUT: an element of this asymptotic ring
3863
+
3864
+ TESTS::
3865
+
3866
+ sage: AR = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
3867
+ sage: AR(5) # indirect doctest
3868
+ 5
3869
+ sage: AR(3*x^2) # indirect doctest
3870
+ 3*x^2
3871
+ sage: x = ZZ['x'].gen(); x.parent()
3872
+ Univariate Polynomial Ring in x over Integer Ring
3873
+ sage: AR(x)
3874
+ x
3875
+ sage: y = ZZ['y'].gen(); AR(y) # indirect doctest
3876
+ Traceback (most recent call last):
3877
+ ...
3878
+ ValueError: Polynomial y is not in
3879
+ Asymptotic Ring <x^ZZ> over Integer Ring
3880
+ > *previous* ValueError: Growth y is not valid in
3881
+ Exact Term Monoid x^ZZ with coefficients in Integer Ring.
3882
+ >> *previous* ValueError: y is not in Growth Group x^ZZ.
3883
+
3884
+ ::
3885
+
3886
+ sage: A = AsymptoticRing(growth_group='p^ZZ', coefficient_ring=QQ)
3887
+ sage: P.<p> = QQ[]
3888
+ sage: A(p) # indirect doctest
3889
+ p
3890
+ sage: A(p^11) # indirect doctest
3891
+ p^11
3892
+ sage: A(2*p^11) # indirect doctest
3893
+ 2*p^11
3894
+ sage: A(3*p^4 + 7/3*p - 8) # indirect doctest
3895
+ 3*p^4 + 7/3*p - 8
3896
+
3897
+ ::
3898
+
3899
+ sage: S = AsymptoticRing(growth_group='x^ZZ * y^ZZ', coefficient_ring=QQ)
3900
+ sage: var('x, y')
3901
+ (x, y)
3902
+ sage: S(x + y) # indirect doctest
3903
+ x + y
3904
+ sage: S(2*x - 4*x*y^6) # indirect doctest
3905
+ -4*x*y^6 + 2*x
3906
+
3907
+ ::
3908
+
3909
+ sage: A.<a,b> = AsymptoticRing('a^ZZ * b^ZZ', QQ)
3910
+ sage: 1/a
3911
+ a^(-1)
3912
+
3913
+ ::
3914
+
3915
+ sage: P.<a, b, c> = ZZ[]
3916
+ sage: A(a + b)
3917
+ a + b
3918
+ sage: A(a + c)
3919
+ Traceback (most recent call last):
3920
+ ...
3921
+ ValueError: Polynomial a + c is not in
3922
+ Asymptotic Ring <a^ZZ * b^ZZ> over Rational Field
3923
+ > *previous* ValueError: Growth c is not valid in
3924
+ Exact Term Monoid a^ZZ * b^ZZ with coefficients in Rational Field.
3925
+ >> *previous* ValueError: c is not in Growth Group a^ZZ * b^ZZ.
3926
+ >...> *previous* ValueError: c is not in any of the factors
3927
+ of Growth Group a^ZZ * b^ZZ
3928
+ >...> *previous* ValueError: c is not in Growth Group a^ZZ.
3929
+ >...> *and* ValueError: c is not in Growth Group b^ZZ.
3930
+
3931
+ ::
3932
+
3933
+ sage: M = AsymptoticRing('m^ZZ', ZZ)
3934
+ sage: N = AsymptoticRing('n^ZZ', QQ)
3935
+ sage: N(M.an_element()) # indirect doctest
3936
+ Traceback (most recent call last):
3937
+ ...
3938
+ ValueError: Cannot include m^3 with parent
3939
+ Exact Term Monoid m^ZZ with coefficients in Integer Ring
3940
+ in Asymptotic Ring <n^ZZ> over Rational Field
3941
+ > *previous* ValueError: Growth m^3 is not valid in
3942
+ Exact Term Monoid n^ZZ with coefficients in Rational Field.
3943
+ >> *previous* ValueError: m^3 is not in Growth Group n^ZZ.
3944
+
3945
+ ::
3946
+
3947
+ sage: M([1]) # indirect doctest
3948
+ Traceback (most recent call last):
3949
+ ...
3950
+ TypeError: Not all list entries of [1] are asymptotic terms,
3951
+ so cannot create an asymptotic expansion in
3952
+ Asymptotic Ring <m^ZZ> over Integer Ring.
3953
+ sage: M(SR.var('a') + 1) # indirect doctest
3954
+ Traceback (most recent call last):
3955
+ ...
3956
+ ValueError: Symbolic expression a + 1 is not in
3957
+ Asymptotic Ring <m^ZZ> over Integer Ring.
3958
+ > *previous* ValueError: a is not in
3959
+ Exact Term Monoid m^ZZ with coefficients in Integer Ring.
3960
+ >> *previous* ValueError: Factor a of a is neither a coefficient
3961
+ (in Integer Ring) nor growth (in Growth Group m^ZZ).
3962
+ """
3963
+ from sage.data_structures.mutable_poset import MutablePoset
3964
+ if isinstance(data, MutablePoset):
3965
+ return self.element_class(self, data, simplify=simplify, convert=convert)
3966
+
3967
+ if type(data) is self.element_class and data.parent() == self:
3968
+ return data
3969
+
3970
+ if isinstance(data, AsymptoticExpansion):
3971
+ return self.element_class(self, data.summands,
3972
+ simplify=simplify, convert=convert)
3973
+
3974
+ from .term_monoid import GenericTerm
3975
+ if isinstance(data, GenericTerm):
3976
+ data = (data,)
3977
+
3978
+ if isinstance(data, (list, tuple)):
3979
+ if not all(isinstance(elem, GenericTerm) for elem in data):
3980
+ raise TypeError('Not all list entries of %s '
3981
+ 'are asymptotic terms, so cannot create an '
3982
+ 'asymptotic expansion in %s.' % (data, self))
3983
+ summands = AsymptoticRing._create_empty_summands_()
3984
+ summands.union_update(data)
3985
+ return self.element_class(self, summands,
3986
+ simplify=simplify, convert=convert)
3987
+
3988
+ if not data:
3989
+ summands = AsymptoticRing._create_empty_summands_()
3990
+ return self.element_class(self, summands,
3991
+ simplify=simplify, convert=False)
3992
+
3993
+ try:
3994
+ P = data.parent()
3995
+ except AttributeError:
3996
+ return self.create_summand('exact', data)
3997
+
3998
+ from .misc import combine_exceptions
3999
+
4000
+ if isinstance(P, SymbolicRing):
4001
+ from sage.symbolic.operators import add_vararg
4002
+ if data.operator() == add_vararg:
4003
+ summands = []
4004
+ for summand in data.operands():
4005
+ # TODO: check if summand is an O-Term here
4006
+ # (see #19425, #19426)
4007
+ try:
4008
+ summands.append(self.create_summand('exact', summand))
4009
+ except ValueError as e:
4010
+ raise combine_exceptions(
4011
+ ValueError('Symbolic expression %s is not in %s.' %
4012
+ (data, self)), e)
4013
+ return sum(summands, self.zero())
4014
+
4015
+ elif isinstance(P, PolynomialRing_generic):
4016
+ p = P.gen()
4017
+ try:
4018
+ return sum(iter(self.create_summand('exact', growth=p**i,
4019
+ coefficient=c)
4020
+ for i, c in enumerate(data)),
4021
+ self.zero())
4022
+ except ValueError as e:
4023
+ raise combine_exceptions(
4024
+ ValueError('Polynomial %s is not in %s' % (data, self)), e)
4025
+
4026
+ elif isinstance(P, MPolynomialRing_base):
4027
+ try:
4028
+ return sum(iter(self.create_summand('exact', growth=g, coefficient=c)
4029
+ for c, g in iter(data)),
4030
+ self.zero())
4031
+ except ValueError as e:
4032
+ raise combine_exceptions(
4033
+ ValueError('Polynomial %s is not in %s' % (data, self)), e)
4034
+
4035
+ elif isinstance(P, (PowerSeriesRing_generic, LazyPowerSeriesRing)):
4036
+ raise NotImplementedError(
4037
+ 'cannot convert %s from the %s to an asymptotic expansion '
4038
+ 'in %s, since growths at other points than +oo are not yet '
4039
+ 'supported' % (data, P, self))
4040
+ # Delete lines above as soon as we can deal with growths
4041
+ # other than the that at going to +oo.
4042
+ from sage.rings.infinity import PlusInfinity
4043
+ p = P.gen()
4044
+ try:
4045
+ result = self(data.polynomial())
4046
+ except ValueError as e:
4047
+ raise combine_exceptions(
4048
+ ValueError('Powerseries %s is not in %s' % (data, self)), e)
4049
+ prec = data.precision_absolute()
4050
+ if prec < PlusInfinity():
4051
+ try:
4052
+ result += self.create_summand('O', growth=p**prec)
4053
+ except ValueError as e:
4054
+ raise combine_exceptions(
4055
+ ValueError('Powerseries %s is not in %s' %
4056
+ (data, self)), e)
4057
+ return result
4058
+
4059
+ return self.create_summand('exact', data)
4060
+
4061
+ def _coerce_map_from_(self, R):
4062
+ r"""
4063
+ Return whether ``R`` coerces into this asymptotic ring.
4064
+
4065
+ INPUT:
4066
+
4067
+ - ``R`` -- a parent
4068
+
4069
+ OUTPUT: boolean
4070
+
4071
+ .. NOTE::
4072
+
4073
+ There are two possible cases: either ``R`` coerces in the
4074
+ :meth:`coefficient_ring` of this asymptotic ring, or ``R``
4075
+ itself is an asymptotic ring, where both the
4076
+ :meth:`growth_group` and the :meth:`coefficient_ring` coerce into
4077
+ the :meth:`growth_group` and the :meth:`coefficient_ring` of this
4078
+ asymptotic ring, respectively.
4079
+
4080
+ TESTS::
4081
+
4082
+ sage: AR_ZZ = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ); AR_ZZ
4083
+ Asymptotic Ring <x^ZZ> over Integer Ring
4084
+ sage: x_ZZ = AR_ZZ.gen()
4085
+ sage: AR_QQ = AsymptoticRing(growth_group='x^QQ', coefficient_ring=QQ); AR_QQ
4086
+ Asymptotic Ring <x^QQ> over Rational Field
4087
+ sage: x_QQ = AR_QQ.gen()
4088
+ sage: AR_QQ.has_coerce_map_from(AR_ZZ) # indirect doctest
4089
+ True
4090
+ sage: x_ZZ * x_QQ
4091
+ x^2
4092
+
4093
+ ::
4094
+
4095
+ sage: AR_QQ.has_coerce_map_from(QQ)
4096
+ True
4097
+ sage: AR_QQ.has_coerce_map_from(ZZ)
4098
+ True
4099
+ """
4100
+ from sage.data_structures.mutable_poset import MutablePoset
4101
+ if R == MutablePoset:
4102
+ return
4103
+ if self.coefficient_ring.has_coerce_map_from(R):
4104
+ return True
4105
+ if self.growth_group.has_coerce_map_from(R):
4106
+ return True
4107
+ elif isinstance(R, AsymptoticRing):
4108
+ if self.growth_group.has_coerce_map_from(R.growth_group) and \
4109
+ self.coefficient_ring.has_coerce_map_from(R.coefficient_ring):
4110
+ return True
4111
+
4112
+ def _repr_(self) -> str:
4113
+ r"""
4114
+ A representation string of this asymptotic ring.
4115
+
4116
+ OUTPUT: string
4117
+
4118
+ EXAMPLES::
4119
+
4120
+ sage: AR = AsymptoticRing(growth_group='x^ZZ',
4121
+ ....: coefficient_ring=ZZ)
4122
+ sage: repr(AR) # indirect doctest
4123
+ 'Asymptotic Ring <x^ZZ> over Integer Ring'
4124
+ """
4125
+ try:
4126
+ G = '<' + self.growth_group._repr_(condense=True) + '>'
4127
+ except TypeError:
4128
+ G = repr(self.growth_group)
4129
+ return 'Asymptotic Ring %s over %s' % (G, self.coefficient_ring)
4130
+
4131
+ def _an_element_(self):
4132
+ r"""
4133
+ Return an element of this asymptotic ring.
4134
+
4135
+ OUTPUT: an :class:`AsymptoticExpansion`
4136
+
4137
+ EXAMPLES::
4138
+
4139
+ sage: AsymptoticRing(growth_group='z^QQ', coefficient_ring=ZZ).an_element()
4140
+ z^(3/2) + O(z^(1/2))
4141
+ sage: AsymptoticRing(growth_group='z^ZZ', coefficient_ring=QQ).an_element()
4142
+ 1/8*z^3 + O(z)
4143
+ sage: AsymptoticRing(growth_group='z^QQ', coefficient_ring=QQ).an_element()
4144
+ 1/8*z^(3/2) + O(z^(1/2))
4145
+ """
4146
+ E = self.term_monoid('exact')
4147
+ O = self.term_monoid('O')
4148
+ return self(E.an_element(), simplify=False, convert=False)**3 + \
4149
+ self(O.an_element(), simplify=False, convert=False)
4150
+
4151
+ def some_elements(self):
4152
+ r"""
4153
+ Return some elements of this term monoid.
4154
+
4155
+ See :class:`TestSuite` for a typical use case.
4156
+
4157
+ OUTPUT: an iterator
4158
+
4159
+ EXAMPLES::
4160
+
4161
+ sage: from itertools import islice
4162
+ sage: A = AsymptoticRing(growth_group='z^QQ', coefficient_ring=ZZ)
4163
+ sage: tuple(islice(A.some_elements(), int(10)))
4164
+ (z^(3/2) + O(z^(1/2)),
4165
+ O(z^(1/2)),
4166
+ z^(3/2) + O(z^(-1/2)),
4167
+ -z^(3/2) + O(z^(1/2)),
4168
+ O(z^(-1/2)),
4169
+ O(z^2),
4170
+ z^6 + O(z^(1/2)),
4171
+ -z^(3/2) + O(z^(-1/2)),
4172
+ O(z^2),
4173
+ z^(3/2) + O(z^(-2)))
4174
+ """
4175
+ from sage.misc.mrange import cantor_product
4176
+ E = self.term_monoid('exact')
4177
+ O = self.term_monoid('O')
4178
+ return iter(self(e, simplify=False, convert=False)**3 +
4179
+ self(o, simplify=False, convert=False)
4180
+ for e, o in cantor_product(E.some_elements(),
4181
+ O.some_elements()))
4182
+
4183
+ def gens(self) -> tuple:
4184
+ r"""
4185
+ Return a tuple with generators of this asymptotic ring.
4186
+
4187
+ OUTPUT: a tuple of asymptotic expansions
4188
+
4189
+ .. NOTE::
4190
+
4191
+ Generators do not necessarily exist. This depends on the
4192
+ underlying growth group. For example,
4193
+ :class:`monomial growth groups <sage.rings.asymptotic.growth_group.MonomialGrowthGroup>`
4194
+ have a generator, and exponential growth groups
4195
+ do not.
4196
+
4197
+ EXAMPLES::
4198
+
4199
+ sage: AR.<x> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
4200
+ sage: AR.gens()
4201
+ (x,)
4202
+ sage: B.<y,z> = AsymptoticRing(growth_group='y^ZZ * z^ZZ', coefficient_ring=QQ)
4203
+ sage: B.gens()
4204
+ (y, z)
4205
+ """
4206
+ return tuple(self.create_summand('exact',
4207
+ growth=g,
4208
+ coefficient=self.coefficient_ring(1))
4209
+ for g in self.growth_group.gens_monomial())
4210
+
4211
+ def gen(self, n=0):
4212
+ r"""
4213
+ Return the ``n``-th generator of this asymptotic ring.
4214
+
4215
+ INPUT:
4216
+
4217
+ - ``n`` -- (default: `0`) a nonnegative integer
4218
+
4219
+ OUTPUT: an asymptotic expansion
4220
+
4221
+ EXAMPLES::
4222
+
4223
+ sage: R.<x> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
4224
+ sage: R.gen()
4225
+ x
4226
+ """
4227
+ return self.gens()[n]
4228
+
4229
+ def ngens(self):
4230
+ r"""
4231
+ Return the number of generators of this asymptotic ring.
4232
+
4233
+ OUTPUT: integer
4234
+
4235
+ EXAMPLES::
4236
+
4237
+ sage: AR.<x> = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
4238
+ sage: AR.ngens()
4239
+ 1
4240
+ """
4241
+ return len(self.growth_group.gens_monomial())
4242
+
4243
+ def coefficients_of_generating_function(self, function, singularities, precision=None,
4244
+ return_singular_expansions=False,
4245
+ error_term=None):
4246
+ r"""
4247
+ Return the asymptotic growth of the coefficients of some
4248
+ generating function by means of Singularity Analysis.
4249
+
4250
+ INPUT:
4251
+
4252
+ - ``function`` -- a callable function in one variable
4253
+
4254
+ - ``singularities`` -- list of dominant singularities of the function
4255
+
4256
+ - ``precision`` -- integer (default: ``None``); if ``None``, then
4257
+ the default precision of the asymptotic ring is used
4258
+
4259
+ - ``return_singular_expansions`` -- boolean (default: ``False``);
4260
+ if set, the singular expansions are also returned
4261
+
4262
+ - ``error_term`` -- (default: ``None``) an asymptotic expansion.
4263
+ If ``None``, then this is interpreted as zero.
4264
+ The contributions of the coefficients are added to ``error_term``
4265
+ during Singularity Analysis.
4266
+
4267
+ OUTPUT:
4268
+
4269
+ - If ``return_singular_expansions=False``: An asymptotic expansion from
4270
+ this ring.
4271
+
4272
+ - If ``return_singular_expansions=True``: A named tuple with
4273
+ components ``asymptotic_expansion`` and
4274
+ ``singular_expansions``. The former contains an asymptotic
4275
+ expansion from this ring, the latter is a dictionary which
4276
+ contains the singular expansions around the singularities.
4277
+
4278
+ .. TODO::
4279
+
4280
+ Make this method more usable by implementing the
4281
+ processing of symbolic expressions.
4282
+
4283
+ EXAMPLES:
4284
+
4285
+ Catalan numbers::
4286
+
4287
+ sage: def catalan(z):
4288
+ ....: return (1-(1-4*z)^(1/2))/(2*z)
4289
+ sage: B.<n> = AsymptoticRing('QQ^n * n^QQ', QQ)
4290
+ sage: B.coefficients_of_generating_function(catalan, (1/4,), precision=3)
4291
+ 1/sqrt(pi)*4^n*n^(-3/2) - 9/8/sqrt(pi)*4^n*n^(-5/2)
4292
+ + 145/128/sqrt(pi)*4^n*n^(-7/2) + O(4^n*n^(-4))
4293
+ sage: B.coefficients_of_generating_function(catalan, (1/4,), precision=2,
4294
+ ....: return_singular_expansions=True)
4295
+ SingularityAnalysisResult(asymptotic_expansion=1/sqrt(pi)*4^n*n^(-3/2)
4296
+ - 9/8/sqrt(pi)*4^n*n^(-5/2) + O(4^n*n^(-3)),
4297
+ singular_expansions={1/4: 2 - 2*T^(-1/2)
4298
+ + 2*T^(-1) - 2*T^(-3/2) + O(T^(-2))})
4299
+
4300
+ Unit fractions::
4301
+
4302
+ sage: def logarithmic(z):
4303
+ ....: return -log(1-z)
4304
+ sage: B.coefficients_of_generating_function(logarithmic, (1,), precision=5)
4305
+ n^(-1) + O(n^(-3))
4306
+
4307
+ Harmonic numbers::
4308
+
4309
+ sage: def harmonic(z):
4310
+ ....: return -log(1-z)/(1-z)
4311
+ sage: B.<n> = AsymptoticRing('QQ^n * n^QQ * log(n)^QQ', QQ)
4312
+ sage: ex = B.coefficients_of_generating_function(harmonic, (1,), precision=13); ex
4313
+ log(n) + euler_gamma + 1/2*n^(-1) - 1/12*n^(-2) + 1/120*n^(-4)
4314
+ + O(n^(-6))
4315
+ sage: ex.has_same_summands(asymptotic_expansions.HarmonicNumber(
4316
+ ....: 'n', precision=5))
4317
+ True
4318
+
4319
+ Positive and negative singularities::
4320
+
4321
+ sage: def permutations_odd_cycles(z):
4322
+ ....: return sqrt((1+z) / (1-z))
4323
+ sage: ex = B.coefficients_of_generating_function(
4324
+ ....: permutations_odd_cycles, (1, -1,), precision=2,
4325
+ ....: ); ex
4326
+ sqrt(2)/sqrt(pi)*n^(-1/2) - 1/2*sqrt(1/2)/sqrt(pi)*n^(-3/2)*(-1)^n
4327
+ + O(n^(-5/2))
4328
+
4329
+ .. WARNING::
4330
+
4331
+ Once singular expansions around points other than infinity
4332
+ are implemented (:issue:`20050`), the output in the case
4333
+ ``return_singular_expansions`` will change to return singular
4334
+ expansions around the singularities.
4335
+
4336
+ In the following example, the result is an exact asymptotic expression
4337
+ for sufficiently large `n` (i.e., there might be finitely many
4338
+ exceptional values). This is encoded by an `O(0)` error term::
4339
+
4340
+ sage: def f(z):
4341
+ ....: return z/(1-z)
4342
+ sage: B.coefficients_of_generating_function(f, (1,), precision=3)
4343
+ Traceback (most recent call last):
4344
+ ...
4345
+ NotImplementedOZero: got 1 + O(0)
4346
+ The error term O(0) means 0 for sufficiently large n.
4347
+
4348
+ In this case, we can manually intervene by adding an error term
4349
+ that suits us::
4350
+
4351
+ sage: B.coefficients_of_generating_function(f, (1,), precision=3,
4352
+ ....: error_term=O(n^-100))
4353
+ 1 + O(n^(-100))
4354
+ """
4355
+ from sage.symbolic.ring import SR
4356
+ from .misc import NotImplementedOZero
4357
+
4358
+ singular_expansions = {}
4359
+
4360
+ OZeroEncountered = False
4361
+
4362
+ A = AsymptoticRing('T^QQ * log(T)^QQ', coefficient_ring=SR,
4363
+ default_prec=precision)
4364
+ T = A.gen()
4365
+
4366
+ if error_term is None:
4367
+ result = self.zero()
4368
+ else:
4369
+ result = error_term
4370
+ for singularity in singularities:
4371
+ singular_expansion = A(function((1 - 1 / T) * singularity))
4372
+ singular_expansions[singularity] = singular_expansion
4373
+
4374
+ try:
4375
+ contribution = singular_expansion._singularity_analysis_(
4376
+ var='Z', zeta=singularity,
4377
+ precision=precision).subs(Z=self.gen())
4378
+ except NotImplementedOZero as ozero:
4379
+ OZeroEncountered = True
4380
+ result += ozero.exact_part.subs(Z=self.gen())
4381
+ else:
4382
+ result += contribution
4383
+
4384
+ if OZeroEncountered and result.is_exact():
4385
+ raise NotImplementedOZero(self, exact_part=result)
4386
+
4387
+ if return_singular_expansions:
4388
+ from collections import namedtuple
4389
+ SingularityAnalysisResult = namedtuple(
4390
+ 'SingularityAnalysisResult',
4391
+ ['asymptotic_expansion', 'singular_expansions'])
4392
+ return SingularityAnalysisResult(
4393
+ asymptotic_expansion=result,
4394
+ singular_expansions=singular_expansions)
4395
+ else:
4396
+ return result
4397
+
4398
+ def create_summand(self, type, data=None, **kwds):
4399
+ r"""
4400
+ Create a simple asymptotic expansion consisting of a single
4401
+ summand.
4402
+
4403
+ INPUT:
4404
+
4405
+ - ``type`` -- 'O' or 'exact'
4406
+
4407
+ - ``data`` -- the element out of which a summand has to be created
4408
+
4409
+ - ``growth`` -- an element of the :meth:`growth_group`
4410
+
4411
+ - ``coefficient`` -- an element of the :meth:`coefficient_ring`
4412
+
4413
+ .. NOTE::
4414
+
4415
+ Either ``growth`` and ``coefficient`` or ``data`` have to
4416
+ be specified.
4417
+
4418
+ OUTPUT: an asymptotic expansion
4419
+
4420
+ .. NOTE::
4421
+
4422
+ This method calls the factory :class:`TermMonoid
4423
+ <sage.rings.asymptotic.term_monoid.TermMonoidFactory>`
4424
+ with the appropriate arguments.
4425
+
4426
+ EXAMPLES::
4427
+
4428
+ sage: R = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ)
4429
+ sage: R.create_summand('O', x^2)
4430
+ O(x^2)
4431
+ sage: R.create_summand('exact', growth=x^456, coefficient=123)
4432
+ 123*x^456
4433
+ sage: R.create_summand('exact', data=12*x^13)
4434
+ 12*x^13
4435
+
4436
+ TESTS::
4437
+
4438
+ sage: R.create_summand('exact', data='12*x^13')
4439
+ 12*x^13
4440
+ sage: R.create_summand('exact', data='x^13 * 12')
4441
+ 12*x^13
4442
+ sage: R.create_summand('exact', data='x^13')
4443
+ x^13
4444
+ sage: R.create_summand('exact', data='12')
4445
+ 12
4446
+ sage: R.create_summand('exact', data=12)
4447
+ 12
4448
+
4449
+ ::
4450
+
4451
+ sage: Z = R.change_parameter(coefficient_ring=Zmod(3))
4452
+ sage: Z.create_summand('exact', data=42)
4453
+ 0
4454
+
4455
+ ::
4456
+
4457
+ sage: R.create_summand('O', growth=42*x^2, coefficient=1)
4458
+ Traceback (most recent call last):
4459
+ ...
4460
+ ValueError: Growth 42*x^2 is not valid in O-Term Monoid x^ZZ with implicit coefficients in Integer Ring.
4461
+ > *previous* ValueError: 42*x^2 is not in Growth Group x^ZZ.
4462
+
4463
+ ::
4464
+
4465
+ sage: AR.<z> = AsymptoticRing('z^QQ', QQ)
4466
+ sage: AR.create_summand('exact', growth='z^2')
4467
+ Traceback (most recent call last):
4468
+ ...
4469
+ TypeError: Cannot create exact term: only 'growth' but
4470
+ no 'coefficient' specified.
4471
+ """
4472
+ from .term_monoid import ZeroCoefficientError
4473
+ TM = self.term_monoid(type)
4474
+
4475
+ if data is None:
4476
+ try:
4477
+ data = kwds.pop('growth')
4478
+ except KeyError:
4479
+ raise TypeError("Neither 'data' nor 'growth' are specified.")
4480
+ if type == 'exact' and kwds.get('coefficient') is None:
4481
+ raise TypeError("Cannot create exact term: only 'growth' "
4482
+ "but no 'coefficient' specified.")
4483
+
4484
+ try:
4485
+ return self(TM(data, **kwds), simplify=False, convert=False)
4486
+ except ZeroCoefficientError:
4487
+ return self.zero()
4488
+
4489
+ def variable_names(self):
4490
+ r"""
4491
+ Return the names of the variables.
4492
+
4493
+ OUTPUT: a tuple of strings
4494
+
4495
+ EXAMPLES::
4496
+
4497
+ sage: A = AsymptoticRing(growth_group='x^ZZ * QQ^y', coefficient_ring=QQ)
4498
+ sage: A.variable_names()
4499
+ ('x', 'y')
4500
+ """
4501
+ return self.growth_group.variable_names()
4502
+
4503
+ def construction(self):
4504
+ r"""
4505
+ Return the construction of this asymptotic ring.
4506
+
4507
+ OUTPUT:
4508
+
4509
+ A pair whose first entry is an
4510
+ :class:`asymptotic ring construction functor <AsymptoticRingFunctor>`
4511
+ and its second entry the coefficient ring.
4512
+
4513
+ EXAMPLES::
4514
+
4515
+ sage: A = AsymptoticRing(growth_group='x^ZZ * QQ^y', coefficient_ring=QQ)
4516
+ sage: A.construction()
4517
+ (AsymptoticRing<x^ZZ * QQ^y * Signs^y>, Rational Field)
4518
+
4519
+ .. SEEALSO::
4520
+
4521
+ :doc:`asymptotic_ring`,
4522
+ :class:`AsymptoticRing`,
4523
+ :class:`AsymptoticRingFunctor`.
4524
+
4525
+ TESTS:
4526
+
4527
+ :issue:`22392`::
4528
+
4529
+ sage: from sage.rings.asymptotic.asymptotic_ring import AsymptoticRing
4530
+ sage: class MyAsymptoticRing(AsymptoticRing):
4531
+ ....: pass
4532
+ sage: A = MyAsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ)
4533
+ sage: A.construction()[0].cls
4534
+ <class '__main__.MyAsymptoticRing'>
4535
+ """
4536
+ return (AsymptoticRingFunctor(self.growth_group,
4537
+ default_prec=self.default_prec,
4538
+ category=self.category(),
4539
+ cls=self._underlying_class()),
4540
+ self.coefficient_ring)
4541
+
4542
+ @staticmethod
4543
+ def B(expression, valid_from=0):
4544
+ r"""
4545
+ Create a B-term.
4546
+
4547
+ INPUT:
4548
+
4549
+ - ``valid_from`` -- dictionary mapping variable names to lower bounds
4550
+ for the corresponding variable. The bound implied by this term is valid when
4551
+ all variables are at least their corresponding lower bound. If a number
4552
+ is passed to ``valid_from``, then the lower bounds for all variables of
4553
+ the asymptotic expansion are set to this number
4554
+
4555
+ OUTPUT: a B-term
4556
+
4557
+ EXAMPLES::
4558
+
4559
+ sage: A.<x> = AsymptoticRing(growth_group='x^ZZ * QQ^y', coefficient_ring=QQ)
4560
+ sage: A.B(2*x^3, {x: 5})
4561
+ B(2*x^3, x >= 5)
4562
+ """
4563
+ return expression.B(valid_from)
4564
+
4565
+
4566
+ class AsymptoticRingFunctor(ConstructionFunctor):
4567
+ r"""
4568
+ A :class:`construction functor <sage.categories.pushout.ConstructionFunctor>`
4569
+ for :class:`asymptotic rings <AsymptoticRing>`.
4570
+
4571
+ INPUT:
4572
+
4573
+ - ``growth_group`` -- a partially ordered group (see
4574
+ :class:`AsymptoticRing` or
4575
+ :doc:`growth_group` for details).
4576
+
4577
+ - ``default_prec`` -- ``None`` (default) or integer
4578
+
4579
+ - ``category`` -- ``None`` (default) or a category
4580
+
4581
+ - ``cls`` -- :class:`AsymptoticRing` (default) or a derived class
4582
+
4583
+ EXAMPLES::
4584
+
4585
+ sage: AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ).construction() # indirect doctest
4586
+ (AsymptoticRing<x^ZZ>, Rational Field)
4587
+
4588
+ .. SEEALSO::
4589
+
4590
+ :doc:`asymptotic_ring`,
4591
+ :class:`AsymptoticRing`,
4592
+ :class:`sage.rings.asymptotic.growth_group.AbstractGrowthGroupFunctor`,
4593
+ :class:`sage.rings.asymptotic.growth_group.ExponentialGrowthGroupFunctor`,
4594
+ :class:`sage.rings.asymptotic.growth_group.MonomialGrowthGroupFunctor`,
4595
+ :class:`sage.categories.pushout.ConstructionFunctor`.
4596
+
4597
+ TESTS::
4598
+
4599
+ sage: X = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ)
4600
+ sage: Y = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=QQ)
4601
+ sage: cm = sage.structure.element.get_coercion_model()
4602
+ sage: cm.record_exceptions()
4603
+ sage: cm.common_parent(X, Y)
4604
+ Asymptotic Ring <x^ZZ * y^ZZ> over Rational Field
4605
+ sage: sage.structure.element.coercion_traceback() # not tested
4606
+
4607
+ ::
4608
+
4609
+ sage: from sage.categories.pushout import pushout
4610
+ sage: pushout(AsymptoticRing(growth_group='x^ZZ', coefficient_ring=ZZ), QQ)
4611
+ Asymptotic Ring <x^ZZ> over Rational Field
4612
+ """
4613
+
4614
+ rank = 13
4615
+
4616
+ def __init__(self, growth_group,
4617
+ default_prec=None, category=None,
4618
+ term_monoid_factory=None, locals=None,
4619
+ cls=None):
4620
+ r"""
4621
+ See :class:`AsymptoticRingFunctor` for details.
4622
+
4623
+ TESTS::
4624
+
4625
+ sage: from sage.rings.asymptotic.asymptotic_ring import AsymptoticRingFunctor
4626
+ sage: from sage.rings.asymptotic.growth_group import GrowthGroup
4627
+ sage: AsymptoticRingFunctor(GrowthGroup('x^ZZ'))
4628
+ AsymptoticRing<x^ZZ>
4629
+ """
4630
+ self.growth_group = growth_group
4631
+ if cls is None:
4632
+ self.cls = AsymptoticRing
4633
+ else:
4634
+ self.cls = cls
4635
+ self._default_prec_ = default_prec
4636
+ self._category_ = category
4637
+ self._term_monoid_factory_ = term_monoid_factory
4638
+ self._locals_ = locals
4639
+
4640
+ from sage.categories.commutative_rings import CommutativeRings
4641
+ super().__init__(CommutativeRings(), CommutativeRings())
4642
+
4643
+ def _repr_(self) -> str:
4644
+ r"""
4645
+ Return a representation string of this functor.
4646
+
4647
+ OUTPUT: string
4648
+
4649
+ TESTS::
4650
+
4651
+ sage: AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ).construction()[0] # indirect doctest
4652
+ AsymptoticRing<x^ZZ>
4653
+
4654
+ :issue:`22392`::
4655
+
4656
+ sage: from sage.rings.asymptotic.asymptotic_ring import AsymptoticRing
4657
+ sage: class MyAsymptoticRing(AsymptoticRing):
4658
+ ....: pass
4659
+ sage: A = MyAsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ)
4660
+ sage: A.construction()
4661
+ (MyAsymptoticRing<x^ZZ>, Rational Field)
4662
+ """
4663
+ return '{}<{}>'.format(self.cls.__name__,
4664
+ self.growth_group._repr_(condense=True))
4665
+
4666
+ def _apply_functor(self, coefficient_ring):
4667
+ r"""
4668
+ Apply this functor to the given ``coefficient_ring``.
4669
+
4670
+ INPUT:
4671
+
4672
+ - ``base`` -- anything :class:`~sage.rings.asymptotic.growth_group.MonomialGrowthGroup` accepts
4673
+
4674
+ OUTPUT: an :class:`AsymptoticRing`
4675
+
4676
+ EXAMPLES::
4677
+
4678
+ sage: A = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ)
4679
+ sage: F, C = A.construction()
4680
+ sage: F(C) # indirect doctest
4681
+ Asymptotic Ring <x^ZZ> over Rational Field
4682
+
4683
+ TESTS:
4684
+
4685
+ :issue:`22392`::
4686
+
4687
+ sage: from sage.rings.asymptotic.asymptotic_ring import AsymptoticRing
4688
+ sage: class MyAsymptoticRing(AsymptoticRing):
4689
+ ....: pass
4690
+ sage: A = MyAsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ)
4691
+ sage: type(A.construction()[0](ZZ))
4692
+ <class '__main__.MyAsymptoticRing_with_category'>
4693
+
4694
+
4695
+ sage: C = CyclotomicField(3)
4696
+ sage: P = C['z']
4697
+ sage: type(P(2) * A.gen())
4698
+ <class '...MyAsymptoticRing_with_category.element_class'>
4699
+
4700
+ :issue:`22396`::
4701
+
4702
+ sage: A.<n> = AsymptoticRing('ZZ^n * n^ZZ', ZZ, default_prec=3)
4703
+ sage: 1/(QQ(1)+n)
4704
+ n^(-1) - n^(-2) + n^(-3) + O(n^(-4))
4705
+ """
4706
+ kwds = {'growth_group': self.growth_group,
4707
+ 'coefficient_ring': coefficient_ring}
4708
+ parameters = ('category', 'default_prec',
4709
+ 'term_monoid_factory', 'locals')
4710
+ for parameter in parameters:
4711
+ value = getattr(self, '_{}_'.format(parameter))
4712
+ if value is not None:
4713
+ kwds[parameter] = value
4714
+ return self.cls(**kwds)
4715
+
4716
+ def merge(self, other):
4717
+ r"""
4718
+ Merge this functor with ``other`` if possible.
4719
+
4720
+ INPUT:
4721
+
4722
+ - ``other`` -- a functor
4723
+
4724
+ OUTPUT: a functor or ``None``
4725
+
4726
+ EXAMPLES::
4727
+
4728
+ sage: X = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ)
4729
+ sage: Y = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=QQ)
4730
+ sage: F_X = X.construction()[0]
4731
+ sage: F_Y = Y.construction()[0]
4732
+ sage: F_X.merge(F_X)
4733
+ AsymptoticRing<x^ZZ>
4734
+ sage: F_X.merge(F_Y)
4735
+ AsymptoticRing<x^ZZ * y^ZZ>
4736
+
4737
+ TESTS:
4738
+
4739
+ :issue:`22396`::
4740
+
4741
+ sage: AN = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=QQ)
4742
+ sage: F_AN = AN.construction()[0]; F_AN._default_prec_ = None
4743
+ sage: A3 = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ, default_prec=3)
4744
+ sage: F_A3 = A3.construction()[0]
4745
+ sage: A5 = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ, default_prec=5)
4746
+ sage: F_A5 = A5.construction()[0]
4747
+
4748
+ sage: F_AN.merge(F_AN)(ZZ).default_prec
4749
+ 20
4750
+ sage: F_AN.merge(F_A3)(ZZ).default_prec
4751
+ 3
4752
+ sage: F_AN.merge(F_A5)(ZZ).default_prec
4753
+ 5
4754
+ sage: F_A3.merge(F_AN)(ZZ).default_prec
4755
+ 3
4756
+ sage: F_A3.merge(F_A3)(ZZ).default_prec
4757
+ 3
4758
+ sage: F_A3.merge(F_A5)(ZZ).default_prec
4759
+ 3
4760
+ sage: F_A5.merge(F_AN)(ZZ).default_prec
4761
+ 5
4762
+ sage: F_A5.merge(F_A3)(ZZ).default_prec
4763
+ 3
4764
+ sage: F_A5.merge(F_A5)(ZZ).default_prec
4765
+ 5
4766
+
4767
+ sage: A = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=QQ)
4768
+ sage: F1 = A.construction()[0]
4769
+ sage: F2 = A.construction()[0]; F2._category_ = Rings()
4770
+ sage: F1.merge(F2)._category_
4771
+ Category of rings
4772
+ """
4773
+ if self == other:
4774
+ return self
4775
+
4776
+ if isinstance(other, AsymptoticRingFunctor) and self.cls == other.cls:
4777
+ from sage.structure.element import get_coercion_model
4778
+ cm = get_coercion_model()
4779
+ try:
4780
+ G = cm.common_parent(self.growth_group, other.growth_group)
4781
+ except TypeError:
4782
+ pass
4783
+ else:
4784
+ if (self._default_prec_ is None
4785
+ and other._default_prec_ is None):
4786
+ default_prec = None
4787
+ elif self._default_prec_ is None:
4788
+ default_prec = other._default_prec_
4789
+ elif other._default_prec_ is None:
4790
+ default_prec = self._default_prec_
4791
+ else:
4792
+ default_prec = min(self._default_prec_,
4793
+ other._default_prec_)
4794
+ if (self._category_ is None
4795
+ and other._category_ is None):
4796
+ category = None
4797
+ elif self._category_ is None:
4798
+ category = other._category_
4799
+ elif other._category_ is None:
4800
+ category = self._category_
4801
+ else:
4802
+ category = self._category_ | other._category_
4803
+
4804
+ return AsymptoticRingFunctor(
4805
+ G,
4806
+ default_prec=default_prec,
4807
+ category=category,
4808
+ cls=self.cls)
4809
+
4810
+ def __eq__(self, other) -> bool:
4811
+ r"""
4812
+ Return whether this functor is equal to ``other``.
4813
+
4814
+ INPUT:
4815
+
4816
+ - ``other`` -- a functor
4817
+
4818
+ OUTPUT: boolean
4819
+
4820
+ EXAMPLES::
4821
+
4822
+ sage: X = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ)
4823
+ sage: Y = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=QQ)
4824
+ sage: F_X = X.construction()[0]
4825
+ sage: F_Y = Y.construction()[0]
4826
+ sage: F_X == F_X
4827
+ True
4828
+ sage: F_X == F_Y
4829
+ False
4830
+ """
4831
+ return (type(self) is type(other)
4832
+ and self.growth_group == other.growth_group
4833
+ and self._default_prec_ == other._default_prec_
4834
+ and self._category_ == other._category_
4835
+ and self.cls == other.cls)
4836
+
4837
+ def __ne__(self, other) -> bool:
4838
+ r"""
4839
+ Return whether this functor is not equal to ``other``.
4840
+
4841
+ INPUT:
4842
+
4843
+ - ``other`` -- a functor
4844
+
4845
+ OUTPUT: boolean
4846
+
4847
+ EXAMPLES::
4848
+
4849
+ sage: X = AsymptoticRing(growth_group='x^ZZ', coefficient_ring=QQ)
4850
+ sage: Y = AsymptoticRing(growth_group='y^ZZ', coefficient_ring=QQ)
4851
+ sage: F_X = X.construction()[0]
4852
+ sage: F_Y = Y.construction()[0]
4853
+ sage: F_X != F_X
4854
+ False
4855
+ sage: F_X != F_Y
4856
+ True
4857
+ """
4858
+ return not self == other