passagemath-symbolics 10.8.1a1__cp311-cp311-macosx_13_0_arm64.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 (182) hide show
  1. passagemath_symbolics/.dylibs/libgmp.10.dylib +0 -0
  2. passagemath_symbolics/__init__.py +3 -0
  3. passagemath_symbolics-10.8.1a1.dist-info/METADATA +186 -0
  4. passagemath_symbolics-10.8.1a1.dist-info/RECORD +182 -0
  5. passagemath_symbolics-10.8.1a1.dist-info/WHEEL +6 -0
  6. passagemath_symbolics-10.8.1a1.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 +2838 -0
  10. sage/calculus/desolvers.py +1864 -0
  11. sage/calculus/predefined.py +51 -0
  12. sage/calculus/tests.py +225 -0
  13. sage/calculus/var.cpython-311-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-311-darwin.so +0 -0
  19. sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1034 -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 +755 -0
  34. sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
  35. sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2419 -0
  36. sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
  37. sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1083 -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 +2991 -0
  45. sage/interfaces/magma_free.py +90 -0
  46. sage/interfaces/maple.py +1402 -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 +553 -0
  55. sage/manifolds/catalog.py +437 -0
  56. sage/manifolds/chart.py +4010 -0
  57. sage/manifolds/chart_func.py +3416 -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 +1668 -0
  71. sage/manifolds/differentiable/diff_form.py +1660 -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 +1522 -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 +912 -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 +1725 -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 +2721 -0
  119. sage/manifolds/subsets/all.py +1 -0
  120. sage/manifolds/subsets/closure.py +131 -0
  121. sage/manifolds/subsets/pullback.py +883 -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 +1347 -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-311-darwin.so +0 -0
  130. sage/matrix/matrix_symbolic_dense.pxd +6 -0
  131. sage/matrix/matrix_symbolic_dense.pyx +1030 -0
  132. sage/matrix/matrix_symbolic_sparse.cpython-311-darwin.so +0 -0
  133. sage/matrix/matrix_symbolic_sparse.pxd +6 -0
  134. sage/matrix/matrix_symbolic_sparse.pyx +1038 -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 +4106 -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 +5205 -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 +987 -0
  151. sage/symbolic/benchmark.py +93 -0
  152. sage/symbolic/callable.py +456 -0
  153. sage/symbolic/callable.pyi +66 -0
  154. sage/symbolic/comparison_impl.pyi +38 -0
  155. sage/symbolic/complexity_measures.py +35 -0
  156. sage/symbolic/constants.py +1286 -0
  157. sage/symbolic/constants_c_impl.pyi +10 -0
  158. sage/symbolic/expression_conversion_algebraic.py +310 -0
  159. sage/symbolic/expression_conversion_sympy.py +317 -0
  160. sage/symbolic/expression_conversions.py +1727 -0
  161. sage/symbolic/function_factory.py +355 -0
  162. sage/symbolic/function_factory.pyi +41 -0
  163. sage/symbolic/getitem_impl.pyi +24 -0
  164. sage/symbolic/integration/all.py +1 -0
  165. sage/symbolic/integration/external.py +271 -0
  166. sage/symbolic/integration/integral.py +1075 -0
  167. sage/symbolic/maxima_wrapper.py +162 -0
  168. sage/symbolic/operators.py +267 -0
  169. sage/symbolic/operators.pyi +61 -0
  170. sage/symbolic/pynac_constant_impl.pyi +13 -0
  171. sage/symbolic/pynac_function_impl.pyi +8 -0
  172. sage/symbolic/random_tests.py +461 -0
  173. sage/symbolic/relation.py +2062 -0
  174. sage/symbolic/ring.cpython-311-darwin.so +0 -0
  175. sage/symbolic/ring.pxd +5 -0
  176. sage/symbolic/ring.pyi +110 -0
  177. sage/symbolic/ring.pyx +1393 -0
  178. sage/symbolic/series_impl.pyi +10 -0
  179. sage/symbolic/subring.py +1025 -0
  180. sage/symbolic/symengine.py +19 -0
  181. sage/symbolic/tests.py +40 -0
  182. sage/symbolic/units.py +1468 -0
@@ -0,0 +1,1348 @@
1
+ # sage_setup: distribution = sagemath-symbolics
2
+ r"""
3
+ Utilities for Calculus
4
+
5
+ This module defines helper functions which are used for simplifications
6
+ and display of symbolic expressions.
7
+
8
+ AUTHORS:
9
+
10
+ - Michal Bejger (2015) : class :class:`ExpressionNice`
11
+ - Eric Gourgoulhon (2015, 2017) : simplification functions
12
+ - Travis Scrimshaw (2016): review tweaks
13
+ - Marius Gerbershagen (2022) : skip simplification of expressions with a single
14
+ number or symbolic variable
15
+ """
16
+
17
+ # *****************************************************************************
18
+ #
19
+ # Copyright (C) 2015 Michal Bejger <bejger@camk.edu.pl>
20
+ # Copyright (C) 2015, 2017 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
21
+ # Copyright (C) 2016 Travis Scrimshaw <tscrimsh@umn.edu>
22
+ #
23
+ # This program is free software: you can redistribute it and/or modify
24
+ # it under the terms of the GNU General Public License as published by
25
+ # the Free Software Foundation, either version 2 of the License, or
26
+ # (at your option) any later version.
27
+ # https://www.gnu.org/licenses/
28
+ # ****************************************************************************
29
+
30
+ from operator import pow as _pow
31
+
32
+ from sage.functions.other import abs_symbolic
33
+ from sage.functions.trig import cos, sin
34
+ from sage.misc.functional import sqrt
35
+ from sage.rings.rational import Rational
36
+ from sage.symbolic.constants import pi
37
+ from sage.symbolic.expression import Expression
38
+ from sage.symbolic.expression_conversions import ExpressionTreeWalker
39
+ from sage.symbolic.ring import SR
40
+
41
+
42
+ class SimplifySqrtReal(ExpressionTreeWalker):
43
+ r"""
44
+ Class for simplifying square roots in the real domain, by walking the
45
+ expression tree.
46
+
47
+ The end user interface is the function :func:`simplify_sqrt_real`.
48
+
49
+ INPUT:
50
+
51
+ - ``ex`` -- a symbolic expression
52
+
53
+ EXAMPLES:
54
+
55
+ Let us consider the square root of an exact square under some assumption::
56
+
57
+ sage: assume(x<1)
58
+ sage: a = sqrt(x^2-2*x+1)
59
+
60
+ The method :meth:`~sage.symbolic.expression.Expression.simplify_full()`
61
+ is ineffective on such an expression::
62
+
63
+ sage: a.simplify_full()
64
+ sqrt(x^2 - 2*x + 1)
65
+
66
+ and the more aggressive method :meth:`~sage.symbolic.expression.Expression.canonicalize_radical()`
67
+ yields a wrong result, given that `x<1`::
68
+
69
+ sage: a.canonicalize_radical() # wrong output!
70
+ x - 1
71
+
72
+ We construct a :class:`SimplifySqrtReal` object ``s`` from the symbolic
73
+ expression ``a``::
74
+
75
+ sage: from sage.manifolds.utilities import SimplifySqrtReal
76
+ sage: s = SimplifySqrtReal(a)
77
+
78
+ We use the ``__call__`` method to walk the expression tree and produce a
79
+ correctly simplified expression::
80
+
81
+ sage: s()
82
+ -x + 1
83
+
84
+ Calling the simplifier ``s`` with an expression actually simplifies this
85
+ expression::
86
+
87
+ sage: s(a) # same as s() since s is built from a
88
+ -x + 1
89
+ sage: s(sqrt(x^2))
90
+ abs(x)
91
+ sage: s(sqrt(1+sqrt(x^2-2*x+1))) # nested sqrt's
92
+ sqrt(-x + 2)
93
+
94
+ Another example where both
95
+ :meth:`~sage.symbolic.expression.Expression.simplify_full()` and
96
+ :meth:`~sage.symbolic.expression.Expression.canonicalize_radical()`
97
+ fail::
98
+
99
+ sage: b = sqrt((x-1)/(x-2))*sqrt(1-x)
100
+ sage: b.simplify_full() # does not simplify
101
+ sqrt(-x + 1)*sqrt((x - 1)/(x - 2))
102
+ sage: b.canonicalize_radical() # wrong output, given that x<1
103
+ (I*x - I)/sqrt(x - 2)
104
+ sage: SimplifySqrtReal(b)() # OK, given that x<1
105
+ -(x - 1)/sqrt(-x + 2)
106
+
107
+ TESTS:
108
+
109
+ We check that the inverse of a square root is well simplified; this is a
110
+ a non-trivial test since ``1/sqrt(x)`` is represented by ``pow(x,-1/2)``
111
+ in the expression tree::
112
+
113
+ sage: SimplifySqrtReal(1/sqrt(x^2-4*x+4))()
114
+ -1/(x - 2)
115
+ sage: SimplifySqrtReal(sqrt((x-2)/((x-3)*(x^2-2*x+1))))()
116
+ -sqrt(-x + 2)/((x - 1)*sqrt(-x + 3))
117
+ sage: forget() # for doctests below
118
+
119
+ .. SEEALSO::
120
+
121
+ :func:`simplify_sqrt_real` for more examples with
122
+ :class:`SimplifySqrtReal` at work.
123
+ """
124
+ def arithmetic(self, ex, operator):
125
+ r"""
126
+ This is the only method of the base class
127
+ :class:`~sage.symbolic.expression_conversions.ExpressionTreeWalker`
128
+ that is reimplemented, since square roots are considered as
129
+ arithmetic operations with ``operator`` = ``pow`` and
130
+ ``ex.operands()[1]`` = ``1/2`` or ``-1/2``.
131
+
132
+ INPUT:
133
+
134
+ - ``ex`` -- a symbolic expression
135
+ - ``operator`` -- an arithmetic operator
136
+
137
+ OUTPUT:
138
+
139
+ - a symbolic expression, equivalent to ``ex`` with square roots
140
+ simplified
141
+
142
+ EXAMPLES::
143
+
144
+ sage: from sage.manifolds.utilities import SimplifySqrtReal
145
+ sage: a = sqrt(x^2+2*x+1)
146
+ sage: s = SimplifySqrtReal(a)
147
+ sage: a.operator()
148
+ <built-in function pow>
149
+ sage: s.arithmetic(a, a.operator())
150
+ abs(x + 1)
151
+
152
+ ::
153
+
154
+ sage: a = x + 1 # no square root
155
+ sage: s.arithmetic(a, a.operator())
156
+ x + 1
157
+
158
+ ::
159
+
160
+ sage: a = x + 1 + sqrt(function('f')(x)^2)
161
+ sage: s.arithmetic(a, a.operator())
162
+ x + abs(f(x)) + 1
163
+ """
164
+ if operator is _pow:
165
+ operands = ex.operands()
166
+ power = operands[1]
167
+ one_half = Rational((1,2))
168
+ minus_one_half = -one_half
169
+ if (power == one_half) or (power == minus_one_half):
170
+ # This is a square root or the inverse of a square root
171
+ w0 = SR.wild(0)
172
+ w1 = SR.wild(1)
173
+ sqrt_pattern = w0**one_half
174
+ inv_sqrt_pattern = w0**minus_one_half
175
+ sqrt_ratio_pattern1 = w0**one_half * w1**minus_one_half
176
+ sqrt_ratio_pattern2 = w0**minus_one_half * w1**one_half
177
+ argum = operands[0] # the argument of sqrt
178
+ if argum.has(sqrt_pattern) or argum.has(inv_sqrt_pattern):
179
+ argum = self(argum) # treatment of nested sqrt's
180
+ den = argum.denominator()
181
+ if not (den == 1): # the argument of sqrt is a fraction
182
+ # NB: after #19312 (integrated in Sage 6.10.beta7), the
183
+ # above test cannot be written as "if den != 1:"
184
+ num = argum.numerator()
185
+ if num < 0 or den < 0:
186
+ ex = sqrt(-num) / sqrt(-den)
187
+ else:
188
+ ex = sqrt(argum)
189
+ else:
190
+ ex = sqrt(argum)
191
+ simpl = SR(ex._maxima_().radcan())
192
+ if (not simpl.match(sqrt_pattern) and
193
+ not simpl.match(inv_sqrt_pattern) and
194
+ not simpl.match(sqrt_ratio_pattern1) and
195
+ not simpl.match(sqrt_ratio_pattern2)):
196
+ # radcan transformed substantially the expression,
197
+ # possibly getting rid of some sqrt; in order to ensure a
198
+ # positive result, the absolute value of radcan's output
199
+ # is taken, the call to simplify() taking care of possible
200
+ # assumptions regarding signs of subexpression of simpl:
201
+ simpl = abs(simpl).simplify()
202
+ if power == minus_one_half:
203
+ simpl = SR(1)/simpl
204
+ return simpl
205
+ # If operator is not a square root, we default to ExpressionTreeWalker:
206
+ return super().arithmetic(ex, operator)
207
+
208
+
209
+ class SimplifyAbsTrig(ExpressionTreeWalker):
210
+ r"""
211
+ Class for simplifying absolute values of cosines or sines (in the real
212
+ domain), by walking the expression tree.
213
+
214
+ The end user interface is the function :func:`simplify_abs_trig`.
215
+
216
+ INPUT:
217
+
218
+ - ``ex`` -- a symbolic expression
219
+
220
+ EXAMPLES:
221
+
222
+ Let us consider the following symbolic expression with some assumption
223
+ on the range of the variable `x`::
224
+
225
+ sage: assume(pi/2<x, x<pi)
226
+ sage: a = abs(cos(x)) + abs(sin(x))
227
+
228
+ The method :meth:`~sage.symbolic.expression.Expression.simplify_full()`
229
+ is ineffective on such an expression::
230
+
231
+ sage: a.simplify_full()
232
+ abs(cos(x)) + abs(sin(x))
233
+
234
+ We construct a :class:`SimplifyAbsTrig` object ``s`` from the symbolic
235
+ expression ``a``::
236
+
237
+ sage: from sage.manifolds.utilities import SimplifyAbsTrig
238
+ sage: s = SimplifyAbsTrig(a)
239
+
240
+ We use the ``__call__`` method to walk the expression tree and produce a
241
+ correctly simplified expression, given that `x\in(\pi/2, \pi)`::
242
+
243
+ sage: s()
244
+ -cos(x) + sin(x)
245
+
246
+ Calling the simplifier ``s`` with an expression actually simplifies this
247
+ expression::
248
+
249
+ sage: s(a) # same as s() since s is built from a
250
+ -cos(x) + sin(x)
251
+ sage: s(abs(cos(x/2)) + abs(sin(x/2))) # pi/4 < x/2 < pi/2
252
+ cos(1/2*x) + sin(1/2*x)
253
+ sage: s(abs(cos(2*x)) + abs(sin(2*x))) # pi < 2 x < 2*pi
254
+ abs(cos(2*x)) - sin(2*x)
255
+ sage: s(abs(sin(2+abs(cos(x))))) # nested abs(sin_or_cos(...))
256
+ sin(-cos(x) + 2)
257
+
258
+ TESTS::
259
+
260
+ sage: forget() # for doctests below
261
+
262
+ .. SEEALSO::
263
+
264
+ :func:`simplify_abs_trig` for more examples with
265
+ :class:`SimplifyAbsTrig` at work.
266
+ """
267
+ def composition(self, ex, operator):
268
+ r"""
269
+ This is the only method of the base class
270
+ :class:`~sage.symbolic.expression_conversions.ExpressionTreeWalker`
271
+ that is reimplemented, since it manages the composition of
272
+ ``abs`` with ``cos`` or ``sin``.
273
+
274
+ INPUT:
275
+
276
+ - ``ex`` -- a symbolic expression
277
+ - ``operator`` -- an operator
278
+
279
+ OUTPUT:
280
+
281
+ - a symbolic expression, equivalent to ``ex`` with ``abs(cos(...))``
282
+ and ``abs(sin(...))`` simplified, according to the range of their
283
+ argument.
284
+
285
+ EXAMPLES::
286
+
287
+ sage: from sage.manifolds.utilities import SimplifyAbsTrig
288
+ sage: assume(-pi/2 < x, x<0)
289
+ sage: a = abs(sin(x))
290
+ sage: s = SimplifyAbsTrig(a)
291
+ sage: a.operator()
292
+ abs
293
+ sage: s.composition(a, a.operator())
294
+ sin(-x)
295
+
296
+ ::
297
+
298
+ sage: a = exp(function('f')(x)) # no abs(sin_or_cos(...))
299
+ sage: a.operator()
300
+ exp
301
+ sage: s.composition(a, a.operator())
302
+ e^f(x)
303
+
304
+ ::
305
+
306
+ sage: forget() # no longer any assumption on x
307
+ sage: a = abs(cos(sin(x))) # simplifiable since -1 <= sin(x) <= 1
308
+ sage: s.composition(a, a.operator())
309
+ cos(sin(x))
310
+ sage: a = abs(sin(cos(x))) # not simplifiable
311
+ sage: s.composition(a, a.operator())
312
+ abs(sin(cos(x)))
313
+ """
314
+ if operator is abs_symbolic:
315
+ argum = ex.operands()[0] # argument of abs
316
+ if argum.operator() is sin:
317
+ # Case of abs(sin(...))
318
+ x = argum.operands()[0] # argument of sin
319
+ w0 = SR.wild()
320
+ if x.has(abs_symbolic(sin(w0))) or x.has(abs_symbolic(cos(w0))):
321
+ x = self(x) # treatment of nested abs(sin_or_cos(...))
322
+ # Simplifications for values of x in the range [-pi, 2*pi]:
323
+ if x >= 0 and x <= pi:
324
+ ex = sin(x)
325
+ elif (x > pi and x <= 2*pi) or (x >= -pi and x < 0):
326
+ ex = -sin(x)
327
+ return ex
328
+ if argum.operator() is cos:
329
+ # Case of abs(cos(...))
330
+ x = argum.operands()[0] # argument of cos
331
+ w0 = SR.wild()
332
+ if x.has(abs_symbolic(sin(w0))) or x.has(abs_symbolic(cos(w0))):
333
+ x = self(x) # treatment of nested abs(sin_or_cos(...))
334
+ # Simplifications for values of x in the range [-pi, 2*pi]:
335
+ if (x >= -pi/2 and x <= pi/2) or (x >= 3*pi/2 and x <= 2*pi):
336
+ ex = cos(x)
337
+ elif (x > pi/2 and x <= 3*pi/2) or (x >= -pi and x < -pi/2):
338
+ ex = -cos(x)
339
+ return ex
340
+ # If no pattern is found, we default to ExpressionTreeWalker:
341
+ return super().composition(ex, operator)
342
+
343
+
344
+ def simplify_sqrt_real(expr):
345
+ r"""
346
+ Simplify ``sqrt`` in symbolic expressions in the real domain.
347
+
348
+ EXAMPLES:
349
+
350
+ Simplifications of basic expressions::
351
+
352
+ sage: from sage.manifolds.utilities import simplify_sqrt_real
353
+ sage: simplify_sqrt_real( sqrt(x^2) )
354
+ abs(x)
355
+ sage: assume(x<0)
356
+ sage: simplify_sqrt_real( sqrt(x^2) )
357
+ -x
358
+ sage: simplify_sqrt_real( sqrt(x^2-2*x+1) )
359
+ -x + 1
360
+ sage: simplify_sqrt_real( sqrt(x^2) + sqrt(x^2-2*x+1) )
361
+ -2*x + 1
362
+
363
+ This improves over
364
+ :meth:`~sage.symbolic.expression.Expression.canonicalize_radical`,
365
+ which yields incorrect results when ``x < 0``::
366
+
367
+ sage: forget() # removes the assumption x<0
368
+ sage: sqrt(x^2).canonicalize_radical()
369
+ x
370
+ sage: assume(x<0)
371
+ sage: sqrt(x^2).canonicalize_radical()
372
+ -x
373
+ sage: sqrt(x^2-2*x+1).canonicalize_radical() # wrong output
374
+ x - 1
375
+ sage: ( sqrt(x^2) + sqrt(x^2-2*x+1) ).canonicalize_radical() # wrong output
376
+ -1
377
+
378
+ Simplification of nested ``sqrt``'s::
379
+
380
+ sage: forget() # removes the assumption x<0
381
+ sage: simplify_sqrt_real( sqrt(1 + sqrt(x^2)) )
382
+ sqrt(abs(x) + 1)
383
+ sage: assume(x<0)
384
+ sage: simplify_sqrt_real( sqrt(1 + sqrt(x^2)) )
385
+ sqrt(-x + 1)
386
+ sage: simplify_sqrt_real( sqrt(x^2 + sqrt(4*x^2) + 1) )
387
+ -x + 1
388
+
389
+ Again, :meth:`~sage.symbolic.expression.Expression.canonicalize_radical`
390
+ fails on the last one::
391
+
392
+ sage: (sqrt(x^2 + sqrt(4*x^2) + 1)).canonicalize_radical()
393
+ x - 1
394
+
395
+ TESTS:
396
+
397
+ Simplification of expressions involving some symbolic derivatives::
398
+
399
+ sage: f = function('f')
400
+ sage: simplify_sqrt_real( diff(f(x), x)/sqrt(x^2-2*x+1) ) # x<0 => x-1<0
401
+ -diff(f(x), x)/(x - 1)
402
+ sage: g = function('g')
403
+ sage: simplify_sqrt_real( sqrt(x^3*diff(f(g(x)), x)^2) ) # x<0
404
+ (-x)^(3/2)*abs(D[0](f)(g(x)))*abs(diff(g(x), x))
405
+ sage: forget() # for doctests below
406
+ """
407
+ w0 = SR.wild()
408
+ one_half = Rational((1,2))
409
+ if expr.has(w0**one_half) or expr.has(w0**(-one_half)):
410
+ return SimplifySqrtReal(expr)()
411
+ return expr
412
+
413
+
414
+ def simplify_abs_trig(expr):
415
+ r"""
416
+ Simplify ``abs(sin(...))`` and ``abs(cos(...))`` in symbolic expressions.
417
+
418
+ EXAMPLES::
419
+
420
+ sage: M = Manifold(3, 'M', structure='topological')
421
+ sage: X.<x,y,z> = M.chart(r'x y:(0,pi) z:(-pi/3,0)')
422
+ sage: X.coord_range()
423
+ x: (-oo, +oo); y: (0, pi); z: (-1/3*pi, 0)
424
+
425
+ Since `x` spans all `\RR`, no simplification of ``abs(sin(x))``
426
+ occurs, while ``abs(sin(y))`` and ``abs(sin(3*z))`` are correctly
427
+ simplified, given that `y \in (0,\pi)` and `z \in (-\pi/3,0)`::
428
+
429
+ sage: from sage.manifolds.utilities import simplify_abs_trig
430
+ sage: simplify_abs_trig( abs(sin(x)) + abs(sin(y)) + abs(sin(3*z)) )
431
+ abs(sin(x)) + sin(y) + sin(-3*z)
432
+
433
+ Note that neither
434
+ :meth:`~sage.symbolic.expression.Expression.simplify_trig` nor
435
+ :meth:`~sage.symbolic.expression.Expression.simplify_full`
436
+ works in this case::
437
+
438
+ sage: s = abs(sin(x)) + abs(sin(y)) + abs(sin(3*z))
439
+ sage: s.simplify_trig()
440
+ abs(4*cos(-z)^2 - 1)*abs(sin(-z)) + abs(sin(x)) + abs(sin(y))
441
+ sage: s.simplify_full()
442
+ abs(4*cos(-z)^2 - 1)*abs(sin(-z)) + abs(sin(x)) + abs(sin(y))
443
+
444
+ despite the following assumptions hold::
445
+
446
+ sage: assumptions()
447
+ [x is real, y is real, y > 0, y < pi, z is real, z > -1/3*pi, z < 0]
448
+
449
+ Additional checks are::
450
+
451
+ sage: simplify_abs_trig( abs(sin(y/2)) ) # shall simplify
452
+ sin(1/2*y)
453
+ sage: simplify_abs_trig( abs(sin(2*y)) ) # must not simplify
454
+ abs(sin(2*y))
455
+ sage: simplify_abs_trig( abs(sin(z/2)) ) # shall simplify
456
+ sin(-1/2*z)
457
+ sage: simplify_abs_trig( abs(sin(4*z)) ) # must not simplify
458
+ abs(sin(-4*z))
459
+
460
+ Simplification of ``abs(cos(...))``::
461
+
462
+ sage: forget()
463
+ sage: M = Manifold(3, 'M', structure='topological')
464
+ sage: X.<x,y,z> = M.chart(r'x y:(0,pi/2) z:(pi/4,3*pi/4)')
465
+ sage: X.coord_range()
466
+ x: (-oo, +oo); y: (0, 1/2*pi); z: (1/4*pi, 3/4*pi)
467
+ sage: simplify_abs_trig( abs(cos(x)) + abs(cos(y)) + abs(cos(2*z)) )
468
+ abs(cos(x)) + cos(y) - cos(2*z)
469
+
470
+ Additional tests::
471
+
472
+ sage: simplify_abs_trig(abs(cos(y-pi/2))) # shall simplify
473
+ cos(-1/2*pi + y)
474
+ sage: simplify_abs_trig(abs(cos(y+pi/2))) # shall simplify
475
+ -cos(1/2*pi + y)
476
+ sage: simplify_abs_trig(abs(cos(y-pi))) # shall simplify
477
+ -cos(-pi + y)
478
+ sage: simplify_abs_trig(abs(cos(2*y))) # must not simplify
479
+ abs(cos(2*y))
480
+ sage: simplify_abs_trig(abs(cos(y/2)) * abs(sin(z))) # shall simplify
481
+ cos(1/2*y)*sin(z)
482
+
483
+ TESTS:
484
+
485
+ Simplification of expressions involving some symbolic derivatives::
486
+
487
+ sage: f = function('f')
488
+ sage: s = abs(cos(x)) + abs(cos(y))*diff(f(x),x) + abs(cos(2*z))
489
+ sage: simplify_abs_trig(s)
490
+ cos(y)*diff(f(x), x) + abs(cos(x)) - cos(2*z)
491
+ sage: s = abs(sin(x))*diff(f(x),x).subs(x=y^2) + abs(cos(y))
492
+ sage: simplify_abs_trig(s)
493
+ abs(sin(x))*D[0](f)(y^2) + cos(y)
494
+ sage: forget() # for doctests below
495
+ """
496
+ w0 = SR.wild()
497
+ if expr.has(abs_symbolic(sin(w0))) or expr.has(abs_symbolic(cos(w0))):
498
+ return SimplifyAbsTrig(expr)()
499
+ return expr
500
+
501
+
502
+ def simplify_chain_real(expr):
503
+ r"""
504
+ Apply a chain of simplifications to a symbolic expression, assuming the
505
+ real domain.
506
+
507
+ This is the simplification chain used in calculus involving coordinate
508
+ functions on real manifolds, as implemented in
509
+ :class:`~sage.manifolds.chart_func.ChartFunction`.
510
+
511
+ The chain is formed by the following functions, called
512
+ successively:
513
+
514
+ #. :meth:`~sage.symbolic.expression.Expression.simplify_factorial`
515
+ #. :meth:`~sage.symbolic.expression.Expression.simplify_trig`
516
+ #. :meth:`~sage.symbolic.expression.Expression.simplify_rational`
517
+ #. :func:`simplify_sqrt_real`
518
+ #. :func:`simplify_abs_trig`
519
+ #. :meth:`~sage.symbolic.expression.Expression.canonicalize_radical`
520
+ #. :meth:`~sage.symbolic.expression.Expression.simplify_log`
521
+ #. :meth:`~sage.symbolic.expression.Expression.simplify_rational`
522
+ #. :meth:`~sage.symbolic.expression.Expression.simplify_trig`
523
+
524
+ EXAMPLES:
525
+
526
+ We consider variables that are coordinates of a chart on a real manifold::
527
+
528
+ sage: M = Manifold(2, 'M', structure='topological')
529
+ sage: X.<x,y> = M.chart('x:(0,1) y')
530
+
531
+ The following assumptions then hold::
532
+
533
+ sage: assumptions()
534
+ [x is real, x > 0, x < 1, y is real]
535
+
536
+ and we have::
537
+
538
+ sage: from sage.manifolds.utilities import simplify_chain_real
539
+ sage: s = sqrt(y^2)
540
+ sage: simplify_chain_real(s)
541
+ abs(y)
542
+
543
+ The above result is correct since ``y`` is real. It is obtained by
544
+ :meth:`~sage.symbolic.expression.Expression.simplify_real` as well::
545
+
546
+ sage: s.simplify_real()
547
+ abs(y)
548
+ sage: s.simplify_full()
549
+ abs(y)
550
+
551
+ Furthermore, we have::
552
+
553
+ sage: s = sqrt(x^2-2*x+1)
554
+ sage: simplify_chain_real(s)
555
+ -x + 1
556
+
557
+ which is correct since `x \in (0,1)`. On this example, neither
558
+ :meth:`~sage.symbolic.expression.Expression.simplify_real`
559
+ nor :meth:`~sage.symbolic.expression.Expression.simplify_full`,
560
+ nor :meth:`~sage.symbolic.expression.Expression.canonicalize_radical`
561
+ give satisfactory results::
562
+
563
+ sage: s.simplify_real() # unsimplified output
564
+ sqrt(x^2 - 2*x + 1)
565
+ sage: s.simplify_full() # unsimplified output
566
+ sqrt(x^2 - 2*x + 1)
567
+ sage: s.canonicalize_radical() # wrong output since x in (0,1)
568
+ x - 1
569
+
570
+ Other simplifications::
571
+
572
+ sage: s = abs(sin(pi*x))
573
+ sage: simplify_chain_real(s) # correct output since x in (0,1)
574
+ sin(pi*x)
575
+ sage: s.simplify_real() # unsimplified output
576
+ abs(sin(pi*x))
577
+ sage: s.simplify_full() # unsimplified output
578
+ abs(sin(pi*x))
579
+
580
+ ::
581
+
582
+ sage: s = cos(y)^2 + sin(y)^2
583
+ sage: simplify_chain_real(s)
584
+ 1
585
+ sage: s.simplify_real() # unsimplified output
586
+ cos(y)^2 + sin(y)^2
587
+ sage: s.simplify_full() # OK
588
+ 1
589
+
590
+ TESTS::
591
+
592
+ sage: forget() # for doctests below
593
+ """
594
+ if expr.number_of_operands() == 0:
595
+ return expr
596
+ expr = expr.simplify_factorial()
597
+ expr = expr.simplify_trig()
598
+ expr = expr.simplify_rational()
599
+ expr = simplify_sqrt_real(expr)
600
+ expr = simplify_abs_trig(expr)
601
+ expr = expr.canonicalize_radical()
602
+ expr = expr.simplify_log('one')
603
+ expr = expr.simplify_rational()
604
+ expr = expr.simplify_trig()
605
+ return expr
606
+
607
+
608
+ def simplify_chain_generic(expr):
609
+ r"""
610
+ Apply a chain of simplifications to a symbolic expression.
611
+
612
+ This is the simplification chain used in calculus involving coordinate
613
+ functions on manifolds over fields different from `\RR`, as implemented in
614
+ :class:`~sage.manifolds.chart_func.ChartFunction`.
615
+
616
+ The chain is formed by the following functions, called
617
+ successively:
618
+
619
+ #. :meth:`~sage.symbolic.expression.Expression.simplify_factorial`
620
+ #. :meth:`~sage.symbolic.expression.Expression.simplify_rectform`
621
+ #. :meth:`~sage.symbolic.expression.Expression.simplify_trig`
622
+ #. :meth:`~sage.symbolic.expression.Expression.simplify_rational`
623
+ #. :meth:`~sage.symbolic.expression.Expression.expand_sum`
624
+
625
+ NB: for the time being, this is identical to
626
+ :meth:`~sage.symbolic.expression.Expression.simplify_full`.
627
+
628
+ EXAMPLES:
629
+
630
+ We consider variables that are coordinates of a chart on a complex
631
+ manifold::
632
+
633
+ sage: M = Manifold(2, 'M', structure='topological', field='complex')
634
+ sage: X.<x,y> = M.chart()
635
+
636
+ Then neither ``x`` nor ``y`` is assumed to be real::
637
+
638
+ sage: assumptions()
639
+ []
640
+
641
+ Accordingly, ``simplify_chain_generic`` does not simplify
642
+ ``sqrt(x^2)`` to ``abs(x)``::
643
+
644
+ sage: from sage.manifolds.utilities import simplify_chain_generic
645
+ sage: s = sqrt(x^2)
646
+ sage: simplify_chain_generic(s)
647
+ sqrt(x^2)
648
+
649
+ This contrasts with the behavior of
650
+ :func:`~sage.manifolds.utilities.simplify_chain_real`.
651
+
652
+ Other simplifications::
653
+
654
+ sage: s = (x+y)^2 - x^2 -2*x*y - y^2
655
+ sage: simplify_chain_generic(s)
656
+ 0
657
+ sage: s = (x^2 - 2*x + 1) / (x^2 -1)
658
+ sage: simplify_chain_generic(s)
659
+ (x - 1)/(x + 1)
660
+ sage: s = cos(2*x) - 2*cos(x)^2 + 1
661
+ sage: simplify_chain_generic(s)
662
+ 0
663
+
664
+ TESTS::
665
+
666
+ sage: forget() # for doctests below
667
+ """
668
+ if expr.number_of_operands() == 0:
669
+ return expr
670
+ expr = expr.simplify_factorial()
671
+ expr = expr.simplify_rectform()
672
+ expr = expr.simplify_trig()
673
+ expr = expr.simplify_rational()
674
+ expr = expr.expand_sum()
675
+ return expr
676
+
677
+
678
+ def simplify_chain_generic_sympy(expr):
679
+ r"""
680
+ Apply a chain of simplifications to a sympy expression.
681
+
682
+ This is the simplification chain used in calculus involving coordinate
683
+ functions on manifolds over fields different from `\RR`, as implemented in
684
+ :class:`~sage.manifolds.chart_func.ChartFunction`.
685
+
686
+ The chain is formed by the following functions, called
687
+ successively:
688
+
689
+ #. :meth:`~sympy.simplify.combsimp`
690
+ #. :meth:`~sympy.simplify.trigsimp`
691
+ #. :meth:`~sympy.core.expand`
692
+ #. :meth:`~sympy.simplify.simplify`
693
+
694
+ EXAMPLES:
695
+
696
+ We consider variables that are coordinates of a chart on a complex
697
+ manifold::
698
+
699
+ sage: forget() # for doctest only
700
+ sage: M = Manifold(2, 'M', structure='topological', field='complex', calc_method='sympy')
701
+ sage: X.<x,y> = M.chart()
702
+
703
+ Then neither ``x`` nor ``y`` is assumed to be real::
704
+
705
+ sage: assumptions()
706
+ []
707
+
708
+ Accordingly, ``simplify_chain_generic_sympy`` does not simplify
709
+ ``sqrt(x^2)`` to ``abs(x)``::
710
+
711
+ sage: from sage.manifolds.utilities import simplify_chain_generic_sympy
712
+ sage: s = (sqrt(x^2))._sympy_()
713
+ sage: simplify_chain_generic_sympy(s)
714
+ sqrt(x**2)
715
+
716
+ This contrasts with the behavior of
717
+ :func:`~sage.manifolds.utilities.simplify_chain_real_sympy`.
718
+
719
+ Other simplifications::
720
+
721
+ sage: s = ((x+y)^2 - x^2 -2*x*y - y^2)._sympy_()
722
+ sage: simplify_chain_generic_sympy(s)
723
+ 0
724
+ sage: s = ((x^2 - 2*x + 1) / (x^2 -1))._sympy_()
725
+ sage: simplify_chain_generic_sympy(s)
726
+ (x - 1)/(x + 1)
727
+ sage: s = (cos(2*x) - 2*cos(x)^2 + 1)._sympy_()
728
+ sage: simplify_chain_generic_sympy(s)
729
+ 0
730
+ """
731
+ expr = expr.combsimp()
732
+ expr = expr.trigsimp()
733
+ expr = expr.expand()
734
+ expr = expr.simplify()
735
+ return expr
736
+
737
+
738
+ def simplify_chain_real_sympy(expr):
739
+ r"""
740
+ Apply a chain of simplifications to a sympy expression, assuming the
741
+ real domain.
742
+
743
+ This is the simplification chain used in calculus involving coordinate
744
+ functions on real manifolds, as implemented in
745
+ :class:`~sage.manifolds.chart_func.ChartFunction`.
746
+
747
+ The chain is formed by the following functions, called
748
+ successively:
749
+
750
+ #. :meth:`~sympy.simplify.combsimp`
751
+ #. :meth:`~sympy.simplify.trigsimp`
752
+ #. :func:`simplify_sqrt_real`
753
+ #. :func:`simplify_abs_trig`
754
+ #. :meth:`~sympy.core.expand`
755
+ #. :meth:`~sympy.simplify.simplify`
756
+
757
+ EXAMPLES:
758
+
759
+ We consider variables that are coordinates of a chart on a real manifold::
760
+
761
+ sage: forget() # for doctest only
762
+ sage: M = Manifold(2, 'M', structure='topological',calc_method='sympy')
763
+ sage: X.<x,y> = M.chart('x:(0,1) y')
764
+
765
+ The following assumptions then hold::
766
+
767
+ sage: assumptions()
768
+ [x is real, x > 0, x < 1, y is real]
769
+
770
+ and we have::
771
+
772
+ sage: from sage.manifolds.utilities import simplify_chain_real_sympy
773
+ sage: s = (sqrt(y^2))._sympy_()
774
+ sage: simplify_chain_real_sympy(s)
775
+ Abs(y)
776
+
777
+ Furthermore, we have::
778
+
779
+ sage: s = (sqrt(x^2-2*x+1))._sympy_()
780
+ sage: simplify_chain_real_sympy(s)
781
+ 1 - x
782
+
783
+ Other simplifications::
784
+
785
+ sage: s = (abs(sin(pi*x)))._sympy_()
786
+ sage: simplify_chain_real_sympy(s) # correct output since x in (0,1)
787
+ sin(pi*x)
788
+
789
+ ::
790
+
791
+ sage: s = (cos(y)^2 + sin(y)^2)._sympy_()
792
+ sage: simplify_chain_real_sympy(s)
793
+ 1
794
+ """
795
+ # TODO: introduce pure SymPy functions instead of simplify_sqrt_real and
796
+ # simplify_abs_trig
797
+ if 'sqrt(' in str(expr):
798
+ expr = simplify_sqrt_real(expr._sage_())._sympy_()
799
+ expr = expr.combsimp()
800
+ expr = expr.trigsimp()
801
+ if 'sqrt(' in str(expr):
802
+ expr = simplify_sqrt_real(expr._sage_())._sympy_()
803
+ if 'Abs(sin(' in str(expr):
804
+ expr = simplify_abs_trig(expr._sage_())._sympy_()
805
+ expr = expr.expand()
806
+ expr = expr.simplify()
807
+ return expr
808
+
809
+ #******************************************************************************
810
+
811
+
812
+ class ExpressionNice(Expression):
813
+ r"""
814
+ Subclass of :class:`~sage.symbolic.expression.Expression` for a
815
+ "human-friendly" display of partial derivatives and the possibility to
816
+ shorten the display by skipping the arguments of symbolic functions.
817
+
818
+ INPUT:
819
+
820
+ - ``ex`` -- symbolic expression
821
+
822
+ EXAMPLES:
823
+
824
+ An expression formed with callable symbolic expressions::
825
+
826
+ sage: var('x y z')
827
+ (x, y, z)
828
+ sage: f = function('f')(x, y)
829
+ sage: g = f.diff(y).diff(x)
830
+ sage: h = function('h')(y, z)
831
+ sage: k = h.diff(z)
832
+ sage: fun = x*g + y*(k-z)^2
833
+
834
+ The standard Pynac display of partial derivatives::
835
+
836
+ sage: fun
837
+ y*(z - diff(h(y, z), z))^2 + x*diff(f(x, y), x, y)
838
+ sage: latex(fun)
839
+ y {\left(z - \frac{\partial}{\partial z}h\left(y, z\right)\right)}^{2} + x \frac{\partial^{2}}{\partial x\partial y}f\left(x, y\right)
840
+
841
+ With :class:`ExpressionNice`, the Pynac notation ``D[...]`` is replaced
842
+ by textbook-like notation::
843
+
844
+ sage: from sage.manifolds.utilities import ExpressionNice
845
+ sage: ExpressionNice(fun)
846
+ y*(z - d(h)/dz)^2 + x*d^2(f)/dxdy
847
+ sage: latex(ExpressionNice(fun))
848
+ y {\left(z - \frac{\partial\,h}{\partial z}\right)}^{2}
849
+ + x \frac{\partial^2\,f}{\partial x\partial y}
850
+
851
+ An example when function variables are themselves functions::
852
+
853
+ sage: f = function('f')(x, y)
854
+ sage: g = function('g')(x, f) # the second variable is the function f
855
+ sage: fun = (g.diff(x))*x - x^2*f.diff(x,y)
856
+ sage: fun
857
+ -x^2*diff(f(x, y), x, y) + (diff(f(x, y), x)*D[1](g)(x, f(x, y)) + D[0](g)(x, f(x, y)))*x
858
+ sage: ExpressionNice(fun)
859
+ -x^2*d^2(f)/dxdy + (d(f)/dx*d(g)/d(f(x, y)) + d(g)/dx)*x
860
+ sage: latex(ExpressionNice(fun))
861
+ -x^{2} \frac{\partial^2\,f}{\partial x\partial y}
862
+ + {\left(\frac{\partial\,f}{\partial x}
863
+ \frac{\partial\,g}{\partial \left( f\left(x, y\right) \right)}
864
+ + \frac{\partial\,g}{\partial x}\right)} x
865
+
866
+ Note that ``D[1](g)(x, f(x,y))`` is rendered as ``d(g)/d(f(x, y))``.
867
+
868
+ An example with multiple differentiations::
869
+
870
+ sage: fun = f.diff(x,x,y,y,x)*x
871
+ sage: fun
872
+ x*diff(f(x, y), x, x, x, y, y)
873
+ sage: ExpressionNice(fun)
874
+ x*d^5(f)/dx^3dy^2
875
+ sage: latex(ExpressionNice(fun))
876
+ x \frac{\partial^5\,f}{\partial x ^ 3\partial y ^ 2}
877
+
878
+ Parentheses are added around powers of partial derivatives to avoid any
879
+ confusion::
880
+
881
+ sage: fun = f.diff(y)^2
882
+ sage: fun
883
+ diff(f(x, y), y)^2
884
+ sage: ExpressionNice(fun)
885
+ (d(f)/dy)^2
886
+ sage: latex(ExpressionNice(fun))
887
+ \left(\frac{\partial\,f}{\partial y}\right)^{2}
888
+
889
+ The explicit mention of function arguments can be omitted for the sake of
890
+ brevity::
891
+
892
+ sage: fun = fun*f
893
+ sage: ExpressionNice(fun)
894
+ f(x, y)*(d(f)/dy)^2
895
+ sage: Manifold.options.omit_function_arguments=True
896
+ sage: ExpressionNice(fun)
897
+ f*(d(f)/dy)^2
898
+ sage: latex(ExpressionNice(fun))
899
+ f \left(\frac{\partial\,f}{\partial y}\right)^{2}
900
+ sage: Manifold.options._reset()
901
+ sage: ExpressionNice(fun)
902
+ f(x, y)*(d(f)/dy)^2
903
+ sage: latex(ExpressionNice(fun))
904
+ f\left(x, y\right) \left(\frac{\partial\,f}{\partial y}\right)^{2}
905
+ """
906
+ def __init__(self, ex):
907
+ r"""
908
+ Initialize ``self``.
909
+
910
+ TESTS::
911
+
912
+ sage: f = function('f')(x)
913
+ sage: df = f.diff(x)
914
+ sage: df
915
+ diff(f(x), x)
916
+ sage: from sage.manifolds.utilities import ExpressionNice
917
+ sage: df_nice = ExpressionNice(df)
918
+ sage: df_nice
919
+ d(f)/dx
920
+ """
921
+ from sage.symbolic.ring import SR
922
+ self._parent = SR
923
+ Expression.__init__(self, SR, x=ex)
924
+
925
+ def _repr_(self):
926
+ r"""
927
+ String representation of the object.
928
+
929
+ EXAMPLES::
930
+
931
+ sage: var('x y z')
932
+ (x, y, z)
933
+ sage: f = function('f')(x, y)
934
+ sage: g = f.diff(y).diff(x)
935
+ sage: h = function('h')(y, z)
936
+ sage: k = h.diff(z)
937
+ sage: fun = x*g + y*(k-z)^2
938
+ sage: fun
939
+ y*(z - diff(h(y, z), z))^2 + x*diff(f(x, y), x, y)
940
+ sage: from sage.manifolds.utilities import ExpressionNice
941
+ sage: ExpressionNice(fun)
942
+ y*(z - d(h)/dz)^2 + x*d^2(f)/dxdy
943
+
944
+ Check that :issue:`33399` is fixed::
945
+
946
+ sage: ExpressionNice(function('f')(x+y, x-y).diff(y))
947
+ d(f)/d(x + y) - d(f)/d(x - y)
948
+ """
949
+ d = self._parent._repr_element_(self)
950
+
951
+ # find all occurrences of diff
952
+ list_d = []
953
+ _list_derivatives(self, list_d)
954
+
955
+ # process the list
956
+ for m in list_d:
957
+ funcname = m[1]
958
+ diffargs = m[3]
959
+ numargs = len(diffargs)
960
+
961
+ if numargs > 1:
962
+ numargs = "^" + str(numargs)
963
+ else:
964
+ numargs = ""
965
+
966
+ variables = m[4]
967
+ strv = [str(v) for v in variables]
968
+
969
+ # checking if the variable is composite
970
+ comp_chars = ['+', '-', '*', '/', '^', '(']
971
+ for i, sv in enumerate(strv):
972
+ if any(c in sv for c in comp_chars):
973
+ strv[i] = "(" + sv + ")"
974
+
975
+ # dictionary to group multiple occurrences of differentiation: d/dxdx -> d/dx^2 etc.
976
+ occ = {i: strv[i] + "^" + str(D) if (D := diffargs.count(i)) > 1
977
+ else strv[i] for i in diffargs}
978
+
979
+ res = f"d{numargs}({funcname})/d" + "d".join(occ.values())
980
+
981
+ # str representation of the operator
982
+ s = self._parent._repr_element_(m[0])
983
+
984
+ # if diff operator is raised to some power (m[5]), put brackets around
985
+ if m[5]:
986
+ res = "(" + res + ")^" + str(m[5])
987
+ o = s + "^" + str(m[5])
988
+ else:
989
+ o = s
990
+
991
+ d = d.replace(o, res)
992
+
993
+ import re
994
+
995
+ from sage.manifolds.manifold import TopologicalManifold
996
+ if TopologicalManifold.options.omit_function_arguments:
997
+ list_f = []
998
+ _list_functions(self, list_f)
999
+
1000
+ for m in list_f:
1001
+ d = re.sub(m[1] + r'\([^)]+\)', m[1], d)
1002
+
1003
+ return d
1004
+
1005
+ def _latex_(self):
1006
+ r"""
1007
+ LaTeX representation of the object.
1008
+
1009
+ EXAMPLES::
1010
+
1011
+ sage: var('x y z')
1012
+ (x, y, z)
1013
+ sage: f = function('f')(x, y)
1014
+ sage: g = f.diff(y).diff(x)
1015
+ sage: h = function('h')(y, z)
1016
+ sage: k = h.diff(z)
1017
+ sage: fun = x*g + y*(k-z)^2
1018
+ sage: fun
1019
+ y*(z - diff(h(y, z), z))^2 + x*diff(f(x, y), x, y)
1020
+ sage: from sage.manifolds.utilities import ExpressionNice
1021
+ sage: ExpressionNice(fun)
1022
+ y*(z - d(h)/dz)^2 + x*d^2(f)/dxdy
1023
+ sage: latex(ExpressionNice(fun))
1024
+ y {\left(z - \frac{\partial\,h}{\partial z}\right)}^{2} + x \frac{\partial^2\,f}{\partial x\partial y}
1025
+
1026
+ Testing the behavior if no latex_name of the function is given::
1027
+
1028
+ sage: f = function('f_x')(x, y)
1029
+ sage: fun = f.diff(y)
1030
+ sage: latex(ExpressionNice(fun))
1031
+ \frac{\partial\,f_{x}}{\partial y}
1032
+
1033
+ If latex_name, it should be used in LaTeX output::
1034
+
1035
+ sage: f = function('f_x', latex_name=r"{\cal F}")(x,y)
1036
+ sage: fun = f.diff(y)
1037
+ sage: latex(ExpressionNice(fun))
1038
+ \frac{\partial\,{\cal F}}{\partial y}
1039
+
1040
+ Check that :issue:`33399` is fixed::
1041
+
1042
+ sage: latex(ExpressionNice(function('f')(x+y, x-y).diff(y)))
1043
+ \frac{\partial\,f}{\partial \left( x + y \right)}
1044
+ - \frac{\partial\,f}{\partial \left( x - y \right)}
1045
+ """
1046
+ from sage.misc.latex import latex
1047
+
1048
+ d = self._parent._latex_element_(self)
1049
+
1050
+ # find all occurrences of diff
1051
+ list_d = []
1052
+ _list_derivatives(self, list_d)
1053
+
1054
+ for m in list_d:
1055
+ if str(m[1]) == str(m[2]):
1056
+ funcname = str(m[1])
1057
+ else:
1058
+ funcname = str(m[2])
1059
+
1060
+ diffargs = m[3]
1061
+ numargs = len(diffargs)
1062
+
1063
+ if numargs > 1:
1064
+ numargs = "^" + str(numargs)
1065
+ else:
1066
+ numargs = ""
1067
+
1068
+ variables = m[4]
1069
+
1070
+ strv = [str(v) for v in variables]
1071
+ latv = [latex(v) for v in variables]
1072
+
1073
+ # checking if the variable is composite
1074
+ comp_chars = ['+', '-', '*', '/', '^', '(']
1075
+ for i, sv in enumerate(strv):
1076
+ if any(c in sv for c in comp_chars):
1077
+ latv[i] = r"\left(" + latv[i] + r"\right)"
1078
+
1079
+ # dictionary to group multiple occurrences of differentiation: d/dxdx -> d/dx^2 etc.
1080
+ occ = {i: (latv[i] + "^" + latex(diffargs.count(i))
1081
+ if diffargs.count(i) > 1 else latv[i])
1082
+ for i in diffargs}
1083
+
1084
+ res = r"\frac{\partial" + numargs + r"\," + funcname + \
1085
+ r"}{\partial " + r"\partial ".join(i for i in occ.values()) + "}"
1086
+
1087
+ # representation of the operator
1088
+ s = self._parent._latex_element_(m[0])
1089
+
1090
+ # if diff operator is raised to some power (m[5]), put brackets around
1091
+ if m[5]:
1092
+ res = r"\left(" + res + r"\right)^{" + str(m[5]) + "}"
1093
+ o = s + "^{" + str(m[5]) + "}"
1094
+ else:
1095
+ o = s
1096
+
1097
+ d = d.replace(o, res)
1098
+
1099
+ from sage.manifolds.manifold import TopologicalManifold
1100
+ if TopologicalManifold.options.omit_function_arguments:
1101
+ list_f = []
1102
+ _list_functions(self, list_f)
1103
+
1104
+ for m in list_f:
1105
+ d = d.replace(str(m[3]) + str(m[4]), str(m[3]))
1106
+
1107
+ return d
1108
+
1109
+
1110
+ def _list_derivatives(ex, list_d, exponent=0):
1111
+ r"""
1112
+ Function to find the occurrences of ``FDerivativeOperator`` in a symbolic
1113
+ expression; inspired by
1114
+ http://ask.sagemath.org/question/10256/how-can-extract-different-terms-from-a-symbolic-expression/?answer=26136#post-id-26136
1115
+
1116
+ INPUT:
1117
+
1118
+ - ``ex`` -- symbolic expression to be analyzed
1119
+ - ``exponent`` -- (optional) exponent of ``FDerivativeOperator``,
1120
+ passed to a next level in the expression tree
1121
+
1122
+ OUTPUT:
1123
+
1124
+ - ``list_d`` -- tuple containing the details of ``FDerivativeOperator``
1125
+ found, in the following order:
1126
+
1127
+ 1. operator
1128
+ 2. function name
1129
+ 3. LaTeX function name
1130
+ 4. parameter set
1131
+ 5. operands
1132
+ 6. exponent (if found, else 0)
1133
+
1134
+ TESTS::
1135
+
1136
+ sage: f = function('f_x', latex_name=r"{\cal F}")(x)
1137
+ sage: df = f.diff(x)^2
1138
+ sage: from sage.manifolds.utilities import _list_derivatives
1139
+ sage: list_d = []
1140
+ sage: _list_derivatives(df, list_d)
1141
+ sage: list_d
1142
+ [(diff(f_x(x), x), 'f_x', {\cal F}, [0], [x], 2)]
1143
+ """
1144
+ op = ex.operator()
1145
+ operands = ex.operands()
1146
+
1147
+ import operator
1148
+
1149
+ from sage.misc.latex import latex, latex_variable_name
1150
+ from sage.symbolic.operators import FDerivativeOperator
1151
+
1152
+ if op:
1153
+ if op is operator.pow:
1154
+ if isinstance(operands[0].operator(), FDerivativeOperator):
1155
+ exponent = operands[1]
1156
+
1157
+ if isinstance(op, FDerivativeOperator):
1158
+ parameter_set = op.parameter_set()
1159
+ function = repr(op.function())
1160
+ latex_function = latex(op.function())
1161
+
1162
+ # case when no latex_name given
1163
+ if function == latex_function:
1164
+ latex_function = latex_variable_name(str(op.function()))
1165
+
1166
+ list_d.append((ex, function, latex_function, parameter_set,
1167
+ operands, exponent))
1168
+
1169
+ for operand in operands:
1170
+ _list_derivatives(operand, list_d, exponent)
1171
+
1172
+
1173
+ def _list_functions(ex, list_f):
1174
+ r"""
1175
+ Function to find the occurrences of symbolic functions in a symbolic
1176
+ expression.
1177
+
1178
+ INPUT:
1179
+
1180
+ - ``ex`` -- symbolic expression to be analyzed
1181
+
1182
+ OUTPUT:
1183
+
1184
+ - ``list_f`` -- tuple containing the details of a symbolic function found,
1185
+ in the following order:
1186
+
1187
+ 1. operator
1188
+ 2. function name
1189
+ 3. arguments
1190
+ 4. LaTeX version of function name
1191
+ 5. LaTeX version of arguments
1192
+
1193
+ TESTS::
1194
+
1195
+ sage: var('x y z')
1196
+ (x, y, z)
1197
+ sage: f = function('f', latex_name=r"{\cal F}")(x, y)
1198
+ sage: g = function('g_x')(x, y)
1199
+ sage: d = sin(x)*g.diff(x)*x*f - x^2*f.diff(x,y)/g
1200
+ sage: from sage.manifolds.utilities import _list_functions
1201
+ sage: list_f = []
1202
+ sage: _list_functions(d, list_f)
1203
+ sage: list_f
1204
+ [(f, 'f', '(x, y)', {\cal F}, \left(x, y\right)),
1205
+ (g_x, 'g_x', '(x, y)', 'g_{x}', \left(x, y\right))]
1206
+ """
1207
+ op = ex.operator()
1208
+ operands = ex.operands()
1209
+
1210
+ from sage.misc.latex import latex, latex_variable_name
1211
+
1212
+ if op:
1213
+ # FIXME: This hack is needed because the NewSymbolicFunction is
1214
+ # a class defined inside of the *function* function_factory().
1215
+ if "NewSymbolicFunction" in str(type(op)):
1216
+ repr_function = repr(op)
1217
+ latex_function = latex(op)
1218
+
1219
+ # case when no latex_name given
1220
+ if repr_function == latex_function:
1221
+ latex_function = latex_variable_name(str(op))
1222
+
1223
+ repr_args = repr(ex.arguments())
1224
+ # remove comma in case of singleton
1225
+ if len(ex.arguments()) == 1:
1226
+ repr_args = repr_args.replace(",","")
1227
+
1228
+ latex_args = latex(ex.arguments())
1229
+
1230
+ list_f.append((op, repr_function, repr_args, latex_function, latex_args))
1231
+
1232
+ for operand in operands:
1233
+ _list_functions(operand, list_f)
1234
+
1235
+ #******************************************************************************
1236
+
1237
+
1238
+ def set_axes_labels(graph, xlabel, ylabel, zlabel, **kwds):
1239
+ r"""
1240
+ Set axes labels for a 3D graphics object ``graph``.
1241
+
1242
+ This is a workaround for the lack of axes labels in 3D plots.
1243
+ This sets the labels as :func:`~sage.plot.plot3d.shapes2.text3d`
1244
+ objects at locations determined from the bounding box of the
1245
+ graphic object ``graph``.
1246
+
1247
+ INPUT:
1248
+
1249
+ - ``graph`` -- :class:`~sage.plot.plot3d.base.Graphics3d`;
1250
+ a 3D graphic object
1251
+ - ``xlabel`` -- string for the x-axis label
1252
+ - ``ylabel`` -- string for the y-axis label
1253
+ - ``zlabel`` -- string for the z-axis label
1254
+ - ``**kwds`` -- options (e.g. color) for text3d
1255
+
1256
+ OUTPUT: the 3D graphic object with text3d labels added
1257
+
1258
+ EXAMPLES::
1259
+
1260
+ sage: # needs sage.plot
1261
+ sage: g = sphere()
1262
+ sage: g.all
1263
+ [Graphics3d Object]
1264
+ sage: from sage.manifolds.utilities import set_axes_labels
1265
+ sage: ga = set_axes_labels(g, 'X', 'Y', 'Z', color='red')
1266
+ sage: ga.all # the 3D frame has now axes labels
1267
+ [Graphics3d Object, Graphics3d Object,
1268
+ Graphics3d Object, Graphics3d Object]
1269
+ """
1270
+ from sage.plot.plot3d.shapes2 import text3d
1271
+ xmin, ymin, zmin = graph.bounding_box()[0]
1272
+ xmax, ymax, zmax = graph.bounding_box()[1]
1273
+ dx = xmax - xmin
1274
+ dy = ymax - ymin
1275
+ dz = zmax - zmin
1276
+ x1 = xmin + dx / 2
1277
+ y1 = ymin + dy / 2
1278
+ z1 = zmin + dz / 2
1279
+ xmin1 = xmin - dx / 20
1280
+ ymin1 = ymin - dy / 20
1281
+ zmin1 = zmin - dz / 20
1282
+ graph += text3d(' ' + xlabel, (x1, ymin1, zmin1), **kwds)
1283
+ graph += text3d(' ' + ylabel, (xmin1, y1, zmin1), **kwds)
1284
+ graph += text3d(' ' + zlabel, (xmin1, ymin1, z1), **kwds)
1285
+ return graph
1286
+
1287
+
1288
+ def exterior_derivative(form):
1289
+ r"""
1290
+ Exterior derivative of a differential form.
1291
+
1292
+ INPUT:
1293
+
1294
+ - ``form`` -- a differential form; this must an instance of either
1295
+
1296
+ * :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField`
1297
+ for a 0-form (scalar field)
1298
+ * :class:`~sage.manifolds.differentiable.diff_form.DiffFormParal` for
1299
+ a `p`-form (`p\geq 1`) on a parallelizable manifold
1300
+ * :class:`~sage.manifolds.differentiable.diff_form.DiffForm` for a
1301
+ a `p`-form (`p\geq 1`) on a non-parallelizable manifold
1302
+
1303
+ OUTPUT:
1304
+
1305
+ - the `(p+1)`-form that is the exterior derivative of ``form``
1306
+
1307
+ EXAMPLES:
1308
+
1309
+ Exterior derivative of a scalar field (0-form)::
1310
+
1311
+ sage: from sage.manifolds.utilities import exterior_derivative
1312
+ sage: M = Manifold(3, 'M')
1313
+ sage: X.<x,y,z> = M.chart()
1314
+ sage: f = M.scalar_field({X: x+y^2+z^3}, name='f')
1315
+ sage: df = exterior_derivative(f); df
1316
+ 1-form df on the 3-dimensional differentiable manifold M
1317
+ sage: df.display()
1318
+ df = dx + 2*y dy + 3*z^2 dz
1319
+
1320
+ An alias is ``xder``::
1321
+
1322
+ sage: from sage.manifolds.utilities import xder
1323
+ sage: df == xder(f)
1324
+ True
1325
+
1326
+ Exterior derivative of a 1-form::
1327
+
1328
+ sage: a = M.one_form(name='a')
1329
+ sage: a[:] = [x+y*z, x-y*z, x*y*z]
1330
+ sage: da = xder(a); da
1331
+ 2-form da on the 3-dimensional differentiable manifold M
1332
+ sage: da.display()
1333
+ da = (-z + 1) dx∧dy + (y*z - y) dx∧dz + (x*z + y) dy∧dz
1334
+ sage: dda = xder(da); dda
1335
+ 3-form dda on the 3-dimensional differentiable manifold M
1336
+ sage: dda.display()
1337
+ dda = 0
1338
+
1339
+ .. SEEALSO::
1340
+
1341
+ :class:`sage.manifolds.differentiable.diff_form.DiffFormParal.exterior_derivative`
1342
+ or :class:`sage.manifolds.differentiable.diff_form.DiffForm.exterior_derivative`
1343
+ for more examples.
1344
+ """
1345
+ return form.exterior_derivative()
1346
+
1347
+
1348
+ xder = exterior_derivative