passagemath-symbolics 10.6.40__cp314-cp314t-macosx_13_0_x86_64.whl

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

Potentially problematic release.


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

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