passagemath-symbolics 10.8.1a1__cp314-cp314t-musllinux_1_2_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. passagemath_symbolics/__init__.py +3 -0
  2. passagemath_symbolics-10.8.1a1.dist-info/METADATA +186 -0
  3. passagemath_symbolics-10.8.1a1.dist-info/RECORD +181 -0
  4. passagemath_symbolics-10.8.1a1.dist-info/WHEEL +5 -0
  5. passagemath_symbolics-10.8.1a1.dist-info/top_level.txt +3 -0
  6. sage/all__sagemath_symbolics.py +17 -0
  7. sage/calculus/all.py +14 -0
  8. sage/calculus/calculus.py +2838 -0
  9. sage/calculus/desolvers.py +1864 -0
  10. sage/calculus/predefined.py +51 -0
  11. sage/calculus/tests.py +225 -0
  12. sage/calculus/var.cpython-314t-aarch64-linux-musl.so +0 -0
  13. sage/calculus/var.pyx +401 -0
  14. sage/dynamics/all__sagemath_symbolics.py +6 -0
  15. sage/dynamics/complex_dynamics/all.py +5 -0
  16. sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
  17. sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-314t-aarch64-linux-musl.so +0 -0
  18. sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1034 -0
  19. sage/ext/all__sagemath_symbolics.py +1 -0
  20. sage/ext_data/kenzo/CP2.txt +45 -0
  21. sage/ext_data/kenzo/CP3.txt +349 -0
  22. sage/ext_data/kenzo/CP4.txt +4774 -0
  23. sage/ext_data/kenzo/README.txt +49 -0
  24. sage/ext_data/kenzo/S4.txt +20 -0
  25. sage/ext_data/magma/latex/latex.m +1021 -0
  26. sage/ext_data/magma/latex/latex.spec +1 -0
  27. sage/ext_data/magma/sage/basic.m +356 -0
  28. sage/ext_data/magma/sage/sage.spec +1 -0
  29. sage/ext_data/magma/spec +9 -0
  30. sage/geometry/all__sagemath_symbolics.py +8 -0
  31. sage/geometry/hyperbolic_space/all.py +5 -0
  32. sage/geometry/hyperbolic_space/hyperbolic_coercion.py +755 -0
  33. sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
  34. sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2419 -0
  35. sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
  36. sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1083 -0
  37. sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
  38. sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
  39. sage/geometry/riemannian_manifolds/all.py +7 -0
  40. sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
  41. sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
  42. sage/interfaces/all__sagemath_symbolics.py +1 -0
  43. sage/interfaces/magma.py +2991 -0
  44. sage/interfaces/magma_free.py +90 -0
  45. sage/interfaces/maple.py +1402 -0
  46. sage/interfaces/mathematica.py +1345 -0
  47. sage/interfaces/mathics.py +1312 -0
  48. sage/interfaces/sympy.py +1398 -0
  49. sage/interfaces/sympy_wrapper.py +197 -0
  50. sage/interfaces/tides.py +938 -0
  51. sage/libs/all__sagemath_symbolics.py +6 -0
  52. sage/manifolds/all.py +7 -0
  53. sage/manifolds/calculus_method.py +553 -0
  54. sage/manifolds/catalog.py +437 -0
  55. sage/manifolds/chart.py +4010 -0
  56. sage/manifolds/chart_func.py +3416 -0
  57. sage/manifolds/continuous_map.py +2183 -0
  58. sage/manifolds/continuous_map_image.py +155 -0
  59. sage/manifolds/differentiable/affine_connection.py +2475 -0
  60. sage/manifolds/differentiable/all.py +1 -0
  61. sage/manifolds/differentiable/automorphismfield.py +1383 -0
  62. sage/manifolds/differentiable/automorphismfield_group.py +604 -0
  63. sage/manifolds/differentiable/bundle_connection.py +1445 -0
  64. sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
  65. sage/manifolds/differentiable/chart.py +1241 -0
  66. sage/manifolds/differentiable/curve.py +1028 -0
  67. sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
  68. sage/manifolds/differentiable/degenerate.py +559 -0
  69. sage/manifolds/differentiable/degenerate_submanifold.py +1668 -0
  70. sage/manifolds/differentiable/diff_form.py +1660 -0
  71. sage/manifolds/differentiable/diff_form_module.py +1062 -0
  72. sage/manifolds/differentiable/diff_map.py +1315 -0
  73. sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
  74. sage/manifolds/differentiable/examples/all.py +1 -0
  75. sage/manifolds/differentiable/examples/euclidean.py +2517 -0
  76. sage/manifolds/differentiable/examples/real_line.py +897 -0
  77. sage/manifolds/differentiable/examples/sphere.py +1186 -0
  78. sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
  79. sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
  80. sage/manifolds/differentiable/integrated_curve.py +4035 -0
  81. sage/manifolds/differentiable/levi_civita_connection.py +841 -0
  82. sage/manifolds/differentiable/manifold.py +4254 -0
  83. sage/manifolds/differentiable/manifold_homset.py +1826 -0
  84. sage/manifolds/differentiable/metric.py +3032 -0
  85. sage/manifolds/differentiable/mixed_form.py +1507 -0
  86. sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
  87. sage/manifolds/differentiable/multivector_module.py +800 -0
  88. sage/manifolds/differentiable/multivectorfield.py +1522 -0
  89. sage/manifolds/differentiable/poisson_tensor.py +268 -0
  90. sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
  91. sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
  92. sage/manifolds/differentiable/scalarfield.py +1343 -0
  93. sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
  94. sage/manifolds/differentiable/symplectic_form.py +912 -0
  95. sage/manifolds/differentiable/symplectic_form_test.py +220 -0
  96. sage/manifolds/differentiable/tangent_space.py +412 -0
  97. sage/manifolds/differentiable/tangent_vector.py +616 -0
  98. sage/manifolds/differentiable/tensorfield.py +4665 -0
  99. sage/manifolds/differentiable/tensorfield_module.py +963 -0
  100. sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
  101. sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
  102. sage/manifolds/differentiable/vector_bundle.py +1725 -0
  103. sage/manifolds/differentiable/vectorfield.py +1717 -0
  104. sage/manifolds/differentiable/vectorfield_module.py +2445 -0
  105. sage/manifolds/differentiable/vectorframe.py +1832 -0
  106. sage/manifolds/family.py +270 -0
  107. sage/manifolds/local_frame.py +1490 -0
  108. sage/manifolds/manifold.py +3090 -0
  109. sage/manifolds/manifold_homset.py +452 -0
  110. sage/manifolds/operators.py +359 -0
  111. sage/manifolds/point.py +994 -0
  112. sage/manifolds/scalarfield.py +3718 -0
  113. sage/manifolds/scalarfield_algebra.py +629 -0
  114. sage/manifolds/section.py +3111 -0
  115. sage/manifolds/section_module.py +831 -0
  116. sage/manifolds/structure.py +229 -0
  117. sage/manifolds/subset.py +2721 -0
  118. sage/manifolds/subsets/all.py +1 -0
  119. sage/manifolds/subsets/closure.py +131 -0
  120. sage/manifolds/subsets/pullback.py +883 -0
  121. sage/manifolds/topological_submanifold.py +891 -0
  122. sage/manifolds/trivialization.py +733 -0
  123. sage/manifolds/utilities.py +1348 -0
  124. sage/manifolds/vector_bundle.py +1347 -0
  125. sage/manifolds/vector_bundle_fiber.py +332 -0
  126. sage/manifolds/vector_bundle_fiber_element.py +111 -0
  127. sage/matrix/all__sagemath_symbolics.py +1 -0
  128. sage/matrix/matrix_symbolic_dense.cpython-314t-aarch64-linux-musl.so +0 -0
  129. sage/matrix/matrix_symbolic_dense.pxd +6 -0
  130. sage/matrix/matrix_symbolic_dense.pyx +1030 -0
  131. sage/matrix/matrix_symbolic_sparse.cpython-314t-aarch64-linux-musl.so +0 -0
  132. sage/matrix/matrix_symbolic_sparse.pxd +6 -0
  133. sage/matrix/matrix_symbolic_sparse.pyx +1038 -0
  134. sage/modules/all__sagemath_symbolics.py +1 -0
  135. sage/modules/vector_callable_symbolic_dense.py +105 -0
  136. sage/modules/vector_symbolic_dense.py +116 -0
  137. sage/modules/vector_symbolic_sparse.py +118 -0
  138. sage/rings/all__sagemath_symbolics.py +4 -0
  139. sage/rings/asymptotic/all.py +6 -0
  140. sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
  141. sage/rings/asymptotic/asymptotic_ring.py +4858 -0
  142. sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4106 -0
  143. sage/rings/asymptotic/growth_group.py +5373 -0
  144. sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
  145. sage/rings/asymptotic/term_monoid.py +5205 -0
  146. sage/rings/function_field/all__sagemath_symbolics.py +2 -0
  147. sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
  148. sage/symbolic/all.py +15 -0
  149. sage/symbolic/assumptions.py +987 -0
  150. sage/symbolic/benchmark.py +93 -0
  151. sage/symbolic/callable.py +456 -0
  152. sage/symbolic/callable.pyi +66 -0
  153. sage/symbolic/comparison_impl.pyi +38 -0
  154. sage/symbolic/complexity_measures.py +35 -0
  155. sage/symbolic/constants.py +1286 -0
  156. sage/symbolic/constants_c_impl.pyi +10 -0
  157. sage/symbolic/expression_conversion_algebraic.py +310 -0
  158. sage/symbolic/expression_conversion_sympy.py +317 -0
  159. sage/symbolic/expression_conversions.py +1727 -0
  160. sage/symbolic/function_factory.py +355 -0
  161. sage/symbolic/function_factory.pyi +41 -0
  162. sage/symbolic/getitem_impl.pyi +24 -0
  163. sage/symbolic/integration/all.py +1 -0
  164. sage/symbolic/integration/external.py +271 -0
  165. sage/symbolic/integration/integral.py +1075 -0
  166. sage/symbolic/maxima_wrapper.py +162 -0
  167. sage/symbolic/operators.py +267 -0
  168. sage/symbolic/operators.pyi +61 -0
  169. sage/symbolic/pynac_constant_impl.pyi +13 -0
  170. sage/symbolic/pynac_function_impl.pyi +8 -0
  171. sage/symbolic/random_tests.py +461 -0
  172. sage/symbolic/relation.py +2062 -0
  173. sage/symbolic/ring.cpython-314t-aarch64-linux-musl.so +0 -0
  174. sage/symbolic/ring.pxd +5 -0
  175. sage/symbolic/ring.pyi +110 -0
  176. sage/symbolic/ring.pyx +1393 -0
  177. sage/symbolic/series_impl.pyi +10 -0
  178. sage/symbolic/subring.py +1025 -0
  179. sage/symbolic/symengine.py +19 -0
  180. sage/symbolic/tests.py +40 -0
  181. sage/symbolic/units.py +1468 -0
@@ -0,0 +1,1727 @@
1
+ # sage_setup: distribution = sagemath-symbolics
2
+ """
3
+ Conversion of symbolic expressions to other types
4
+
5
+ This module provides routines for converting new symbolic expressions
6
+ to other types. Primarily, it provides a class :class:`Converter`
7
+ which will walk the expression tree and make calls to methods
8
+ overridden by subclasses.
9
+ """
10
+ ###############################################################################
11
+ # Sage: Open Source Mathematical Software
12
+ # Copyright (C) 2009 Mike Hansen <mhansen@gmail.com>
13
+ #
14
+ # Distributed under the terms of the GNU General Public License (GPL),
15
+ # version 2 or any later version. The full text of the GPL is available at:
16
+ # https://www.gnu.org/licenses/
17
+ ###############################################################################
18
+
19
+ from functools import reduce
20
+ from operator import add, eq, mul, neg, pow, truediv
21
+
22
+ from sage.functions.log import exp
23
+ from sage.misc.lazy_import import lazy_import
24
+ from sage.rings.number_field.number_field_element_base import NumberFieldElement_base
25
+ from sage.structure.element import Expression, InfinityElement
26
+ from sage.symbolic.operators import (
27
+ FDerivativeOperator,
28
+ add_vararg,
29
+ arithmetic_operators,
30
+ mul_vararg,
31
+ relation_operators,
32
+ )
33
+ from sage.symbolic.ring import SR
34
+
35
+ lazy_import('sage.rings.universal_cyclotomic_field', 'UniversalCyclotomicField')
36
+ lazy_import('sage.symbolic.expression_conversion_sympy', ['SympyConverter', 'sympy_converter'])
37
+ lazy_import('sage.symbolic.expression_conversion_algebraic', ['AlgebraicConverter', 'algebraic'])
38
+ lazy_import('sage.symbolic.expression_conversion_fricas', ['FriCASConverter', 'fricas_converter'])
39
+
40
+
41
+ class FakeExpression:
42
+ r"""
43
+ Pynac represents `x/y` as `xy^{-1}`. Often, tree-walkers would prefer
44
+ to see divisions instead of multiplications and negative exponents.
45
+ To allow for this (since Pynac internally doesn't have division at all),
46
+ there is a possibility to pass use_fake_div=True; this will rewrite
47
+ an Expression into a mixture of Expression and FakeExpression nodes,
48
+ where the FakeExpression nodes are used to represent divisions.
49
+ These nodes are intended to act sufficiently like Expression nodes
50
+ that tree-walkers won't care about the difference.
51
+ """
52
+
53
+ def __init__(self, operands, operator):
54
+ """
55
+ EXAMPLES::
56
+
57
+ sage: from sage.symbolic.expression_conversions import FakeExpression
58
+ sage: import operator; x,y = var('x,y')
59
+ sage: FakeExpression([x, y], operator.truediv)
60
+ FakeExpression([x, y], <built-in function truediv>)
61
+ """
62
+ self._operands = operands
63
+ self._operator = operator
64
+
65
+ def __repr__(self):
66
+ """
67
+ EXAMPLES::
68
+
69
+ sage: from sage.symbolic.expression_conversions import FakeExpression
70
+ sage: import operator; x,y = var('x,y')
71
+ sage: FakeExpression([x, y], operator.truediv)
72
+ FakeExpression([x, y], <built-in function truediv>)
73
+ """
74
+ return "FakeExpression(%r, %r)" % (self._operands, self._operator)
75
+
76
+ def pyobject(self):
77
+ """
78
+ EXAMPLES::
79
+
80
+ sage: from sage.symbolic.expression_conversions import FakeExpression
81
+ sage: import operator; x,y = var('x,y')
82
+ sage: f = FakeExpression([x, y], operator.truediv)
83
+ sage: f.pyobject()
84
+ Traceback (most recent call last):
85
+ ...
86
+ TypeError: self must be a numeric expression
87
+ """
88
+ raise TypeError('self must be a numeric expression')
89
+
90
+ def operands(self):
91
+ """
92
+ EXAMPLES::
93
+
94
+ sage: from sage.symbolic.expression_conversions import FakeExpression
95
+ sage: import operator; x,y = var('x,y')
96
+ sage: f = FakeExpression([x, y], operator.truediv)
97
+ sage: f.operands()
98
+ [x, y]
99
+ """
100
+ return self._operands
101
+
102
+ def __getitem__(self, i):
103
+ """
104
+ EXAMPLES::
105
+
106
+ sage: from sage.symbolic.expression_conversions import FakeExpression
107
+ sage: import operator; x,y = var('x,y')
108
+ sage: f = FakeExpression([x, y], operator.truediv)
109
+ sage: f[0]
110
+ x
111
+ """
112
+ return self._operands[i]
113
+
114
+ def operator(self):
115
+ """
116
+ EXAMPLES::
117
+
118
+ sage: from sage.symbolic.expression_conversions import FakeExpression
119
+ sage: import operator; x,y = var('x,y')
120
+ sage: f = FakeExpression([x, y], operator.truediv)
121
+ sage: f.operator()
122
+ <built-in function truediv>
123
+ """
124
+ return self._operator
125
+
126
+ def _fast_callable_(self, etb):
127
+ """
128
+ EXAMPLES::
129
+
130
+ sage: from sage.symbolic.expression_conversions import FakeExpression
131
+ sage: import operator; x,y = var('x,y')
132
+ sage: f = FakeExpression([x, y], operator.truediv)
133
+ sage: fast_callable(f, vars=['x','y']).op_list()
134
+ [('load_arg', 0), ('load_arg', 1), 'div', 'return']
135
+ """
136
+ return fast_callable(self, etb)
137
+
138
+
139
+ class Converter:
140
+ def __init__(self, use_fake_div=False):
141
+ """
142
+ If use_fake_div is set to True, then the converter will try to
143
+ replace expressions whose operator is operator.mul with the
144
+ corresponding expression whose operator is operator.truediv.
145
+
146
+ EXAMPLES::
147
+
148
+ sage: from sage.symbolic.expression_conversions import Converter
149
+ sage: c = Converter(use_fake_div=True)
150
+ sage: c.use_fake_div
151
+ True
152
+ """
153
+ self.use_fake_div = use_fake_div
154
+
155
+ def __call__(self, ex=None):
156
+ """
157
+ .. NOTE::
158
+
159
+ If this object does not have an attribute ``ex``, then an argument
160
+ must be passed into :meth:`__call__`.
161
+
162
+ EXAMPLES::
163
+
164
+ sage: from sage.symbolic.expression_conversions import Converter
165
+ sage: c = Converter(use_fake_div=True)
166
+ sage: c(SR(2))
167
+ Traceback (most recent call last):
168
+ ...
169
+ NotImplementedError: pyobject
170
+ sage: c(x+2)
171
+ Traceback (most recent call last):
172
+ ...
173
+ NotImplementedError: arithmetic
174
+ sage: c(x)
175
+ Traceback (most recent call last):
176
+ ...
177
+ NotImplementedError: symbol
178
+ sage: c(x==2)
179
+ Traceback (most recent call last):
180
+ ...
181
+ NotImplementedError: relation
182
+ sage: c(sin(x))
183
+ Traceback (most recent call last):
184
+ ...
185
+ NotImplementedError: composition
186
+ sage: c(function('f')(x).diff(x))
187
+ Traceback (most recent call last):
188
+ ...
189
+ NotImplementedError: derivative
190
+
191
+ We can set a default value for the argument by setting
192
+ the ``ex`` attribute::
193
+
194
+ sage: c.ex = SR(2)
195
+ sage: c()
196
+ Traceback (most recent call last):
197
+ ...
198
+ NotImplementedError: pyobject
199
+ """
200
+ if ex is None:
201
+ ex = self.ex
202
+
203
+ try:
204
+ obj = ex.pyobject()
205
+ return self.pyobject(ex, obj)
206
+ except TypeError as err:
207
+ if 'self must be a numeric expression' not in err.args:
208
+ raise err
209
+
210
+ operator = ex.operator()
211
+ if operator is None:
212
+ return self.symbol(ex)
213
+
214
+ if operator in arithmetic_operators:
215
+ if getattr(self, 'use_fake_div', False) and (operator is mul or operator is mul_vararg):
216
+ div = self.get_fake_div(ex)
217
+ return self.arithmetic(div, div.operator())
218
+ return self.arithmetic(ex, operator)
219
+ elif operator in relation_operators:
220
+ return self.relation(ex, operator)
221
+ elif isinstance(operator, FDerivativeOperator):
222
+ return self.derivative(ex, operator)
223
+ elif operator is tuple:
224
+ return self.tuple(ex)
225
+ else:
226
+ return self.composition(ex, operator)
227
+
228
+ def get_fake_div(self, ex):
229
+ """
230
+ EXAMPLES::
231
+
232
+ sage: from sage.symbolic.expression_conversions import Converter
233
+ sage: c = Converter(use_fake_div=True)
234
+ sage: c.get_fake_div(sin(x)/x)
235
+ FakeExpression([sin(x), x], <built-in function truediv>)
236
+ sage: c.get_fake_div(-1*sin(x))
237
+ FakeExpression([sin(x)], <built-in function neg>)
238
+ sage: c.get_fake_div(-x)
239
+ FakeExpression([x], <built-in function neg>)
240
+ sage: c.get_fake_div((2*x^3+2*x-1)/((x-2)*(x+1)))
241
+ FakeExpression([2*x^3 + 2*x - 1, FakeExpression([x + 1, x - 2], <built-in function mul>)], <built-in function truediv>)
242
+
243
+ Check if :issue:`8056` is fixed, i.e., if numerator is 1.::
244
+
245
+ sage: c.get_fake_div(1/pi/x)
246
+ FakeExpression([1, FakeExpression([pi, x], <built-in function mul>)], <built-in function truediv>)
247
+ """
248
+ d = []
249
+ n = []
250
+ for arg in ex.operands():
251
+ ops = arg.operands()
252
+ try:
253
+ if arg.operator() is pow and repr(ops[1]) == '-1':
254
+ d.append(ops[0])
255
+ else:
256
+ n.append(arg)
257
+ except TypeError:
258
+ n.append(arg)
259
+
260
+ len_d = len(d)
261
+ if len_d == 0:
262
+ repr_n = [repr(_) for _ in n]
263
+ if len(n) == 2 and "-1" in repr_n:
264
+ a = n[0] if repr_n[1] == "-1" else n[1]
265
+ return FakeExpression([a], neg)
266
+ else:
267
+ return ex
268
+ elif len_d == 1:
269
+ d = d[0]
270
+ else:
271
+ d = FakeExpression(d, mul)
272
+
273
+ if len(n) == 0:
274
+ return FakeExpression([SR.one(), d], truediv)
275
+ elif len(n) == 1:
276
+ n = n[0]
277
+ else:
278
+ n = FakeExpression(n, mul)
279
+
280
+ return FakeExpression([n, d], truediv)
281
+
282
+ def pyobject(self, ex, obj):
283
+ """
284
+ The input to this method is the result of calling
285
+ :meth:`pyobject` on a symbolic expression.
286
+
287
+ .. NOTE::
288
+
289
+ Note that if a constant such as ``pi`` is encountered in
290
+ the expression tree, its corresponding pyobject which is an
291
+ instance of :class:`sage.symbolic.constants.Pi` will be
292
+ passed into this method. One cannot do arithmetic using
293
+ such an object.
294
+
295
+ TESTS::
296
+
297
+ sage: from sage.symbolic.expression_conversions import Converter
298
+ sage: f = SR(1)
299
+ sage: Converter().pyobject(f, f.pyobject())
300
+ Traceback (most recent call last):
301
+ ...
302
+ NotImplementedError: pyobject
303
+ """
304
+ raise NotImplementedError("pyobject")
305
+
306
+ def symbol(self, ex):
307
+ """
308
+ The input to this method is a symbolic expression which
309
+ corresponds to a single variable. For example, this method
310
+ could be used to return a generator for a polynomial ring.
311
+
312
+ TESTS::
313
+
314
+ sage: from sage.symbolic.expression_conversions import Converter
315
+ sage: Converter().symbol(x)
316
+ Traceback (most recent call last):
317
+ ...
318
+ NotImplementedError: symbol
319
+ """
320
+ raise NotImplementedError("symbol")
321
+
322
+ def relation(self, ex, operator):
323
+ """
324
+ The input to this method is a symbolic expression which
325
+ corresponds to a relation.
326
+
327
+ TESTS::
328
+
329
+ sage: from sage.symbolic.expression_conversions import Converter
330
+ sage: import operator
331
+ sage: Converter().relation(x==3, operator.eq)
332
+ Traceback (most recent call last):
333
+ ...
334
+ NotImplementedError: relation
335
+ sage: Converter().relation(x==3, operator.lt)
336
+ Traceback (most recent call last):
337
+ ...
338
+ NotImplementedError: relation
339
+ """
340
+ raise NotImplementedError("relation")
341
+
342
+ def derivative(self, ex, operator):
343
+ """
344
+ The input to this method is a symbolic expression which
345
+ corresponds to a relation.
346
+
347
+ TESTS::
348
+
349
+ sage: from sage.symbolic.expression_conversions import Converter
350
+ sage: a = function('f')(x).diff(x); a
351
+ diff(f(x), x)
352
+ sage: Converter().derivative(a, a.operator())
353
+ Traceback (most recent call last):
354
+ ...
355
+ NotImplementedError: derivative
356
+ """
357
+ raise NotImplementedError("derivative")
358
+
359
+ def arithmetic(self, ex, operator):
360
+ """
361
+ The input to this method is a symbolic expression and the
362
+ infix operator corresponding to that expression. Typically,
363
+ one will convert all of the arguments and then perform the
364
+ operation afterward.
365
+
366
+ TESTS::
367
+
368
+ sage: from sage.symbolic.expression_conversions import Converter
369
+ sage: f = x + 2
370
+ sage: Converter().arithmetic(f, f.operator())
371
+ Traceback (most recent call last):
372
+ ...
373
+ NotImplementedError: arithmetic
374
+ """
375
+ raise NotImplementedError("arithmetic")
376
+
377
+ def composition(self, ex, operator):
378
+ """
379
+ The input to this method is a symbolic expression and its
380
+ operator. This method will get called when you have a symbolic
381
+ function application.
382
+
383
+ TESTS::
384
+
385
+ sage: from sage.symbolic.expression_conversions import Converter
386
+ sage: f = sin(2)
387
+ sage: Converter().composition(f, f.operator())
388
+ Traceback (most recent call last):
389
+ ...
390
+ NotImplementedError: composition
391
+ """
392
+ raise NotImplementedError("composition")
393
+
394
+
395
+ class InterfaceInit(Converter):
396
+ def __init__(self, interface):
397
+ """
398
+ EXAMPLES::
399
+
400
+ sage: from sage.symbolic.expression_conversions import InterfaceInit
401
+ sage: m = InterfaceInit(maxima)
402
+ sage: a = pi + 2
403
+ sage: m(a)
404
+ '(%pi)+(2)'
405
+ sage: m(sin(a))
406
+ 'sin((%pi)+(2))'
407
+ sage: m(exp(x^2) + pi + 2)
408
+ '(%pi)+(exp((_SAGE_VAR_x)^(2)))+(2)'
409
+ """
410
+ self.name_init = "_%s_init_" % interface.name()
411
+ self.interface = interface
412
+ self.relation_symbols = interface._relation_symbols()
413
+
414
+ def symbol(self, ex):
415
+ """
416
+ EXAMPLES::
417
+
418
+ sage: from sage.symbolic.expression_conversions import InterfaceInit
419
+ sage: m = InterfaceInit(maxima)
420
+ sage: m.symbol(x)
421
+ '_SAGE_VAR_x'
422
+ sage: f(x) = x
423
+ sage: m.symbol(f)
424
+ '_SAGE_VAR_x'
425
+ sage: ii = InterfaceInit(gp) # needs sage.libs.pari
426
+ sage: ii.symbol(x) # needs sage.libs.pari
427
+ 'x'
428
+ sage: g = InterfaceInit(giac) # needs sage.libs.giac
429
+ sage: g.symbol(x) # needs sage.libs.giac
430
+ 'sageVARx'
431
+ """
432
+ if self.interface.name() == 'maxima':
433
+ return '_SAGE_VAR_' + repr(SR(ex))
434
+ if self.interface.name() == 'giac':
435
+ return 'sageVAR' + repr(SR(ex))
436
+ return repr(SR(ex))
437
+
438
+ def pyobject(self, ex, obj):
439
+ """
440
+ EXAMPLES::
441
+
442
+ sage: # needs sage.libs.pari
443
+ sage: from sage.symbolic.expression_conversions import InterfaceInit
444
+ sage: ii = InterfaceInit(gp)
445
+ sage: f = 2+SR(I)
446
+ sage: ii.pyobject(f, f.pyobject())
447
+ 'I + 2'
448
+ sage: ii.pyobject(SR(2), 2)
449
+ '2'
450
+ sage: ii.pyobject(pi, pi.pyobject())
451
+ 'Pi'
452
+ """
453
+ if (self.interface.name() in ['pari', 'gp'] and isinstance(obj, NumberFieldElement_base)):
454
+ from sage.rings.number_field.number_field_element_quadratic import (
455
+ NumberFieldElement_gaussian,
456
+ )
457
+ if isinstance(obj, NumberFieldElement_gaussian):
458
+ return repr(obj)
459
+ try:
460
+ return getattr(obj, self.name_init)()
461
+ except AttributeError:
462
+ return repr(obj)
463
+
464
+ def relation(self, ex, operator):
465
+ """
466
+ EXAMPLES::
467
+
468
+ sage: import operator
469
+ sage: from sage.symbolic.expression_conversions import InterfaceInit
470
+ sage: m = InterfaceInit(maxima)
471
+ sage: m.relation(x==3, operator.eq)
472
+ '_SAGE_VAR_x = 3'
473
+ sage: m.relation(x==3, operator.lt)
474
+ '_SAGE_VAR_x < 3'
475
+ """
476
+ return "%s %s %s" % (self(ex.lhs()), self.relation_symbols[operator],
477
+ self(ex.rhs()))
478
+
479
+ def tuple(self, ex):
480
+ """
481
+ EXAMPLES::
482
+
483
+ sage: from sage.symbolic.expression_conversions import InterfaceInit
484
+ sage: m = InterfaceInit(maxima)
485
+ sage: t = SR._force_pyobject((3, 4, e^x))
486
+ sage: m.tuple(t)
487
+ '[3,4,exp(_SAGE_VAR_x)]'
488
+ """
489
+ x = map(self, ex.operands())
490
+ X = ','.join(x)
491
+ return str(self.interface._left_list_delim()) + X + str(self.interface._right_list_delim())
492
+
493
+ def derivative(self, ex, operator):
494
+ """
495
+ EXAMPLES::
496
+
497
+ sage: from sage.symbolic.expression_conversions import InterfaceInit
498
+ sage: m = InterfaceInit(maxima)
499
+ sage: f = function('f')
500
+ sage: a = f(x).diff(x); a
501
+ diff(f(x), x)
502
+ sage: print(m.derivative(a, a.operator()))
503
+ diff('f(_SAGE_VAR_x), _SAGE_VAR_x, 1)
504
+ sage: b = f(x).diff(x, x)
505
+ sage: print(m.derivative(b, b.operator()))
506
+ diff('f(_SAGE_VAR_x), _SAGE_VAR_x, 2)
507
+
508
+ We can also convert expressions where the argument is not just a
509
+ variable, but the result is an "at" expression using temporary
510
+ variables::
511
+
512
+ sage: y = var('y')
513
+ sage: t = (f(x*y).diff(x))/y
514
+ sage: t
515
+ D[0](f)(x*y)
516
+ sage: m.derivative(t, t.operator())
517
+ "at(diff('f(_SAGE_VAR__symbol0), _SAGE_VAR__symbol0, 1), [_SAGE_VAR__symbol0 = (_SAGE_VAR_x)*(_SAGE_VAR_y)])"
518
+
519
+ TESTS:
520
+
521
+ Most of these confirm that :issue:`7401` was fixed::
522
+
523
+ sage: t = var('t'); f = function('f')(t)
524
+ sage: a = 2^e^t * f.subs(t=e^t) * diff(f, t).subs(t=e^t) + 2*t
525
+ sage: solve(a == 0, diff(f, t).subs(t=e^t))
526
+ [D[0](f)(e^t) == -2^(-e^t + 1)*t/f(e^t)]
527
+
528
+ ::
529
+
530
+ sage: f = function('f')(x)
531
+ sage: df = f.diff(x); df
532
+ diff(f(x), x)
533
+ sage: maxima(df)
534
+ 'diff('f(_SAGE_VAR_x),_SAGE_VAR_x,1)
535
+
536
+ ::
537
+
538
+ sage: from sage.interfaces.maxima_lib import maxima
539
+ sage: a = df.subs(x=exp(x)); a
540
+ D[0](f)(e^x)
541
+ sage: b = maxima(a); b
542
+ %at('diff('f(_SAGE_VAR__symbol0),_SAGE_VAR__symbol0,1),_SAGE_VAR__symbol0 = %e^_SAGE_VAR_x)
543
+ sage: bool(b.sage() == a)
544
+ True
545
+
546
+ ::
547
+
548
+ sage: from sage.interfaces.maxima_lib import maxima
549
+ sage: a = df.subs(x=4); a
550
+ D[0](f)(4)
551
+ sage: b = maxima(a); b
552
+ %at('diff('f(_SAGE_VAR__symbol0),_SAGE_VAR__symbol0,1),_SAGE_VAR__symbol0 = 4)
553
+ sage: bool(b.sage() == a)
554
+ True
555
+
556
+ It also works with more than one variable. Note the preferred
557
+ syntax ``function('f')(x, y)`` to create a general symbolic
558
+ function of more than one variable::
559
+
560
+ sage: x, y = var('x y')
561
+ sage: f = function('f')(x, y)
562
+ sage: f_x = f.diff(x); f_x
563
+ diff(f(x, y), x)
564
+ sage: maxima(f_x)
565
+ 'diff('f(_SAGE_VAR_x,_SAGE_VAR_y),_SAGE_VAR_x,1)
566
+
567
+ ::
568
+
569
+ sage: from sage.interfaces.maxima_lib import maxima
570
+ sage: a = f_x.subs(x=4); a
571
+ D[0](f)(4, y)
572
+ sage: b = maxima(a); b
573
+ %at('diff('f(_SAGE_VAR__symbol0,_SAGE_VAR_y),_SAGE_VAR__symbol0,1),_SAGE_VAR__symbol0 = 4)
574
+ sage: bool(b.sage() == a)
575
+ True
576
+
577
+ ::
578
+
579
+ sage: from sage.interfaces.maxima_lib import maxima
580
+ sage: a = f_x.subs(x=4).subs(y=8); a
581
+ D[0](f)(4, 8)
582
+ sage: b = maxima(a); b
583
+ %at('diff('f(_SAGE_VAR__symbol0,8),_SAGE_VAR__symbol0,1),_SAGE_VAR__symbol0 = 4)
584
+ sage: bool(b.sage() == a)
585
+ True
586
+
587
+ Test a special case (:issue:`16697`)::
588
+
589
+ sage: x,y = var('x,y')
590
+ sage: (gamma_inc(x,y).diff(x))
591
+ diff(gamma(x, y), x)
592
+ sage: (gamma_inc(x,x+1).diff(x)).simplify()
593
+ -(x + 1)^(x - 1)*e^(-x - 1) + D[0](gamma)(x, x + 1)
594
+ """
595
+ # This code should probably be moved into the interface
596
+ # object in a nice way.
597
+ if self.name_init != "_maxima_init_":
598
+ raise NotImplementedError
599
+ args = ex.operands()
600
+ if (not all(isinstance(v, Expression) and v.is_symbol() for v in args) or
601
+ len(args) != len(set(args))):
602
+ # An evaluated derivative of the form f'(1) is not a
603
+ # symbolic variable, yet we would like to treat it like
604
+ # one. So, we replace the argument `1` with a temporary
605
+ # variable e.g. `_symbol0` and then evaluate the
606
+ # derivative f'(_symbol0) symbolically at _symbol0=1. See
607
+ # trac #12796. Note that we cannot use SR.temp_var here
608
+ # since two conversions of the same expression have to be
609
+ # equal.
610
+ temp_args = [SR.symbol("_symbol%s" % i) for i in range(len(args))]
611
+ f = operator.function()(*temp_args)
612
+ params = operator.parameter_set()
613
+ params = ["%s, %s" % (temp_args[i]._maxima_init_(), params.count(i)) for i in set(params)]
614
+ subs = ["%s = %s" % (t._maxima_init_(), a._maxima_init_())
615
+ for t, a in zip(temp_args, args)]
616
+ outstr = "at(diff(%s, %s), [%s])" % (f._maxima_init_(),
617
+ ", ".join(params),
618
+ ", ".join(subs))
619
+ else:
620
+ f = operator.function()(*args)
621
+ params = operator.parameter_set()
622
+ params = ["%s, %s" % (args[i]._maxima_init_(), params.count(i))
623
+ for i in set(params)]
624
+ outstr = "diff(%s, %s)" % (f._maxima_init_(),
625
+ ", ".join(params))
626
+ return outstr
627
+
628
+ def arithmetic(self, ex, operator):
629
+ """
630
+ EXAMPLES::
631
+
632
+ sage: import operator
633
+ sage: from sage.symbolic.expression_conversions import InterfaceInit
634
+ sage: m = InterfaceInit(maxima)
635
+ sage: m.arithmetic(x+2, sage.symbolic.operators.add_vararg)
636
+ '(_SAGE_VAR_x)+(2)'
637
+ """
638
+ args = ["(%s)" % self(op) for op in ex.operands()]
639
+ return arithmetic_operators[operator].join(args)
640
+
641
+ def composition(self, ex, operator):
642
+ """
643
+ EXAMPLES::
644
+
645
+ sage: from sage.symbolic.expression_conversions import InterfaceInit
646
+ sage: m = InterfaceInit(maxima)
647
+ sage: m.composition(sin(x), sin)
648
+ 'sin(_SAGE_VAR_x)'
649
+ sage: m.composition(ceil(x), ceil)
650
+ 'ceiling(_SAGE_VAR_x)'
651
+
652
+ sage: m = InterfaceInit(mathematica)
653
+ sage: m.composition(sin(x), sin)
654
+ 'Sin[x]'
655
+ """
656
+ ops = ex.operands()
657
+ # FIXME: consider stripping pyobjects() in ops
658
+ if hasattr(operator, self.name_init + "evaled_"):
659
+ return getattr(operator, self.name_init + "evaled_")(*ops)
660
+ else:
661
+ ops = [self(_) for _ in ops]
662
+ try:
663
+ op = getattr(operator, self.name_init)()
664
+ except (TypeError, AttributeError):
665
+ op = repr(operator)
666
+
667
+ return self.interface._function_call_string(op, ops, [])
668
+
669
+
670
+ ##############
671
+ # Polynomial #
672
+ ##############
673
+ class PolynomialConverter(Converter):
674
+ def __init__(self, ex, base_ring=None, ring=None):
675
+ """
676
+ A converter from symbolic expressions to polynomials.
677
+
678
+ See :func:`polynomial` for details.
679
+
680
+ EXAMPLES::
681
+
682
+ sage: from sage.symbolic.expression_conversions import PolynomialConverter
683
+ sage: x, y = var('x,y')
684
+ sage: p = PolynomialConverter(x+y, base_ring=QQ)
685
+ sage: p.base_ring
686
+ Rational Field
687
+ sage: p.ring
688
+ Multivariate Polynomial Ring in x, y over Rational Field
689
+
690
+ sage: p = PolynomialConverter(x, base_ring=QQ)
691
+ sage: p.base_ring
692
+ Rational Field
693
+ sage: p.ring
694
+ Univariate Polynomial Ring in x over Rational Field
695
+
696
+ sage: p = PolynomialConverter(x, ring=QQ['x,y'])
697
+ sage: p.base_ring
698
+ Rational Field
699
+ sage: p.ring
700
+ Multivariate Polynomial Ring in x, y over Rational Field
701
+
702
+ sage: p = PolynomialConverter(x+y, ring=QQ['x'])
703
+ Traceback (most recent call last):
704
+ ...
705
+ TypeError: y is not a variable of Univariate Polynomial Ring in x over Rational Field
706
+
707
+ TESTS::
708
+
709
+ sage: t, x, z = SR.var('t,x,z')
710
+ sage: QQ[i]['x,y,z,t'](4*I*t + 2*x -12*z + 2) # needs sage.rings.number_field
711
+ 2*x - 12*z + (4*I)*t + 2
712
+ """
713
+ if not (ring is None or base_ring is None):
714
+ raise TypeError("either base_ring or ring must be specified, but not both")
715
+ self.ex = ex
716
+
717
+ if ring is not None:
718
+ base_ring = ring.base_ring()
719
+ self.varnames = ring.variable_names_recursive()
720
+ for v in ex.variables():
721
+ if repr(v) not in self.varnames and v not in base_ring:
722
+ raise TypeError("%s is not a variable of %s" % (v, ring))
723
+ self.ring = ring
724
+ self.base_ring = base_ring
725
+ elif base_ring is not None:
726
+ self.base_ring = base_ring
727
+ vars = self.ex.variables()
728
+ if len(vars) == 0:
729
+ vars = ['x']
730
+ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
731
+ self.ring = PolynomialRing(self.base_ring, names=vars)
732
+ self.varnames = self.ring.variable_names()
733
+ else:
734
+ raise TypeError("either a ring or base ring must be specified")
735
+
736
+ def symbol(self, ex):
737
+ """
738
+ Return a variable in the polynomial ring.
739
+
740
+ EXAMPLES::
741
+
742
+ sage: from sage.symbolic.expression_conversions import PolynomialConverter
743
+ sage: p = PolynomialConverter(x, base_ring=QQ)
744
+ sage: p.symbol(x)
745
+ x
746
+ sage: _.parent()
747
+ Univariate Polynomial Ring in x over Rational Field
748
+ sage: y = var('y')
749
+ sage: p = PolynomialConverter(x*y, ring=SR['x'])
750
+ sage: p.symbol(y)
751
+ y
752
+ """
753
+ try:
754
+ # The symbol is one of the polynomial generators
755
+ return self.ring(repr(ex))
756
+ except TypeError:
757
+ # The symbol should go into the base ring
758
+ return self.base_ring(repr(ex))
759
+
760
+ def pyobject(self, ex, obj):
761
+ """
762
+ EXAMPLES::
763
+
764
+ sage: from sage.symbolic.expression_conversions import PolynomialConverter
765
+ sage: p = PolynomialConverter(x, base_ring=QQ)
766
+ sage: f = SR(2)
767
+ sage: p.pyobject(f, f.pyobject())
768
+ 2
769
+ sage: _.parent()
770
+ Rational Field
771
+ """
772
+ return self.base_ring(obj)
773
+
774
+ def composition(self, ex, operator):
775
+ """
776
+ EXAMPLES::
777
+
778
+ sage: from sage.symbolic.expression_conversions import PolynomialConverter
779
+ sage: a = sin(2)
780
+ sage: p = PolynomialConverter(a*x, base_ring=RR)
781
+ sage: p.composition(a, a.operator())
782
+ 0.909297426825682
783
+ """
784
+ return self.base_ring(ex)
785
+
786
+ def relation(self, ex, op):
787
+ """
788
+ EXAMPLES::
789
+
790
+ sage: import operator
791
+ sage: from sage.symbolic.expression_conversions import PolynomialConverter
792
+
793
+ sage: x, y = var('x, y')
794
+ sage: p = PolynomialConverter(x, base_ring=RR)
795
+
796
+ sage: p.relation(x==3, operator.eq)
797
+ x - 3.00000000000000
798
+ sage: p.relation(x==3, operator.lt)
799
+ Traceback (most recent call last):
800
+ ...
801
+ ValueError: Unable to represent as a polynomial
802
+
803
+ sage: p = PolynomialConverter(x - y, base_ring=QQ)
804
+ sage: p.relation(x^2 - y^3 + 1 == x^3, operator.eq)
805
+ -x^3 - y^3 + x^2 + 1
806
+ """
807
+ import operator
808
+ if op == operator.eq:
809
+ return self(ex.lhs()) - self(ex.rhs())
810
+ raise ValueError("Unable to represent as a polynomial")
811
+
812
+ def arithmetic(self, ex, operator):
813
+ """
814
+ EXAMPLES::
815
+
816
+ sage: import operator
817
+ sage: from sage.symbolic.expression_conversions import PolynomialConverter
818
+
819
+ sage: x, y = var('x, y')
820
+ sage: p = PolynomialConverter(x, base_ring=RR)
821
+ sage: p.arithmetic(pi+e, operator.add)
822
+ 5.85987448204884
823
+ sage: p.arithmetic(x^2, operator.pow)
824
+ x^2
825
+
826
+ sage: p = PolynomialConverter(x+y, base_ring=RR)
827
+ sage: p.arithmetic(x*y+y^2, operator.add)
828
+ x*y + y^2
829
+
830
+ sage: p = PolynomialConverter(y^(3/2), ring=SR['x'])
831
+ sage: p.arithmetic(y^(3/2), operator.pow)
832
+ y^(3/2)
833
+ sage: _.parent()
834
+ Symbolic Ring
835
+ """
836
+ if not any(repr(v) in self.varnames for v in ex.variables()):
837
+ return self.base_ring(ex)
838
+ elif operator == pow:
839
+ from sage.rings.integer import Integer
840
+ base, exp = ex.operands()
841
+ return self(base)**Integer(exp)
842
+ if operator == add_vararg:
843
+ operator = add
844
+ elif operator == mul_vararg:
845
+ operator = mul
846
+ ops = [self(a) for a in ex.operands()]
847
+ return reduce(operator, ops)
848
+
849
+
850
+ def polynomial(ex, base_ring=None, ring=None):
851
+ """
852
+ Return a polynomial from the symbolic expression ``ex``.
853
+
854
+ INPUT:
855
+
856
+ - ``ex`` -- a symbolic expression
857
+
858
+ - ``base_ring``, ``ring`` -- either a
859
+ ``base_ring`` or a polynomial ``ring`` can be
860
+ specified for the parent of result.
861
+ If just a ``base_ring`` is given, then the variables
862
+ of the ``base_ring`` will be the variables of the expression ``ex``.
863
+
864
+ OUTPUT: a polynomial
865
+
866
+ EXAMPLES::
867
+
868
+ sage: from sage.symbolic.expression_conversions import polynomial
869
+ sage: f = x^2 + 2
870
+ sage: polynomial(f, base_ring=QQ)
871
+ x^2 + 2
872
+ sage: _.parent()
873
+ Univariate Polynomial Ring in x over Rational Field
874
+
875
+ sage: polynomial(f, ring=QQ['x,y'])
876
+ x^2 + 2
877
+ sage: _.parent()
878
+ Multivariate Polynomial Ring in x, y over Rational Field
879
+
880
+ sage: x, y = var('x, y')
881
+ sage: polynomial(x + y^2, ring=QQ['x,y'])
882
+ y^2 + x
883
+ sage: _.parent()
884
+ Multivariate Polynomial Ring in x, y over Rational Field
885
+
886
+ sage: s,t = var('s,t')
887
+ sage: expr = t^2-2*s*t+1
888
+ sage: expr.polynomial(None,ring=SR['t'])
889
+ t^2 - 2*s*t + 1
890
+ sage: _.parent()
891
+ Univariate Polynomial Ring in t over Symbolic Ring
892
+
893
+ sage: polynomial(x*y, ring=SR['x'])
894
+ y*x
895
+
896
+ sage: polynomial(y - sqrt(x), ring=SR['y'])
897
+ y - sqrt(x)
898
+ sage: _.list()
899
+ [-sqrt(x), 1]
900
+
901
+ The polynomials can have arbitrary (constant) coefficients so long as
902
+ they coerce into the base ring::
903
+
904
+ sage: polynomial(2^sin(2)*x^2 + exp(3), base_ring=RR)
905
+ 1.87813065119873*x^2 + 20.0855369231877
906
+ """
907
+ converter = PolynomialConverter(ex, base_ring=base_ring, ring=ring)
908
+ res = converter()
909
+ return converter.ring(res)
910
+
911
+
912
+ class LaurentPolynomialConverter(PolynomialConverter):
913
+ def __init__(self, ex, base_ring=None, ring=None):
914
+ """
915
+ A converter from symbolic expressions to Laurent polynomials.
916
+
917
+ See :func:`laurent_polynomial` for details.
918
+
919
+ TESTS::
920
+
921
+ sage: from sage.symbolic.expression_conversions import LaurentPolynomialConverter
922
+ sage: x, y = var('x,y')
923
+ sage: p = LaurentPolynomialConverter(x+1/y, base_ring=QQ)
924
+ sage: p.base_ring
925
+ Rational Field
926
+ sage: p.ring
927
+ Multivariate Laurent Polynomial Ring in x, y over Rational Field
928
+ """
929
+ super().__init__(ex, base_ring, ring)
930
+
931
+ if ring is None and base_ring is not None:
932
+ from sage.rings.polynomial.laurent_polynomial_ring import (
933
+ LaurentPolynomialRing,
934
+ )
935
+ self.ring = LaurentPolynomialRing(self.base_ring,
936
+ names=self.varnames)
937
+
938
+
939
+ def laurent_polynomial(ex, base_ring=None, ring=None):
940
+ """
941
+ Return a Laurent polynomial from the symbolic expression ``ex``.
942
+
943
+ INPUT:
944
+
945
+ - ``ex`` -- a symbolic expression
946
+
947
+ - ``base_ring``, ``ring`` -- either a
948
+ ``base_ring`` or a Laurent polynomial ``ring`` can be
949
+ specified for the parent of result.
950
+ If just a ``base_ring`` is given, then the variables
951
+ of the ``base_ring`` will be the variables of the expression ``ex``.
952
+
953
+ OUTPUT: a Laurent polynomial
954
+
955
+ EXAMPLES::
956
+
957
+ sage: from sage.symbolic.expression_conversions import laurent_polynomial
958
+ sage: f = x^2 + 2/x
959
+ sage: laurent_polynomial(f, base_ring=QQ)
960
+ 2*x^-1 + x^2
961
+ sage: _.parent()
962
+ Univariate Laurent Polynomial Ring in x over Rational Field
963
+
964
+ sage: laurent_polynomial(f, ring=LaurentPolynomialRing(QQ, 'x, y'))
965
+ x^2 + 2*x^-1
966
+ sage: _.parent()
967
+ Multivariate Laurent Polynomial Ring in x, y over Rational Field
968
+
969
+ sage: x, y = var('x, y')
970
+ sage: laurent_polynomial(x + 1/y^2, ring=LaurentPolynomialRing(QQ, 'x, y'))
971
+ x + y^-2
972
+ sage: _.parent()
973
+ Multivariate Laurent Polynomial Ring in x, y over Rational Field
974
+ """
975
+ converter = LaurentPolynomialConverter(ex, base_ring=base_ring, ring=ring)
976
+ res = converter()
977
+ return converter.ring(res)
978
+
979
+
980
+ #################
981
+ # Fast Callable #
982
+ #################
983
+
984
+ class FastCallableConverter(Converter):
985
+ def __init__(self, ex, etb):
986
+ """
987
+ EXAMPLES::
988
+
989
+ sage: from sage.symbolic.expression_conversions import FastCallableConverter
990
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
991
+ sage: etb = ExpressionTreeBuilder(vars=['x'])
992
+ sage: f = FastCallableConverter(x+2, etb)
993
+ sage: f.ex
994
+ x + 2
995
+ sage: f.etb
996
+ <sage.ext.fast_callable.ExpressionTreeBuilder object at 0x...>
997
+ sage: f.use_fake_div
998
+ True
999
+ """
1000
+ self.ex = ex
1001
+ self.etb = etb
1002
+ Converter.__init__(self, use_fake_div=True)
1003
+
1004
+ def pyobject(self, ex, obj):
1005
+ r"""
1006
+ EXAMPLES::
1007
+
1008
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1009
+ sage: etb = ExpressionTreeBuilder(vars=['x'])
1010
+ sage: pi._fast_callable_(etb)
1011
+ pi
1012
+ sage: etb = ExpressionTreeBuilder(vars=['x'], domain=RDF)
1013
+ sage: pi._fast_callable_(etb)
1014
+ 3.141592653589793
1015
+ """
1016
+ from sage.symbolic.constants import Constant
1017
+ if isinstance(obj, Constant):
1018
+ obj = obj.expression()
1019
+ return self.etb.constant(obj)
1020
+
1021
+ def relation(self, ex, operator):
1022
+ """
1023
+ EXAMPLES::
1024
+
1025
+ sage: ff = fast_callable(x == 2, vars=['x'])
1026
+ sage: ff(2)
1027
+ 0
1028
+ sage: ff(4)
1029
+ 2
1030
+ sage: ff = fast_callable(x < 2, vars=['x'])
1031
+ Traceback (most recent call last):
1032
+ ...
1033
+ NotImplementedError
1034
+ """
1035
+ if operator is not eq:
1036
+ raise NotImplementedError
1037
+ return self(ex.lhs() - ex.rhs())
1038
+
1039
+ def arithmetic(self, ex, operator):
1040
+ r"""
1041
+ EXAMPLES::
1042
+
1043
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1044
+ sage: etb = ExpressionTreeBuilder(vars=['x','y'])
1045
+ sage: var('x,y')
1046
+ (x, y)
1047
+ sage: (x+y)._fast_callable_(etb)
1048
+ add(v_0, v_1)
1049
+ sage: (-x)._fast_callable_(etb)
1050
+ neg(v_0)
1051
+ sage: (x+y+x^2)._fast_callable_(etb)
1052
+ add(add(ipow(v_0, 2), v_0), v_1)
1053
+
1054
+ TESTS:
1055
+
1056
+ Check if rational functions with numerator 1 can
1057
+ be converted. (:issue:`8056`)::
1058
+
1059
+ sage: (1/pi/x)._fast_callable_(etb)
1060
+ div(1, mul(pi, v_0))
1061
+
1062
+ sage: etb = ExpressionTreeBuilder(vars=['x'], domain=RDF)
1063
+ sage: (x^7)._fast_callable_(etb)
1064
+ ipow(v_0, 7)
1065
+ sage: f(x) = 1/pi/x; plot(f,2,3) # needs sage.plot
1066
+ Graphics object consisting of 1 graphics primitive
1067
+ """
1068
+ # This used to convert the operands first. Doing it this way
1069
+ # instead gives a chance to notice powers with an integer
1070
+ # exponent before the exponent gets (potentially) converted
1071
+ # to another type.
1072
+ operands = ex.operands()
1073
+ if operator is pow:
1074
+ exponent = operands[1]
1075
+ if exponent == -1:
1076
+ return self.etb.call(truediv, 1, operands[0])
1077
+ elif exponent == 0.5:
1078
+ from sage.misc.functional import sqrt
1079
+ return self.etb.call(sqrt, operands[0])
1080
+ elif exponent == -0.5:
1081
+ from sage.misc.functional import sqrt
1082
+ return self.etb.call(truediv, 1, self.etb.call(sqrt, operands[0]))
1083
+ elif operator is neg:
1084
+ return self.etb.call(operator, operands[0])
1085
+ if operator == add_vararg:
1086
+ operator = add
1087
+ elif operator == mul_vararg:
1088
+ operator = mul
1089
+ return reduce(lambda x, y: self.etb.call(operator, x, y), operands)
1090
+
1091
+ def symbol(self, ex):
1092
+ r"""
1093
+ Given an ExpressionTreeBuilder, return an Expression representing
1094
+ this value.
1095
+
1096
+ EXAMPLES::
1097
+
1098
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1099
+ sage: etb = ExpressionTreeBuilder(vars=['x','y'])
1100
+ sage: x, y, z = var('x,y,z')
1101
+ sage: x._fast_callable_(etb)
1102
+ v_0
1103
+ sage: y._fast_callable_(etb)
1104
+ v_1
1105
+ sage: z._fast_callable_(etb)
1106
+ Traceback (most recent call last):
1107
+ ...
1108
+ ValueError: Variable 'z' not found...
1109
+ """
1110
+ return self.etb.var(SR(ex))
1111
+
1112
+ def composition(self, ex, function):
1113
+ r"""
1114
+ Given an ExpressionTreeBuilder, return an Expression representing
1115
+ this value.
1116
+
1117
+ EXAMPLES::
1118
+
1119
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1120
+ sage: etb = ExpressionTreeBuilder(vars=['x','y'])
1121
+ sage: x,y = var('x,y')
1122
+ sage: sin(sqrt(x+y))._fast_callable_(etb)
1123
+ sin(sqrt(add(v_0, v_1)))
1124
+ sage: arctan2(x,y)._fast_callable_(etb)
1125
+ {arctan2}(v_0, v_1)
1126
+ """
1127
+ return self.etb.call(function, *ex.operands())
1128
+
1129
+ def tuple(self, ex):
1130
+ r"""
1131
+ Given a symbolic tuple, return its elements as a Python list.
1132
+
1133
+ EXAMPLES::
1134
+
1135
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1136
+ sage: etb = ExpressionTreeBuilder(vars=['x'])
1137
+ sage: SR._force_pyobject((2, 3, x^2))._fast_callable_(etb)
1138
+ [2, 3, x^2]
1139
+ """
1140
+ return ex.operands()
1141
+
1142
+
1143
+ def fast_callable(ex, etb):
1144
+ """
1145
+ Given an ExpressionTreeBuilder *etb*, return an Expression representing
1146
+ the symbolic expression *ex*.
1147
+
1148
+ EXAMPLES::
1149
+
1150
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1151
+ sage: etb = ExpressionTreeBuilder(vars=['x','y'])
1152
+ sage: x,y = var('x,y')
1153
+ sage: f = y+2*x^2
1154
+ sage: f._fast_callable_(etb)
1155
+ add(mul(ipow(v_0, 2), 2), v_1)
1156
+
1157
+ sage: f = (2*x^3+2*x-1)/((x-2)*(x+1))
1158
+ sage: f._fast_callable_(etb)
1159
+ div(add(add(mul(ipow(v_0, 3), 2), mul(v_0, 2)), -1), mul(add(v_0, 1), add(v_0, -2)))
1160
+ """
1161
+ return FastCallableConverter(ex, etb)()
1162
+
1163
+
1164
+ class RingConverter(Converter):
1165
+ def __init__(self, R, subs_dict=None):
1166
+ """
1167
+ A class to convert expressions to other rings.
1168
+
1169
+ EXAMPLES::
1170
+
1171
+ sage: from sage.symbolic.expression_conversions import RingConverter
1172
+ sage: R = RingConverter(RIF, subs_dict={x:2})
1173
+ sage: R.ring
1174
+ Real Interval Field with 53 bits of precision
1175
+ sage: R.subs_dict
1176
+ {x: 2}
1177
+ sage: R(pi+e)
1178
+ 5.85987448204884?
1179
+ sage: loads(dumps(R))
1180
+ <sage.symbolic.expression_conversions.RingConverter object at 0x...>
1181
+ """
1182
+ self.subs_dict = {} if subs_dict is None else subs_dict
1183
+ self.ring = R
1184
+
1185
+ def symbol(self, ex):
1186
+ """
1187
+ All symbols appearing in the expression must either appear in
1188
+ *subs_dict* or be convertible by the ring's element
1189
+ constructor in order for the conversion to be successful.
1190
+
1191
+ EXAMPLES::
1192
+
1193
+ sage: from sage.symbolic.expression_conversions import RingConverter
1194
+ sage: R = RingConverter(RIF, subs_dict={x:2})
1195
+ sage: R(x+pi)
1196
+ 5.141592653589794?
1197
+
1198
+ sage: R = RingConverter(RIF)
1199
+ sage: R(x+pi)
1200
+ Traceback (most recent call last):
1201
+ ...
1202
+ TypeError: unable to simplify to a real interval approximation
1203
+
1204
+ sage: R = RingConverter(QQ['x'])
1205
+ sage: R(x^2+x)
1206
+ x^2 + x
1207
+ sage: R(x^2+x).parent()
1208
+ Univariate Polynomial Ring in x over Rational Field
1209
+ """
1210
+ try:
1211
+ return self.ring(self.subs_dict[ex])
1212
+ except KeyError:
1213
+ return self.ring(ex)
1214
+
1215
+ def pyobject(self, ex, obj):
1216
+ """
1217
+ EXAMPLES::
1218
+
1219
+ sage: from sage.symbolic.expression_conversions import RingConverter
1220
+ sage: R = RingConverter(RIF)
1221
+ sage: R(SR(5/2))
1222
+ 2.5000000000000000?
1223
+ """
1224
+ return self.ring(obj)
1225
+
1226
+ def arithmetic(self, ex, operator):
1227
+ """
1228
+ EXAMPLES::
1229
+
1230
+ sage: from sage.symbolic.expression_conversions import RingConverter
1231
+ sage: P.<z> = ZZ[]
1232
+ sage: R = RingConverter(P, subs_dict={x:z})
1233
+ sage: a = 2*x^2 + x + 3
1234
+ sage: R(a)
1235
+ 2*z^2 + z + 3
1236
+ """
1237
+ if operator not in [pow, add_vararg, mul_vararg]:
1238
+ raise TypeError
1239
+
1240
+ operands = ex.operands()
1241
+ if operator is pow:
1242
+ from sage.rings.integer import Integer
1243
+ from sage.rings.rational import Rational
1244
+ base, expt = operands
1245
+
1246
+ if expt == Rational((1, 2)):
1247
+ from sage.misc.functional import sqrt
1248
+ return sqrt(self(base))
1249
+ try:
1250
+ expt = Integer(expt)
1251
+ except TypeError:
1252
+ pass
1253
+
1254
+ base = self(base)
1255
+ return base ** expt
1256
+
1257
+ if operator == add_vararg:
1258
+ operator = add
1259
+ elif operator == mul_vararg:
1260
+ operator = mul
1261
+ return reduce(operator, map(self, operands))
1262
+
1263
+ def composition(self, ex, operator):
1264
+ """
1265
+ EXAMPLES::
1266
+
1267
+ sage: from sage.symbolic.expression_conversions import RingConverter
1268
+ sage: R = RingConverter(RIF)
1269
+ sage: R(cos(2))
1270
+ -0.4161468365471424?
1271
+ """
1272
+ res = operator(*[self(op) for op in ex.operands()])
1273
+ if res.parent() is not self.ring:
1274
+ raise TypeError
1275
+ else:
1276
+ return res
1277
+
1278
+
1279
+ class ExpressionTreeWalker(Converter):
1280
+ def __init__(self, ex):
1281
+ """
1282
+ A class that walks the tree. Mainly for subclassing.
1283
+
1284
+ EXAMPLES::
1285
+
1286
+ sage: from sage.symbolic.expression_conversions import ExpressionTreeWalker
1287
+ sage: from sage.symbolic.random_tests import random_expr
1288
+ sage: ex = sin(atan(0,hold=True)+hypergeometric((1,),(1,),x))
1289
+ sage: s = ExpressionTreeWalker(ex)
1290
+ sage: bool(s() == ex)
1291
+ True
1292
+ sage: set_random_seed(0) # random_expr is unstable
1293
+ sage: foo = random_expr(20, nvars=2)
1294
+ sage: s = ExpressionTreeWalker(foo)
1295
+ sage: bool(s() == foo)
1296
+ True
1297
+ """
1298
+ self.ex = ex
1299
+
1300
+ def symbol(self, ex):
1301
+ """
1302
+ EXAMPLES::
1303
+
1304
+ sage: from sage.symbolic.expression_conversions import ExpressionTreeWalker
1305
+ sage: s = ExpressionTreeWalker(x)
1306
+ sage: bool(s.symbol(x) == x)
1307
+ True
1308
+ """
1309
+ return ex
1310
+
1311
+ def pyobject(self, ex, obj):
1312
+ """
1313
+ EXAMPLES::
1314
+
1315
+ sage: from sage.symbolic.expression_conversions import ExpressionTreeWalker
1316
+ sage: f = SR(2)
1317
+ sage: s = ExpressionTreeWalker(f)
1318
+ sage: bool(s.pyobject(f, f.pyobject()) == f.pyobject())
1319
+ True
1320
+ """
1321
+ return ex
1322
+
1323
+ def relation(self, ex, operator):
1324
+ """
1325
+ EXAMPLES::
1326
+
1327
+ sage: from sage.symbolic.expression_conversions import ExpressionTreeWalker
1328
+ sage: foo = function('foo')
1329
+ sage: eq = foo(x) == x
1330
+ sage: s = ExpressionTreeWalker(eq)
1331
+ sage: s.relation(eq, eq.operator()) == eq
1332
+ True
1333
+ """
1334
+ return operator(self(ex.lhs()), self(ex.rhs()))
1335
+
1336
+ def arithmetic(self, ex, operator):
1337
+ """
1338
+ EXAMPLES::
1339
+
1340
+ sage: from sage.symbolic.expression_conversions import ExpressionTreeWalker
1341
+ sage: foo = function('foo')
1342
+ sage: f = x*foo(x) + pi/foo(x)
1343
+ sage: s = ExpressionTreeWalker(f)
1344
+ sage: bool(s.arithmetic(f, f.operator()) == f)
1345
+ True
1346
+ """
1347
+ return reduce(operator, map(self, ex.operands()))
1348
+
1349
+ def composition(self, ex, operator):
1350
+ """
1351
+ EXAMPLES::
1352
+
1353
+ sage: from sage.symbolic.expression_conversions import ExpressionTreeWalker
1354
+ sage: foo = function('foo')
1355
+ sage: f = foo(atan2(0, 0, hold=True))
1356
+ sage: s = ExpressionTreeWalker(f)
1357
+ sage: bool(s.composition(f, f.operator()) == f)
1358
+ True
1359
+ """
1360
+ from sage.symbolic.function import Function
1361
+ if isinstance(operator, Function):
1362
+ return operator(*map(self, ex.operands()), hold=True)
1363
+ else:
1364
+ return operator(*map(self, ex.operands()))
1365
+
1366
+ def derivative(self, ex, operator):
1367
+ """
1368
+ EXAMPLES::
1369
+
1370
+ sage: from sage.symbolic.expression_conversions import ExpressionTreeWalker
1371
+ sage: foo = function('foo')
1372
+ sage: f = foo(x).diff(x)
1373
+ sage: s = ExpressionTreeWalker(f)
1374
+ sage: bool(s.derivative(f, f.operator()) == f)
1375
+ True
1376
+ """
1377
+ return operator(*map(self, ex.operands()))
1378
+
1379
+ def tuple(self, ex):
1380
+ """
1381
+ EXAMPLES::
1382
+
1383
+ sage: from sage.symbolic.expression_conversions import ExpressionTreeWalker
1384
+ sage: foo = function('foo')
1385
+ sage: f = hypergeometric((1,2,3,),(x,),x)
1386
+ sage: s = ExpressionTreeWalker(f)
1387
+ sage: bool(s() == f)
1388
+ True
1389
+ """
1390
+ return ex.operands()
1391
+
1392
+
1393
+ class SubstituteFunction(ExpressionTreeWalker):
1394
+ def __init__(self, ex, *args):
1395
+ """
1396
+ A class that walks the tree and replaces occurrences of a
1397
+ function with another.
1398
+
1399
+ EXAMPLES::
1400
+
1401
+ sage: from sage.symbolic.expression_conversions import SubstituteFunction
1402
+ sage: foo = function('foo'); bar = function('bar')
1403
+ sage: s = SubstituteFunction(foo(x), {foo: bar})
1404
+ sage: s(1/foo(foo(x)) + foo(2))
1405
+ 1/bar(bar(x)) + bar(2)
1406
+
1407
+ TESTS:
1408
+
1409
+ Check that the old syntax still works::
1410
+
1411
+ sage: s = SubstituteFunction(foo(x), foo, bar)
1412
+ sage: s(1/foo(foo(x)) + foo(2))
1413
+ 1/bar(bar(x)) + bar(2)
1414
+ """
1415
+ if len(args) == 2:
1416
+ self.substitutions = {args[0]: args[1]}
1417
+ elif len(args) == 1:
1418
+ self.substitutions = args[0]
1419
+ else:
1420
+ raise TypeError('SubstituteFunction takes either one or two arguments.')
1421
+ self.ex = ex
1422
+
1423
+ def composition(self, ex, operator):
1424
+ """
1425
+ EXAMPLES::
1426
+
1427
+ sage: from sage.symbolic.expression_conversions import SubstituteFunction
1428
+ sage: foo = function('foo'); bar = function('bar')
1429
+ sage: s = SubstituteFunction(foo(x), {foo: bar})
1430
+ sage: f = foo(x)
1431
+ sage: s.composition(f, f.operator())
1432
+ bar(x)
1433
+ sage: f = foo(foo(x))
1434
+ sage: s.composition(f, f.operator())
1435
+ bar(bar(x))
1436
+ sage: f = sin(foo(x))
1437
+ sage: s.composition(f, f.operator())
1438
+ sin(bar(x))
1439
+ sage: f = foo(sin(x))
1440
+ sage: s.composition(f, f.operator())
1441
+ bar(sin(x))
1442
+ """
1443
+ new = self.substitutions.get(operator)
1444
+ if new is not None:
1445
+ return new(*[self(_) for _ in ex.operands()])
1446
+ else:
1447
+ return super().composition(ex, operator)
1448
+
1449
+ def derivative(self, ex, operator):
1450
+ """
1451
+ EXAMPLES::
1452
+
1453
+ sage: from sage.symbolic.expression_conversions import SubstituteFunction
1454
+ sage: foo = function('foo'); bar = function('bar')
1455
+ sage: s = SubstituteFunction(foo(x), {foo: bar})
1456
+ sage: f = foo(x).diff(x)
1457
+ sage: s.derivative(f, f.operator())
1458
+ diff(bar(x), x)
1459
+
1460
+ TESTS:
1461
+
1462
+ We can substitute functions under a derivative operator,
1463
+ :issue:`12801`::
1464
+
1465
+ sage: f = function('f')
1466
+ sage: g = function('g')
1467
+ sage: f(g(x)).diff(x).substitute_function({g: sin})
1468
+ cos(x)*D[0](f)(sin(x))
1469
+ """
1470
+ new = self.substitutions.get(operator.function())
1471
+ if new is not None:
1472
+ return operator.change_function(new)(*[self(_) for _ in ex.operands()])
1473
+ else:
1474
+ return operator(*[self(_) for _ in ex.operands()])
1475
+
1476
+
1477
+ class Exponentialize(ExpressionTreeWalker):
1478
+ # Implementation note: this code is executed once at first
1479
+ # reference in the code using it, therefore avoiding rebuilding
1480
+ # the same canned results dictionary at each call.
1481
+ from sage.calculus.var import function
1482
+ from sage.functions.hyperbolic import cosh, coth, csch, sech, sinh, tanh
1483
+ from sage.functions.trig import cos, cot, csc, sec, sin, tan
1484
+ from sage.rings.integer import Integer
1485
+ from sage.symbolic.constants import I, e
1486
+ from sage.symbolic.ring import SR
1487
+ half = Integer(1) / Integer(2)
1488
+ two = Integer(2)
1489
+ x = SR.var("x")
1490
+ CircDict = {
1491
+ sin: (-half*I*exp(I*x) + half*I*exp(-I*x)).function(x),
1492
+ cos: (half*exp(I*x) + half*exp(-I*x)).function(x),
1493
+ sec: (two/(exp(I*x) + exp(-I*x))).function(x),
1494
+ csc: (two*I/(exp(I*x) - exp(-I*x))).function(x),
1495
+ tan: (-I*(exp(I*x) - exp(-I*x))/(exp(I*x) + exp(-I*x))).function(x),
1496
+ cot: (I*(exp(I*x) + exp(-I*x))/(exp(I*x) - exp(-I*x))).function(x),
1497
+ sinh: (-half*exp(-x) + half*exp(x)).function(x),
1498
+ cosh: (half*exp(-x) + half*exp(x)).function(x),
1499
+ sech: (two/(exp(-x) + exp(x))).function(x),
1500
+ csch: (-two/(exp(-x) - exp(x))).function(x),
1501
+ tanh: (-(exp(-x) - exp(x))/(exp(x) + exp(-x))).function(x),
1502
+ coth: (-(exp(-x) + exp(x))/(exp(-x) - exp(x))).function(x)
1503
+ }
1504
+ Circs = list(CircDict)
1505
+
1506
+ def __init__(self, ex):
1507
+ """
1508
+ A class that walks a symbolic expression tree and replace circular
1509
+ and hyperbolic functions by their respective exponential
1510
+ expressions.
1511
+
1512
+ EXAMPLES::
1513
+
1514
+ sage: from sage.symbolic.expression_conversions import Exponentialize
1515
+ sage: d = Exponentialize(sin(x))
1516
+ sage: d(sin(x))
1517
+ -1/2*I*e^(I*x) + 1/2*I*e^(-I*x)
1518
+ sage: d(cosh(x))
1519
+ 1/2*e^(-x) + 1/2*e^x
1520
+ """
1521
+ self.ex = ex
1522
+
1523
+ def composition(self, ex, op):
1524
+ r"""
1525
+ Return the composition of ``self`` with ``ex`` by ``op``.
1526
+
1527
+ EXAMPLES::
1528
+
1529
+ sage: x = SR.var("x")
1530
+ sage: from sage.symbolic.expression_conversions import Exponentialize
1531
+ sage: p = x
1532
+ sage: s = Exponentialize(p)
1533
+ sage: q = sin(x)
1534
+ sage: s.composition(q, q.operator())
1535
+ -1/2*I*e^(I*x) + 1/2*I*e^(-I*x)
1536
+ """
1537
+ if op in self.Circs:
1538
+ return self.CircDict.get(op)(*[self(oper)
1539
+ for oper in ex.operands()])
1540
+ return super().composition(ex, op)
1541
+
1542
+
1543
+ class DeMoivre(ExpressionTreeWalker):
1544
+ def __init__(self, ex, force=False):
1545
+ r"""
1546
+ A class that walks a symbolic expression tree and replaces
1547
+ occurrences of complex exponentials (optionally, all
1548
+ exponentials) by their respective trigonometric expressions.
1549
+
1550
+ INPUT:
1551
+
1552
+ - ``force`` -- boolean (default: ``False``); replace `\exp(x)`
1553
+ with `\cosh(x) + \sinh(x)`
1554
+
1555
+ EXAMPLES::
1556
+
1557
+ sage: a, b = SR.var("a, b")
1558
+ sage: from sage.symbolic.expression_conversions import DeMoivre
1559
+ sage: d = DeMoivre(e^a)
1560
+ sage: d(e^(a+I*b))
1561
+ (cos(b) + I*sin(b))*e^a
1562
+ """
1563
+ self.ex = ex
1564
+ self.force = force
1565
+
1566
+ def composition(self, ex, op):
1567
+ """
1568
+ Return the composition of ``self`` with ``ex`` by ``op``.
1569
+
1570
+ EXAMPLES::
1571
+
1572
+ sage: x, a, b = SR.var('x, a, b')
1573
+ sage: from sage.symbolic.expression_conversions import DeMoivre
1574
+ sage: p = exp(x)
1575
+ sage: s = DeMoivre(p)
1576
+ sage: q = exp(a+I*b)
1577
+ sage: s.composition(q, q.operator())
1578
+ (cos(b) + I*sin(b))*e^a
1579
+ """
1580
+ if op is not exp:
1581
+ # return super().composition(ex, op)
1582
+ return op(*[self(oper) for oper in ex.operands()])
1583
+
1584
+ from sage.functions.hyperbolic import cosh, sinh
1585
+ from sage.functions.trig import cos, sin
1586
+ from sage.rings.imaginary_unit import I
1587
+ from sage.symbolic.ring import SR
1588
+ arg = self(ex.operands()[0])()
1589
+ w0, w1 = (SR.wild(u) for u in range(2))
1590
+ D = arg.match(w0 + I*w1)
1591
+ if D is not None:
1592
+ A = D.get(w1)
1593
+ return exp(D.get(w0))*(cos(A) + I*sin(A))
1594
+ D = arg.match(I*w0)
1595
+ if D is not None:
1596
+ A = D.get(w0)
1597
+ return cos(A) + I*sin(A)
1598
+ if self.force:
1599
+ return cosh(arg) + sinh(arg)
1600
+ return exp(arg)
1601
+
1602
+
1603
+ # Half_angle transformation. Sometimes useful in integration
1604
+
1605
+ class HalfAngle(ExpressionTreeWalker):
1606
+ """
1607
+ A class that walks a symbolic expression tree, replacing each
1608
+ occurrence of a trigonometric or hyperbolic function by its
1609
+ expression as a rational fraction in the (hyperbolic) tangent
1610
+ of half the original argument.
1611
+ """
1612
+ # Code executed once at first class reference: create canned formulae.
1613
+ from sage.calculus.var import function
1614
+ from sage.functions.hyperbolic import cosh, coth, csch, sech, sinh, tanh
1615
+ from sage.functions.trig import cos, cot, csc, sec, sin, tan
1616
+ from sage.rings.integer import Integer
1617
+ from sage.symbolic.ring import SR
1618
+ x = SR.var("x")
1619
+ one = Integer(1)
1620
+ two = Integer(2)
1621
+ half = one / two
1622
+ halfx = half * x
1623
+ HalvesDict = {
1624
+ sin: two * tan(halfx) / (tan(halfx)**2 + one).function(x),
1625
+ cos: -(tan(halfx)**2 - one) / (tan(halfx)**2 + one).function(x),
1626
+ tan: -two * tan(halfx) / (tan(halfx)**2 - one).function(x),
1627
+ csc: half * (tan(halfx)**2 + one) / tan(halfx).function(x),
1628
+ sec: -(tan(halfx)**2 + one) / (tan(halfx)**2 - one).function(x),
1629
+ cot: -half * (tan(halfx)**2 - one) / tan(halfx).function(x),
1630
+ sinh: -two * tanh(halfx) / (tanh(halfx)**2 - one).function(x),
1631
+ cosh: -(tanh(halfx)**2 + one) / (tanh(halfx)**2 - one).function(x),
1632
+ tanh: two * tanh(halfx) / (tanh(halfx)**2 + one).function(x),
1633
+ csch: -half * (tanh(halfx)**2 - one) / tanh(halfx).function(x),
1634
+ sech: -(tanh(halfx)**2 - one) / (tanh(halfx)**2 + one).function(x),
1635
+ coth: half * (tanh(halfx)**2 + one) / tanh(halfx).function(x)
1636
+ }
1637
+ Halves = list(HalvesDict)
1638
+
1639
+ def __init__(self, ex):
1640
+ """
1641
+ A class that walks a symbolic expression tree, replacing each
1642
+ occurrence of a trigonometric or hyperbolic function by its
1643
+ expression as a rational fraction in the (hyperbolic) tangent
1644
+ of half the original argument.
1645
+
1646
+ EXAMPLES::
1647
+
1648
+ sage: a, b = SR.var("a, b")
1649
+ sage: from sage.symbolic.expression_conversions import HalfAngle
1650
+ sage: HalfAngle(tan(a))(tan(a)+4)
1651
+ -2*tan(1/2*a)/(tan(1/2*a)^2 - 1) + 4
1652
+ """
1653
+ self.ex = ex
1654
+
1655
+ def composition(self, ex, op):
1656
+ """
1657
+ Compose.
1658
+
1659
+ EXAMPLES::
1660
+
1661
+ sage: from sage.symbolic.expression_conversions import HalfAngle
1662
+ sage: x, t = SR.var("x, t")
1663
+ sage: a = HalfAngle(cos(3*x)/(4-cos(x)).trig_expand())()
1664
+ sage: a.subs(tan(x/2) == t).simplify_full()
1665
+ (2*(t^2 + 1)*cos(3/2*x)^2 - t^2 - 1)/(5*t^2 + 3)
1666
+ """
1667
+ if op in self.Halves:
1668
+ return self.HalvesDict.get(op)(*[self(x) for x in ex.operands()])
1669
+ return super().composition(ex, op)
1670
+
1671
+
1672
+ class HoldRemover(ExpressionTreeWalker):
1673
+ def __init__(self, ex, exclude=None):
1674
+ """
1675
+ A class that walks the tree and evaluates every operator
1676
+ that is not in a given list of exceptions.
1677
+
1678
+ EXAMPLES::
1679
+
1680
+ sage: from sage.symbolic.expression_conversions import HoldRemover
1681
+ sage: ex = sin(pi*cos(0, hold=True), hold=True); ex
1682
+ sin(pi*cos(0))
1683
+ sage: h = HoldRemover(ex)
1684
+ sage: h()
1685
+ 0
1686
+ sage: h = HoldRemover(ex, [sin])
1687
+ sage: h()
1688
+ sin(pi)
1689
+ sage: h = HoldRemover(ex, [cos])
1690
+ sage: h()
1691
+ sin(pi*cos(0))
1692
+ sage: ex = atan2(0, 0, hold=True) + hypergeometric([1,2], [3,4], 0, hold=True)
1693
+ sage: h = HoldRemover(ex, [atan2])
1694
+ sage: h()
1695
+ arctan2(0, 0) + 1
1696
+ sage: h = HoldRemover(ex, [hypergeometric])
1697
+ sage: h()
1698
+ NaN + hypergeometric((1, 2), (3, 4), 0)
1699
+ """
1700
+ self.ex = ex
1701
+ if exclude is None:
1702
+ exclude = []
1703
+ self._exclude = exclude
1704
+
1705
+ def composition(self, ex, operator):
1706
+ """
1707
+ EXAMPLES::
1708
+
1709
+ sage: from sage.symbolic.expression_conversions import HoldRemover
1710
+ sage: ex = sin(pi*cos(0, hold=True), hold=True); ex
1711
+ sin(pi*cos(0))
1712
+ sage: h = HoldRemover(ex)
1713
+ sage: h()
1714
+ 0
1715
+ """
1716
+ from sage.calculus.calculus import symbolic_product, symbolic_sum
1717
+ from sage.functions.other import Function_prod, Function_sum
1718
+ if not operator:
1719
+ return self
1720
+ if isinstance(operator, Function_sum):
1721
+ return symbolic_sum(*map(self, ex.operands()))
1722
+ if isinstance(operator, Function_prod):
1723
+ return symbolic_product(*map(self, ex.operands()))
1724
+ if operator in self._exclude:
1725
+ return operator(*map(self, ex.operands()), hold=True)
1726
+ else:
1727
+ return operator(*map(self, ex.operands()))