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,3416 @@
1
+ # sage_setup: distribution = sagemath-symbolics
2
+ r"""
3
+ Chart Functions
4
+
5
+ In the context of a topological manifold `M` over a topological field
6
+ `K`, a *chart function* is a function from a chart codomain
7
+ to `K`.
8
+ In other words, a chart function is a `K`-valued function of the coordinates
9
+ associated to some chart. The internal coordinate expressions of chart
10
+ functions and calculus on them are taken in charge by different calculus
11
+ methods, at the choice of the user:
12
+
13
+ - Sage's default symbolic engine (Pynac + Maxima), implemented via the
14
+ Symbolic Ring (``SR``)
15
+ - SymPy engine, denoted ``sympy`` hereafter
16
+
17
+ See :class:`~sage.manifolds.calculus_method.CalculusMethod` for details.
18
+
19
+ AUTHORS:
20
+
21
+ - Marco Mancini (2017) : initial version
22
+ - Eric Gourgoulhon (2015) : for a previous class implementing only SR
23
+ calculus (CoordFunctionSymb)
24
+ - Florentin Jaffredo (2018) : series expansion with respect to a given
25
+ parameter
26
+ """
27
+
28
+ # ****************************************************************************
29
+ # Copyright (C) 2017 Marco Mancini <marco.mancini@obspm.fr>
30
+ # Copyright (C) 2018 Florentin Jaffredo <florentin.jaffredo@polytechnique.edu>
31
+ #
32
+ # Distributed under the terms of the GNU General Public License (GPL)
33
+ # as published by the Free Software Foundation; either version 2 of
34
+ # the License, or (at your option) any later version.
35
+ # https://www.gnu.org/licenses/
36
+ # ****************************************************************************
37
+ from typing import Self
38
+
39
+ from sage.categories.commutative_algebras import CommutativeAlgebras
40
+ from sage.manifolds.utilities import ExpressionNice
41
+ from sage.misc.cachefunc import cached_method
42
+ from sage.structure.element import AlgebraElement, ModuleElementWithMutability
43
+ from sage.structure.mutability import Mutability
44
+ from sage.structure.parent import Parent
45
+ from sage.structure.sage_object import SageObject
46
+ from sage.structure.unique_representation import UniqueRepresentation
47
+ from sage.symbolic.ring import SR
48
+
49
+ try:
50
+ import sympy
51
+ except ImportError:
52
+ pass
53
+
54
+
55
+ class ChartFunction(AlgebraElement, ModuleElementWithMutability):
56
+ r"""
57
+ Function of coordinates of a given chart.
58
+
59
+ If `(U, \varphi)` is a chart on a topological manifold `M` of
60
+ dimension `n` over a topological field `K`, a *chart function*
61
+ associated to `(U, \varphi)` is a map
62
+
63
+ .. MATH::
64
+
65
+ \begin{array}{llcl}
66
+ f:& V \subset K^n & \longrightarrow & K \\
67
+ & (x^1, \ldots, x^n) & \longmapsto & f(x^1, \ldots, x^n),
68
+ \end{array}
69
+
70
+ where `V` is the codomain of `\varphi`. In other words, `f` is a
71
+ `K`-valued function of the coordinates associated to the chart
72
+ `(U, \varphi)`.
73
+
74
+ The chart function `f` can be represented by expressions pertaining to
75
+ different calculus methods; the currently implemented ones are
76
+
77
+ - ``SR`` (Sage's Symbolic Ring)
78
+ - ``SymPy``
79
+
80
+ See :meth:`~sage.manifolds.chart_func.ChartFunction.expr` for details.
81
+
82
+ INPUT:
83
+
84
+ - ``parent`` -- the algebra of chart functions on the chart
85
+ `(U, \varphi)`
86
+
87
+ - ``expression`` -- (default: ``None``) a symbolic expression representing
88
+ `f(x^1, \ldots, x^n)`, where `(x^1, \ldots, x^n)` are the
89
+ coordinates of the chart `(U, \varphi)`
90
+
91
+ - ``calc_method`` -- string (default: ``None``); the calculus method with
92
+ respect to which the internal expression of ``self`` must be initialized
93
+ from ``expression``. One of
94
+
95
+ - ``'SR'``: Sage's default symbolic engine (Symbolic Ring)
96
+ - ``'sympy'``: SymPy
97
+ - ``None``: the chart current calculus method is assumed
98
+
99
+ - ``expansion_symbol`` -- (default: ``None``) symbolic variable (the "small
100
+ parameter") with respect to which the coordinate expression is expanded
101
+ in power series (around the zero value of this variable)
102
+
103
+ - ``order`` -- integer (default: ``None``); the order of the expansion
104
+ if ``expansion_symbol`` is not ``None``; the *order* is defined as the
105
+ degree of the polynomial representing the truncated power series in
106
+ ``expansion_symbol``
107
+
108
+ .. WARNING::
109
+
110
+ The value of ``order`` is `n-1`, where `n` is the order of the
111
+ big `O` in the power series expansion
112
+
113
+ EXAMPLES:
114
+
115
+ A symbolic chart function on a 2-dimensional manifold::
116
+
117
+ sage: M = Manifold(2, 'M', structure='topological')
118
+ sage: X.<x,y> = M.chart()
119
+ sage: f = X.function(x^2+3*y+1)
120
+ sage: type(f)
121
+ <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
122
+ sage: f.display()
123
+ (x, y) ↦ x^2 + 3*y + 1
124
+ sage: f(x,y)
125
+ x^2 + 3*y + 1
126
+
127
+ The symbolic expression is returned when asking for the direct display of
128
+ the function::
129
+
130
+ sage: f
131
+ x^2 + 3*y + 1
132
+ sage: latex(f)
133
+ x^{2} + 3 \, y + 1
134
+
135
+ A similar output is obtained by means of the method :meth:`expr`::
136
+
137
+ sage: f.expr()
138
+ x^2 + 3*y + 1
139
+
140
+ The expression returned by :meth:`expr` is by default a Sage symbolic
141
+ expression::
142
+
143
+ sage: type(f.expr())
144
+ <class 'sage.symbolic.expression.Expression'>
145
+
146
+ A SymPy expression can also be asked for::
147
+
148
+ sage: f.expr('sympy')
149
+ x**2 + 3*y + 1
150
+ sage: type(f.expr('sympy'))
151
+ <class 'sympy.core.add.Add'>
152
+
153
+ The value of the function at specified coordinates is obtained by means
154
+ of the standard parentheses notation::
155
+
156
+ sage: f(2,-1)
157
+ 2
158
+ sage: var('a b')
159
+ (a, b)
160
+ sage: f(a,b)
161
+ a^2 + 3*b + 1
162
+
163
+ An unspecified chart function::
164
+
165
+ sage: g = X.function(function('G')(x, y))
166
+ sage: g
167
+ G(x, y)
168
+ sage: g.display()
169
+ (x, y) ↦ G(x, y)
170
+ sage: g.expr()
171
+ G(x, y)
172
+ sage: g(2,3)
173
+ G(2, 3)
174
+
175
+ Coordinate functions can be compared to other values::
176
+
177
+ sage: f = X.function(x^2+3*y+1)
178
+ sage: f == 2
179
+ False
180
+ sage: f == x^2 + 3*y + 1
181
+ True
182
+ sage: g = X.function(x*y)
183
+ sage: f == g
184
+ False
185
+ sage: h = X.function(x^2+3*y+1)
186
+ sage: f == h
187
+ True
188
+
189
+ A coercion by means of the restriction is implemented::
190
+
191
+ sage: D = M.open_subset('D')
192
+ sage: X_D = X.restrict(D, x^2+y^2<1) # open disk
193
+ sage: c = X_D.function(x^2)
194
+ sage: c + f
195
+ 2*x^2 + 3*y + 1
196
+
197
+ Expansion to a given order with respect to a small parameter::
198
+
199
+ sage: t = var('t') # the small parameter
200
+ sage: f = X.function(cos(t)*x*y, expansion_symbol=t, order=2)
201
+
202
+ The expansion is triggered by the call to :meth:`simplify`::
203
+
204
+ sage: f
205
+ x*y*cos(t)
206
+ sage: f.simplify()
207
+ -1/2*t^2*x*y + x*y
208
+
209
+ .. RUBRIC:: Differences between ``ChartFunction`` and callable
210
+ symbolic expressions
211
+
212
+ Callable symbolic expressions are defined directly from symbolic
213
+ expressions of the coordinates::
214
+
215
+ sage: f0(x,y) = x^2 + 3*y + 1
216
+ sage: type(f0)
217
+ <class 'sage.symbolic.expression.Expression'>
218
+ sage: f0
219
+ (x, y) |--> x^2 + 3*y + 1
220
+ sage: f0(x,y)
221
+ x^2 + 3*y + 1
222
+
223
+ To get an output similar to that of ``f0`` for a chart function, we must
224
+ use the method :meth:`display`::
225
+
226
+ sage: f = X.function(x^2+3*y+1)
227
+ sage: f
228
+ x^2 + 3*y + 1
229
+ sage: f.display()
230
+ (x, y) ↦ x^2 + 3*y + 1
231
+ sage: f(x,y)
232
+ x^2 + 3*y + 1
233
+
234
+ More importantly, instances of :class:`ChartFunction` differ from
235
+ callable symbolic expression by the automatic simplifications in all
236
+ operations. For instance, adding the two callable symbolic expressions::
237
+
238
+ sage: f0(x,y,z) = cos(x)^2 ; g0(x,y,z) = sin(x)^2
239
+
240
+ results in::
241
+
242
+ sage: f0 + g0
243
+ (x, y, z) |--> cos(x)^2 + sin(x)^2
244
+
245
+ To get `1`, one has to call
246
+ :meth:`~sage.symbolic.expression.Expression.simplify_trig`::
247
+
248
+ sage: (f0 + g0).simplify_trig()
249
+ (x, y, z) |--> 1
250
+
251
+ On the contrary, the sum of the corresponding :class:`ChartFunction`
252
+ instances is automatically simplified (see
253
+ :func:`~sage.manifolds.utilities.simplify_chain_real` and
254
+ :func:`~sage.manifolds.utilities.simplify_chain_generic` for details)::
255
+
256
+ sage: f = X.function(cos(x)^2) ; g = X.function(sin(x)^2)
257
+ sage: f + g
258
+ 1
259
+
260
+ Another difference regards the display of partial derivatives:
261
+ for callable symbolic functions, it involves ``diff``::
262
+
263
+ sage: g = function('g')(x, y)
264
+ sage: f0(x,y) = diff(g, x) + diff(g, y)
265
+ sage: f0
266
+ (x, y) |--> diff(g(x, y), x) + diff(g(x, y), y)
267
+
268
+ while for chart functions, the display is more "textbook" like::
269
+
270
+ sage: f = X.function(diff(g, x) + diff(g, y))
271
+ sage: f
272
+ d(g)/dx + d(g)/dy
273
+
274
+ The difference is even more dramatic on LaTeX outputs::
275
+
276
+ sage: latex(f0)
277
+ \left( x, y \right) \ {\mapsto} \ \frac{\partial}{\partial x}g\left(x, y\right) + \frac{\partial}{\partial y}g\left(x, y\right)
278
+ sage: latex(f)
279
+ \frac{\partial\,g}{\partial x} + \frac{\partial\,g}{\partial y}
280
+
281
+ Note that this regards only the display of coordinate functions:
282
+ internally, the ``diff`` notation is still used, as we can check by asking
283
+ for the symbolic expression stored in ``f``::
284
+
285
+ sage: f.expr()
286
+ diff(g(x, y), x) + diff(g(x, y), y)
287
+
288
+ One can switch to Pynac notation by changing the options::
289
+
290
+ sage: Manifold.options.textbook_output=False
291
+ sage: latex(f)
292
+ \frac{\partial}{\partial x}g\left(x, y\right) + \frac{\partial}{\partial y}g\left(x, y\right)
293
+ sage: Manifold.options._reset()
294
+ sage: latex(f)
295
+ \frac{\partial\,g}{\partial x} + \frac{\partial\,g}{\partial y}
296
+
297
+ Another difference between :class:`ChartFunction` and
298
+ callable symbolic expression is the possibility to switch off the display
299
+ of the arguments of unspecified functions. Consider for instance::
300
+
301
+ sage: f = X.function(function('u')(x, y) * function('v')(x, y))
302
+ sage: f
303
+ u(x, y)*v(x, y)
304
+ sage: f0(x,y) = function('u')(x, y) * function('v')(x, y)
305
+ sage: f0
306
+ (x, y) |--> u(x, y)*v(x, y)
307
+
308
+ If there is a clear understanding that `u` and `v` are functions of
309
+ `(x,y)`, the explicit mention of the latter can be cumbersome in lengthy
310
+ tensor expressions. We can switch it off by::
311
+
312
+ sage: Manifold.options.omit_function_arguments=True
313
+ sage: f
314
+ u*v
315
+
316
+ Note that neither the callable symbolic expression ``f0`` nor the internal
317
+ expression of ``f`` is affected by the above command::
318
+
319
+ sage: f0
320
+ (x, y) |--> u(x, y)*v(x, y)
321
+ sage: f.expr()
322
+ u(x, y)*v(x, y)
323
+
324
+ We revert to the default behavior by::
325
+
326
+ sage: Manifold.options._reset()
327
+ sage: f
328
+ u(x, y)*v(x, y)
329
+
330
+ .. automethod:: __call__
331
+ """
332
+
333
+ def __init__(
334
+ self,
335
+ parent,
336
+ expression=None,
337
+ calc_method=None,
338
+ expansion_symbol=None,
339
+ order=None,
340
+ ):
341
+ r"""
342
+ Initialize ``self``.
343
+
344
+ TESTS:
345
+
346
+ Chart function on a real manifold::
347
+
348
+ sage: M = Manifold(2, 'M', structure='topological')
349
+ sage: X.<x,y> = M.chart()
350
+ sage: f = X.function(x^3+y); f
351
+ x^3 + y
352
+ sage: type(f)
353
+ <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
354
+ sage: TestSuite(f).run()
355
+
356
+ Using SymPy::
357
+
358
+ sage: X.calculus_method().set('sympy')
359
+ sage: f = X.function(x^3+y)
360
+ sage: f
361
+ x**3 + y
362
+ sage: TestSuite(f).run()
363
+
364
+ Chart function on a complex manifold::
365
+
366
+ sage: N = Manifold(2, 'N', structure='topological', field='complex')
367
+ sage: Y.<z,w> = N.chart()
368
+ sage: g = Y.function(i*z + 2*w); g
369
+ 2*w + I*z
370
+ sage: TestSuite(g).run()
371
+ """
372
+ ModuleElementWithMutability.__init__(self, parent)
373
+ self._chart = parent._chart
374
+ self._nc = len(self._chart[:])
375
+ self._express = {}
376
+ # set the calculation method managing
377
+ self._calc_method = self._chart._calc_method
378
+ if expression is not None:
379
+ if calc_method is None:
380
+ calc_method = self._calc_method._current
381
+ self._express[calc_method] = self._calc_method._tranf[calc_method](
382
+ expression
383
+ )
384
+ # Derived quantities:
385
+ self._der = None # list of partial derivatives (to be set by diff()
386
+ # and unset by del_derived())
387
+ self._expansion_symbol = expansion_symbol
388
+ self._order = order
389
+
390
+ def _simplify(self, expr):
391
+ """
392
+ Simplify the expression `expr` using `self._calc_method.simplify`.
393
+
394
+ If needed, truncate the expression to the predefined order in the
395
+ power series with respect to a small parameter.
396
+
397
+ INPUT:
398
+
399
+ - ``expr`` -- expression to simplify
400
+
401
+ OUTPUT: simplified expression
402
+
403
+ EXAMPLES:
404
+
405
+ sage: M = Manifold(2, 'M', structure='topological')
406
+ sage: c_xy.<x,y> = M.chart()
407
+ sage: fc = c_xy.function(x+2*y^3)
408
+ sage: fc._simplify(x+x)
409
+ 2*x
410
+ """
411
+ res = self._calc_method.simplify(expr)
412
+ if self._expansion_symbol is not None and self._calc_method._current == 'SR':
413
+ res = res.series(self._expansion_symbol, self._order + 1).truncate()
414
+ return res
415
+
416
+ def chart(self):
417
+ r"""
418
+ Return the chart with respect to which ``self`` is defined.
419
+
420
+ OUTPUT: a :class:`~sage.manifolds.chart.Chart`
421
+
422
+ EXAMPLES::
423
+
424
+ sage: M = Manifold(2, 'M', structure='topological')
425
+ sage: X.<x,y> = M.chart()
426
+ sage: f = X.function(1+x+y^2)
427
+ sage: f.chart()
428
+ Chart (M, (x, y))
429
+ sage: f.chart() is X
430
+ True
431
+ """
432
+ return self._chart
433
+
434
+ def scalar_field(self, name=None, latex_name=None):
435
+ r"""
436
+ Construct the scalar field that has ``self`` as coordinate expression.
437
+
438
+ The domain of the scalar field is the open subset covered by the
439
+ chart on which ``self`` is defined.
440
+
441
+ INPUT:
442
+
443
+ - ``name`` -- (default: ``None``) name given to the scalar field
444
+
445
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
446
+ scalar field; if ``None``, the LaTeX symbol is set to ``name``
447
+
448
+ OUTPUT: a :class:`~sage.manifolds.scalarfield.ScalarField`
449
+
450
+ EXAMPLES:
451
+
452
+ Construction of a scalar field on a 2-dimensional manifold::
453
+
454
+ sage: M = Manifold(2, 'M', structure='topological')
455
+ sage: c_xy.<x,y> = M.chart()
456
+ sage: fc = c_xy.function(x+2*y^3)
457
+ sage: f = fc.scalar_field() ; f
458
+ Scalar field on the 2-dimensional topological manifold M
459
+ sage: f.display()
460
+ M → ℝ
461
+ (x, y) ↦ 2*y^3 + x
462
+ sage: f.coord_function(c_xy) is fc
463
+ True
464
+ """
465
+ alg = self._chart.domain().scalar_field_algebra()
466
+ return alg.element_class(
467
+ alg, coord_expression={self._chart: self}, name=name, latex_name=latex_name
468
+ )
469
+
470
+ def expr(self, method=None):
471
+ r"""
472
+ Return the symbolic expression of ``self`` in terms of the chart
473
+ coordinates, as an object of a specified calculus method.
474
+
475
+ INPUT:
476
+
477
+ - ``method`` -- string (default: ``None``); the calculus method which
478
+ the returned expression belongs to. One of
479
+
480
+ - ``'SR'``: Sage's default symbolic engine (Symbolic Ring)
481
+ - ``'sympy'``: SymPy
482
+ - ``None``: the chart current calculus method is assumed
483
+
484
+ OUTPUT:
485
+
486
+ - a :class:`Sage symbolic expression <sage.symbolic.expression.Expression>`
487
+ if ``method`` is ``'SR'``
488
+ - a SymPy object if ``method`` is ``'sympy'``
489
+
490
+ EXAMPLES:
491
+
492
+ Chart function on a 2-dimensional manifold::
493
+
494
+ sage: M = Manifold(2, 'M', structure='topological')
495
+ sage: X.<x,y> = M.chart()
496
+ sage: f = X.function(x^2+y)
497
+ sage: f.expr()
498
+ x^2 + y
499
+ sage: type(f.expr())
500
+ <class 'sage.symbolic.expression.Expression'>
501
+
502
+ Asking for the SymPy expression::
503
+
504
+ sage: f.expr('sympy')
505
+ x**2 + y
506
+ sage: type(f.expr('sympy'))
507
+ <class 'sympy.core.add.Add'>
508
+
509
+ The default corresponds to the current calculus method, here the one
510
+ based on the Symbolic Ring ``SR``::
511
+
512
+ sage: f.expr() is f.expr('SR')
513
+ True
514
+
515
+ If we change the current calculus method on chart ``X``, we change the
516
+ default::
517
+
518
+ sage: X.calculus_method().set('sympy')
519
+ sage: f.expr()
520
+ x**2 + y
521
+ sage: f.expr() is f.expr('sympy')
522
+ True
523
+ sage: X.calculus_method().set('SR') # revert back to SR
524
+
525
+ Internally, the expressions corresponding to various calculus methods
526
+ are stored in the dictionary ``_express``::
527
+
528
+ sage: for method in sorted(f._express):
529
+ ....: print("'{}': {}".format(method, f._express[method]))
530
+ ....:
531
+ 'SR': x^2 + y
532
+ 'sympy': x**2 + y
533
+
534
+ The method :meth:`expr` is useful for accessing to all the
535
+ symbolic expression functionalities in Sage; for instance::
536
+
537
+ sage: var('a')
538
+ a
539
+ sage: f = X.function(a*x*y); f.display()
540
+ (x, y) ↦ a*x*y
541
+ sage: f.expr()
542
+ a*x*y
543
+ sage: f.expr().subs(a=2)
544
+ 2*x*y
545
+
546
+ Note that for substituting the value of a coordinate, the function
547
+ call can be used as well::
548
+
549
+ sage: f(x,3)
550
+ 3*a*x
551
+ sage: bool( f(x,3) == f.expr().subs(y=3) )
552
+ True
553
+ """
554
+ if method is None:
555
+ method = self._calc_method._current
556
+ if method in self._express:
557
+ return self._express[method]
558
+ else:
559
+ for vv in self._express.values():
560
+ try:
561
+ self._express[method] = self._calc_method._tranf[method](vv)
562
+ return self._express[method]
563
+ except (KeyError, ValueError):
564
+ pass
565
+ raise ValueError("no expression found for converting to {}".format(method))
566
+
567
+ def set_expr(self, calc_method, expression):
568
+ r"""
569
+ Add an expression in a particular calculus method ``self``.
570
+ Some control is done to verify the consistency between the
571
+ different representations of the same expression.
572
+
573
+ INPUT:
574
+
575
+ - ``calc_method`` -- calculus method
576
+
577
+ - ``expression`` -- symbolic expression
578
+
579
+ EXAMPLES::
580
+
581
+ sage: M = Manifold(2, 'M', structure='topological')
582
+ sage: X.<x,y> = M.chart()
583
+ sage: f = X.function(1+x^2)
584
+ sage: f._repr_()
585
+ 'x^2 + 1'
586
+ sage: f.set_expr('sympy','x**2+1')
587
+ sage: f # indirect doctest
588
+ x^2 + 1
589
+
590
+ sage: g = X.function(1+x^3)
591
+ sage: g._repr_()
592
+ 'x^3 + 1'
593
+ sage: g.set_expr('sympy','x**2+y')
594
+ Traceback (most recent call last):
595
+ ...
596
+ ValueError: Expressions are not equal
597
+ """
598
+ if self.is_immutable():
599
+ raise ValueError(
600
+ "the expressions of an immutable element cannot be changed"
601
+ )
602
+ for vv in self._express.values():
603
+ if not bool(
604
+ self._calc_method._tranf[calc_method](expression)
605
+ == self._calc_method._tranf[calc_method](vv)
606
+ ):
607
+ raise ValueError("Expressions are not equal")
608
+ self._express[calc_method] = expression
609
+
610
+ def _repr_(self):
611
+ r"""
612
+ String representation of ``self``.
613
+
614
+ TESTS::
615
+
616
+ sage: M = Manifold(2, 'M', structure='topological')
617
+ sage: X.<x,y> = M.chart()
618
+ sage: f = X.function(1+x*y)
619
+ sage: f._repr_()
620
+ 'x*y + 1'
621
+ sage: repr(f) # indirect doctest
622
+ 'x*y + 1'
623
+ sage: f # indirect doctest
624
+ x*y + 1
625
+ """
626
+ curr = self._calc_method._current
627
+ if curr == 'SR' and self._chart.manifold().options.textbook_output:
628
+ return str(ExpressionNice(self.expr(curr)))
629
+ else:
630
+ return str(self.expr(curr))
631
+
632
+ def _latex_(self):
633
+ r"""
634
+ LaTeX representation of ``self``.
635
+
636
+ TESTS::
637
+
638
+ sage: M = Manifold(2, 'M', structure='topological')
639
+ sage: X.<x,y> = M.chart()
640
+ sage: f = X.function(cos(x*y/2))
641
+ sage: f._latex_()
642
+ \cos\left(\frac{1}{2} \, x y\right)
643
+ sage: latex(f) # indirect doctest
644
+ \cos\left(\frac{1}{2} \, x y\right)
645
+ """
646
+ curr = self._calc_method._current
647
+ if curr == 'SR' and self._chart.manifold().options.textbook_output:
648
+ out_expr = ExpressionNice(self._express[curr])
649
+ else:
650
+ out_expr = self._express[curr]
651
+ return self._calc_method._latex_dict[curr](out_expr)
652
+
653
+ def display(self):
654
+ r"""
655
+ Display ``self`` in arrow notation.
656
+ For display the standard ``SR`` representation is used.
657
+
658
+ The output is either text-formatted (console mode) or
659
+ LaTeX-formatted (notebook mode).
660
+
661
+ EXAMPLES:
662
+
663
+ Coordinate function on a 2-dimensional manifold::
664
+
665
+ sage: M = Manifold(2, 'M', structure='topological')
666
+ sage: X.<x,y> = M.chart()
667
+ sage: f = X.function(cos(x*y/2))
668
+ sage: f.display()
669
+ (x, y) ↦ cos(1/2*x*y)
670
+ sage: latex(f.display())
671
+ \left(x, y\right) \mapsto \cos\left(\frac{1}{2} \, x y\right)
672
+
673
+ A shortcut is ``disp()``::
674
+
675
+ sage: f.disp()
676
+ (x, y) ↦ cos(1/2*x*y)
677
+
678
+ Display of the zero function::
679
+
680
+ sage: X.zero_function().display()
681
+ (x, y) ↦ 0
682
+ """
683
+ from sage.tensor.modules.format_utilities import FormattedExpansion
684
+ from sage.typeset.unicode_characters import unicode_mapsto
685
+
686
+ curr = self._calc_method._current
687
+ expr = self.expr(curr)
688
+ if curr == 'SR' and self._chart.manifold().options.textbook_output:
689
+ expr = ExpressionNice(expr)
690
+ latex_func = self._calc_method._latex_dict[curr]
691
+ resu_txt = str(self._chart[:]) + ' ' + unicode_mapsto + ' ' + str(expr)
692
+ resu_latex = latex_func(self._chart[:]) + r' \mapsto ' + latex_func(expr)
693
+ return FormattedExpansion(resu_txt, resu_latex)
694
+
695
+ disp = display
696
+
697
+ def __call__(self, *coords, **options):
698
+ r"""
699
+ Compute the value of the function at specified coordinates.
700
+
701
+ INPUT:
702
+
703
+ - ``*coords`` -- list of coordinates `(x^1, \ldots, x^n)`,
704
+ where the function `f` is to be evaluated
705
+ - ``**options`` -- allows to pass ``simplify=False`` to disable the
706
+ call of the simplification chain on the result
707
+
708
+ OUTPUT:
709
+
710
+ - the value `f(x^1, \ldots, x^n)`, where `f` is the current
711
+ chart function
712
+
713
+ EXAMPLES::
714
+
715
+ sage: M = Manifold(2, 'M', structure='topological')
716
+ sage: X.<x,y> = M.chart()
717
+ sage: f = X.function(sin(x*y))
718
+ sage: f.__call__(-2, 3)
719
+ -sin(6)
720
+ sage: f(-2, 3)
721
+ -sin(6)
722
+ sage: var('a b')
723
+ (a, b)
724
+ sage: f.__call__(a, b)
725
+ sin(a*b)
726
+ sage: f(a,b)
727
+ sin(a*b)
728
+ sage: f.__call__(pi, 1)
729
+ 0
730
+ sage: f.__call__(pi, 1/2)
731
+ 1
732
+
733
+ With SymPy::
734
+
735
+ sage: X.calculus_method().set('sympy')
736
+ sage: f(-2,3)
737
+ -sin(6)
738
+ sage: type(f(-2,3))
739
+ <class 'sympy.core.mul.Mul'>
740
+ sage: f(a,b)
741
+ sin(a*b)
742
+ sage: type(f(a,b))
743
+ sin
744
+ sage: type(f(pi,1))
745
+ <class 'sympy.core.numbers.Zero'>
746
+ sage: f(pi, 1/2)
747
+ 1
748
+ sage: type(f(pi, 1/2))
749
+ <class 'sympy.core.numbers.One'>
750
+ """
751
+ if len(coords) != self._nc:
752
+ raise ValueError("bad number of coordinates")
753
+ calc = self._calc_method
754
+ curr = calc._current
755
+ if curr == 'SR':
756
+ xx = self._chart._xx
757
+ co = [calc._tranf['SR'](c) for c in coords]
758
+ elif curr == 'sympy':
759
+ xx = [x._sympy_() for x in self._chart._xx]
760
+ co = [calc._tranf['sympy'](c) for c in coords]
761
+ substitutions = dict(zip(xx, co))
762
+ resu = self.expr(curr).subs(substitutions)
763
+ if 'simplify' in options:
764
+ if options['simplify']:
765
+ return calc.simplify(resu, method=curr)
766
+ else:
767
+ return resu
768
+ else:
769
+ return calc.simplify(resu, method=curr)
770
+
771
+ def __bool__(self):
772
+ r"""
773
+ Return ``True`` if ``self`` is nonzero and ``False`` otherwise.
774
+
775
+ This method is called by :meth:`~sage.structure.element.Element.is_zero()`.
776
+
777
+ EXAMPLES:
778
+
779
+ Coordinate functions associated to a 2-dimensional chart::
780
+
781
+ sage: M = Manifold(2, 'M', structure='topological')
782
+ sage: X.<x,y> = M.chart()
783
+ sage: f = X.function(x^2+3*y+1)
784
+ sage: bool(f)
785
+ True
786
+ sage: f.is_zero()
787
+ False
788
+ sage: f == 0
789
+ False
790
+ sage: g = X.function(0)
791
+ sage: bool(g)
792
+ False
793
+ sage: g.is_zero()
794
+ True
795
+ sage: X.calculus_method().set('sympy')
796
+ sage: g.is_zero()
797
+ True
798
+ sage: g == 0
799
+ True
800
+ sage: X.zero_function().is_zero()
801
+ True
802
+ sage: X.zero_function() == 0
803
+ True
804
+ """
805
+ curr = self._calc_method._current
806
+ if curr == 'SR':
807
+ val = self.expr(curr).is_zero()
808
+ elif curr == 'sympy':
809
+ val = self.expr(curr).is_zero
810
+ return not val
811
+
812
+ def is_trivial_zero(self):
813
+ r"""
814
+ Check if ``self`` is trivially equal to zero without any
815
+ simplification.
816
+
817
+ This method is supposed to be fast as compared with
818
+ ``self.is_zero()`` or ``self == 0`` and is intended to be
819
+ used in library code where trying to obtain a mathematically
820
+ correct result by applying potentially expensive rewrite rules
821
+ is not desirable.
822
+
823
+ EXAMPLES::
824
+
825
+ sage: M = Manifold(2, 'M', structure='topological')
826
+ sage: X.<x,y> = M.chart()
827
+ sage: f = X.function(0)
828
+ sage: f.is_trivial_zero()
829
+ True
830
+ sage: f = X.function(float(0.0))
831
+ sage: f.is_trivial_zero()
832
+ True
833
+ sage: f = X.function(x-x)
834
+ sage: f.is_trivial_zero()
835
+ True
836
+ sage: X.zero_function().is_trivial_zero()
837
+ True
838
+
839
+ No simplification is attempted, so that ``False`` is returned for
840
+ non-trivial cases::
841
+
842
+ sage: f = X.function(cos(x)^2 + sin(x)^2 - 1)
843
+ sage: f.is_trivial_zero()
844
+ False
845
+
846
+ On the contrary, the method
847
+ :meth:`~sage.structure.element.Element.is_zero` and the direct
848
+ comparison to zero involve some simplification algorithms and
849
+ return ``True``::
850
+
851
+ sage: f.is_zero()
852
+ True
853
+ sage: f == 0
854
+ True
855
+ """
856
+ curr = self._calc_method._current
857
+ return self._calc_method.is_trivial_zero(self.expr(curr))
858
+
859
+ def is_trivial_one(self):
860
+ r"""
861
+ Check if ``self`` is trivially equal to one without any
862
+ simplification.
863
+
864
+ This method is supposed to be fast as compared with
865
+ ``self == 1`` and is intended to be used in library code where
866
+ trying to obtain a mathematically correct result by applying
867
+ potentially expensive rewrite rules is not desirable.
868
+
869
+ EXAMPLES::
870
+
871
+ sage: M = Manifold(2, 'M', structure='topological')
872
+ sage: X.<x,y> = M.chart()
873
+ sage: f = X.function(1)
874
+ sage: f.is_trivial_one()
875
+ True
876
+ sage: f = X.function(float(1.0))
877
+ sage: f.is_trivial_one()
878
+ True
879
+ sage: f = X.function(x-x+1)
880
+ sage: f.is_trivial_one()
881
+ True
882
+ sage: X.one_function().is_trivial_one()
883
+ True
884
+
885
+ No simplification is attempted, so that ``False`` is returned for
886
+ non-trivial cases::
887
+
888
+ sage: f = X.function(cos(x)^2 + sin(x)^2)
889
+ sage: f.is_trivial_one()
890
+ False
891
+
892
+ On the contrary, the method
893
+ :meth:`~sage.structure.element.Element.is_zero` and the direct
894
+ comparison to one involve some simplification algorithms and
895
+ return ``True``::
896
+
897
+ sage: (f - 1).is_zero()
898
+ True
899
+ sage: f == 1
900
+ True
901
+ """
902
+ curr = self._calc_method._current
903
+ return self._calc_method.is_trivial_zero(self.expr(curr) - SR.one())
904
+
905
+ # TODO: Remove this method as soon as issue #28629 is solved?
906
+ def is_unit(self):
907
+ r"""
908
+ Return ``True`` iff ``self`` is not trivially zero since most chart
909
+ functions are invertible and an actual computation would take too much
910
+ time.
911
+
912
+ EXAMPLES::
913
+
914
+ sage: M = Manifold(2, 'M', structure='topological')
915
+ sage: X.<x,y> = M.chart()
916
+ sage: f = X.function(x^2+3*y+1)
917
+ sage: f.is_unit()
918
+ True
919
+ sage: zero = X.function(0)
920
+ sage: zero.is_unit()
921
+ False
922
+ """
923
+ return not self.is_trivial_zero()
924
+
925
+ def copy(self):
926
+ r"""
927
+ Return an exact copy of the object.
928
+
929
+ OUTPUT: a :class:`ChartFunctionSymb`
930
+
931
+ EXAMPLES::
932
+
933
+ sage: M = Manifold(2, 'M', structure='topological')
934
+ sage: X.<x,y> = M.chart()
935
+ sage: f = X.function(x+y^2)
936
+ sage: g = f.copy(); g
937
+ y^2 + x
938
+
939
+ By construction, ``g`` is identical to ``f``::
940
+
941
+ sage: type(g) == type(f)
942
+ True
943
+ sage: g == f
944
+ True
945
+
946
+ but it is not the same object::
947
+
948
+ sage: g is f
949
+ False
950
+ """
951
+ resu = type(self)(self.parent())
952
+ for kk, vv in self._express.items():
953
+ resu._express[kk] = vv
954
+ resu._expansion_symbol = self._expansion_symbol
955
+ resu._order = self._order
956
+ return resu
957
+
958
+ def derivative(self, coord):
959
+ r"""
960
+ Partial derivative with respect to a coordinate.
961
+
962
+ INPUT:
963
+
964
+ - ``coord`` -- either the coordinate `x^i` with respect
965
+ to which the derivative of the chart function `f` is to be
966
+ taken, or the index `i` labelling this coordinate (with the
967
+ index convention defined on the chart domain via the parameter
968
+ ``start_index``)
969
+
970
+ OUTPUT:
971
+
972
+ - a :class:`ChartFunction` representing the partial
973
+ derivative `\frac{\partial f}{\partial x^i}`
974
+
975
+ EXAMPLES:
976
+
977
+ Partial derivatives of a 2-dimensional chart function::
978
+
979
+ sage: M = Manifold(2, 'M', structure='topological')
980
+ sage: X.<x,y> = M.chart(calc_method='SR')
981
+ sage: f = X.function(x^2+3*y+1); f
982
+ x^2 + 3*y + 1
983
+ sage: f.derivative(x)
984
+ 2*x
985
+ sage: f.derivative(y)
986
+ 3
987
+
988
+ An alias is ``diff``::
989
+
990
+ sage: f.diff(x)
991
+ 2*x
992
+
993
+ Each partial derivative is itself a chart function::
994
+
995
+ sage: type(f.diff(x))
996
+ <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
997
+
998
+ The same result is returned by the function ``diff``::
999
+
1000
+ sage: diff(f, x)
1001
+ 2*x
1002
+
1003
+ An index can be used instead of the coordinate symbol::
1004
+
1005
+ sage: f.diff(0)
1006
+ 2*x
1007
+ sage: diff(f, 1)
1008
+ 3
1009
+
1010
+ The index range depends on the convention used on the chart's domain::
1011
+
1012
+ sage: M = Manifold(2, 'M', structure='topological', start_index=1)
1013
+ sage: X.<x,y> = M.chart()
1014
+ sage: f = X.function(x^2+3*y+1)
1015
+ sage: f.diff(0)
1016
+ Traceback (most recent call last):
1017
+ ...
1018
+ ValueError: coordinate index out of range
1019
+ sage: f.diff(1)
1020
+ 2*x
1021
+ sage: f.diff(2)
1022
+ 3
1023
+
1024
+ The same test with SymPy::
1025
+
1026
+ sage: M = Manifold(2, 'M', structure='topological')
1027
+ sage: X.<x,y> = M.chart(calc_method='sympy')
1028
+ sage: f = X.function(x^2+3*y+1); f
1029
+ x**2 + 3*y + 1
1030
+ sage: f.diff(x)
1031
+ 2*x
1032
+ sage: f.diff(y)
1033
+ 3
1034
+ """
1035
+ from sage.calculus.functional import diff
1036
+ from sage.rings.integer import Integer
1037
+
1038
+ if self._der is None:
1039
+ # the list of partial derivatives has to be updated
1040
+ curr = self._calc_method._current
1041
+ if curr == 'SR':
1042
+ self._der = [
1043
+ type(self)(
1044
+ self.parent(),
1045
+ self._simplify(diff(self.expr(), xx)),
1046
+ expansion_symbol=self._expansion_symbol,
1047
+ order=self._order,
1048
+ )
1049
+ for xx in self._chart[:]
1050
+ ]
1051
+ elif curr == 'sympy':
1052
+ self._der = [
1053
+ type(self)(
1054
+ self.parent(),
1055
+ self._simplify(sympy.diff(self.expr(), xx._sympy_())),
1056
+ )
1057
+ for xx in self._chart[:]
1058
+ ]
1059
+ if isinstance(coord, (int, Integer)):
1060
+ # NB: for efficiency, we access directly to the "private" attributes
1061
+ # of other classes. A more conventional OOP writing would be
1062
+ # coordsi = coord - self._chart.domain().start_index()
1063
+ coordsi = coord - self._chart.domain()._sindex
1064
+ if coordsi < 0 or coordsi >= self._nc:
1065
+ raise ValueError("coordinate index out of range")
1066
+ return self._der[coordsi]
1067
+ else:
1068
+ return self._der[self._chart[:].index(coord)]
1069
+
1070
+ diff = derivative
1071
+
1072
+ def __eq__(self, other):
1073
+ r"""
1074
+ Comparison (equality) operator.
1075
+
1076
+ INPUT:
1077
+
1078
+ - ``other`` -- a :class:`ChartFunction` or a value
1079
+
1080
+ OUTPUT: ``True`` if ``self`` is equal to ``other``, or ``False`` otherwise
1081
+
1082
+ TESTS:
1083
+
1084
+ Coordinate functions associated to a 2-dimensional chart::
1085
+
1086
+ sage: M = Manifold(2, 'M', structure='topological')
1087
+ sage: X.<x,y> = M.chart()
1088
+ sage: f = X.function(x+y^2)
1089
+ sage: g = X.function(x+y^2)
1090
+ sage: f == g
1091
+ True
1092
+ sage: f = X.function(x+y^2)
1093
+ sage: g = X.function(x+y**2,'sympy')
1094
+ sage: f._express; g._express
1095
+ {'SR': y^2 + x}
1096
+ {'sympy': x + y**2}
1097
+ sage: f == g
1098
+ True
1099
+ sage: f == 1
1100
+ False
1101
+ sage: h = X.function(1)
1102
+ sage: h == 1
1103
+ True
1104
+ sage: h == f
1105
+ False
1106
+ sage: h == 0
1107
+ False
1108
+ sage: X.function(0) == 0
1109
+ True
1110
+ sage: X.zero_function() == 0
1111
+ True
1112
+ """
1113
+ if other is self:
1114
+ return True
1115
+ if isinstance(other, ChartFunction):
1116
+ if other.parent() != self.parent():
1117
+ return False
1118
+ else:
1119
+ if self._calc_method._current in self._express:
1120
+ method = self._calc_method._current
1121
+ else:
1122
+ method = list(self._express)[0] # pick a random method
1123
+ # other.expr(method)
1124
+ if method == 'sympy':
1125
+ return bool(
1126
+ sympy.simplify(other.expr(method) - self.expr(method)) == 0
1127
+ )
1128
+ return bool(other.expr(method) == self.expr(method))
1129
+ else:
1130
+ return bool(self.expr(self._calc_method._current) == other)
1131
+
1132
+ def __ne__(self, other):
1133
+ r"""
1134
+ Inequality operator.
1135
+
1136
+ INPUT:
1137
+
1138
+ - ``other`` -- a :class:`ChartFunction`
1139
+
1140
+ OUTPUT:
1141
+
1142
+ - ``True`` if ``self`` is different from ``other``, ``False``
1143
+ otherwise
1144
+
1145
+ TESTS::
1146
+
1147
+ sage: M = Manifold(2, 'M', structure='topological')
1148
+ sage: X.<x,y> = M.chart()
1149
+ sage: f = X.function(x-y)
1150
+ sage: f != X.function(x*y)
1151
+ True
1152
+ sage: f != X.function(x)
1153
+ True
1154
+ sage: f != X.function(x-y)
1155
+ False
1156
+ """
1157
+ return not (self == other)
1158
+
1159
+ def __neg__(self):
1160
+ r"""
1161
+ Unary minus operator.
1162
+
1163
+ OUTPUT: the opposite of ``self``
1164
+
1165
+ TESTS:
1166
+
1167
+ Coordinate functions associated to a 2-dimensional chart::
1168
+
1169
+ sage: M = Manifold(2, 'M', structure='topological')
1170
+ sage: X.<x,y> = M.chart(calc_method='sympy')
1171
+ sage: f = X.function(x+y^2)
1172
+ sage: g = -f; g
1173
+ -x - y**2
1174
+ sage: type(g)
1175
+ <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
1176
+ sage: -g == f
1177
+ True
1178
+ """
1179
+ curr = self._calc_method._current
1180
+ resu = type(self)(self.parent())
1181
+ resu._express[curr] = self._simplify(-self.expr())
1182
+ resu._order = self._order
1183
+ resu._expansion_symbol = self._expansion_symbol
1184
+ return resu
1185
+
1186
+ def __invert__(self):
1187
+ r"""
1188
+ Inverse operator.
1189
+
1190
+ If `f` denotes the current chart function and `K` the topological
1191
+ field over which the manifold is defined, the *inverse* of `f` is the
1192
+ chart function `1/f`, where `1` of the multiplicative identity
1193
+ of `K`.
1194
+
1195
+ OUTPUT: the inverse of ``self``
1196
+
1197
+ TESTS:
1198
+
1199
+ Coordinate functions associated to a 2-dimensional chart::
1200
+
1201
+ sage: M = Manifold(2, 'M', structure='topological')
1202
+ sage: X.<x,y> = M.chart()
1203
+ sage: f = X.function(1+x^2+y^2)
1204
+ sage: g = f.__invert__(); g
1205
+ 1/(x^2 + y^2 + 1)
1206
+ sage: type(g)
1207
+ <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
1208
+ sage: g == ~f
1209
+ True
1210
+ sage: g.__invert__() == f
1211
+ True
1212
+
1213
+ The same test with SymPy::
1214
+
1215
+ sage: M = Manifold(2, 'M', structure='topological')
1216
+ sage: X.<x,y> = M.chart(calc_method='sympy')
1217
+ sage: f = X.function(1+x^2+y^2)
1218
+ sage: g = f.__invert__(); g
1219
+ 1/(x**2 + y**2 + 1)
1220
+ sage: type(g)
1221
+ <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
1222
+ sage: g == ~f
1223
+ True
1224
+ sage: g.__invert__() == f
1225
+ True
1226
+ """
1227
+ curr = self._calc_method._current
1228
+ if curr == 'SR':
1229
+ return type(self)(
1230
+ self.parent(),
1231
+ calc_method='SR',
1232
+ expression=self._simplify(SR.one() / self.expr()),
1233
+ )
1234
+ # NB: self._express.__invert__() would return 1/self._express
1235
+ # (cf. the code of __invert__ in src/sage/symbolic/expression.pyx)
1236
+ # Here we prefer SR(1)/self._express
1237
+ return type(self)(
1238
+ self.parent(),
1239
+ calc_method=curr,
1240
+ expression=self._simplify(1 / self.expr()),
1241
+ expansion_symbol=self._expansion_symbol,
1242
+ order=self._order,
1243
+ )
1244
+
1245
+ def _add_(self, other):
1246
+ r"""
1247
+ Addition operator.
1248
+
1249
+ INPUT:
1250
+
1251
+ - ``other`` -- a :class:`ChartFunction` or a value
1252
+
1253
+ OUTPUT:
1254
+
1255
+ - chart function resulting from the addition of ``self``
1256
+ and ``other``
1257
+
1258
+ TESTS::
1259
+
1260
+ sage: M = Manifold(2, 'M', structure='topological')
1261
+ sage: X.<x,y> = M.chart(calc_method='SR')
1262
+
1263
+ sage: f = X.function(x+y^2)
1264
+ sage: g = X.function(x+1)
1265
+ sage: s = f + g; s.display()
1266
+ (x, y) ↦ y^2 + 2*x + 1
1267
+ sage: type(s)
1268
+ <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
1269
+ sage: (f + 0).display()
1270
+ (x, y) ↦ y^2 + x
1271
+ sage: (f + X.zero_function()).display()
1272
+ (x, y) ↦ y^2 + x
1273
+ sage: (f + 1).display()
1274
+ (x, y) ↦ y^2 + x + 1
1275
+ sage: (f + pi).display()
1276
+ (x, y) ↦ pi + y^2 + x
1277
+ sage: (f + x).display()
1278
+ (x, y) ↦ y^2 + 2*x
1279
+ sage: (f + -f).display()
1280
+ (x, y) ↦ 0
1281
+
1282
+ The same test with SymPy::
1283
+
1284
+ sage: X.calculus_method().set('sympy')
1285
+ sage: f = X.function(x+y^2)
1286
+ sage: g = X.function(x+1)
1287
+ sage: s = f + g; s.display()
1288
+ (x, y) ↦ 2*x + y**2 + 1
1289
+ sage: (f + 0).display()
1290
+ (x, y) ↦ x + y**2
1291
+ sage: (f + X.zero_function()).display()
1292
+ (x, y) ↦ x + y**2
1293
+ sage: (f + 1).display()
1294
+ (x, y) ↦ x + y**2 + 1
1295
+ sage: (f + pi).display()
1296
+ (x, y) ↦ x + y**2 + pi
1297
+ sage: (f + x).display()
1298
+ (x, y) ↦ 2*x + y**2
1299
+ sage: (f + -f).display()
1300
+ (x, y) ↦ 0
1301
+ """
1302
+ curr = self._calc_method._current
1303
+ if other._expansion_symbol is not None:
1304
+ res = other._simplify(self.expr() + other.expr())
1305
+ else:
1306
+ res = self._simplify(self.expr() + other.expr())
1307
+ if curr == 'SR' and res.is_trivial_zero():
1308
+ # NB: "if res == 0" would be too expensive (cf. #22859)
1309
+ return self.parent().zero()
1310
+ if other._expansion_symbol is not None:
1311
+ return type(self)(
1312
+ self.parent(),
1313
+ res,
1314
+ expansion_symbol=other._expansion_symbol,
1315
+ order=other._order,
1316
+ )
1317
+ else:
1318
+ return type(self)(
1319
+ self.parent(),
1320
+ res,
1321
+ expansion_symbol=self._expansion_symbol,
1322
+ order=self._order,
1323
+ )
1324
+
1325
+ def _sub_(self, other):
1326
+ r"""
1327
+ Subtraction operator.
1328
+
1329
+ INPUT:
1330
+
1331
+ - ``other`` -- a :class:`ChartFunction` or a value
1332
+
1333
+ OUTPUT:
1334
+
1335
+ - chart function resulting from the subtraction of ``other``
1336
+ from ``self``
1337
+
1338
+ TESTS::
1339
+
1340
+ sage: M = Manifold(2, 'M', structure='topological')
1341
+ sage: X.<x,y> = M.chart()
1342
+ sage: f = X.function(x+y^2)
1343
+ sage: g = X.function(x+1)
1344
+ sage: s = f - g; s.display()
1345
+ (x, y) ↦ y^2 - 1
1346
+ sage: type(s)
1347
+ <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
1348
+ sage: (f - 0).display()
1349
+ (x, y) ↦ y^2 + x
1350
+ sage: (f - X.zero_function()).display()
1351
+ (x, y) ↦ y^2 + x
1352
+ sage: (f - 1).display()
1353
+ (x, y) ↦ y^2 + x - 1
1354
+ sage: (f - x).display()
1355
+ (x, y) ↦ y^2
1356
+ sage: (f - pi).display()
1357
+ (x, y) ↦ -pi + y^2 + x
1358
+ sage: (f - f).display()
1359
+ (x, y) ↦ 0
1360
+ sage: (f - g) == -(g - f)
1361
+ True
1362
+
1363
+ Tests with SymPy::
1364
+
1365
+ sage: X.calculus_method().set('sympy')
1366
+ sage: h = X.function(2*(x+y^2))
1367
+ sage: s = h - f
1368
+ sage: s.display()
1369
+ (x, y) ↦ x + y**2
1370
+ sage: s.expr()
1371
+ x + y**2
1372
+ """
1373
+ curr = self._calc_method._current
1374
+ if other._expansion_symbol is not None:
1375
+ res = other._simplify(self.expr() - other.expr())
1376
+ else:
1377
+ res = self._simplify(self.expr() - other.expr())
1378
+ if curr == 'SR' and res.is_trivial_zero():
1379
+ # NB: "if res == 0" would be too expensive (cf. #22859)
1380
+ return self.parent().zero()
1381
+ if other._expansion_symbol is not None:
1382
+ return type(self)(
1383
+ self.parent(),
1384
+ res,
1385
+ expansion_symbol=other._expansion_symbol,
1386
+ order=other._order,
1387
+ )
1388
+ else:
1389
+ return type(self)(
1390
+ self.parent(),
1391
+ res,
1392
+ expansion_symbol=self._expansion_symbol,
1393
+ order=self._order,
1394
+ )
1395
+
1396
+ def _mul_(self, other):
1397
+ r"""
1398
+ Multiplication operator.
1399
+
1400
+ INPUT:
1401
+
1402
+ - ``other`` -- a :class:`ChartFunction` or a value
1403
+
1404
+ OUTPUT:
1405
+
1406
+ - chart function resulting from the multiplication of ``self``
1407
+ by ``other``
1408
+
1409
+ TESTS::
1410
+
1411
+ sage: M = Manifold(2, 'M', structure='topological')
1412
+ sage: X.<x,y> = M.chart()
1413
+ sage: f = X.function(x+y)
1414
+ sage: g = X.function(x-y)
1415
+ sage: s = f._mul_(g); s.display()
1416
+ (x, y) ↦ x^2 - y^2
1417
+ sage: type(s)
1418
+ <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
1419
+ sage: (f * 0).display()
1420
+ (x, y) ↦ 0
1421
+ sage: (f * X.zero_function()).display()
1422
+ (x, y) ↦ 0
1423
+ sage: (f * (1/f)).display()
1424
+ (x, y) ↦ 1
1425
+
1426
+ The same test with SymPy::
1427
+
1428
+ sage: X.calculus_method().set('sympy')
1429
+ sage: f = X.function(x+y)
1430
+ sage: g = X.function(x-y)
1431
+ sage: s = f._mul_(g); s.expr()
1432
+ x**2 - y**2
1433
+ sage: (f * 0).expr()
1434
+ 0
1435
+ sage: (f * X.zero_function()).expr()
1436
+ 0
1437
+ sage: (f * (1/f)).expr()
1438
+ 1
1439
+ """
1440
+ curr = self._calc_method._current
1441
+ if other._expansion_symbol is not None:
1442
+ res = other._simplify(self.expr() * other.expr())
1443
+ else:
1444
+ res = self._simplify(self.expr() * other.expr())
1445
+ if curr == 'SR' and res.is_trivial_zero():
1446
+ # NB: "if res == 0" would be too expensive (cf. #22859)
1447
+ return self.parent().zero()
1448
+ if other._expansion_symbol is not None:
1449
+ return type(self)(
1450
+ self.parent(),
1451
+ res,
1452
+ expansion_symbol=other._expansion_symbol,
1453
+ order=other._order,
1454
+ )
1455
+ else:
1456
+ return type(self)(
1457
+ self.parent(),
1458
+ res,
1459
+ expansion_symbol=self._expansion_symbol,
1460
+ order=self._order,
1461
+ )
1462
+
1463
+ def _rmul_(self, other):
1464
+ """
1465
+ Return ``other * self``.
1466
+
1467
+ EXAMPLES::
1468
+
1469
+ sage: M = Manifold(2, 'M', structure='topological')
1470
+ sage: X.<x,y> = M.chart()
1471
+ sage: one = X.function_ring().one()
1472
+ sage: 2 * one
1473
+ 2
1474
+ sage: f = X.function(x+y)
1475
+ sage: (f * pi).display()
1476
+ (x, y) ↦ pi*(x + y)
1477
+ sage: (x * f).display()
1478
+ (x, y) ↦ (x + y)*x
1479
+
1480
+ The same test with SymPy::
1481
+
1482
+ sage: X.calculus_method().set('sympy')
1483
+ sage: f = X.function(x+y)
1484
+ sage: (f * pi).expr()
1485
+ pi*(x + y)
1486
+ sage: (x * f).expr()
1487
+ x*(x + y)
1488
+ """
1489
+ curr = self._calc_method._current
1490
+ try:
1491
+ other = self._calc_method._tranf[curr](other)
1492
+ except (TypeError, ValueError):
1493
+ return
1494
+ return type(self)(
1495
+ self.parent(),
1496
+ other * self.expr(),
1497
+ expansion_symbol=self._expansion_symbol,
1498
+ order=self._order,
1499
+ )
1500
+
1501
+ def _lmul_(self, other):
1502
+ """
1503
+ Return ``self * other``.
1504
+
1505
+ EXAMPLES::
1506
+
1507
+ sage: M = Manifold(2, 'M', structure='topological')
1508
+ sage: X.<x,y> = M.chart()
1509
+ sage: one = X.function_ring().one()
1510
+ sage: one * 2
1511
+ 2
1512
+ sage: f = X.function(x+y)
1513
+ sage: (f * 2).display()
1514
+ (x, y) ↦ 2*x + 2*y
1515
+ sage: (f * pi).display()
1516
+ (x, y) ↦ pi*(x + y)
1517
+
1518
+ The same test with SymPy::
1519
+
1520
+ sage: X.calculus_method().set('sympy')
1521
+ sage: f = X.function(x+y)
1522
+ sage: (f * 2).display()
1523
+ (x, y) ↦ 2*x + 2*y
1524
+ sage: (f * pi).display()
1525
+ (x, y) ↦ pi*(x + y)
1526
+ """
1527
+ curr = self._calc_method._current
1528
+ try:
1529
+ other = self._calc_method._tranf[curr](other)
1530
+ except (TypeError, ValueError):
1531
+ return
1532
+ return type(self)(
1533
+ self.parent(),
1534
+ self.expr() * other,
1535
+ expansion_symbol=self._expansion_symbol,
1536
+ order=self._order,
1537
+ )
1538
+
1539
+ def _div_(self, other):
1540
+ r"""
1541
+ Division operator.
1542
+
1543
+ INPUT:
1544
+
1545
+ - ``other`` -- a :class:`ChartFunction` or a value
1546
+
1547
+ OUTPUT:
1548
+
1549
+ - chart function resulting from the division of ``self``
1550
+ by ``other``
1551
+
1552
+ TESTS::
1553
+
1554
+ sage: M = Manifold(2, 'M', structure='topological')
1555
+ sage: X.<x,y> = M.chart()
1556
+ sage: f = X.function(x+y)
1557
+ sage: g = X.function(1+x^2+y^2)
1558
+ sage: s = f._div_(g); s.display()
1559
+ (x, y) ↦ (x + y)/(x^2 + y^2 + 1)
1560
+ sage: type(s)
1561
+ <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
1562
+ sage: f / X.zero_function()
1563
+ Traceback (most recent call last):
1564
+ ...
1565
+ ZeroDivisionError: division of a chart function by zero
1566
+ sage: (f / 1).display()
1567
+ (x, y) ↦ x + y
1568
+ sage: (f / 2).display()
1569
+ (x, y) ↦ 1/2*x + 1/2*y
1570
+ sage: (f / pi).display()
1571
+ (x, y) ↦ (x + y)/pi
1572
+ sage: (f / (1+x^2)).display()
1573
+ (x, y) ↦ (x + y)/(x^2 + 1)
1574
+ sage: (f / (1+x^2)).display()
1575
+ (x, y) ↦ (x + y)/(x^2 + 1)
1576
+ sage: (f / g) == ~(g / f)
1577
+ True
1578
+
1579
+ The same test with SymPy::
1580
+
1581
+ sage: X.calculus_method().set('sympy')
1582
+ sage: f = X.function(x+y)
1583
+ sage: g = X.function(1+x**2+y**2)
1584
+ sage: s = f._div_(g); s.display()
1585
+ (x, y) ↦ (x + y)/(x**2 + y**2 + 1)
1586
+ sage: (f / g) == ~(g / f)
1587
+ True
1588
+ """
1589
+ if other.is_zero():
1590
+ raise ZeroDivisionError("division of a chart function by zero")
1591
+ curr = self._calc_method._current
1592
+ res = self._simplify(self.expr() / other.expr())
1593
+ if curr == 'SR' and res.is_trivial_zero():
1594
+ # NB: "if res == 0" would be too expensive (cf. #22859)
1595
+ return self.parent().zero()
1596
+ return type(self)(
1597
+ self.parent(),
1598
+ res,
1599
+ expansion_symbol=self._expansion_symbol,
1600
+ order=self._order,
1601
+ )
1602
+
1603
+ def exp(self):
1604
+ r"""
1605
+ Exponential of ``self``.
1606
+
1607
+ OUTPUT:
1608
+
1609
+ - chart function `\exp(f)`, where `f` is the current
1610
+ chart function
1611
+
1612
+ EXAMPLES::
1613
+
1614
+ sage: M = Manifold(2, 'M', structure='topological')
1615
+ sage: X.<x,y> = M.chart()
1616
+ sage: f = X.function(x+y)
1617
+ sage: f.exp()
1618
+ e^(x + y)
1619
+ sage: exp(f) # equivalent to f.exp()
1620
+ e^(x + y)
1621
+ sage: exp(f).display()
1622
+ (x, y) ↦ e^(x + y)
1623
+ sage: exp(X.zero_function())
1624
+ 1
1625
+
1626
+ The same test with SymPy::
1627
+
1628
+ sage: X.calculus_method().set('sympy')
1629
+ sage: f = X.function(x+y)
1630
+ sage: f.exp()
1631
+ exp(x + y)
1632
+ sage: exp(f) # equivalent to f.exp()
1633
+ exp(x + y)
1634
+ sage: exp(f).display()
1635
+ (x, y) ↦ exp(x + y)
1636
+ sage: exp(X.zero_function())
1637
+ 1
1638
+ """
1639
+ curr = self._calc_method._current
1640
+ if curr == 'SR':
1641
+ val = self.expr().exp()
1642
+ elif curr == 'sympy':
1643
+ val = sympy.exp(self.expr())
1644
+ return type(self)(
1645
+ self.parent(),
1646
+ self._simplify(val),
1647
+ expansion_symbol=self._expansion_symbol,
1648
+ order=self._order,
1649
+ )
1650
+
1651
+ def log(self, base=None):
1652
+ r"""
1653
+ Logarithm of ``self``.
1654
+
1655
+ INPUT:
1656
+
1657
+ - ``base`` -- (default: ``None``) base of the logarithm; if ``None``,
1658
+ the natural logarithm (i.e. logarithm to base `e`) is returned
1659
+
1660
+ OUTPUT:
1661
+
1662
+ - chart function `\log_a(f)`, where `f` is the current chart
1663
+ function and `a` is the base
1664
+
1665
+ EXAMPLES::
1666
+
1667
+ sage: M = Manifold(2, 'M', structure='topological')
1668
+ sage: X.<x,y> = M.chart()
1669
+ sage: f = X.function(x+y)
1670
+ sage: f.log()
1671
+ log(x + y)
1672
+ sage: log(f) # equivalent to f.log()
1673
+ log(x + y)
1674
+ sage: log(f).display()
1675
+ (x, y) ↦ log(x + y)
1676
+ sage: f.log(2)
1677
+ log(x + y)/log(2)
1678
+ sage: log(f, 2)
1679
+ log(x + y)/log(2)
1680
+
1681
+ The same test with SymPy::
1682
+
1683
+ sage: X.calculus_method().set('sympy')
1684
+ sage: f = X.function(x+y)
1685
+ sage: f.log()
1686
+ log(x + y)
1687
+ sage: log(f) # equivalent to f.log()
1688
+ log(x + y)
1689
+ sage: log(f).display()
1690
+ (x, y) ↦ log(x + y)
1691
+ sage: f.log(2)
1692
+ log(x + y)/log(2)
1693
+ sage: log(f, 2)
1694
+ log(x + y)/log(2)
1695
+ """
1696
+ curr = self._calc_method._current
1697
+ if curr == 'SR':
1698
+ val = self.expr().log(base)
1699
+ elif curr == 'sympy':
1700
+ val = (
1701
+ sympy.log(self.expr()) if base is None else sympy.log(self.expr(), base)
1702
+ )
1703
+ return type(self)(
1704
+ self.parent(),
1705
+ self._simplify(val),
1706
+ expansion_symbol=self._expansion_symbol,
1707
+ order=self._order,
1708
+ )
1709
+
1710
+ def __pow__(self, exponent):
1711
+ r"""
1712
+ Power of ``self``.
1713
+
1714
+ INPUT:
1715
+
1716
+ - ``exponent`` -- the exponent
1717
+
1718
+ OUTPUT:
1719
+
1720
+ - chart function `f^a`, where `f` is the current chart
1721
+ function and `a` is the exponent
1722
+
1723
+ EXAMPLES::
1724
+
1725
+ sage: M = Manifold(2, 'M', structure='topological')
1726
+ sage: X.<x,y> = M.chart()
1727
+ sage: f = X.function(x+y)
1728
+ sage: f.__pow__(3)
1729
+ x^3 + 3*x^2*y + 3*x*y^2 + y^3
1730
+ sage: f^3 # equivalent to f.__pow__(3)
1731
+ x^3 + 3*x^2*y + 3*x*y^2 + y^3
1732
+ sage: f.__pow__(3).display()
1733
+ (x, y) ↦ x^3 + 3*x^2*y + 3*x*y^2 + y^3
1734
+ sage: pow(f,3).display()
1735
+ (x, y) ↦ x^3 + 3*x^2*y + 3*x*y^2 + y^3
1736
+ sage: (f^3).display()
1737
+ (x, y) ↦ x^3 + 3*x^2*y + 3*x*y^2 + y^3
1738
+ sage: pow(X.zero_function(), 3).display()
1739
+ (x, y) ↦ 0
1740
+
1741
+ The same test with SymPy::
1742
+
1743
+ sage: X.calculus_method().set('sympy')
1744
+ sage: f = X.function(x+y)
1745
+ sage: f.__pow__(3)
1746
+ x**3 + 3*x**2*y + 3*x*y**2 + y**3
1747
+ sage: f^3 # equivalent to f.__pow__(3)
1748
+ x**3 + 3*x**2*y + 3*x*y**2 + y**3
1749
+ sage: f.__pow__(3).display()
1750
+ (x, y) ↦ x**3 + 3*x**2*y + 3*x*y**2 + y**3
1751
+ sage: pow(f,3).display()
1752
+ (x, y) ↦ x**3 + 3*x**2*y + 3*x*y**2 + y**3
1753
+ sage: (f^3).display()
1754
+ (x, y) ↦ x**3 + 3*x**2*y + 3*x*y**2 + y**3
1755
+ sage: pow(X.zero_function(), 3).display()
1756
+ (x, y) ↦ 0
1757
+ """
1758
+ curr = self._calc_method._current
1759
+ if curr == 'SR':
1760
+ val = pow(self.expr(), exponent)
1761
+ elif curr == 'sympy':
1762
+ val = self.expr() ** exponent
1763
+ return type(self)(
1764
+ self.parent(),
1765
+ self._simplify(val),
1766
+ expansion_symbol=self._expansion_symbol,
1767
+ order=self._order,
1768
+ )
1769
+
1770
+ def sqrt(self):
1771
+ r"""
1772
+ Square root of ``self``.
1773
+
1774
+ OUTPUT:
1775
+
1776
+ - chart function `\sqrt{f}`, where `f` is the current
1777
+ chart function
1778
+
1779
+ EXAMPLES::
1780
+
1781
+ sage: M = Manifold(2, 'M', structure='topological')
1782
+ sage: X.<x,y> = M.chart()
1783
+ sage: f = X.function(x+y)
1784
+ sage: f.sqrt()
1785
+ sqrt(x + y)
1786
+ sage: sqrt(f) # equivalent to f.sqrt()
1787
+ sqrt(x + y)
1788
+ sage: sqrt(f).display()
1789
+ (x, y) ↦ sqrt(x + y)
1790
+ sage: sqrt(X.zero_function()).display()
1791
+ (x, y) ↦ 0
1792
+ """
1793
+ curr = self._calc_method._current
1794
+ if curr == 'SR':
1795
+ val = self.expr().sqrt()
1796
+ elif curr == 'sympy':
1797
+ val = sympy.sqrt(self.expr())
1798
+ return type(self)(
1799
+ self.parent(),
1800
+ self._simplify(val),
1801
+ expansion_symbol=self._expansion_symbol,
1802
+ order=self._order,
1803
+ )
1804
+
1805
+ def cos(self):
1806
+ r"""
1807
+ Cosine of ``self``.
1808
+
1809
+ OUTPUT:
1810
+
1811
+ - chart function `\cos(f)`, where `f` is the current
1812
+ chart function
1813
+
1814
+ EXAMPLES::
1815
+
1816
+ sage: M = Manifold(2, 'M', structure='topological')
1817
+ sage: X.<x,y> = M.chart()
1818
+ sage: f = X.function(x*y)
1819
+ sage: f.cos()
1820
+ cos(x*y)
1821
+ sage: cos(f) # equivalent to f.cos()
1822
+ cos(x*y)
1823
+ sage: cos(f).display()
1824
+ (x, y) ↦ cos(x*y)
1825
+ sage: cos(X.zero_function()).display()
1826
+ (x, y) ↦ 1
1827
+
1828
+ The same tests with SymPy::
1829
+
1830
+ sage: X.calculus_method().set('sympy')
1831
+ sage: f.cos()
1832
+ cos(x*y)
1833
+ sage: cos(f) # equivalent to f.cos()
1834
+ cos(x*y)
1835
+ """
1836
+ curr = self._calc_method._current
1837
+ if curr == 'SR':
1838
+ val = self.expr().cos()
1839
+ elif curr == 'sympy':
1840
+ val = sympy.cos(self.expr())
1841
+ return type(self)(
1842
+ self.parent(),
1843
+ self._simplify(val),
1844
+ expansion_symbol=self._expansion_symbol,
1845
+ order=self._order,
1846
+ )
1847
+
1848
+ def sin(self):
1849
+ r"""
1850
+ Sine of ``self``.
1851
+
1852
+ OUTPUT:
1853
+
1854
+ - chart function `\sin(f)`, where `f` is the current
1855
+ chart function
1856
+
1857
+ EXAMPLES::
1858
+
1859
+ sage: M = Manifold(2, 'M', structure='topological')
1860
+ sage: X.<x,y> = M.chart()
1861
+ sage: f = X.function(x*y)
1862
+ sage: f.sin()
1863
+ sin(x*y)
1864
+ sage: sin(f) # equivalent to f.sin()
1865
+ sin(x*y)
1866
+ sage: sin(f).display()
1867
+ (x, y) ↦ sin(x*y)
1868
+ sage: sin(X.zero_function()) == X.zero_function()
1869
+ True
1870
+ sage: f = X.function(2-cos(x)^2+y)
1871
+ sage: g = X.function(-sin(x)^2+y)
1872
+ sage: (f+g).simplify()
1873
+ 2*y + 1
1874
+
1875
+ The same tests with SymPy::
1876
+
1877
+ sage: X.calculus_method().set('sympy')
1878
+ sage: f = X.function(x*y)
1879
+ sage: f.sin()
1880
+ sin(x*y)
1881
+ sage: sin(f) # equivalent to f.sin()
1882
+ sin(x*y)
1883
+ """
1884
+ curr = self._calc_method._current
1885
+ if curr == 'SR':
1886
+ val = self.expr().sin()
1887
+ elif curr == 'sympy':
1888
+ val = sympy.sin(self.expr())
1889
+ return type(self)(
1890
+ self.parent(),
1891
+ self._simplify(val),
1892
+ expansion_symbol=self._expansion_symbol,
1893
+ order=self._order,
1894
+ )
1895
+
1896
+ def tan(self):
1897
+ r"""
1898
+ Tangent of ``self``.
1899
+
1900
+ OUTPUT:
1901
+
1902
+ - chart function `\tan(f)`, where `f` is the current
1903
+ chart function
1904
+
1905
+ EXAMPLES::
1906
+
1907
+ sage: M = Manifold(2, 'M', structure='topological')
1908
+ sage: X.<x,y> = M.chart()
1909
+ sage: f = X.function(x*y)
1910
+ sage: f.tan()
1911
+ sin(x*y)/cos(x*y)
1912
+ sage: tan(f) # equivalent to f.tan()
1913
+ sin(x*y)/cos(x*y)
1914
+ sage: tan(f).display()
1915
+ (x, y) ↦ sin(x*y)/cos(x*y)
1916
+ sage: tan(X.zero_function()) == X.zero_function()
1917
+ True
1918
+
1919
+ The same test with SymPy::
1920
+
1921
+ sage: M.set_calculus_method('sympy')
1922
+ sage: g = X.function(x*y)
1923
+ sage: g.tan()
1924
+ tan(x*y)
1925
+ sage: tan(g) # equivalent to g.tan()
1926
+ tan(x*y)
1927
+ sage: tan(g).display()
1928
+ (x, y) ↦ tan(x*y)
1929
+ """
1930
+ curr = self._calc_method._current
1931
+ if curr == 'SR':
1932
+ val = self.expr().tan()
1933
+ elif curr == 'sympy':
1934
+ val = sympy.tan(self.expr())
1935
+ return type(self)(
1936
+ self.parent(),
1937
+ self._simplify(val),
1938
+ expansion_symbol=self._expansion_symbol,
1939
+ order=self._order,
1940
+ )
1941
+
1942
+ def arccos(self):
1943
+ r"""
1944
+ Arc cosine of ``self``.
1945
+
1946
+ OUTPUT:
1947
+
1948
+ - chart function `\arccos(f)`, where `f` is the current
1949
+ chart function
1950
+
1951
+ EXAMPLES::
1952
+
1953
+ sage: M = Manifold(2, 'M', structure='topological')
1954
+ sage: X.<x,y> = M.chart()
1955
+ sage: f = X.function(x*y)
1956
+ sage: f.arccos()
1957
+ arccos(x*y)
1958
+ sage: arccos(f) # equivalent to f.arccos()
1959
+ arccos(x*y)
1960
+ sage: acos(f) # equivalent to f.arccos()
1961
+ arccos(x*y)
1962
+ sage: arccos(f).display()
1963
+ (x, y) ↦ arccos(x*y)
1964
+ sage: arccos(X.zero_function()).display()
1965
+ (x, y) ↦ 1/2*pi
1966
+
1967
+ The same test with SymPy::
1968
+
1969
+ sage: M.set_calculus_method('sympy')
1970
+ sage: f = X.function(x*y)
1971
+ sage: f.arccos()
1972
+ acos(x*y)
1973
+ sage: arccos(f) # equivalent to f.arccos()
1974
+ acos(x*y)
1975
+ sage: acos(f) # equivalent to f.arccos()
1976
+ acos(x*y)
1977
+ sage: arccos(f).display()
1978
+ (x, y) ↦ acos(x*y)
1979
+ """
1980
+ curr = self._calc_method._current
1981
+ if curr == 'SR':
1982
+ val = self.expr().arccos()
1983
+ elif curr == 'sympy':
1984
+ val = sympy.acos(self.expr())
1985
+ return type(self)(
1986
+ self.parent(),
1987
+ self._simplify(val),
1988
+ expansion_symbol=self._expansion_symbol,
1989
+ order=self._order,
1990
+ )
1991
+
1992
+ def arcsin(self):
1993
+ r"""
1994
+ Arc sine of ``self``.
1995
+
1996
+ OUTPUT:
1997
+
1998
+ - chart function `\arcsin(f)`, where `f` is the current
1999
+ chart function
2000
+
2001
+ EXAMPLES::
2002
+
2003
+ sage: M = Manifold(2, 'M', structure='topological')
2004
+ sage: X.<x,y> = M.chart()
2005
+ sage: f = X.function(x*y)
2006
+ sage: f.arcsin()
2007
+ arcsin(x*y)
2008
+ sage: arcsin(f) # equivalent to f.arcsin()
2009
+ arcsin(x*y)
2010
+ sage: asin(f) # equivalent to f.arcsin()
2011
+ arcsin(x*y)
2012
+ sage: arcsin(f).display()
2013
+ (x, y) ↦ arcsin(x*y)
2014
+ sage: arcsin(X.zero_function()) == X.zero_function()
2015
+ True
2016
+
2017
+ The same tests with SymPy::
2018
+
2019
+ sage: X.calculus_method().set('sympy')
2020
+ sage: f.arcsin()
2021
+ asin(x*y)
2022
+ sage: arcsin(f) # equivalent to f.arcsin()
2023
+ asin(x*y)
2024
+ sage: asin(f) # equivalent to f.arcsin()
2025
+ asin(x*y)
2026
+ """
2027
+ curr = self._calc_method._current
2028
+ if curr == 'SR':
2029
+ val = self.expr().arcsin()
2030
+ elif curr == 'sympy':
2031
+ val = sympy.asin(self.expr())
2032
+ return type(self)(
2033
+ self.parent(),
2034
+ self._simplify(val),
2035
+ expansion_symbol=self._expansion_symbol,
2036
+ order=self._order,
2037
+ )
2038
+
2039
+ def arctan(self):
2040
+ r"""
2041
+ Arc tangent of ``self``.
2042
+
2043
+ OUTPUT:
2044
+
2045
+ - chart function `\arctan(f)`, where `f` is the current
2046
+ chart function
2047
+
2048
+ EXAMPLES::
2049
+
2050
+ sage: M = Manifold(2, 'M', structure='topological')
2051
+ sage: X.<x,y> = M.chart()
2052
+ sage: f = X.function(x*y)
2053
+ sage: f.arctan()
2054
+ arctan(x*y)
2055
+ sage: arctan(f) # equivalent to f.arctan()
2056
+ arctan(x*y)
2057
+ sage: atan(f) # equivalent to f.arctan()
2058
+ arctan(x*y)
2059
+ sage: arctan(f).display()
2060
+ (x, y) ↦ arctan(x*y)
2061
+ sage: arctan(X.zero_function()) == X.zero_function()
2062
+ True
2063
+
2064
+ The same tests with SymPy::
2065
+
2066
+ sage: X.calculus_method().set('sympy')
2067
+ sage: f.arctan()
2068
+ atan(x*y)
2069
+ sage: arctan(f) # equivalent to f.arctan()
2070
+ atan(x*y)
2071
+ sage: atan(f) # equivalent to f.arctan()
2072
+ atan(x*y)
2073
+ """
2074
+ curr = self._calc_method._current
2075
+ if curr == 'SR':
2076
+ val = self.expr().arctan()
2077
+ elif curr == 'sympy':
2078
+ val = sympy.atan(self.expr())
2079
+ return type(self)(
2080
+ self.parent(),
2081
+ self._simplify(val),
2082
+ expansion_symbol=self._expansion_symbol,
2083
+ order=self._order,
2084
+ )
2085
+
2086
+ def cosh(self):
2087
+ r"""
2088
+ Hyperbolic cosine of ``self``.
2089
+
2090
+ OUTPUT:
2091
+
2092
+ - chart function `\cosh(f)`, where `f` is the current
2093
+ chart function
2094
+
2095
+ EXAMPLES::
2096
+
2097
+ sage: M = Manifold(2, 'M', structure='topological')
2098
+ sage: X.<x,y> = M.chart()
2099
+ sage: f = X.function(x*y)
2100
+ sage: f.cosh()
2101
+ cosh(x*y)
2102
+ sage: cosh(f) # equivalent to f.cosh()
2103
+ cosh(x*y)
2104
+ sage: cosh(f).display()
2105
+ (x, y) ↦ cosh(x*y)
2106
+ sage: cosh(X.zero_function()).display()
2107
+ (x, y) ↦ 1
2108
+
2109
+ The same tests with SymPy::
2110
+
2111
+ sage: X.calculus_method().set('sympy')
2112
+ sage: f.cosh()
2113
+ cosh(x*y)
2114
+ sage: cosh(f) # equivalent to f.cosh()
2115
+ cosh(x*y)
2116
+ """
2117
+ curr = self._calc_method._current
2118
+ if curr == 'SR':
2119
+ val = self.expr().cosh()
2120
+ elif curr == 'sympy':
2121
+ val = sympy.cosh(self.expr())
2122
+ return type(self)(
2123
+ self.parent(),
2124
+ self._simplify(val),
2125
+ expansion_symbol=self._expansion_symbol,
2126
+ order=self._order,
2127
+ )
2128
+
2129
+ def sinh(self):
2130
+ r"""
2131
+ Hyperbolic sine of ``self``.
2132
+
2133
+ OUTPUT:
2134
+
2135
+ - chart function `\sinh(f)`, where `f` is the current
2136
+ chart function
2137
+
2138
+ EXAMPLES::
2139
+
2140
+ sage: M = Manifold(2, 'M', structure='topological')
2141
+ sage: X.<x,y> = M.chart()
2142
+ sage: f = X.function(x*y)
2143
+ sage: f.sinh()
2144
+ sinh(x*y)
2145
+ sage: sinh(f) # equivalent to f.sinh()
2146
+ sinh(x*y)
2147
+ sage: sinh(f).display()
2148
+ (x, y) ↦ sinh(x*y)
2149
+ sage: sinh(X.zero_function()) == X.zero_function()
2150
+ True
2151
+
2152
+ The same tests with SymPy::
2153
+
2154
+ sage: X.calculus_method().set('sympy')
2155
+ sage: f.sinh()
2156
+ sinh(x*y)
2157
+ sage: sinh(f) # equivalent to f.sinh()
2158
+ sinh(x*y)
2159
+ """
2160
+ curr = self._calc_method._current
2161
+ if curr == 'SR':
2162
+ val = self.expr().sinh()
2163
+ elif curr == 'sympy':
2164
+ val = sympy.sinh(self.expr())
2165
+ return type(self)(
2166
+ self.parent(),
2167
+ self._simplify(val),
2168
+ expansion_symbol=self._expansion_symbol,
2169
+ order=self._order,
2170
+ )
2171
+
2172
+ def tanh(self):
2173
+ r"""
2174
+ Hyperbolic tangent of ``self``.
2175
+
2176
+ OUTPUT:
2177
+
2178
+ - chart function `\tanh(f)`, where `f` is the current
2179
+ chart function
2180
+
2181
+ EXAMPLES::
2182
+
2183
+ sage: M = Manifold(2, 'M', structure='topological')
2184
+ sage: X.<x,y> = M.chart()
2185
+ sage: f = X.function(x*y)
2186
+ sage: f.tanh()
2187
+ sinh(x*y)/cosh(x*y)
2188
+ sage: tanh(f) # equivalent to f.tanh()
2189
+ sinh(x*y)/cosh(x*y)
2190
+ sage: tanh(f).display()
2191
+ (x, y) ↦ sinh(x*y)/cosh(x*y)
2192
+ sage: tanh(X.zero_function()) == X.zero_function()
2193
+ True
2194
+
2195
+ The same tests with SymPy::
2196
+
2197
+ sage: X.calculus_method().set('sympy')
2198
+ sage: f.tanh()
2199
+ tanh(x*y)
2200
+ sage: tanh(f) # equivalent to f.tanh()
2201
+ tanh(x*y)
2202
+ """
2203
+ curr = self._calc_method._current
2204
+ if curr == 'SR':
2205
+ val = self.expr().tanh()
2206
+ elif curr == 'sympy':
2207
+ val = sympy.tanh(self.expr())
2208
+ return type(self)(
2209
+ self.parent(),
2210
+ self._simplify(val),
2211
+ expansion_symbol=self._expansion_symbol,
2212
+ order=self._order,
2213
+ )
2214
+
2215
+ def arccosh(self):
2216
+ r"""
2217
+ Inverse hyperbolic cosine of ``self``.
2218
+
2219
+ OUTPUT:
2220
+
2221
+ - chart function `\mathrm{arccosh}(f)`, where `f` is the current
2222
+ chart function
2223
+
2224
+ EXAMPLES::
2225
+
2226
+ sage: M = Manifold(2, 'M', structure='topological')
2227
+ sage: X.<x,y> = M.chart()
2228
+ sage: f = X.function(x*y)
2229
+ sage: f.arccosh()
2230
+ arccosh(x*y)
2231
+ sage: arccosh(f) # equivalent to f.arccosh()
2232
+ arccosh(x*y)
2233
+ sage: acosh(f) # equivalent to f.arccosh()
2234
+ arccosh(x*y)
2235
+ sage: arccosh(f).display()
2236
+ (x, y) ↦ arccosh(x*y)
2237
+ sage: arccosh(X.function(1)) == X.zero_function()
2238
+ True
2239
+
2240
+ The same tests with SymPy::
2241
+
2242
+ sage: X.calculus_method().set('sympy')
2243
+ sage: f.arccosh()
2244
+ acosh(x*y)
2245
+ sage: arccosh(f) # equivalent to f.arccosh()
2246
+ acosh(x*y)
2247
+ sage: acosh(f) # equivalent to f.arccosh()
2248
+ acosh(x*y)
2249
+ """
2250
+ curr = self._calc_method._current
2251
+ if curr == 'SR':
2252
+ val = self.expr().arccosh()
2253
+ elif curr == 'sympy':
2254
+ val = sympy.acosh(self.expr())
2255
+ return type(self)(
2256
+ self.parent(),
2257
+ self._simplify(val),
2258
+ expansion_symbol=self._expansion_symbol,
2259
+ order=self._order,
2260
+ )
2261
+
2262
+ def arcsinh(self):
2263
+ r"""
2264
+ Inverse hyperbolic sine of ``self``.
2265
+
2266
+ OUTPUT:
2267
+
2268
+ - chart function `\mathrm{arcsinh}(f)`, where `f` is the current
2269
+ chart function
2270
+
2271
+ EXAMPLES::
2272
+
2273
+ sage: M = Manifold(2, 'M', structure='topological')
2274
+ sage: X.<x,y> = M.chart()
2275
+ sage: f = X.function(x*y)
2276
+ sage: f.arcsinh()
2277
+ arcsinh(x*y)
2278
+ sage: arcsinh(f) # equivalent to f.arcsinh()
2279
+ arcsinh(x*y)
2280
+ sage: asinh(f) # equivalent to f.arcsinh()
2281
+ arcsinh(x*y)
2282
+ sage: arcsinh(f).display()
2283
+ (x, y) ↦ arcsinh(x*y)
2284
+ sage: arcsinh(X.zero_function()) == X.zero_function()
2285
+ True
2286
+
2287
+ The same tests with SymPy::
2288
+
2289
+ sage: X.calculus_method().set('sympy')
2290
+ sage: f.arcsinh()
2291
+ asinh(x*y)
2292
+ sage: arcsinh(f) # equivalent to f.arcsinh()
2293
+ asinh(x*y)
2294
+ sage: asinh(f) # equivalent to f.arcsinh()
2295
+ asinh(x*y)
2296
+ """
2297
+ curr = self._calc_method._current
2298
+ if curr == 'SR':
2299
+ val = self.expr().arcsinh()
2300
+ elif curr == 'sympy':
2301
+ val = sympy.asinh(self.expr())
2302
+ return type(self)(
2303
+ self.parent(),
2304
+ self._simplify(val),
2305
+ expansion_symbol=self._expansion_symbol,
2306
+ order=self._order,
2307
+ )
2308
+
2309
+ def arctanh(self):
2310
+ r"""
2311
+ Inverse hyperbolic tangent of ``self``.
2312
+
2313
+ OUTPUT:
2314
+
2315
+ - chart function `\mathrm{arctanh}(f)`, where `f` is the
2316
+ current chart function
2317
+
2318
+ EXAMPLES::
2319
+
2320
+ sage: M = Manifold(2, 'M', structure='topological')
2321
+ sage: X.<x,y> = M.chart()
2322
+ sage: f = X.function(x*y)
2323
+ sage: f.arctanh()
2324
+ arctanh(x*y)
2325
+ sage: arctanh(f) # equivalent to f.arctanh()
2326
+ arctanh(x*y)
2327
+ sage: atanh(f) # equivalent to f.arctanh()
2328
+ arctanh(x*y)
2329
+ sage: arctanh(f).display()
2330
+ (x, y) ↦ arctanh(x*y)
2331
+ sage: arctanh(X.zero_function()) == X.zero_function()
2332
+ True
2333
+
2334
+ The same tests with SymPy::
2335
+
2336
+ sage: X.calculus_method().set('sympy')
2337
+ sage: f.arctanh()
2338
+ atanh(x*y)
2339
+ sage: arctanh(f) # equivalent to f.arctanh()
2340
+ atanh(x*y)
2341
+ sage: atanh(f) # equivalent to f.arctanh()
2342
+ atanh(x*y)
2343
+ """
2344
+ curr = self._calc_method._current
2345
+ if curr == 'SR':
2346
+ val = self.expr().arctanh()
2347
+ elif curr == 'sympy':
2348
+ val = sympy.atanh(self.expr())
2349
+ return type(self)(
2350
+ self.parent(),
2351
+ self._simplify(val),
2352
+ expansion_symbol=self._expansion_symbol,
2353
+ order=self._order,
2354
+ )
2355
+
2356
+ def __abs__(self):
2357
+ r"""
2358
+ Absolute value of ``self``.
2359
+
2360
+ OUTPUT:
2361
+
2362
+ - chart function `\mathrm{abs}(f)`, where `f` is the
2363
+ current chart function
2364
+
2365
+ EXAMPLES::
2366
+
2367
+ sage: M = Manifold(2, 'M', structure='topological')
2368
+ sage: X.<x,y> = M.chart()
2369
+ sage: f = X.function(x*y)
2370
+ sage: f.abs()
2371
+ abs(x)*abs(y)
2372
+ sage: abs(f) # equivalent to f.abs()
2373
+ abs(x)*abs(y)
2374
+ sage: abs(f).display()
2375
+ (x, y) ↦ abs(x)*abs(y)
2376
+ sage: abs(X.zero_function()) == X.zero_function()
2377
+ True
2378
+
2379
+ The same tests with SymPy::
2380
+
2381
+ sage: X.calculus_method().set('sympy')
2382
+ sage: f.abs()
2383
+ Abs(x*y)
2384
+ sage: abs(f) # equivalent to f.abs()
2385
+ Abs(x*y)
2386
+ """
2387
+ curr = self._calc_method._current
2388
+ if curr == 'SR':
2389
+ val = self.expr().abs()
2390
+ elif curr == 'sympy':
2391
+ val = abs(self.expr())
2392
+ return type(self)(
2393
+ self.parent(),
2394
+ self._simplify(val),
2395
+ expansion_symbol=self._expansion_symbol,
2396
+ order=self._order,
2397
+ )
2398
+
2399
+ def _del_derived(self):
2400
+ r"""
2401
+ Delete the derived quantities.
2402
+
2403
+ TESTS::
2404
+
2405
+ sage: M = Manifold(2, 'M', structure='topological')
2406
+ sage: X.<x,y> = M.chart()
2407
+ sage: f = X.function(cos(x*y))
2408
+ sage: f._der
2409
+ sage: f.diff(x)
2410
+ -y*sin(x*y)
2411
+ sage: f._der
2412
+ [-y*sin(x*y), -x*sin(x*y)]
2413
+ sage: f._del_derived()
2414
+ sage: f._der
2415
+
2416
+ The same tests with SymPy::
2417
+
2418
+ sage: X.calculus_method().set('sympy')
2419
+ sage: f = X.function(cos(x*y))
2420
+ sage: f._der
2421
+ sage: f.diff(x)
2422
+ -y*sin(x*y)
2423
+ sage: f._der
2424
+ [-y*sin(x*y), -x*sin(x*y)]
2425
+ sage: type(f._der[0]._express['sympy'])
2426
+ <class 'sympy.core.mul.Mul'>
2427
+ sage: f._del_derived()
2428
+ sage: f._der
2429
+ """
2430
+ self._der = None # reset of the partial derivatives
2431
+
2432
+ def simplify(self) -> Self:
2433
+ r"""
2434
+ Simplify the coordinate expression of ``self``.
2435
+
2436
+ For details about the employed chain of simplifications for the ``SR``
2437
+ calculus method, see
2438
+ :func:`~sage.manifolds.utilities.simplify_chain_real` for chart
2439
+ functions on real manifolds and
2440
+ :func:`~sage.manifolds.utilities.simplify_chain_generic` for the
2441
+ generic case.
2442
+
2443
+ If ``self`` has been defined with the small parameter
2444
+ ``expansion_symbol`` and some truncation order, the coordinate
2445
+ expression of ``self`` will be expanded in power series of that
2446
+ parameter and truncated to the given order.
2447
+
2448
+ OUTPUT: ``self`` with its coordinate expression simplified
2449
+
2450
+ EXAMPLES:
2451
+
2452
+ Simplification of a chart function on a 2-dimensional manifold::
2453
+
2454
+ sage: M = Manifold(2, 'M', structure='topological')
2455
+ sage: X.<x,y> = M.chart()
2456
+ sage: f = X.function(cos(x)^2 + sin(x)^2 + sqrt(x^2))
2457
+ sage: f.display()
2458
+ (x, y) ↦ cos(x)^2 + sin(x)^2 + abs(x)
2459
+ sage: f.simplify()
2460
+ abs(x) + 1
2461
+
2462
+ The method ``simplify()`` has changed the expression of ``f``::
2463
+
2464
+ sage: f.display()
2465
+ (x, y) ↦ abs(x) + 1
2466
+
2467
+ Another example::
2468
+
2469
+ sage: f = X.function((x^2-1)/(x+1)); f
2470
+ (x^2 - 1)/(x + 1)
2471
+ sage: f.simplify()
2472
+ x - 1
2473
+
2474
+ Examples taking into account the declared range of a coordinate::
2475
+
2476
+ sage: M = Manifold(2, 'M', structure='topological')
2477
+ sage: X.<x,y> = M.chart('x:(1,+oo) y')
2478
+ sage: f = X.function(sqrt(x^2-2*x+1)); f
2479
+ sqrt(x^2 - 2*x + 1)
2480
+ sage: f.simplify()
2481
+ x - 1
2482
+
2483
+ ::
2484
+
2485
+ sage: forget() # to clear the previous assumption on x
2486
+ sage: M = Manifold(2, 'M', structure='topological')
2487
+ sage: X.<x,y> = M.chart('x:(-oo,0) y')
2488
+ sage: f = X.function(sqrt(x^2-2*x+1)); f
2489
+ sqrt(x^2 - 2*x + 1)
2490
+ sage: f.simplify()
2491
+ -x + 1
2492
+
2493
+ The same tests with SymPy::
2494
+
2495
+ sage: forget() # to clear the previous assumption on x
2496
+ sage: M = Manifold(2, 'M', structure='topological')
2497
+ sage: X.<x,y> = M.chart(calc_method='sympy')
2498
+ sage: f = X.function(cos(x)^2 + sin(x)^2 + sqrt(x^2)); f
2499
+ sin(x)**2 + cos(x)**2 + Abs(x)
2500
+ sage: f.simplify()
2501
+ Abs(x) + 1
2502
+
2503
+ ::
2504
+
2505
+ sage: f = X.function((x^2-1)/(x+1)); f
2506
+ (x**2 - 1)/(x + 1)
2507
+ sage: f.simplify()
2508
+ x - 1
2509
+
2510
+ ::
2511
+
2512
+ sage: M = Manifold(2, 'M', structure='topological')
2513
+ sage: X.<x,y> = M.chart('x:(1,+oo) y', calc_method='sympy')
2514
+ sage: f = X.function(sqrt(x^2-2*x+1)); f
2515
+ sqrt(x**2 - 2*x + 1)
2516
+ sage: f.simplify()
2517
+ x - 1
2518
+
2519
+ ::
2520
+
2521
+ sage: forget() # to clear the previous assumption on x
2522
+ sage: M = Manifold(2, 'M', structure='topological')
2523
+ sage: X.<x,y> = M.chart('x:(-oo,0) y', calc_method='sympy')
2524
+ sage: f = X.function(sqrt(x^2-2*x+1)); f
2525
+ sqrt(x**2 - 2*x + 1)
2526
+ sage: f.simplify()
2527
+ 1 - x
2528
+
2529
+ Power series expansion with respect to a small parameter `t` (at
2530
+ the moment, this is implemented only for the ``SR`` calculus backend,
2531
+ hence the first line below)::
2532
+
2533
+ sage: X.calculus_method().set('SR')
2534
+ sage: t = var('t')
2535
+ sage: f = X.function(exp(t*x), expansion_symbol=t, order=3)
2536
+
2537
+ At this stage, `f` is not expanded in power series::
2538
+
2539
+ sage: f
2540
+ e^(t*x)
2541
+
2542
+ Invoking ``simplify()`` triggers the expansion to the given order::
2543
+
2544
+ sage: f.simplify()
2545
+ 1/6*t^3*x^3 + 1/2*t^2*x^2 + t*x + 1
2546
+ sage: f.display()
2547
+ (x, y) ↦ 1/6*t^3*x^3 + 1/2*t^2*x^2 + t*x + 1
2548
+ """
2549
+ curr = self._calc_method._current
2550
+ self._express[curr] = self._simplify(self.expr(curr))
2551
+ self._del_derived()
2552
+ return self
2553
+
2554
+ def factor(self) -> Self:
2555
+ r"""
2556
+ Factorize the coordinate expression of ``self``.
2557
+
2558
+ OUTPUT: ``self`` with its expression factorized
2559
+
2560
+ EXAMPLES:
2561
+
2562
+ Factorization of a 2-dimensional chart function::
2563
+
2564
+ sage: M = Manifold(2, 'M', structure='topological')
2565
+ sage: X.<x,y> = M.chart()
2566
+ sage: f = X.function(x^2 + 2*x*y + y^2)
2567
+ sage: f.display()
2568
+ (x, y) ↦ x^2 + 2*x*y + y^2
2569
+ sage: f.factor()
2570
+ (x + y)^2
2571
+
2572
+ The method ``factor()`` has changed the expression of ``f``::
2573
+
2574
+ sage: f.display()
2575
+ (x, y) ↦ (x + y)^2
2576
+
2577
+ The same test with SymPy ::
2578
+
2579
+ sage: X.calculus_method().set('sympy')
2580
+ sage: g = X.function(x^2 + 2*x*y + y^2)
2581
+ sage: g.display()
2582
+ (x, y) ↦ x**2 + 2*x*y + y**2
2583
+ sage: g.factor()
2584
+ (x + y)**2
2585
+ """
2586
+ curr = self._calc_method._current
2587
+ self._express[curr] = self.expr().factor()
2588
+ self._del_derived()
2589
+ return self
2590
+
2591
+ def expand(self) -> Self:
2592
+ r"""
2593
+ Expand the coordinate expression of ``self``.
2594
+
2595
+ OUTPUT: ``self`` with its expression expanded
2596
+
2597
+ EXAMPLES:
2598
+
2599
+ Expanding a 2-dimensional chart function::
2600
+
2601
+ sage: M = Manifold(2, 'M', structure='topological')
2602
+ sage: X.<x,y> = M.chart()
2603
+ sage: f = X.function((x - y)^2)
2604
+ sage: f.display()
2605
+ (x, y) ↦ (x - y)^2
2606
+ sage: f.expand()
2607
+ x^2 - 2*x*y + y^2
2608
+
2609
+ The method ``expand()`` has changed the expression of ``f``::
2610
+
2611
+ sage: f.display()
2612
+ (x, y) ↦ x^2 - 2*x*y + y^2
2613
+
2614
+ The same test with SymPy ::
2615
+
2616
+ sage: X.calculus_method().set('sympy')
2617
+ sage: g = X.function((x - y)^2)
2618
+ sage: g.expand()
2619
+ x**2 - 2*x*y + y**2
2620
+ """
2621
+ curr = self._calc_method._current
2622
+ self._express[curr] = self.expr().expand()
2623
+ self._del_derived()
2624
+ return self
2625
+
2626
+ def collect(self, s) -> Self:
2627
+ r"""
2628
+ Collect the coefficients of `s` in the expression of ``self``
2629
+ into a group.
2630
+
2631
+ INPUT:
2632
+
2633
+ - ``s`` -- the symbol whose coefficients will be collected
2634
+
2635
+ OUTPUT:
2636
+
2637
+ - ``self`` with the coefficients of ``s`` grouped in
2638
+ its expression
2639
+
2640
+ EXAMPLES:
2641
+
2642
+ Action on a 2-dimensional chart function::
2643
+
2644
+ sage: M = Manifold(2, 'M', structure='topological')
2645
+ sage: X.<x,y> = M.chart()
2646
+ sage: f = X.function(x^2*y + x*y + (x*y)^2)
2647
+ sage: f.display()
2648
+ (x, y) ↦ x^2*y^2 + x^2*y + x*y
2649
+ sage: f.collect(y)
2650
+ x^2*y^2 + (x^2 + x)*y
2651
+
2652
+ The method ``collect()`` has changed the expression of ``f``::
2653
+
2654
+ sage: f.display()
2655
+ (x, y) ↦ x^2*y^2 + (x^2 + x)*y
2656
+
2657
+ The same test with SymPy ::
2658
+
2659
+ sage: X.calculus_method().set('sympy')
2660
+ sage: f = X.function(x^2*y + x*y + (x*y)^2)
2661
+ sage: f.display()
2662
+ (x, y) ↦ x**2*y**2 + x**2*y + x*y
2663
+ sage: f.collect(y)
2664
+ x**2*y**2 + y*(x**2 + x)
2665
+ """
2666
+ curr = self._calc_method._current
2667
+ self._express[curr] = self.expr().collect(s)
2668
+ self._del_derived()
2669
+ return self
2670
+
2671
+ def collect_common_factors(self) -> Self:
2672
+ r"""
2673
+ Collect common factors in the expression of ``self``.
2674
+
2675
+ This method does not perform a full factorization but only looks
2676
+ for factors which are already explicitly present.
2677
+
2678
+ OUTPUT:
2679
+
2680
+ - ``self`` with the common factors collected in
2681
+ its expression
2682
+
2683
+ EXAMPLES:
2684
+
2685
+ Action on a 2-dimensional chart function::
2686
+
2687
+ sage: M = Manifold(2, 'M', structure='topological')
2688
+ sage: X.<x,y> = M.chart()
2689
+ sage: f = X.function(x/(x^2*y + x*y))
2690
+ sage: f.display()
2691
+ (x, y) ↦ x/(x^2*y + x*y)
2692
+ sage: f.collect_common_factors()
2693
+ 1/((x + 1)*y)
2694
+
2695
+ The method ``collect_common_factors()`` has changed the expression
2696
+ of ``f``::
2697
+
2698
+ sage: f.display()
2699
+ (x, y) ↦ 1/((x + 1)*y)
2700
+
2701
+ The same test with SymPy::
2702
+
2703
+ sage: X.calculus_method().set('sympy')
2704
+ sage: g = X.function(x/(x^2*y + x*y))
2705
+ sage: g.display()
2706
+ (x, y) ↦ x/(x**2*y + x*y)
2707
+ sage: g.collect_common_factors()
2708
+ 1/(y*(x + 1))
2709
+ """
2710
+ curr = self._calc_method._current
2711
+ if curr == 'sympy':
2712
+ self._express[curr] = self.expr().simplify()
2713
+ else:
2714
+ self._express[curr] = self.expr().collect_common_factors()
2715
+ self._del_derived()
2716
+ return self
2717
+
2718
+
2719
+ class ChartFunctionRing(Parent, UniqueRepresentation):
2720
+ """
2721
+ Ring of all chart functions on a chart.
2722
+
2723
+ INPUT:
2724
+
2725
+ - ``chart`` -- a coordinate chart, as an instance of class
2726
+ :class:`~sage.manifolds.chart.Chart`
2727
+
2728
+ EXAMPLES:
2729
+
2730
+ The ring of all chart functions w.r.t. to a chart::
2731
+
2732
+ sage: M = Manifold(2, 'M', structure='topological')
2733
+ sage: X.<x,y> = M.chart()
2734
+ sage: FR = X.function_ring(); FR
2735
+ Ring of chart functions on Chart (M, (x, y))
2736
+ sage: type(FR)
2737
+ <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category'>
2738
+ sage: FR.category()
2739
+ Category of commutative algebras over Symbolic Ring
2740
+
2741
+ Coercions by means of restrictions are implemented::
2742
+
2743
+ sage: FR_X = X.function_ring()
2744
+ sage: D = M.open_subset('D')
2745
+ sage: X_D = X.restrict(D, x^2+y^2<1) # open disk
2746
+ sage: FR_X_D = X_D.function_ring()
2747
+ sage: FR_X_D.has_coerce_map_from(FR_X)
2748
+ True
2749
+
2750
+ But only if the charts are compatible::
2751
+
2752
+ sage: Y.<t,z> = D.chart()
2753
+ sage: FR_Y = Y.function_ring()
2754
+ sage: FR_Y.has_coerce_map_from(FR_X)
2755
+ False
2756
+ """
2757
+
2758
+ Element = ChartFunction
2759
+
2760
+ def __init__(self, chart):
2761
+ """
2762
+ Initialize ``self``.
2763
+
2764
+ EXAMPLES::
2765
+
2766
+ sage: M = Manifold(2, 'M', structure='topological')
2767
+ sage: X.<x,y> = M.chart()
2768
+ sage: FR = X.function_ring()
2769
+ sage: TestSuite(FR).run()
2770
+ """
2771
+ self._chart = chart
2772
+ Parent.__init__(self, base=SR, category=CommutativeAlgebras(SR))
2773
+
2774
+ def _element_constructor_(self, expression, calc_method=None):
2775
+ r"""
2776
+ Construct a chart function.
2777
+
2778
+ INPUT:
2779
+
2780
+ - ``expression`` -- Expression
2781
+ - ``calc_method`` -- Calculation method (default: ``None``)
2782
+
2783
+ TESTS::
2784
+
2785
+ sage: M = Manifold(2, 'M', structure='topological')
2786
+ sage: X.<x,y> = M.chart()
2787
+ sage: FR = X.function_ring()
2788
+ sage: f = FR._element_constructor_(sin(x*y))
2789
+ sage: f
2790
+ sin(x*y)
2791
+ sage: f.parent() is FR
2792
+ True
2793
+ sage: D = M.open_subset('D')
2794
+ sage: X_D = X.restrict(D, x^2+y^2<1)
2795
+ sage: FR_D = X_D.function_ring()
2796
+ sage: FR_D(f)
2797
+ sin(x*y)
2798
+ """
2799
+ if isinstance(expression, ChartFunction):
2800
+ if self._chart in expression._chart._subcharts:
2801
+ expression = expression.expr(method=calc_method)
2802
+ return self.element_class(self, expression, calc_method=calc_method)
2803
+
2804
+ def _coerce_map_from_(self, other):
2805
+ r"""
2806
+ Determine whether coercion to ``self`` exists from ``other``.
2807
+
2808
+ TESTS::
2809
+
2810
+ sage: M = Manifold(2, 'M', structure='topological')
2811
+ sage: X.<x,y> = M.chart()
2812
+ sage: FR = X.function_ring()
2813
+ sage: FR.has_coerce_map_from(RR)
2814
+ True
2815
+ sage: D = M.open_subset('D')
2816
+ sage: X_D = X.restrict(D, x^2+y^2<1)
2817
+ sage: FR_D = X_D.function_ring()
2818
+ sage: FR_D.has_coerce_map_from(FR)
2819
+ True
2820
+ """
2821
+ if SR.has_coerce_map_from(other):
2822
+ return True
2823
+ if isinstance(other, ChartFunctionRing):
2824
+ if self._chart in other._chart._subcharts:
2825
+ return True
2826
+ return False
2827
+
2828
+ def _repr_(self):
2829
+ r"""
2830
+ Return a string representation of ``self``.
2831
+
2832
+ EXAMPLES::
2833
+
2834
+ sage: M = Manifold(2, 'M', structure='topological')
2835
+ sage: X.<x,y> = M.chart()
2836
+ sage: X.function_ring()
2837
+ Ring of chart functions on Chart (M, (x, y))
2838
+ """
2839
+ return "Ring of chart functions on {}".format(self._chart)
2840
+
2841
+ def is_integral_domain(self, proof=True):
2842
+ """
2843
+ Return ``False`` as ``self`` is not an integral domain.
2844
+
2845
+ EXAMPLES::
2846
+
2847
+ sage: M = Manifold(2, 'M', structure='topological')
2848
+ sage: X.<x,y> = M.chart()
2849
+ sage: FR = X.function_ring()
2850
+ sage: FR.is_integral_domain()
2851
+ False
2852
+ sage: FR.is_field()
2853
+ False
2854
+ """
2855
+ return False
2856
+
2857
+ @cached_method
2858
+ def zero(self):
2859
+ """
2860
+ Return the constant function `0` in ``self``.
2861
+
2862
+ EXAMPLES::
2863
+
2864
+ sage: M = Manifold(2, 'M', structure='topological')
2865
+ sage: X.<x,y> = M.chart()
2866
+ sage: FR = X.function_ring()
2867
+ sage: FR.zero()
2868
+ 0
2869
+
2870
+ sage: # needs sage.rings.padics
2871
+ sage: M = Manifold(2, 'M', structure='topological', field=Qp(5))
2872
+ sage: X.<x,y> = M.chart()
2873
+ sage: X.function_ring().zero()
2874
+ 0
2875
+ """
2876
+ if self._chart.manifold().base_field_type() in ['real', 'complex']:
2877
+ elt = SR.zero()
2878
+ else:
2879
+ elt = self._chart.manifold().base_field().zero()
2880
+ res = self.element_class(self, elt)
2881
+ res.set_immutable()
2882
+ return res
2883
+
2884
+ @cached_method
2885
+ def one(self):
2886
+ """
2887
+ Return the constant function `1` in ``self``.
2888
+
2889
+ EXAMPLES::
2890
+
2891
+ sage: M = Manifold(2, 'M', structure='topological')
2892
+ sage: X.<x,y> = M.chart()
2893
+ sage: FR = X.function_ring()
2894
+ sage: FR.one()
2895
+ 1
2896
+
2897
+ sage: # needs sage.rings.padics
2898
+ sage: M = Manifold(2, 'M', structure='topological', field=Qp(5))
2899
+ sage: X.<x,y> = M.chart()
2900
+ sage: X.function_ring().one()
2901
+ 1 + O(5^20)
2902
+ """
2903
+ if self._chart.manifold().base_field_type() in ['real', 'complex']:
2904
+ elt = SR.one()
2905
+ else:
2906
+ elt = self._chart.manifold().base_field().one()
2907
+ res = self.element_class(self, elt)
2908
+ res.set_immutable()
2909
+ return res
2910
+
2911
+ is_field = is_integral_domain
2912
+
2913
+
2914
+ class MultiCoordFunction(SageObject, Mutability):
2915
+ r"""
2916
+ Coordinate function to some Cartesian power of the base field.
2917
+
2918
+ If `n` and `m` are two positive integers and `(U, \varphi)` is a chart on
2919
+ a topological manifold `M` of dimension `n` over a topological field `K`,
2920
+ a *multi-coordinate function* associated to `(U, \varphi)` is a map
2921
+
2922
+ .. MATH::
2923
+
2924
+ \begin{array}{llcl}
2925
+ f:& V \subset K^n & \longrightarrow & K^m \\
2926
+ & (x^1, \ldots, x^n) & \longmapsto & (f_1(x^1, \ldots, x^n),
2927
+ \ldots, f_m(x^1, \ldots, x^n)),
2928
+ \end{array}
2929
+
2930
+ where `V` is the codomain of `\varphi`. In other words, `f` is a
2931
+ `K^m`-valued function of the coordinates associated to the chart
2932
+ `(U, \varphi)`. Each component `f_i` (`1 \leq i \leq m`) is a coordinate
2933
+ function and is therefore stored as a
2934
+ :class:`~sage.manifolds.chart_func.ChartFunction`.
2935
+
2936
+ INPUT:
2937
+
2938
+ - ``chart`` -- the chart `(U, \varphi)`
2939
+ - ``expressions`` -- list (or tuple) of length `m` of elements to
2940
+ construct the coordinate functions `f_i` (`1 \leq i \leq m`); for
2941
+ symbolic coordinate functions, this must be symbolic expressions
2942
+ involving the chart coordinates, while for numerical coordinate
2943
+ functions, this must be data file names
2944
+
2945
+ EXAMPLES:
2946
+
2947
+ A function `f: V \subset \RR^2 \longrightarrow \RR^3`::
2948
+
2949
+ sage: forget() # to clear the previous assumption on x
2950
+ sage: M = Manifold(2, 'M', structure='topological')
2951
+ sage: X.<x,y> = M.chart()
2952
+ sage: f = X.multifunction(x-y, x*y, cos(x)*exp(y)); f
2953
+ Coordinate functions (x - y, x*y, cos(x)*e^y) on the Chart (M, (x, y))
2954
+ sage: type(f)
2955
+ <class 'sage.manifolds.chart_func.MultiCoordFunction'>
2956
+ sage: f(x,y)
2957
+ (x - y, x*y, cos(x)*e^y)
2958
+ sage: latex(f)
2959
+ \left(x - y, x y, \cos\left(x\right) e^{y}\right)
2960
+
2961
+ Each real-valued function `f_i` (`1 \leq i \leq m`) composing `f` can
2962
+ be accessed via the square-bracket operator, by providing `i-1` as an
2963
+ argument::
2964
+
2965
+ sage: f[0]
2966
+ x - y
2967
+ sage: f[1]
2968
+ x*y
2969
+ sage: f[2]
2970
+ cos(x)*e^y
2971
+
2972
+ We can give a more verbose explanation of each function::
2973
+
2974
+ sage: f[0].display()
2975
+ (x, y) ↦ x - y
2976
+
2977
+ Each ``f[i-1]`` is an instance of
2978
+ :class:`~sage.manifolds.chart_func.ChartFunction`::
2979
+
2980
+ sage: isinstance(f[0], sage.manifolds.chart_func.ChartFunction)
2981
+ True
2982
+
2983
+ A class :class:`MultiCoordFunction` can represent a
2984
+ real-valued function (case `m = 1`), although one should
2985
+ rather employ the class :class:`~sage.manifolds.chart_func.ChartFunction`
2986
+ for this purpose::
2987
+
2988
+ sage: g = X.multifunction(x*y^2)
2989
+ sage: g(x,y)
2990
+ (x*y^2,)
2991
+
2992
+ Evaluating the functions at specified coordinates::
2993
+
2994
+ sage: f(1,2)
2995
+ (-1, 2, cos(1)*e^2)
2996
+ sage: var('a b')
2997
+ (a, b)
2998
+ sage: f(a,b)
2999
+ (a - b, a*b, cos(a)*e^b)
3000
+ sage: g(1,2)
3001
+ (4,)
3002
+ """
3003
+
3004
+ def __init__(self, chart, expressions):
3005
+ r"""
3006
+ Initialize ``self``.
3007
+
3008
+ TESTS::
3009
+
3010
+ sage: M = Manifold(3, 'M', structure='topological')
3011
+ sage: X.<x,y,z> = M.chart()
3012
+ sage: f = X.multifunction(x+y+z, x*y*z); f
3013
+ Coordinate functions (x + y + z, x*y*z) on the Chart (M, (x, y, z))
3014
+ sage: type(f)
3015
+ <class 'sage.manifolds.chart_func.MultiCoordFunction'>
3016
+ sage: TestSuite(f).run()
3017
+ """
3018
+ self._chart = chart
3019
+ self._nc = len(self._chart._xx) # number of coordinates
3020
+ self._nf = len(expressions) # number of functions
3021
+ self._functions = tuple(chart.function(express) for express in expressions)
3022
+ Mutability.__init__(self)
3023
+
3024
+ def _repr_(self):
3025
+ r"""
3026
+ String representation of ``self``.
3027
+
3028
+ TESTS::
3029
+
3030
+ sage: M = Manifold(2, 'M', structure='topological')
3031
+ sage: X.<x,y> = M.chart()
3032
+ sage: f = X.multifunction(x-y, x*y, cos(x)*exp(y))
3033
+ sage: f._repr_()
3034
+ 'Coordinate functions (x - y, x*y, cos(x)*e^y) on the Chart (M, (x, y))'
3035
+ sage: f
3036
+ Coordinate functions (x - y, x*y, cos(x)*e^y) on the Chart (M, (x, y))
3037
+ """
3038
+ return "Coordinate functions {} on the {}".format(self._functions, self._chart)
3039
+
3040
+ def _latex_(self):
3041
+ r"""
3042
+ LaTeX representation of the object.
3043
+
3044
+ TESTS::
3045
+
3046
+ sage: M = Manifold(2, 'M', structure='topological')
3047
+ sage: X.<x,y> = M.chart()
3048
+ sage: f = X.multifunction(x-y, x*y, cos(x)*exp(y))
3049
+ sage: f._latex_()
3050
+ \left(x - y, x y, \cos\left(x\right) e^{y}\right)
3051
+ sage: latex(f)
3052
+ \left(x - y, x y, \cos\left(x\right) e^{y}\right)
3053
+ """
3054
+ from sage.misc.latex import latex
3055
+
3056
+ return latex(self._functions)
3057
+
3058
+ def expr(self, method=None):
3059
+ r"""
3060
+ Return a tuple of data, the item no. `i` being sufficient to
3061
+ reconstruct the coordinate function no. `i`.
3062
+
3063
+ In other words, if ``f`` is a multi-coordinate function, then
3064
+ ``f.chart().multifunction(*(f.expr()))`` results in a
3065
+ multi-coordinate function identical to ``f``.
3066
+
3067
+ INPUT:
3068
+
3069
+ - ``method`` -- string (default: ``None``); the calculus method which
3070
+ the returned expressions belong to. One of
3071
+
3072
+ - ``'SR'``: Sage's default symbolic engine (Symbolic Ring)
3073
+ - ``'sympy'``: SymPy
3074
+ - ``None``: the chart current calculus method is assumed
3075
+
3076
+ OUTPUT:
3077
+
3078
+ - a tuple of the symbolic expressions of the chart functions
3079
+ composing ``self``
3080
+
3081
+ EXAMPLES::
3082
+
3083
+ sage: M = Manifold(2, 'M', structure='topological')
3084
+ sage: X.<x,y> = M.chart()
3085
+ sage: f = X.multifunction(x-y, x*y, cos(x)*exp(y))
3086
+ sage: f.expr()
3087
+ (x - y, x*y, cos(x)*e^y)
3088
+ sage: type(f.expr()[0])
3089
+ <class 'sage.symbolic.expression.Expression'>
3090
+
3091
+ A SymPy output::
3092
+
3093
+ sage: f.expr('sympy')
3094
+ (x - y, x*y, exp(y)*cos(x))
3095
+ sage: type(f.expr('sympy')[0])
3096
+ <class 'sympy.core.add.Add'>
3097
+
3098
+ One shall always have::
3099
+
3100
+ sage: f.chart().multifunction(*(f.expr())) == f
3101
+ True
3102
+ """
3103
+ return tuple(func.expr(method=method) for func in self._functions)
3104
+
3105
+ def chart(self):
3106
+ r"""
3107
+ Return the chart with respect to which ``self`` is defined.
3108
+
3109
+ OUTPUT: a :class:`~sage.manifolds.chart.Chart`
3110
+
3111
+ EXAMPLES::
3112
+
3113
+ sage: M = Manifold(2, 'M', structure='topological')
3114
+ sage: X.<x,y> = M.chart()
3115
+ sage: f = X.multifunction(x-y, x*y, cos(x)*exp(y))
3116
+ sage: f.chart()
3117
+ Chart (M, (x, y))
3118
+ sage: f.chart() is X
3119
+ True
3120
+ """
3121
+ return self._chart
3122
+
3123
+ def __eq__(self, other):
3124
+ r"""
3125
+ Comparison (equality) operator.
3126
+
3127
+ INPUT:
3128
+
3129
+ - ``other`` -- a :class:`MultiCoordFunction`
3130
+
3131
+ OUTPUT: ``True`` if ``self`` is equal to ``other``, ``False`` otherwise
3132
+
3133
+ TESTS::
3134
+
3135
+ sage: M = Manifold(2, 'M', structure='topological')
3136
+ sage: X.<x,y> = M.chart()
3137
+ sage: f = X.multifunction(x-y, x*y, cos(x*y))
3138
+ sage: f == X.multifunction(x-y, x*y)
3139
+ False
3140
+ sage: f == X.multifunction(x-y, x*y, 2)
3141
+ False
3142
+ sage: f == X.multifunction(x-y, x*y, cos(y*x))
3143
+ True
3144
+ sage: Y.<u,v> = M.chart()
3145
+ sage: f == Y.multifunction(u-v, u*v, cos(u*v))
3146
+ False
3147
+ """
3148
+ if other is self:
3149
+ return True
3150
+ if not isinstance(other, MultiCoordFunction):
3151
+ return False
3152
+ if other._chart != self._chart:
3153
+ return False
3154
+ if other._nf != self._nf:
3155
+ return False
3156
+ return all(other._functions[i] == self._functions[i] for i in range(self._nf))
3157
+
3158
+ def __ne__(self, other):
3159
+ r"""
3160
+ Inequality operator.
3161
+
3162
+ INPUT:
3163
+
3164
+ - ``other`` -- a :class:`MultiCoordFunction`
3165
+
3166
+ OUTPUT:
3167
+
3168
+ - ``True`` if ``self`` is different from ``other``, ``False``
3169
+ otherwise
3170
+
3171
+ TESTS::
3172
+
3173
+ sage: M = Manifold(2, 'M', structure='topological')
3174
+ sage: X.<x,y> = M.chart()
3175
+ sage: f = X.multifunction(x-y, x*y, cos(x*y))
3176
+ sage: f != X.multifunction(x-y, x*y)
3177
+ True
3178
+ sage: f != X.multifunction(x, y, 2)
3179
+ True
3180
+ sage: f != X.multifunction(x-y, x*y, cos(x*y))
3181
+ False
3182
+ """
3183
+ return not (self == other)
3184
+
3185
+ def __getitem__(self, index):
3186
+ r"""
3187
+ Return a specified function of the set represented by ``self``.
3188
+
3189
+ INPUT:
3190
+
3191
+ - ``index`` -- index `i` of the function (`0 \leq i \leq m-1`)
3192
+
3193
+ OUTPUT:
3194
+
3195
+ -- a :class:`ChartFunction` representing the function
3196
+
3197
+ TESTS::
3198
+
3199
+ sage: M = Manifold(2, 'M', structure='topological')
3200
+ sage: X.<x,y> = M.chart()
3201
+ sage: f = X.multifunction(x-y, x*y, cos(x*y))
3202
+ sage: f.__getitem__(0)
3203
+ x - y
3204
+ sage: f.__getitem__(1)
3205
+ x*y
3206
+ sage: f.__getitem__(2)
3207
+ cos(x*y)
3208
+ sage: f[0], f[1], f[2]
3209
+ (x - y, x*y, cos(x*y))
3210
+ """
3211
+ return self._functions[index]
3212
+
3213
+ def __call__(self, *coords, **options):
3214
+ r"""
3215
+ Compute the values of the functions at specified coordinates.
3216
+
3217
+ INPUT:
3218
+
3219
+ - ``*coords`` -- list of coordinates where the functions are
3220
+ to be evaluated
3221
+ - ``**options`` -- allows to pass some options, e.g.,
3222
+ ``simplify=False`` to disable simplification for symbolic
3223
+ coordinate functions
3224
+
3225
+ OUTPUT: tuple containing the values of the `m` functions
3226
+
3227
+ TESTS::
3228
+
3229
+ sage: M = Manifold(2, 'M', structure='topological')
3230
+ sage: X.<x,y> = M.chart()
3231
+ sage: f = X.multifunction(x-y, x*y, cos(x*y))
3232
+ sage: f.__call__(2,3)
3233
+ (-1, 6, cos(6))
3234
+ sage: f(2,3)
3235
+ (-1, 6, cos(6))
3236
+ sage: f.__call__(x,y)
3237
+ (x - y, x*y, cos(x*y))
3238
+ """
3239
+ return tuple(func(*coords, **options) for func in self._functions)
3240
+
3241
+ @cached_method
3242
+ def jacobian(self):
3243
+ r"""
3244
+ Return the Jacobian matrix of the system of coordinate functions.
3245
+
3246
+ ``jacobian()`` is a 2-dimensional array of size `m \times n`,
3247
+ where `m` is the number of functions and `n` the number of
3248
+ coordinates, the generic element being
3249
+ `J_{ij} = \frac{\partial f_i}{\partial x^j}` with `1 \leq i \leq m`
3250
+ (row index) and `1 \leq j \leq n` (column index).
3251
+
3252
+ OUTPUT:
3253
+
3254
+ - Jacobian matrix as a 2-dimensional array ``J`` of
3255
+ coordinate functions with ``J[i-1][j-1]`` being
3256
+ `J_{ij} = \frac{\partial f_i}{\partial x^j}`
3257
+ for `1 \leq i \leq m` and `1 \leq j \leq n`
3258
+
3259
+ EXAMPLES:
3260
+
3261
+ Jacobian of a set of 3 functions of 2 coordinates::
3262
+
3263
+ sage: M = Manifold(2, 'M', structure='topological')
3264
+ sage: X.<x,y> = M.chart()
3265
+ sage: f = X.multifunction(x-y, x*y, y^3*cos(x))
3266
+ sage: f.jacobian()
3267
+ [ 1 -1]
3268
+ [ y x]
3269
+ [ -y^3*sin(x) 3*y^2*cos(x)]
3270
+
3271
+ Each element of the result is a
3272
+ :class:`chart function <ChartFunction>`::
3273
+
3274
+ sage: type(f.jacobian()[2,0])
3275
+ <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
3276
+ sage: f.jacobian()[2,0].display()
3277
+ (x, y) ↦ -y^3*sin(x)
3278
+
3279
+ Test of the computation::
3280
+
3281
+ sage: [[f.jacobian()[i,j] == f[i].diff(j) for j in range(2)] for i in range(3)]
3282
+ [[True, True], [True, True], [True, True]]
3283
+
3284
+ Test with ``start_index = 1``::
3285
+
3286
+ sage: M = Manifold(2, 'M', structure='topological', start_index=1)
3287
+ sage: X.<x,y> = M.chart()
3288
+ sage: f = X.multifunction(x-y, x*y, y^3*cos(x))
3289
+ sage: f.jacobian()
3290
+ [ 1 -1]
3291
+ [ y x]
3292
+ [ -y^3*sin(x) 3*y^2*cos(x)]
3293
+ sage: [[f.jacobian()[i,j] == f[i].diff(j+1) for j in range(2)] # note the j+1
3294
+ ....: for i in range(3)]
3295
+ [[True, True], [True, True], [True, True]]
3296
+ """
3297
+ from sage.matrix.constructor import matrix
3298
+
3299
+ mat = matrix(
3300
+ [[func.diff(coord) for coord in self._chart[:]] for func in self._functions]
3301
+ )
3302
+ mat.set_immutable()
3303
+ return mat
3304
+
3305
+ @cached_method
3306
+ def jacobian_det(self):
3307
+ r"""
3308
+ Return the Jacobian determinant of the system of functions.
3309
+
3310
+ The number `m` of coordinate functions must equal the number `n`
3311
+ of coordinates.
3312
+
3313
+ OUTPUT: a :class:`ChartFunction` representing the determinant
3314
+
3315
+ EXAMPLES:
3316
+
3317
+ Jacobian determinant of a set of 2 functions of 2 coordinates::
3318
+
3319
+ sage: M = Manifold(2, 'M', structure='topological')
3320
+ sage: X.<x,y> = M.chart()
3321
+ sage: f = X.multifunction(x-y, x*y)
3322
+ sage: f.jacobian_det()
3323
+ x + y
3324
+
3325
+ The output of :meth:`jacobian_det` is an instance of
3326
+ :class:`ChartFunction` and can therefore be called on specific
3327
+ values of the coordinates, e.g. `(x,y) = (1,2)`::
3328
+
3329
+ sage: type(f.jacobian_det())
3330
+ <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
3331
+ sage: f.jacobian_det().display()
3332
+ (x, y) ↦ x + y
3333
+ sage: f.jacobian_det()(1,2)
3334
+ 3
3335
+
3336
+ The result is cached::
3337
+
3338
+ sage: f.jacobian_det() is f.jacobian_det()
3339
+ True
3340
+
3341
+ We verify the determinant of the Jacobian::
3342
+
3343
+ sage: f.jacobian_det() == det(matrix([[f[i].diff(j).expr() for j in range(2)]
3344
+ ....: for i in range(2)]))
3345
+ True
3346
+
3347
+ An example using SymPy::
3348
+
3349
+ sage: M.set_calculus_method('sympy')
3350
+ sage: g = X.multifunction(x*y^3, e^x)
3351
+ sage: g.jacobian_det()
3352
+ -3*x*y**2*exp(x)
3353
+ sage: type(g.jacobian_det().expr())
3354
+ <class 'sympy.core.mul.Mul'>
3355
+
3356
+ Jacobian determinant of a set of 3 functions of 3 coordinates::
3357
+
3358
+ sage: M = Manifold(3, 'M', structure='topological')
3359
+ sage: X.<x,y,z> = M.chart()
3360
+ sage: f = X.multifunction(x*y+z^2, z^2*x+y^2*z, (x*y*z)^3)
3361
+ sage: f.jacobian_det().display()
3362
+ (x, y, z) ↦ 6*x^3*y^5*z^3 - 3*x^4*y^3*z^4 - 12*x^2*y^4*z^5 + 6*x^3*y^2*z^6
3363
+
3364
+ We verify the determinant of the Jacobian::
3365
+
3366
+ sage: f.jacobian_det() == det(matrix([[f[i].diff(j).expr() for j in range(3)]
3367
+ ....: for i in range(3)]))
3368
+ True
3369
+ """
3370
+ from sage.matrix.constructor import matrix
3371
+
3372
+ if self._nf != self._nc:
3373
+ raise ValueError("the Jacobian matrix is not a square matrix")
3374
+ mat = self.jacobian()
3375
+ # TODO: do the computation without the 'SR' enforcement
3376
+ mat_expr = matrix(
3377
+ [
3378
+ [mat[i, j].expr(method='SR') for i in range(self._nc)]
3379
+ for j in range(self._nc)
3380
+ ]
3381
+ )
3382
+ det = mat_expr.det() # the unsimplified determinant
3383
+ func = self._functions[0]
3384
+ return type(func)(
3385
+ func.parent(),
3386
+ func._calc_method.simplify(det, method='SR'),
3387
+ calc_method=self._chart._calc_method._current,
3388
+ )
3389
+
3390
+ def set_immutable(self):
3391
+ r"""
3392
+ Set ``self`` and all chart functions of ``self`` immutable.
3393
+
3394
+ EXAMPLES:
3395
+
3396
+ Declare a coordinate function immutable::
3397
+
3398
+ sage: M = Manifold(3, 'M', structure='topological')
3399
+ sage: X.<x,y,z> = M.chart()
3400
+ sage: f = X.multifunction(x+y+z, x*y*z)
3401
+ sage: f.is_immutable()
3402
+ False
3403
+ sage: f.set_immutable()
3404
+ sage: f.is_immutable()
3405
+ True
3406
+
3407
+ The chart functions are now immutable, too::
3408
+
3409
+ sage: f[0].parent()
3410
+ Ring of chart functions on Chart (M, (x, y, z))
3411
+ sage: f[0].is_immutable()
3412
+ True
3413
+ """
3414
+ for func in self._functions:
3415
+ func.set_immutable()
3416
+ Mutability.set_immutable(self)