passagemath-symbolics 10.6.37__cp310-cp310-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_symbolics/__init__.py +3 -0
- passagemath_symbolics-10.6.37.dist-info/METADATA +187 -0
- passagemath_symbolics-10.6.37.dist-info/RECORD +171 -0
- passagemath_symbolics-10.6.37.dist-info/WHEEL +5 -0
- passagemath_symbolics-10.6.37.dist-info/top_level.txt +3 -0
- sage/all__sagemath_symbolics.py +17 -0
- sage/calculus/all.py +14 -0
- sage/calculus/calculus.py +2826 -0
- sage/calculus/desolvers.py +1866 -0
- sage/calculus/predefined.py +51 -0
- sage/calculus/tests.py +225 -0
- sage/calculus/var.cpython-310-x86_64-linux-gnu.so +0 -0
- sage/calculus/var.pyx +401 -0
- sage/dynamics/all__sagemath_symbolics.py +6 -0
- sage/dynamics/complex_dynamics/all.py +5 -0
- sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-310-x86_64-linux-gnu.so +0 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1035 -0
- sage/ext/all__sagemath_symbolics.py +1 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/ext_data/magma/latex/latex.m +1021 -0
- sage/ext_data/magma/latex/latex.spec +1 -0
- sage/ext_data/magma/sage/basic.m +356 -0
- sage/ext_data/magma/sage/sage.spec +1 -0
- sage/ext_data/magma/spec +9 -0
- sage/geometry/all__sagemath_symbolics.py +8 -0
- sage/geometry/hyperbolic_space/all.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_coercion.py +743 -0
- sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2409 -0
- sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
- sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1082 -0
- sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
- sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
- sage/geometry/riemannian_manifolds/all.py +7 -0
- sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
- sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
- sage/interfaces/all__sagemath_symbolics.py +1 -0
- sage/interfaces/magma.py +3017 -0
- sage/interfaces/magma_free.py +92 -0
- sage/interfaces/maple.py +1397 -0
- sage/interfaces/mathematica.py +1345 -0
- sage/interfaces/mathics.py +1312 -0
- sage/interfaces/sympy.py +1398 -0
- sage/interfaces/sympy_wrapper.py +197 -0
- sage/interfaces/tides.py +938 -0
- sage/libs/all__sagemath_symbolics.py +6 -0
- sage/manifolds/all.py +7 -0
- sage/manifolds/calculus_method.py +555 -0
- sage/manifolds/catalog.py +437 -0
- sage/manifolds/chart.py +4019 -0
- sage/manifolds/chart_func.py +3419 -0
- sage/manifolds/continuous_map.py +2183 -0
- sage/manifolds/continuous_map_image.py +155 -0
- sage/manifolds/differentiable/affine_connection.py +2475 -0
- sage/manifolds/differentiable/all.py +1 -0
- sage/manifolds/differentiable/automorphismfield.py +1383 -0
- sage/manifolds/differentiable/automorphismfield_group.py +604 -0
- sage/manifolds/differentiable/bundle_connection.py +1445 -0
- sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
- sage/manifolds/differentiable/chart.py +1241 -0
- sage/manifolds/differentiable/curve.py +1028 -0
- sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
- sage/manifolds/differentiable/degenerate.py +559 -0
- sage/manifolds/differentiable/degenerate_submanifold.py +1671 -0
- sage/manifolds/differentiable/diff_form.py +1658 -0
- sage/manifolds/differentiable/diff_form_module.py +1062 -0
- sage/manifolds/differentiable/diff_map.py +1315 -0
- sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
- sage/manifolds/differentiable/examples/all.py +1 -0
- sage/manifolds/differentiable/examples/euclidean.py +2517 -0
- sage/manifolds/differentiable/examples/real_line.py +897 -0
- sage/manifolds/differentiable/examples/sphere.py +1186 -0
- sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
- sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
- sage/manifolds/differentiable/integrated_curve.py +4035 -0
- sage/manifolds/differentiable/levi_civita_connection.py +841 -0
- sage/manifolds/differentiable/manifold.py +4254 -0
- sage/manifolds/differentiable/manifold_homset.py +1826 -0
- sage/manifolds/differentiable/metric.py +3032 -0
- sage/manifolds/differentiable/mixed_form.py +1507 -0
- sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
- sage/manifolds/differentiable/multivector_module.py +800 -0
- sage/manifolds/differentiable/multivectorfield.py +1520 -0
- sage/manifolds/differentiable/poisson_tensor.py +268 -0
- sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
- sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
- sage/manifolds/differentiable/scalarfield.py +1343 -0
- sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
- sage/manifolds/differentiable/symplectic_form.py +910 -0
- sage/manifolds/differentiable/symplectic_form_test.py +220 -0
- sage/manifolds/differentiable/tangent_space.py +412 -0
- sage/manifolds/differentiable/tangent_vector.py +616 -0
- sage/manifolds/differentiable/tensorfield.py +4665 -0
- sage/manifolds/differentiable/tensorfield_module.py +963 -0
- sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
- sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
- sage/manifolds/differentiable/vector_bundle.py +1728 -0
- sage/manifolds/differentiable/vectorfield.py +1717 -0
- sage/manifolds/differentiable/vectorfield_module.py +2445 -0
- sage/manifolds/differentiable/vectorframe.py +1832 -0
- sage/manifolds/family.py +270 -0
- sage/manifolds/local_frame.py +1490 -0
- sage/manifolds/manifold.py +3090 -0
- sage/manifolds/manifold_homset.py +452 -0
- sage/manifolds/operators.py +359 -0
- sage/manifolds/point.py +994 -0
- sage/manifolds/scalarfield.py +3718 -0
- sage/manifolds/scalarfield_algebra.py +629 -0
- sage/manifolds/section.py +3111 -0
- sage/manifolds/section_module.py +831 -0
- sage/manifolds/structure.py +229 -0
- sage/manifolds/subset.py +2764 -0
- sage/manifolds/subsets/all.py +1 -0
- sage/manifolds/subsets/closure.py +131 -0
- sage/manifolds/subsets/pullback.py +885 -0
- sage/manifolds/topological_submanifold.py +891 -0
- sage/manifolds/trivialization.py +733 -0
- sage/manifolds/utilities.py +1348 -0
- sage/manifolds/vector_bundle.py +1342 -0
- sage/manifolds/vector_bundle_fiber.py +332 -0
- sage/manifolds/vector_bundle_fiber_element.py +111 -0
- sage/matrix/all__sagemath_symbolics.py +1 -0
- sage/matrix/matrix_symbolic_dense.cpython-310-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_symbolic_dense.pxd +6 -0
- sage/matrix/matrix_symbolic_dense.pyx +1022 -0
- sage/matrix/matrix_symbolic_sparse.cpython-310-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_symbolic_sparse.pxd +6 -0
- sage/matrix/matrix_symbolic_sparse.pyx +1029 -0
- sage/modules/all__sagemath_symbolics.py +1 -0
- sage/modules/vector_callable_symbolic_dense.py +105 -0
- sage/modules/vector_symbolic_dense.py +116 -0
- sage/modules/vector_symbolic_sparse.py +118 -0
- sage/rings/all__sagemath_symbolics.py +4 -0
- sage/rings/asymptotic/all.py +6 -0
- sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
- sage/rings/asymptotic/asymptotic_ring.py +4858 -0
- sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4153 -0
- sage/rings/asymptotic/growth_group.py +5373 -0
- sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
- sage/rings/asymptotic/term_monoid.py +5237 -0
- sage/rings/function_field/all__sagemath_symbolics.py +2 -0
- sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
- sage/symbolic/all.py +15 -0
- sage/symbolic/assumptions.py +985 -0
- sage/symbolic/benchmark.py +93 -0
- sage/symbolic/callable.py +459 -0
- sage/symbolic/complexity_measures.py +35 -0
- sage/symbolic/constants.py +1287 -0
- sage/symbolic/expression_conversion_algebraic.py +310 -0
- sage/symbolic/expression_conversion_sympy.py +317 -0
- sage/symbolic/expression_conversions.py +1713 -0
- sage/symbolic/function_factory.py +355 -0
- sage/symbolic/integration/all.py +1 -0
- sage/symbolic/integration/external.py +270 -0
- sage/symbolic/integration/integral.py +1115 -0
- sage/symbolic/maxima_wrapper.py +162 -0
- sage/symbolic/operators.py +267 -0
- sage/symbolic/random_tests.py +462 -0
- sage/symbolic/relation.py +1907 -0
- sage/symbolic/ring.cpython-310-x86_64-linux-gnu.so +0 -0
- sage/symbolic/ring.pxd +5 -0
- sage/symbolic/ring.pyx +1396 -0
- sage/symbolic/subring.py +1025 -0
- sage/symbolic/symengine.py +19 -0
- sage/symbolic/tests.py +40 -0
- 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
|