passagemath-symbolics 10.6.40__cp314-cp314t-macosx_13_0_x86_64.whl

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

Potentially problematic release.


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

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