passagemath-symbolics 10.6.43__cp314-cp314t-musllinux_1_2_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 (171) hide show
  1. passagemath_symbolics/__init__.py +3 -0
  2. passagemath_symbolics-10.6.43.dist-info/METADATA +187 -0
  3. passagemath_symbolics-10.6.43.dist-info/RECORD +171 -0
  4. passagemath_symbolics-10.6.43.dist-info/WHEEL +5 -0
  5. passagemath_symbolics-10.6.43.dist-info/top_level.txt +3 -0
  6. sage/all__sagemath_symbolics.py +17 -0
  7. sage/calculus/all.py +14 -0
  8. sage/calculus/calculus.py +2826 -0
  9. sage/calculus/desolvers.py +1866 -0
  10. sage/calculus/predefined.py +51 -0
  11. sage/calculus/tests.py +225 -0
  12. sage/calculus/var.cpython-314t-x86_64-linux-musl.so +0 -0
  13. sage/calculus/var.pyx +401 -0
  14. sage/dynamics/all__sagemath_symbolics.py +6 -0
  15. sage/dynamics/complex_dynamics/all.py +5 -0
  16. sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
  17. sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-314t-x86_64-linux-musl.so +0 -0
  18. sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1035 -0
  19. sage/ext/all__sagemath_symbolics.py +1 -0
  20. sage/ext_data/kenzo/CP2.txt +45 -0
  21. sage/ext_data/kenzo/CP3.txt +349 -0
  22. sage/ext_data/kenzo/CP4.txt +4774 -0
  23. sage/ext_data/kenzo/README.txt +49 -0
  24. sage/ext_data/kenzo/S4.txt +20 -0
  25. sage/ext_data/magma/latex/latex.m +1021 -0
  26. sage/ext_data/magma/latex/latex.spec +1 -0
  27. sage/ext_data/magma/sage/basic.m +356 -0
  28. sage/ext_data/magma/sage/sage.spec +1 -0
  29. sage/ext_data/magma/spec +9 -0
  30. sage/geometry/all__sagemath_symbolics.py +8 -0
  31. sage/geometry/hyperbolic_space/all.py +5 -0
  32. sage/geometry/hyperbolic_space/hyperbolic_coercion.py +743 -0
  33. sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
  34. sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2409 -0
  35. sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
  36. sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1082 -0
  37. sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
  38. sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
  39. sage/geometry/riemannian_manifolds/all.py +7 -0
  40. sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
  41. sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
  42. sage/interfaces/all__sagemath_symbolics.py +1 -0
  43. sage/interfaces/magma.py +3017 -0
  44. sage/interfaces/magma_free.py +92 -0
  45. sage/interfaces/maple.py +1397 -0
  46. sage/interfaces/mathematica.py +1345 -0
  47. sage/interfaces/mathics.py +1312 -0
  48. sage/interfaces/sympy.py +1398 -0
  49. sage/interfaces/sympy_wrapper.py +197 -0
  50. sage/interfaces/tides.py +938 -0
  51. sage/libs/all__sagemath_symbolics.py +6 -0
  52. sage/manifolds/all.py +7 -0
  53. sage/manifolds/calculus_method.py +555 -0
  54. sage/manifolds/catalog.py +437 -0
  55. sage/manifolds/chart.py +4019 -0
  56. sage/manifolds/chart_func.py +3419 -0
  57. sage/manifolds/continuous_map.py +2183 -0
  58. sage/manifolds/continuous_map_image.py +155 -0
  59. sage/manifolds/differentiable/affine_connection.py +2475 -0
  60. sage/manifolds/differentiable/all.py +1 -0
  61. sage/manifolds/differentiable/automorphismfield.py +1383 -0
  62. sage/manifolds/differentiable/automorphismfield_group.py +604 -0
  63. sage/manifolds/differentiable/bundle_connection.py +1445 -0
  64. sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
  65. sage/manifolds/differentiable/chart.py +1241 -0
  66. sage/manifolds/differentiable/curve.py +1028 -0
  67. sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
  68. sage/manifolds/differentiable/degenerate.py +559 -0
  69. sage/manifolds/differentiable/degenerate_submanifold.py +1671 -0
  70. sage/manifolds/differentiable/diff_form.py +1658 -0
  71. sage/manifolds/differentiable/diff_form_module.py +1062 -0
  72. sage/manifolds/differentiable/diff_map.py +1315 -0
  73. sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
  74. sage/manifolds/differentiable/examples/all.py +1 -0
  75. sage/manifolds/differentiable/examples/euclidean.py +2517 -0
  76. sage/manifolds/differentiable/examples/real_line.py +897 -0
  77. sage/manifolds/differentiable/examples/sphere.py +1186 -0
  78. sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
  79. sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
  80. sage/manifolds/differentiable/integrated_curve.py +4035 -0
  81. sage/manifolds/differentiable/levi_civita_connection.py +841 -0
  82. sage/manifolds/differentiable/manifold.py +4254 -0
  83. sage/manifolds/differentiable/manifold_homset.py +1826 -0
  84. sage/manifolds/differentiable/metric.py +3032 -0
  85. sage/manifolds/differentiable/mixed_form.py +1507 -0
  86. sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
  87. sage/manifolds/differentiable/multivector_module.py +800 -0
  88. sage/manifolds/differentiable/multivectorfield.py +1520 -0
  89. sage/manifolds/differentiable/poisson_tensor.py +268 -0
  90. sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
  91. sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
  92. sage/manifolds/differentiable/scalarfield.py +1343 -0
  93. sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
  94. sage/manifolds/differentiable/symplectic_form.py +910 -0
  95. sage/manifolds/differentiable/symplectic_form_test.py +220 -0
  96. sage/manifolds/differentiable/tangent_space.py +412 -0
  97. sage/manifolds/differentiable/tangent_vector.py +616 -0
  98. sage/manifolds/differentiable/tensorfield.py +4665 -0
  99. sage/manifolds/differentiable/tensorfield_module.py +963 -0
  100. sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
  101. sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
  102. sage/manifolds/differentiable/vector_bundle.py +1728 -0
  103. sage/manifolds/differentiable/vectorfield.py +1717 -0
  104. sage/manifolds/differentiable/vectorfield_module.py +2445 -0
  105. sage/manifolds/differentiable/vectorframe.py +1832 -0
  106. sage/manifolds/family.py +270 -0
  107. sage/manifolds/local_frame.py +1490 -0
  108. sage/manifolds/manifold.py +3090 -0
  109. sage/manifolds/manifold_homset.py +452 -0
  110. sage/manifolds/operators.py +359 -0
  111. sage/manifolds/point.py +994 -0
  112. sage/manifolds/scalarfield.py +3718 -0
  113. sage/manifolds/scalarfield_algebra.py +629 -0
  114. sage/manifolds/section.py +3111 -0
  115. sage/manifolds/section_module.py +831 -0
  116. sage/manifolds/structure.py +229 -0
  117. sage/manifolds/subset.py +2764 -0
  118. sage/manifolds/subsets/all.py +1 -0
  119. sage/manifolds/subsets/closure.py +131 -0
  120. sage/manifolds/subsets/pullback.py +885 -0
  121. sage/manifolds/topological_submanifold.py +891 -0
  122. sage/manifolds/trivialization.py +733 -0
  123. sage/manifolds/utilities.py +1348 -0
  124. sage/manifolds/vector_bundle.py +1342 -0
  125. sage/manifolds/vector_bundle_fiber.py +332 -0
  126. sage/manifolds/vector_bundle_fiber_element.py +111 -0
  127. sage/matrix/all__sagemath_symbolics.py +1 -0
  128. sage/matrix/matrix_symbolic_dense.cpython-314t-x86_64-linux-musl.so +0 -0
  129. sage/matrix/matrix_symbolic_dense.pxd +6 -0
  130. sage/matrix/matrix_symbolic_dense.pyx +1022 -0
  131. sage/matrix/matrix_symbolic_sparse.cpython-314t-x86_64-linux-musl.so +0 -0
  132. sage/matrix/matrix_symbolic_sparse.pxd +6 -0
  133. sage/matrix/matrix_symbolic_sparse.pyx +1029 -0
  134. sage/modules/all__sagemath_symbolics.py +1 -0
  135. sage/modules/vector_callable_symbolic_dense.py +105 -0
  136. sage/modules/vector_symbolic_dense.py +116 -0
  137. sage/modules/vector_symbolic_sparse.py +118 -0
  138. sage/rings/all__sagemath_symbolics.py +4 -0
  139. sage/rings/asymptotic/all.py +6 -0
  140. sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
  141. sage/rings/asymptotic/asymptotic_ring.py +4858 -0
  142. sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4153 -0
  143. sage/rings/asymptotic/growth_group.py +5373 -0
  144. sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
  145. sage/rings/asymptotic/term_monoid.py +5237 -0
  146. sage/rings/function_field/all__sagemath_symbolics.py +2 -0
  147. sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
  148. sage/symbolic/all.py +15 -0
  149. sage/symbolic/assumptions.py +985 -0
  150. sage/symbolic/benchmark.py +93 -0
  151. sage/symbolic/callable.py +459 -0
  152. sage/symbolic/complexity_measures.py +35 -0
  153. sage/symbolic/constants.py +1287 -0
  154. sage/symbolic/expression_conversion_algebraic.py +310 -0
  155. sage/symbolic/expression_conversion_sympy.py +317 -0
  156. sage/symbolic/expression_conversions.py +1713 -0
  157. sage/symbolic/function_factory.py +355 -0
  158. sage/symbolic/integration/all.py +1 -0
  159. sage/symbolic/integration/external.py +270 -0
  160. sage/symbolic/integration/integral.py +1115 -0
  161. sage/symbolic/maxima_wrapper.py +162 -0
  162. sage/symbolic/operators.py +267 -0
  163. sage/symbolic/random_tests.py +462 -0
  164. sage/symbolic/relation.py +1907 -0
  165. sage/symbolic/ring.cpython-314t-x86_64-linux-musl.so +0 -0
  166. sage/symbolic/ring.pxd +5 -0
  167. sage/symbolic/ring.pyx +1396 -0
  168. sage/symbolic/subring.py +1025 -0
  169. sage/symbolic/symengine.py +19 -0
  170. sage/symbolic/tests.py +40 -0
  171. sage/symbolic/units.py +1470 -0
@@ -0,0 +1,3718 @@
1
+ # sage_setup: distribution = sagemath-symbolics
2
+ r"""
3
+ Scalar Fields
4
+
5
+ Given a topological manifold `M` over a topological field `K` (in most
6
+ applications, `K = \RR` or `K = \CC`), a *scalar field* on `M` is a
7
+ continuous map
8
+
9
+ .. MATH::
10
+
11
+ f: M \longrightarrow K
12
+
13
+ Scalar fields are implemented by the class :class:`ScalarField`.
14
+
15
+ AUTHORS:
16
+
17
+ - Eric Gourgoulhon, Michal Bejger (2013-2015): initial version
18
+ - Travis Scrimshaw (2016): review tweaks
19
+ - Marco Mancini (2017): SymPy as an optional symbolic engine, alternative to SR
20
+ - Florentin Jaffredo (2018) : series expansion with respect to a given
21
+ parameter
22
+ - Michael Jung (2019) : improve restrictions; make ``display()`` show all
23
+ distinct expressions
24
+
25
+ REFERENCES:
26
+
27
+ - [Lee2011]_
28
+ - [KN1963]_
29
+ """
30
+
31
+ # *****************************************************************************
32
+ # Copyright (C) 2015 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
33
+ # Copyright (C) 2015 Michal Bejger <bejger@camk.edu.pl>
34
+ # Copyright (C) 2016 Travis Scrimshaw <tscrimsh@umn.edu>
35
+ # Copyright (C) 2017 Marco Mancini <marco.mancini@obspm.fr>
36
+ #
37
+ # Distributed under the terms of the GNU General Public License (GPL)
38
+ # as published by the Free Software Foundation; either version 2 of
39
+ # the License, or (at your option) any later version.
40
+ # https://www.gnu.org/licenses/
41
+ # *****************************************************************************
42
+
43
+ from __future__ import annotations
44
+
45
+ from typing import TYPE_CHECKING, Optional
46
+
47
+ from sage.manifolds.chart_func import ChartFunction
48
+ from sage.misc.cachefunc import cached_method
49
+ from sage.structure.element import (
50
+ CommutativeAlgebraElement,
51
+ ModuleElementWithMutability,
52
+ )
53
+ from sage.symbolic.expression import Expression
54
+
55
+ if TYPE_CHECKING:
56
+ from sage.manifolds.chart import Chart
57
+ from sage.tensor.modules.format_utilities import FormattedExpansion
58
+
59
+
60
+ class ScalarField(CommutativeAlgebraElement, ModuleElementWithMutability):
61
+ r"""
62
+ Scalar field on a topological manifold.
63
+
64
+ Given a topological manifold `M` over a topological field `K` (in most
65
+ applications, `K = \RR` or `K = \CC`), a *scalar field on* `M` is a
66
+ continuous map
67
+
68
+ .. MATH::
69
+
70
+ f: M \longrightarrow K.
71
+
72
+ A scalar field on `M` is an element of the commutative algebra
73
+ `C^0(M)` (see
74
+ :class:`~sage.manifolds.scalarfield_algebra.ScalarFieldAlgebra`).
75
+
76
+ INPUT:
77
+
78
+ - ``parent`` -- the algebra of scalar fields containing the scalar field
79
+ (must be an instance of class
80
+ :class:`~sage.manifolds.scalarfield_algebra.ScalarFieldAlgebra`)
81
+
82
+ - ``coord_expression`` -- (default: ``None``) coordinate expression(s) of
83
+ the scalar field; this can be either
84
+
85
+ * a dictionary of coordinate expressions in various charts on
86
+ the domain, with the charts as keys;
87
+ * a single coordinate expression; if the argument ``chart`` is
88
+ ``'all'``, this expression is set to all the charts defined
89
+ on the open set; otherwise, the expression is set in the
90
+ specific chart provided by the argument ``chart``
91
+
92
+ - ``chart`` -- (default: ``None``) chart defining the coordinates used
93
+ in ``coord_expression`` when the latter is a single coordinate
94
+ expression; if none is provided (default), the default chart of the
95
+ open set is assumed. If ``chart=='all'``, ``coord_expression`` is
96
+ assumed to be independent of the chart (constant scalar field).
97
+
98
+ - ``name`` -- (default: ``None``) string; name (symbol) given to the
99
+ scalar field
100
+
101
+ - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote the
102
+ scalar field; if none is provided, the LaTeX symbol is set to ``name``
103
+
104
+ If ``coord_expression`` is ``None`` or incomplete, coordinate
105
+ expressions can be added after the creation of the object, by means of
106
+ the methods :meth:`add_expr`, :meth:`add_expr_by_continuation` and
107
+ :meth:`set_expr`.
108
+
109
+ EXAMPLES:
110
+
111
+ A scalar field on the 2-sphere::
112
+
113
+ sage: M = Manifold(2, 'M', structure='topological') # the 2-dimensional sphere S^2
114
+ sage: U = M.open_subset('U') # complement of the North pole
115
+ sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
116
+ sage: V = M.open_subset('V') # complement of the South pole
117
+ sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
118
+ sage: M.declare_union(U,V) # S^2 is the union of U and V
119
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)),
120
+ ....: intersection_name='W',
121
+ ....: restrictions1= x^2+y^2!=0,
122
+ ....: restrictions2= u^2+v^2!=0)
123
+ sage: uv_to_xy = xy_to_uv.inverse()
124
+ sage: f = M.scalar_field({c_xy: 1/(1+x^2+y^2), c_uv: (u^2+v^2)/(1+u^2+v^2)},
125
+ ....: name='f') ; f
126
+ Scalar field f on the 2-dimensional topological manifold M
127
+ sage: f.display()
128
+ f: M → ℝ
129
+ on U: (x, y) ↦ 1/(x^2 + y^2 + 1)
130
+ on V: (u, v) ↦ (u^2 + v^2)/(u^2 + v^2 + 1)
131
+
132
+ For scalar fields defined by a single coordinate expression, the latter
133
+ can be passed instead of the dictionary over the charts::
134
+
135
+ sage: g = U.scalar_field(x*y, chart=c_xy, name='g') ; g
136
+ Scalar field g on the Open subset U of the 2-dimensional topological
137
+ manifold M
138
+
139
+ The above is indeed equivalent to::
140
+
141
+ sage: g = U.scalar_field({c_xy: x*y}, name='g') ; g
142
+ Scalar field g on the Open subset U of the 2-dimensional topological
143
+ manifold M
144
+
145
+ Since ``c_xy`` is the default chart of ``U``, the argument ``chart`` can
146
+ be skipped::
147
+
148
+ sage: g = U.scalar_field(x*y, name='g') ; g
149
+ Scalar field g on the Open subset U of the 2-dimensional topological
150
+ manifold M
151
+
152
+ The scalar field `g` is defined on `U` and has an expression in terms of
153
+ the coordinates `(u,v)` on `W=U\cap V`::
154
+
155
+ sage: g.display()
156
+ g: U → ℝ
157
+ (x, y) ↦ x*y
158
+ on W: (u, v) ↦ u*v/(u^4 + 2*u^2*v^2 + v^4)
159
+
160
+ Scalar fields on `M` can also be declared with a single chart::
161
+
162
+ sage: f = M.scalar_field(1/(1+x^2+y^2), chart=c_xy, name='f') ; f
163
+ Scalar field f on the 2-dimensional topological manifold M
164
+
165
+ Their definition must then be completed by providing the expressions on
166
+ other charts, via the method :meth:`add_expr`, to get a global cover of
167
+ the manifold::
168
+
169
+ sage: f.add_expr((u^2+v^2)/(1+u^2+v^2), chart=c_uv)
170
+ sage: f.display()
171
+ f: M → ℝ
172
+ on U: (x, y) ↦ 1/(x^2 + y^2 + 1)
173
+ on V: (u, v) ↦ (u^2 + v^2)/(u^2 + v^2 + 1)
174
+
175
+ We can even first declare the scalar field without any coordinate
176
+ expression and provide them subsequently::
177
+
178
+ sage: f = M.scalar_field(name='f')
179
+ sage: f.add_expr(1/(1+x^2+y^2), chart=c_xy)
180
+ sage: f.add_expr((u^2+v^2)/(1+u^2+v^2), chart=c_uv)
181
+ sage: f.display()
182
+ f: M → ℝ
183
+ on U: (x, y) ↦ 1/(x^2 + y^2 + 1)
184
+ on V: (u, v) ↦ (u^2 + v^2)/(u^2 + v^2 + 1)
185
+
186
+ We may also use the method :meth:`add_expr_by_continuation` to complete
187
+ the coordinate definition using the analytic continuation from domains in
188
+ which charts overlap::
189
+
190
+ sage: f = M.scalar_field(1/(1+x^2+y^2), chart=c_xy, name='f') ; f
191
+ Scalar field f on the 2-dimensional topological manifold M
192
+ sage: f.add_expr_by_continuation(c_uv, U.intersection(V))
193
+ sage: f.display()
194
+ f: M → ℝ
195
+ on U: (x, y) ↦ 1/(x^2 + y^2 + 1)
196
+ on V: (u, v) ↦ (u^2 + v^2)/(u^2 + v^2 + 1)
197
+
198
+ A scalar field can also be defined by some unspecified function of the
199
+ coordinates::
200
+
201
+ sage: h = U.scalar_field(function('H')(x, y), name='h') ; h
202
+ Scalar field h on the Open subset U of the 2-dimensional topological
203
+ manifold M
204
+ sage: h.display()
205
+ h: U → ℝ
206
+ (x, y) ↦ H(x, y)
207
+ on W: (u, v) ↦ H(u/(u^2 + v^2), v/(u^2 + v^2))
208
+
209
+ We may use the argument ``latex_name`` to specify the LaTeX symbol denoting
210
+ the scalar field if the latter is different from ``name``::
211
+
212
+ sage: latex(f)
213
+ f
214
+ sage: f = M.scalar_field({c_xy: 1/(1+x^2+y^2), c_uv: (u^2+v^2)/(1+u^2+v^2)},
215
+ ....: name='f', latex_name=r'\mathcal{F}')
216
+ sage: latex(f)
217
+ \mathcal{F}
218
+
219
+ The coordinate expression in a given chart is obtained via the method
220
+ :meth:`expr`, which returns a symbolic expression::
221
+
222
+ sage: f.expr(c_uv)
223
+ (u^2 + v^2)/(u^2 + v^2 + 1)
224
+ sage: type(f.expr(c_uv))
225
+ <class 'sage.symbolic.expression.Expression'>
226
+
227
+ The method :meth:`coord_function` returns instead a function of the
228
+ chart coordinates, i.e. an instance of
229
+ :class:`~sage.manifolds.chart_func.ChartFunction`::
230
+
231
+ sage: f.coord_function(c_uv)
232
+ (u^2 + v^2)/(u^2 + v^2 + 1)
233
+ sage: type(f.coord_function(c_uv))
234
+ <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
235
+ sage: f.coord_function(c_uv).display()
236
+ (u, v) ↦ (u^2 + v^2)/(u^2 + v^2 + 1)
237
+
238
+ The value returned by the method :meth:`expr` is actually the coordinate
239
+ expression of the chart function::
240
+
241
+ sage: f.expr(c_uv) is f.coord_function(c_uv).expr()
242
+ True
243
+
244
+ A constant scalar field is declared by setting the argument ``chart`` to
245
+ ``'all'``::
246
+
247
+ sage: c = M.scalar_field(2, chart='all', name='c') ; c
248
+ Scalar field c on the 2-dimensional topological manifold M
249
+ sage: c.display()
250
+ c: M → ℝ
251
+ on U: (x, y) ↦ 2
252
+ on V: (u, v) ↦ 2
253
+
254
+ A shortcut is to use the method
255
+ :meth:`~sage.manifolds.manifold.TopologicalManifold.constant_scalar_field`::
256
+
257
+ sage: c == M.constant_scalar_field(2)
258
+ True
259
+
260
+ The constant value can be some unspecified parameter::
261
+
262
+ sage: var('a')
263
+ a
264
+ sage: c = M.constant_scalar_field(a, name='c') ; c
265
+ Scalar field c on the 2-dimensional topological manifold M
266
+ sage: c.display()
267
+ c: M → ℝ
268
+ on U: (x, y) ↦ a
269
+ on V: (u, v) ↦ a
270
+
271
+ A special case of constant field is the zero scalar field::
272
+
273
+ sage: zer = M.constant_scalar_field(0) ; zer
274
+ Scalar field zero on the 2-dimensional topological manifold M
275
+ sage: zer.display()
276
+ zero: M → ℝ
277
+ on U: (x, y) ↦ 0
278
+ on V: (u, v) ↦ 0
279
+
280
+ It can be obtained directly by means of the function
281
+ :meth:`~sage.manifolds.manifold.TopologicalManifold.zero_scalar_field`::
282
+
283
+ sage: zer is M.zero_scalar_field()
284
+ True
285
+
286
+ A third way is to get it as the zero element of the algebra `C^0(M)`
287
+ of scalar fields on `M` (see below)::
288
+
289
+ sage: zer is M.scalar_field_algebra().zero()
290
+ True
291
+
292
+ The constant scalar fields zero and one are immutable, and therefore
293
+ their expressions cannot be changed::
294
+
295
+ sage: zer.is_immutable()
296
+ True
297
+ sage: zer.set_expr(x)
298
+ Traceback (most recent call last):
299
+ ...
300
+ ValueError: the expressions of an immutable element cannot be
301
+ changed
302
+ sage: one = M.one_scalar_field()
303
+ sage: one.is_immutable()
304
+ True
305
+ sage: one.set_expr(x)
306
+ Traceback (most recent call last):
307
+ ...
308
+ ValueError: the expressions of an immutable element cannot be
309
+ changed
310
+
311
+ Other scalar fields can be declared immutable, too::
312
+
313
+ sage: c.is_immutable()
314
+ False
315
+ sage: c.set_immutable()
316
+ sage: c.is_immutable()
317
+ True
318
+ sage: c.set_expr(y^2)
319
+ Traceback (most recent call last):
320
+ ...
321
+ ValueError: the expressions of an immutable element cannot be
322
+ changed
323
+ sage: c.set_name('b')
324
+ Traceback (most recent call last):
325
+ ...
326
+ ValueError: the name of an immutable element cannot be changed
327
+
328
+ Immutable elements are hashable and can therefore be used as keys for
329
+ dictionaries::
330
+
331
+ sage: {c: 1}[c]
332
+ 1
333
+
334
+ By definition, a scalar field acts on the manifold's points, sending
335
+ them to elements of the manifold's base field (real numbers in the
336
+ present case)::
337
+
338
+ sage: N = M.point((0,0), chart=c_uv) # the North pole
339
+ sage: S = M.point((0,0), chart=c_xy) # the South pole
340
+ sage: E = M.point((1,0), chart=c_xy) # a point at the equator
341
+ sage: f(N)
342
+ 0
343
+ sage: f(S)
344
+ 1
345
+ sage: f(E)
346
+ 1/2
347
+ sage: h(E)
348
+ H(1, 0)
349
+ sage: c(E)
350
+ a
351
+ sage: zer(E)
352
+ 0
353
+
354
+ A scalar field can be compared to another scalar field::
355
+
356
+ sage: f == g
357
+ False
358
+
359
+ ...to a symbolic expression::
360
+
361
+ sage: f == x*y
362
+ False
363
+ sage: g == x*y
364
+ True
365
+ sage: c == a
366
+ True
367
+
368
+ ...to a number::
369
+
370
+ sage: f == 2
371
+ False
372
+ sage: zer == 0
373
+ True
374
+
375
+ ...to anything else::
376
+
377
+ sage: f == M
378
+ False
379
+
380
+ Standard mathematical functions are implemented::
381
+
382
+ sage: sqrt(f)
383
+ Scalar field sqrt(f) on the 2-dimensional topological manifold M
384
+ sage: sqrt(f).display()
385
+ sqrt(f): M → ℝ
386
+ on U: (x, y) ↦ 1/sqrt(x^2 + y^2 + 1)
387
+ on V: (u, v) ↦ sqrt(u^2 + v^2)/sqrt(u^2 + v^2 + 1)
388
+
389
+ ::
390
+
391
+ sage: tan(f)
392
+ Scalar field tan(f) on the 2-dimensional topological manifold M
393
+ sage: tan(f).display()
394
+ tan(f): M → ℝ
395
+ on U: (x, y) ↦ sin(1/(x^2 + y^2 + 1))/cos(1/(x^2 + y^2 + 1))
396
+ on V: (u, v) ↦ sin((u^2 + v^2)/(u^2 + v^2 + 1))/cos((u^2 + v^2)/(u^2 + v^2 + 1))
397
+
398
+ .. RUBRIC:: Arithmetics of scalar fields
399
+
400
+ Scalar fields on `M` (resp. `U`) belong to the algebra `C^0(M)`
401
+ (resp. `C^0(U)`)::
402
+
403
+ sage: f.parent()
404
+ Algebra of scalar fields on the 2-dimensional topological manifold M
405
+ sage: f.parent() is M.scalar_field_algebra()
406
+ True
407
+ sage: g.parent()
408
+ Algebra of scalar fields on the Open subset U of the 2-dimensional
409
+ topological manifold M
410
+ sage: g.parent() is U.scalar_field_algebra()
411
+ True
412
+
413
+ Consequently, scalar fields can be added::
414
+
415
+ sage: s = f + c ; s
416
+ Scalar field f+c on the 2-dimensional topological manifold M
417
+ sage: s.display()
418
+ f+c: M → ℝ
419
+ on U: (x, y) ↦ (a*x^2 + a*y^2 + a + 1)/(x^2 + y^2 + 1)
420
+ on V: (u, v) ↦ ((a + 1)*u^2 + (a + 1)*v^2 + a)/(u^2 + v^2 + 1)
421
+
422
+ and subtracted::
423
+
424
+ sage: s = f - c ; s
425
+ Scalar field f-c on the 2-dimensional topological manifold M
426
+ sage: s.display()
427
+ f-c: M → ℝ
428
+ on U: (x, y) ↦ -(a*x^2 + a*y^2 + a - 1)/(x^2 + y^2 + 1)
429
+ on V: (u, v) ↦ -((a - 1)*u^2 + (a - 1)*v^2 + a)/(u^2 + v^2 + 1)
430
+
431
+ Some tests::
432
+
433
+ sage: f + zer == f
434
+ True
435
+ sage: f - f == zer
436
+ True
437
+ sage: f + (-f) == zer
438
+ True
439
+ sage: (f+c)-f == c
440
+ True
441
+ sage: (f-c)+c == f
442
+ True
443
+
444
+ We may add a number (interpreted as a constant scalar field) to a scalar
445
+ field::
446
+
447
+ sage: s = f + 1 ; s
448
+ Scalar field f+1 on the 2-dimensional topological manifold M
449
+ sage: s.display()
450
+ f+1: M → ℝ
451
+ on U: (x, y) ↦ (x^2 + y^2 + 2)/(x^2 + y^2 + 1)
452
+ on V: (u, v) ↦ (2*u^2 + 2*v^2 + 1)/(u^2 + v^2 + 1)
453
+ sage: (f+1)-1 == f
454
+ True
455
+
456
+ The number can represented by a symbolic variable::
457
+
458
+ sage: s = a + f ; s
459
+ Scalar field on the 2-dimensional topological manifold M
460
+ sage: s == c + f
461
+ True
462
+
463
+ However if the symbolic variable is a chart coordinate, the addition
464
+ is performed only on the chart domain::
465
+
466
+ sage: s = f + x; s
467
+ Scalar field on the 2-dimensional topological manifold M
468
+ sage: s.display()
469
+ M → ℝ
470
+ on U: (x, y) ↦ (x^3 + x*y^2 + x + 1)/(x^2 + y^2 + 1)
471
+ on W: (u, v) ↦ (u^4 + v^4 + u^3 + (2*u^2 + u)*v^2 + u)/(u^4 + v^4 + (2*u^2 + 1)*v^2 + u^2)
472
+ sage: s = f + u; s
473
+ Scalar field on the 2-dimensional topological manifold M
474
+ sage: s.display()
475
+ M → ℝ
476
+ on W: (x, y) ↦ (x^3 + (x + 1)*y^2 + x^2 + x)/(x^4 + y^4 + (2*x^2 + 1)*y^2 + x^2)
477
+ on V: (u, v) ↦ (u^3 + (u + 1)*v^2 + u^2 + u)/(u^2 + v^2 + 1)
478
+
479
+ The addition of two scalar fields with different domains is possible if
480
+ the domain of one of them is a subset of the domain of the other; the
481
+ domain of the result is then this subset::
482
+
483
+ sage: f.domain()
484
+ 2-dimensional topological manifold M
485
+ sage: g.domain()
486
+ Open subset U of the 2-dimensional topological manifold M
487
+ sage: s = f + g ; s
488
+ Scalar field f+g on the Open subset U of the 2-dimensional topological
489
+ manifold M
490
+ sage: s.domain()
491
+ Open subset U of the 2-dimensional topological manifold M
492
+ sage: s.display()
493
+ f+g: U → ℝ
494
+ (x, y) ↦ (x*y^3 + (x^3 + x)*y + 1)/(x^2 + y^2 + 1)
495
+ on W: (u, v) ↦ (u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6 + u*v^3
496
+ + (u^3 + u)*v)/(u^6 + v^6 + (3*u^2 + 1)*v^4 + u^4 + (3*u^4 + 2*u^2)*v^2)
497
+
498
+ The operation actually performed is `f|_U + g`::
499
+
500
+ sage: s == f.restrict(U) + g
501
+ True
502
+
503
+ In Sage framework, the addition of `f` and `g` is permitted because
504
+ there is a *coercion* of the parent of `f`, namely `C^0(M)`, to
505
+ the parent of `g`, namely `C^0(U)` (see
506
+ :class:`~sage.manifolds.scalarfield_algebra.ScalarFieldAlgebra`)::
507
+
508
+ sage: CM = M.scalar_field_algebra()
509
+ sage: CU = U.scalar_field_algebra()
510
+ sage: CU.has_coerce_map_from(CM)
511
+ True
512
+
513
+ The coercion map is nothing but the restriction to domain `U`::
514
+
515
+ sage: CU.coerce(f) == f.restrict(U)
516
+ True
517
+
518
+ Since the algebra `C^0(M)` is a vector space over `\RR`, scalar fields
519
+ can be multiplied by a number, either an explicit one::
520
+
521
+ sage: s = 2*f ; s
522
+ Scalar field on the 2-dimensional topological manifold M
523
+ sage: s.display()
524
+ M → ℝ
525
+ on U: (x, y) ↦ 2/(x^2 + y^2 + 1)
526
+ on V: (u, v) ↦ 2*(u^2 + v^2)/(u^2 + v^2 + 1)
527
+
528
+ or a symbolic one::
529
+
530
+ sage: s = a*f ; s
531
+ Scalar field on the 2-dimensional topological manifold M
532
+ sage: s.display()
533
+ M → ℝ
534
+ on U: (x, y) ↦ a/(x^2 + y^2 + 1)
535
+ on V: (u, v) ↦ (u^2 + v^2)*a/(u^2 + v^2 + 1)
536
+
537
+ However, if the symbolic variable is a chart coordinate, the
538
+ multiplication is performed only in the corresponding chart::
539
+
540
+ sage: s = x*f; s
541
+ Scalar field on the 2-dimensional topological manifold M
542
+ sage: s.display()
543
+ M → ℝ
544
+ on U: (x, y) ↦ x/(x^2 + y^2 + 1)
545
+ on W: (u, v) ↦ u/(u^2 + v^2 + 1)
546
+ sage: s = u*f; s
547
+ Scalar field on the 2-dimensional topological manifold M
548
+ sage: s.display()
549
+ M → ℝ
550
+ on W: (x, y) ↦ x/(x^4 + y^4 + (2*x^2 + 1)*y^2 + x^2)
551
+ on V: (u, v) ↦ (u^2 + v^2)*u/(u^2 + v^2 + 1)
552
+
553
+ Some tests::
554
+
555
+ sage: 0*f == 0
556
+ True
557
+ sage: 0*f == zer
558
+ True
559
+ sage: 1*f == f
560
+ True
561
+ sage: (-2)*f == - f - f
562
+ True
563
+
564
+ The ring multiplication of the algebras `C^0(M)` and `C^0(U)`
565
+ is the pointwise multiplication of functions::
566
+
567
+ sage: s = f*f ; s
568
+ Scalar field f*f on the 2-dimensional topological manifold M
569
+ sage: s.display()
570
+ f*f: M → ℝ
571
+ on U: (x, y) ↦ 1/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1)
572
+ on V: (u, v) ↦ (u^4 + 2*u^2*v^2 + v^4)/(u^4 + v^4 + 2*(u^2 + 1)*v^2
573
+ + 2*u^2 + 1)
574
+ sage: s = g*h ; s
575
+ Scalar field g*h on the Open subset U of the 2-dimensional topological
576
+ manifold M
577
+ sage: s.display()
578
+ g*h: U → ℝ
579
+ (x, y) ↦ x*y*H(x, y)
580
+ on W: (u, v) ↦ u*v*H(u/(u^2 + v^2), v/(u^2 + v^2))/(u^4 + 2*u^2*v^2 + v^4)
581
+
582
+ Thanks to the coercion `C^0(M) \to C^0(U)` mentioned above,
583
+ it is possible to multiply a scalar field defined on `M` by a
584
+ scalar field defined on `U`, the result being a scalar field
585
+ defined on `U`::
586
+
587
+ sage: f.domain(), g.domain()
588
+ (2-dimensional topological manifold M,
589
+ Open subset U of the 2-dimensional topological manifold M)
590
+ sage: s = f*g ; s
591
+ Scalar field f*g on the Open subset U of the 2-dimensional topological
592
+ manifold M
593
+ sage: s.display()
594
+ f*g: U → ℝ
595
+ (x, y) ↦ x*y/(x^2 + y^2 + 1)
596
+ on W: (u, v) ↦ u*v/(u^4 + v^4 + (2*u^2 + 1)*v^2 + u^2)
597
+ sage: s == f.restrict(U)*g
598
+ True
599
+
600
+ Scalar fields can be divided (pointwise division)::
601
+
602
+ sage: s = f/c ; s
603
+ Scalar field f/c on the 2-dimensional topological manifold M
604
+ sage: s.display()
605
+ f/c: M → ℝ
606
+ on U: (x, y) ↦ 1/(a*x^2 + a*y^2 + a)
607
+ on V: (u, v) ↦ (u^2 + v^2)/(a*u^2 + a*v^2 + a)
608
+ sage: s = g/h ; s
609
+ Scalar field g/h on the Open subset U of the 2-dimensional topological
610
+ manifold M
611
+ sage: s.display()
612
+ g/h: U → ℝ
613
+ (x, y) ↦ x*y/H(x, y)
614
+ on W: (u, v) ↦ u*v/((u^4 + 2*u^2*v^2 + v^4)*H(u/(u^2 + v^2), v/(u^2 + v^2)))
615
+ sage: s = f/g ; s
616
+ Scalar field f/g on the Open subset U of the 2-dimensional topological
617
+ manifold M
618
+ sage: s.display()
619
+ f/g: U → ℝ
620
+ (x, y) ↦ 1/(x*y^3 + (x^3 + x)*y)
621
+ on W: (u, v) ↦ (u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6)/(u*v^3 + (u^3 + u)*v)
622
+ sage: s == f.restrict(U)/g
623
+ True
624
+
625
+ For scalar fields defined on a single chart domain, we may perform some
626
+ arithmetics with symbolic expressions involving the chart coordinates::
627
+
628
+ sage: s = g + x^2 - y ; s
629
+ Scalar field on the Open subset U of the 2-dimensional topological
630
+ manifold M
631
+ sage: s.display()
632
+ U → ℝ
633
+ (x, y) ↦ x^2 + (x - 1)*y
634
+ on W: (u, v) ↦ -(v^3 - u^2 + (u^2 - u)*v)/(u^4 + 2*u^2*v^2 + v^4)
635
+
636
+ ::
637
+
638
+ sage: s = g*x ; s
639
+ Scalar field on the Open subset U of the 2-dimensional topological
640
+ manifold M
641
+ sage: s.display()
642
+ U → ℝ
643
+ (x, y) ↦ x^2*y
644
+ on W: (u, v) ↦ u^2*v/(u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6)
645
+
646
+ ::
647
+
648
+ sage: s = g/x ; s
649
+ Scalar field on the Open subset U of the 2-dimensional topological
650
+ manifold M
651
+ sage: s.display()
652
+ U → ℝ
653
+ (x, y) ↦ y
654
+ on W: (u, v) ↦ v/(u^2 + v^2)
655
+ sage: s = x/g ; s
656
+ Scalar field on the Open subset U of the 2-dimensional topological
657
+ manifold M
658
+ sage: s.display()
659
+ U → ℝ
660
+ (x, y) ↦ 1/y
661
+ on W: (u, v) ↦ (u^2 + v^2)/v
662
+
663
+
664
+ .. RUBRIC:: Examples with SymPy as the symbolic engine
665
+
666
+ From now on, we ask that all symbolic calculus on manifold `M` are
667
+ performed by SymPy::
668
+
669
+ sage: M.set_calculus_method('sympy')
670
+
671
+ We define `f` as above::
672
+
673
+ sage: f = M.scalar_field({c_xy: 1/(1+x^2+y^2), c_uv: (u^2+v^2)/(1+u^2+v^2)},
674
+ ....: name='f') ; f
675
+ Scalar field f on the 2-dimensional topological manifold M
676
+ sage: f.display() # notice the SymPy display of exponents
677
+ f: M → ℝ
678
+ on U: (x, y) ↦ 1/(x**2 + y**2 + 1)
679
+ on V: (u, v) ↦ (u**2 + v**2)/(u**2 + v**2 + 1)
680
+ sage: type(f.coord_function(c_xy).expr())
681
+ <class 'sympy.core.power.Pow'>
682
+
683
+ The scalar field `g` defined on `U`::
684
+
685
+ sage: g = U.scalar_field({c_xy: x*y}, name='g')
686
+ sage: g.display() # again notice the SymPy display of exponents
687
+ g: U → ℝ
688
+ (x, y) ↦ x*y
689
+ on W: (u, v) ↦ u*v/(u**4 + 2*u**2*v**2 + v**4)
690
+
691
+ Definition on a single chart and subsequent completion::
692
+
693
+ sage: f = M.scalar_field(1/(1+x^2+y^2), chart=c_xy, name='f')
694
+ sage: f.add_expr((u^2+v^2)/(1+u^2+v^2), chart=c_uv)
695
+ sage: f.display()
696
+ f: M → ℝ
697
+ on U: (x, y) ↦ 1/(x**2 + y**2 + 1)
698
+ on V: (u, v) ↦ (u**2 + v**2)/(u**2 + v**2 + 1)
699
+
700
+ Definition without any coordinate expression and subsequent completion::
701
+
702
+ sage: f = M.scalar_field(name='f')
703
+ sage: f.add_expr(1/(1+x^2+y^2), chart=c_xy)
704
+ sage: f.add_expr((u^2+v^2)/(1+u^2+v^2), chart=c_uv)
705
+ sage: f.display()
706
+ f: M → ℝ
707
+ on U: (x, y) ↦ 1/(x**2 + y**2 + 1)
708
+ on V: (u, v) ↦ (u**2 + v**2)/(u**2 + v**2 + 1)
709
+
710
+ Use of :meth:`add_expr_by_continuation`::
711
+
712
+ sage: f = M.scalar_field(1/(1+x^2+y^2), chart=c_xy, name='f')
713
+ sage: f.add_expr_by_continuation(c_uv, U.intersection(V))
714
+ sage: f.display()
715
+ f: M → ℝ
716
+ on U: (x, y) ↦ 1/(x**2 + y**2 + 1)
717
+ on V: (u, v) ↦ (u**2 + v**2)/(u**2 + v**2 + 1)
718
+
719
+ A scalar field defined by some unspecified function of the
720
+ coordinates::
721
+
722
+ sage: h = U.scalar_field(function('H')(x, y), name='h') ; h
723
+ Scalar field h on the Open subset U of the 2-dimensional topological
724
+ manifold M
725
+ sage: h.display()
726
+ h: U → ℝ
727
+ (x, y) ↦ H(x, y)
728
+ on W: (u, v) ↦ H(u/(u**2 + v**2), v/(u**2 + v**2))
729
+
730
+ The coordinate expression in a given chart is obtained via the method
731
+ :meth:`expr`, which in the present context, returns a SymPy object::
732
+
733
+ sage: f.expr(c_uv)
734
+ (u**2 + v**2)/(u**2 + v**2 + 1)
735
+ sage: type(f.expr(c_uv))
736
+ <class 'sympy.core.mul.Mul'>
737
+
738
+ The method :meth:`coord_function` returns instead a function of the
739
+ chart coordinates, i.e. an instance of
740
+ :class:`~sage.manifolds.chart_func.ChartFunction`::
741
+
742
+ sage: f.coord_function(c_uv)
743
+ (u**2 + v**2)/(u**2 + v**2 + 1)
744
+ sage: type(f.coord_function(c_uv))
745
+ <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
746
+ sage: f.coord_function(c_uv).display()
747
+ (u, v) ↦ (u**2 + v**2)/(u**2 + v**2 + 1)
748
+
749
+ The value returned by the method :meth:`expr` is actually the coordinate
750
+ expression of the chart function::
751
+
752
+ sage: f.expr(c_uv) is f.coord_function(c_uv).expr()
753
+ True
754
+
755
+ We may ask for the ``SR`` representation of the coordinate function::
756
+
757
+ sage: f.coord_function(c_uv).expr('SR')
758
+ (u^2 + v^2)/(u^2 + v^2 + 1)
759
+
760
+ A constant scalar field with SymPy representation::
761
+
762
+ sage: c = M.constant_scalar_field(2, name='c')
763
+ sage: c.display()
764
+ c: M → ℝ
765
+ on U: (x, y) ↦ 2
766
+ on V: (u, v) ↦ 2
767
+ sage: type(c.expr(c_xy))
768
+ <class 'sympy.core.numbers.Integer'>
769
+
770
+ The constant value can be some unspecified parameter::
771
+
772
+ sage: var('a')
773
+ a
774
+ sage: c = M.constant_scalar_field(a, name='c')
775
+ sage: c.display()
776
+ c: M → ℝ
777
+ on U: (x, y) ↦ a
778
+ on V: (u, v) ↦ a
779
+ sage: type(c.expr(c_xy))
780
+ <class 'sympy.core.symbol.Symbol'>
781
+
782
+ The zero scalar field::
783
+
784
+ sage: zer = M.constant_scalar_field(0) ; zer
785
+ Scalar field zero on the 2-dimensional topological manifold M
786
+ sage: zer.display()
787
+ zero: M → ℝ
788
+ on U: (x, y) ↦ 0
789
+ on V: (u, v) ↦ 0
790
+ sage: type(zer.expr(c_xy))
791
+ <class 'sympy.core.numbers.Zero'>
792
+ sage: zer is M.zero_scalar_field()
793
+ True
794
+
795
+ Action of scalar fields on manifold's points::
796
+
797
+ sage: N = M.point((0,0), chart=c_uv) # the North pole
798
+ sage: S = M.point((0,0), chart=c_xy) # the South pole
799
+ sage: E = M.point((1,0), chart=c_xy) # a point at the equator
800
+ sage: f(N)
801
+ 0
802
+ sage: f(S)
803
+ 1
804
+ sage: f(E)
805
+ 1/2
806
+ sage: h(E)
807
+ H(1, 0)
808
+ sage: c(E)
809
+ a
810
+ sage: zer(E)
811
+ 0
812
+
813
+ A scalar field can be compared to another scalar field::
814
+
815
+ sage: f == g
816
+ False
817
+
818
+ ...to a symbolic expression::
819
+
820
+ sage: f == x*y
821
+ False
822
+ sage: g == x*y
823
+ True
824
+ sage: c == a
825
+ True
826
+
827
+ ...to a number::
828
+
829
+ sage: f == 2
830
+ False
831
+ sage: zer == 0
832
+ True
833
+
834
+ ...to anything else::
835
+
836
+ sage: f == M
837
+ False
838
+
839
+ Standard mathematical functions are implemented::
840
+
841
+ sage: sqrt(f)
842
+ Scalar field sqrt(f) on the 2-dimensional topological manifold M
843
+ sage: sqrt(f).display()
844
+ sqrt(f): M → ℝ
845
+ on U: (x, y) ↦ 1/sqrt(x**2 + y**2 + 1)
846
+ on V: (u, v) ↦ sqrt(u**2 + v**2)/sqrt(u**2 + v**2 + 1)
847
+
848
+ ::
849
+
850
+ sage: tan(f)
851
+ Scalar field tan(f) on the 2-dimensional topological manifold M
852
+ sage: tan(f).display()
853
+ tan(f): M → ℝ
854
+ on U: (x, y) ↦ tan(1/(x**2 + y**2 + 1))
855
+ on V: (u, v) ↦ tan((u**2 + v**2)/(u**2 + v**2 + 1))
856
+
857
+ .. RUBRIC:: Arithmetics of scalar fields with SymPy
858
+
859
+ Scalar fields on `M` (resp. `U`) belong to the algebra `C^0(M)`
860
+ (resp. `C^0(U)`)::
861
+
862
+ sage: f.parent()
863
+ Algebra of scalar fields on the 2-dimensional topological manifold M
864
+ sage: f.parent() is M.scalar_field_algebra()
865
+ True
866
+ sage: g.parent()
867
+ Algebra of scalar fields on the Open subset U of the 2-dimensional
868
+ topological manifold M
869
+ sage: g.parent() is U.scalar_field_algebra()
870
+ True
871
+
872
+ Consequently, scalar fields can be added::
873
+
874
+ sage: s = f + c ; s
875
+ Scalar field f+c on the 2-dimensional topological manifold M
876
+ sage: s.display()
877
+ f+c: M → ℝ
878
+ on U: (x, y) ↦ (a*x**2 + a*y**2 + a + 1)/(x**2 + y**2 + 1)
879
+ on V: (u, v) ↦ (a*u**2 + a*v**2 + a + u**2 + v**2)/(u**2 + v**2 + 1)
880
+
881
+ and subtracted::
882
+
883
+ sage: s = f - c ; s
884
+ Scalar field f-c on the 2-dimensional topological manifold M
885
+ sage: s.display()
886
+ f-c: M → ℝ
887
+ on U: (x, y) ↦ (-a*x**2 - a*y**2 - a + 1)/(x**2 + y**2 + 1)
888
+ on V: (u, v) ↦ (-a*u**2 - a*v**2 - a + u**2 + v**2)/(u**2 + v**2 + 1)
889
+
890
+ Some tests::
891
+
892
+ sage: f + zer == f
893
+ True
894
+ sage: f - f == zer
895
+ True
896
+ sage: f + (-f) == zer
897
+ True
898
+ sage: (f+c)-f == c
899
+ True
900
+ sage: (f-c)+c == f
901
+ True
902
+
903
+ We may add a number (interpreted as a constant scalar field) to a scalar
904
+ field::
905
+
906
+ sage: s = f + 1 ; s
907
+ Scalar field f+1 on the 2-dimensional topological manifold M
908
+ sage: s.display()
909
+ f+1: M → ℝ
910
+ on U: (x, y) ↦ (x**2 + y**2 + 2)/(x**2 + y**2 + 1)
911
+ on V: (u, v) ↦ (2*u**2 + 2*v**2 + 1)/(u**2 + v**2 + 1)
912
+ sage: (f+1)-1 == f
913
+ True
914
+
915
+ The number can represented by a symbolic variable::
916
+
917
+ sage: s = a + f ; s
918
+ Scalar field on the 2-dimensional topological manifold M
919
+ sage: s == c + f
920
+ True
921
+
922
+ However if the symbolic variable is a chart coordinate, the addition
923
+ is performed only on the chart domain::
924
+
925
+ sage: s = f + x; s
926
+ Scalar field on the 2-dimensional topological manifold M
927
+ sage: s.display()
928
+ M → ℝ
929
+ on U: (x, y) ↦ (x**3 + x*y**2 + x + 1)/(x**2 + y**2 + 1)
930
+ on W: (u, v) ↦ (u**4 + u**3 + 2*u**2*v**2 + u*v**2 + u + v**4)/(u**4 + 2*u**2*v**2 + u**2 + v**4 + v**2)
931
+ sage: s = f + u; s
932
+ Scalar field on the 2-dimensional topological manifold M
933
+ sage: s.display()
934
+ M → ℝ
935
+ on W: (x, y) ↦ (x**3 + x**2 + x*y**2 + x + y**2)/(x**4 + 2*x**2*y**2 + x**2 + y**4 + y**2)
936
+ on V: (u, v) ↦ (u**3 + u**2 + u*v**2 + u + v**2)/(u**2 + v**2 + 1)
937
+
938
+ The addition of two scalar fields with different domains is possible if
939
+ the domain of one of them is a subset of the domain of the other; the
940
+ domain of the result is then this subset::
941
+
942
+ sage: f.domain()
943
+ 2-dimensional topological manifold M
944
+ sage: g.domain()
945
+ Open subset U of the 2-dimensional topological manifold M
946
+ sage: s = f + g ; s
947
+ Scalar field f+g on the Open subset U of the 2-dimensional topological
948
+ manifold M
949
+ sage: s.domain()
950
+ Open subset U of the 2-dimensional topological manifold M
951
+ sage: s.display()
952
+ f+g: U → ℝ
953
+ (x, y) ↦ (x**3*y + x*y**3 + x*y + 1)/(x**2 + y**2 + 1)
954
+ on W: (u, v) ↦ (u**6 + 3*u**4*v**2 + u**3*v + 3*u**2*v**4 + u*v**3 + u*v + v**6)/(u**6 + 3*u**4*v**2 + u**4 + 3*u**2*v**4 + 2*u**2*v**2 + v**6 + v**4)
955
+
956
+ The operation actually performed is `f|_U + g`::
957
+
958
+ sage: s == f.restrict(U) + g
959
+ True
960
+
961
+ Since the algebra `C^0(M)` is a vector space over `\RR`, scalar fields
962
+ can be multiplied by a number, either an explicit one::
963
+
964
+ sage: s = 2*f ; s
965
+ Scalar field on the 2-dimensional topological manifold M
966
+ sage: s.display()
967
+ M → ℝ
968
+ on U: (x, y) ↦ 2/(x**2 + y**2 + 1)
969
+ on V: (u, v) ↦ 2*(u**2 + v**2)/(u**2 + v**2 + 1)
970
+
971
+ or a symbolic one::
972
+
973
+ sage: s = a*f ; s
974
+ Scalar field on the 2-dimensional topological manifold M
975
+ sage: s.display()
976
+ M → ℝ
977
+ on U: (x, y) ↦ a/(x**2 + y**2 + 1)
978
+ on V: (u, v) ↦ a*(u**2 + v**2)/(u**2 + v**2 + 1)
979
+
980
+ However, if the symbolic variable is a chart coordinate, the
981
+ multiplication is performed only in the corresponding chart::
982
+
983
+ sage: s = x*f; s
984
+ Scalar field on the 2-dimensional topological manifold M
985
+ sage: s.display()
986
+ M → ℝ
987
+ on U: (x, y) ↦ x/(x**2 + y**2 + 1)
988
+ on W: (u, v) ↦ u/(u**2 + v**2 + 1)
989
+ sage: s = u*f; s
990
+ Scalar field on the 2-dimensional topological manifold M
991
+ sage: s.display()
992
+ M → ℝ
993
+ on W: (x, y) ↦ x/(x**4 + 2*x**2*y**2 + x**2 + y**4 + y**2)
994
+ on V: (u, v) ↦ u*(u**2 + v**2)/(u**2 + v**2 + 1)
995
+
996
+ Some tests::
997
+
998
+ sage: 0*f == 0
999
+ True
1000
+ sage: 0*f == zer
1001
+ True
1002
+ sage: 1*f == f
1003
+ True
1004
+ sage: (-2)*f == - f - f
1005
+ True
1006
+
1007
+ The ring multiplication of the algebras `C^0(M)` and `C^0(U)`
1008
+ is the pointwise multiplication of functions::
1009
+
1010
+ sage: s = f*f ; s
1011
+ Scalar field f*f on the 2-dimensional topological manifold M
1012
+ sage: s.display()
1013
+ f*f: M → ℝ
1014
+ on U: (x, y) ↦ 1/(x**4 + 2*x**2*y**2 + 2*x**2 + y**4 + 2*y**2 + 1)
1015
+ on V: (u, v) ↦ (u**4 + 2*u**2*v**2 + v**4)/(u**4 + 2*u**2*v**2 + 2*u**2 + v**4 + 2*v**2 + 1)
1016
+
1017
+ sage: s = g*h ; s
1018
+ Scalar field g*h on the Open subset U of the 2-dimensional topological
1019
+ manifold M
1020
+ sage: s.display()
1021
+ g*h: U → ℝ
1022
+ (x, y) ↦ x*y*H(x, y)
1023
+ on W: (u, v) ↦ u*v*H(u/(u**2 + v**2), v/(u**2 + v**2))/(u**4 + 2*u**2*v**2 + v**4)
1024
+
1025
+ Thanks to the coercion `C^0(M) \to C^0(U)` mentioned above,
1026
+ it is possible to multiply a scalar field defined on `M` by a
1027
+ scalar field defined on `U`, the result being a scalar field
1028
+ defined on `U`::
1029
+
1030
+ sage: f.domain(), g.domain()
1031
+ (2-dimensional topological manifold M,
1032
+ Open subset U of the 2-dimensional topological manifold M)
1033
+ sage: s = f*g ; s
1034
+ Scalar field f*g on the Open subset U of the 2-dimensional topological
1035
+ manifold M
1036
+ sage: s.display()
1037
+ f*g: U → ℝ
1038
+ (x, y) ↦ x*y/(x**2 + y**2 + 1)
1039
+ on W: (u, v) ↦ u*v/(u**4 + 2*u**2*v**2 + u**2 + v**4 + v**2)
1040
+
1041
+ sage: s == f.restrict(U)*g
1042
+ True
1043
+
1044
+ Scalar fields can be divided (pointwise division)::
1045
+
1046
+ sage: s = f/c ; s
1047
+ Scalar field f/c on the 2-dimensional topological manifold M
1048
+ sage: s.display()
1049
+ f/c: M → ℝ
1050
+ on U: (x, y) ↦ 1/(a*(x**2 + y**2 + 1))
1051
+ on V: (u, v) ↦ (u**2 + v**2)/(a*(u**2 + v**2 + 1))
1052
+ sage: s = g/h ; s
1053
+ Scalar field g/h on the Open subset U of the 2-dimensional topological
1054
+ manifold M
1055
+ sage: s.display()
1056
+ g/h: U → ℝ
1057
+ (x, y) ↦ x*y/H(x, y)
1058
+ on W: (u, v) ↦ u*v/((u**4 + 2*u**2*v**2 + v**4)*H(u/(u**2 + v**2), v/(u**2 + v**2)))
1059
+
1060
+ sage: s = f/g ; s
1061
+ Scalar field f/g on the Open subset U of the 2-dimensional topological
1062
+ manifold M
1063
+ sage: s.display()
1064
+ f/g: U → ℝ
1065
+ (x, y) ↦ 1/(x*y*(x**2 + y**2 + 1))
1066
+ on W: (u, v) ↦ (u**6 + 3*u**4*v**2 + 3*u**2*v**4 + v**6)/(u*v*(u**2 + v**2 + 1))
1067
+ sage: s == f.restrict(U)/g
1068
+ True
1069
+
1070
+ For scalar fields defined on a single chart domain, we may perform some
1071
+ arithmetics with symbolic expressions involving the chart coordinates::
1072
+
1073
+ sage: s = g + x^2 - y ; s
1074
+ Scalar field on the Open subset U of the 2-dimensional topological manifold M
1075
+ sage: s.display()
1076
+ U → ℝ
1077
+ (x, y) ↦ x**2 + x*y - y
1078
+ on W: (u, v) ↦ (-u**2*v + u**2 + u*v - v**3)/(u**4 + 2*u**2*v**2 + v**4)
1079
+
1080
+
1081
+ ::
1082
+
1083
+ sage: s = g*x ; s
1084
+ Scalar field on the Open subset U of the 2-dimensional topological
1085
+ manifold M
1086
+ sage: s.display()
1087
+ U → ℝ
1088
+ (x, y) ↦ x**2*y
1089
+ on W: (u, v) ↦ u**2*v/(u**6 + 3*u**4*v**2 + 3*u**2*v**4 + v**6)
1090
+
1091
+ ::
1092
+
1093
+ sage: s = g/x ; s
1094
+ Scalar field on the Open subset U of the 2-dimensional topological
1095
+ manifold M
1096
+ sage: s.display()
1097
+ U → ℝ
1098
+ (x, y) ↦ y
1099
+ on W: (u, v) ↦ v/(u**2 + v**2)
1100
+ sage: s = x/g ; s
1101
+ Scalar field on the Open subset U of the 2-dimensional topological
1102
+ manifold M
1103
+ sage: s.display()
1104
+ U → ℝ
1105
+ (x, y) ↦ 1/y
1106
+ on W: (u, v) ↦ u**2/v + v
1107
+
1108
+ The test suite is passed::
1109
+
1110
+ sage: TestSuite(f).run()
1111
+ sage: TestSuite(zer).run()
1112
+ """
1113
+
1114
+ _name: Optional[str]
1115
+
1116
+ def __init__(self, parent, coord_expression=None, chart=None, name=None,
1117
+ latex_name=None):
1118
+ r"""
1119
+ Construct a scalar field.
1120
+
1121
+ TESTS::
1122
+
1123
+ sage: M = Manifold(2, 'M', structure='topological')
1124
+ sage: X.<x,y> = M.chart()
1125
+ sage: f = M.scalar_field({X: x+y}, name='f') ; f
1126
+ Scalar field f on the 2-dimensional topological manifold M
1127
+ sage: from sage.manifolds.scalarfield import ScalarField
1128
+ sage: isinstance(f, ScalarField)
1129
+ True
1130
+ sage: f.parent()
1131
+ Algebra of scalar fields on the 2-dimensional topological
1132
+ manifold M
1133
+ sage: TestSuite(f).run()
1134
+ """
1135
+ super().__init__(parent) # both super classes have same signature
1136
+ domain = parent._domain
1137
+ self._domain = domain
1138
+ self._manifold = domain.manifold()
1139
+ self._is_zero = False
1140
+ # a priori, may be changed below or via
1141
+ # method __bool__()
1142
+
1143
+ self._name = name
1144
+ if latex_name is None:
1145
+ self._latex_name = self._name
1146
+ else:
1147
+ self._latex_name = latex_name
1148
+ self._express = {}
1149
+ # dict of coordinate expressions (ChartFunction
1150
+ # instances) with charts as keys
1151
+
1152
+ if coord_expression is not None:
1153
+ if isinstance(coord_expression, dict):
1154
+ for chart, expression in coord_expression.items():
1155
+ if isinstance(expression, ChartFunction):
1156
+ self._express[chart] = expression
1157
+ else:
1158
+ self._express[chart] = chart.function(expression)
1159
+ elif isinstance(coord_expression, ChartFunction):
1160
+ self._express[coord_expression.chart()] = coord_expression
1161
+ else:
1162
+ if chart is None:
1163
+ chart = self._domain.default_chart()
1164
+ if chart == 'all':
1165
+ # coord_expression is the same in all charts (constant
1166
+ # scalar field)
1167
+ for ch in self._domain.atlas():
1168
+ self._express[ch] = ch.function(coord_expression)
1169
+ else:
1170
+ self._express[chart] = chart.function(coord_expression)
1171
+ self._init_derived() # initialization of derived quantities
1172
+
1173
+ # ### Required methods for an algebra element (beside arithmetic) ###
1174
+
1175
+ def __bool__(self):
1176
+ r"""
1177
+ Return ``True`` if ``self`` is nonzero and ``False`` otherwise.
1178
+
1179
+ This method is called by :meth:`~sage.structure.element.Element.is_zero()`.
1180
+
1181
+ EXAMPLES:
1182
+
1183
+ Tests on a 2-dimensional manifold::
1184
+
1185
+ sage: M = Manifold(2, 'M', structure='topological')
1186
+ sage: c_xy.<x,y> = M.chart()
1187
+ sage: f = M.scalar_field(x*y)
1188
+ sage: f.is_zero()
1189
+ False
1190
+ sage: f.set_expr(0)
1191
+ sage: f.is_zero()
1192
+ True
1193
+ sage: g = M.scalar_field(0)
1194
+ sage: g.is_zero()
1195
+ True
1196
+ sage: M.zero_scalar_field().is_zero()
1197
+ True
1198
+ """
1199
+ if self._is_zero:
1200
+ return False
1201
+ if not self._express:
1202
+ # undefined scalar field
1203
+ return True
1204
+ for funct in self._express.values():
1205
+ if not funct.is_zero():
1206
+ self._is_zero = False
1207
+ return True
1208
+ self._is_zero = True
1209
+ return False
1210
+
1211
+ def is_trivial_zero(self):
1212
+ r"""
1213
+ Check if ``self`` is trivially equal to zero without any
1214
+ simplification.
1215
+
1216
+ This method is supposed to be fast as compared with
1217
+ ``self.is_zero()`` or ``self == 0`` and is intended to be
1218
+ used in library code where trying to obtain a mathematically
1219
+ correct result by applying potentially expensive rewrite rules
1220
+ is not desirable.
1221
+
1222
+ EXAMPLES::
1223
+
1224
+ sage: M = Manifold(2, 'M', structure='topological')
1225
+ sage: X.<x,y> = M.chart()
1226
+ sage: f = M.scalar_field({X: 0})
1227
+ sage: f.is_trivial_zero()
1228
+ True
1229
+ sage: f = M.scalar_field(0)
1230
+ sage: f.is_trivial_zero()
1231
+ True
1232
+ sage: M.zero_scalar_field().is_trivial_zero()
1233
+ True
1234
+ sage: f = M.scalar_field({X: x+y})
1235
+ sage: f.is_trivial_zero()
1236
+ False
1237
+
1238
+ Scalar field defined by means of two charts::
1239
+
1240
+ sage: U1 = M.open_subset('U1'); X1.<x1,y1> = U1.chart()
1241
+ sage: U2 = M.open_subset('U2'); X2.<x2,y2> = U2.chart()
1242
+ sage: f = M.scalar_field({X1: 0, X2: 0})
1243
+ sage: f.is_trivial_zero()
1244
+ True
1245
+ sage: f = M.scalar_field({X1: 0, X2: 1})
1246
+ sage: f.is_trivial_zero()
1247
+ False
1248
+
1249
+ No simplification is attempted, so that ``False`` is returned for
1250
+ non-trivial cases::
1251
+
1252
+ sage: f = M.scalar_field({X: cos(x)^2 + sin(x)^2 - 1})
1253
+ sage: f.is_trivial_zero()
1254
+ False
1255
+
1256
+ On the contrary, the method
1257
+ :meth:`~sage.structure.element.Element.is_zero` and the direct
1258
+ comparison to zero involve some simplification algorithms and
1259
+ return ``True``::
1260
+
1261
+ sage: f.is_zero()
1262
+ True
1263
+ sage: f == 0
1264
+ True
1265
+ """
1266
+ if self._is_zero:
1267
+ return True
1268
+ return all(func.is_trivial_zero() for func in self._express.values())
1269
+
1270
+ def is_trivial_one(self):
1271
+ r"""
1272
+ Check if ``self`` is trivially equal to one without any
1273
+ simplification.
1274
+
1275
+ This method is supposed to be fast as compared with
1276
+ ``self == 1`` and is intended to be used in library code where
1277
+ trying to obtain a mathematically correct result by applying
1278
+ potentially expensive rewrite rules is not desirable.
1279
+
1280
+ EXAMPLES::
1281
+
1282
+ sage: M = Manifold(2, 'M', structure='topological')
1283
+ sage: X.<x,y> = M.chart()
1284
+ sage: f = M.scalar_field({X: 1})
1285
+ sage: f.is_trivial_one()
1286
+ True
1287
+ sage: f = M.scalar_field(1)
1288
+ sage: f.is_trivial_one()
1289
+ True
1290
+ sage: M.one_scalar_field().is_trivial_one()
1291
+ True
1292
+ sage: f = M.scalar_field({X: x+y})
1293
+ sage: f.is_trivial_one()
1294
+ False
1295
+
1296
+ Scalar field defined by means of two charts::
1297
+
1298
+ sage: U1 = M.open_subset('U1'); X1.<x1,y1> = U1.chart()
1299
+ sage: U2 = M.open_subset('U2'); X2.<x2,y2> = U2.chart()
1300
+ sage: f = M.scalar_field({X1: 1, X2: 1})
1301
+ sage: f.is_trivial_one()
1302
+ True
1303
+ sage: f = M.scalar_field({X1: 0, X2: 1})
1304
+ sage: f.is_trivial_one()
1305
+ False
1306
+
1307
+ No simplification is attempted, so that ``False`` is returned for
1308
+ non-trivial cases::
1309
+
1310
+ sage: f = M.scalar_field({X: cos(x)^2 + sin(x)^2})
1311
+ sage: f.is_trivial_one()
1312
+ False
1313
+
1314
+ On the contrary, the method
1315
+ :meth:`~sage.structure.element.Element.is_zero` and the direct
1316
+ comparison to one involve some simplification algorithms and
1317
+ return ``True``::
1318
+
1319
+ sage: (f - 1).is_zero()
1320
+ True
1321
+ sage: f == 1
1322
+ True
1323
+ """
1324
+ return all(func.is_trivial_one() for func in self._express.values())
1325
+
1326
+ # TODO: Remove this method as soon as issue #28629 is solved?
1327
+ def is_unit(self):
1328
+ r"""
1329
+ Return ``True`` iff ``self`` is not trivially zero in at least one of
1330
+ the given expressions since most scalar fields are invertible and a
1331
+ complete computation would take too much time.
1332
+
1333
+ EXAMPLES::
1334
+
1335
+ sage: M = Manifold(2, 'M', structure='top')
1336
+ sage: one = M.scalar_field_algebra().one()
1337
+ sage: one.is_unit()
1338
+ True
1339
+ sage: zero = M.scalar_field_algebra().zero()
1340
+ sage: zero.is_unit()
1341
+ False
1342
+ """
1343
+ if self._is_zero:
1344
+ return False
1345
+ return not any(func.is_trivial_zero()
1346
+ for func in self._express.values())
1347
+
1348
+ def __eq__(self, other):
1349
+ r"""
1350
+ Comparison (equality) operator.
1351
+
1352
+ INPUT:
1353
+
1354
+ - ``other`` -- a scalar field (or something else)
1355
+
1356
+ OUTPUT: ``True`` if ``self`` is equal to ``other``, ``False`` otherwise
1357
+
1358
+ TESTS::
1359
+
1360
+ sage: M = Manifold(2, 'M', structure='topological')
1361
+ sage: X.<x,y> = M.chart()
1362
+ sage: f = M.scalar_field({X: x+y})
1363
+ sage: f == 1
1364
+ False
1365
+ sage: f == M.zero_scalar_field()
1366
+ False
1367
+ sage: g = M.scalar_field({X: x+y})
1368
+ sage: f == g
1369
+ True
1370
+ sage: h = M.scalar_field({X: 1})
1371
+ sage: h == M.one_scalar_field()
1372
+ True
1373
+ sage: h == 1
1374
+ True
1375
+ """
1376
+ from sage.manifolds.differentiable.mixed_form import MixedForm
1377
+
1378
+ if other is self:
1379
+ return True
1380
+ if isinstance(other, MixedForm):
1381
+ # use comparison of MixedForm:
1382
+ return other == self
1383
+ if not isinstance(other, ScalarField):
1384
+ # We try a conversion of other to a scalar field, except if
1385
+ # other is None (since this would generate an undefined scalar
1386
+ # field)
1387
+ if other is None:
1388
+ return False
1389
+ try:
1390
+ other = self.parent()(other) # conversion to a scalar field
1391
+ except Exception:
1392
+ return False
1393
+ if other._domain != self._domain:
1394
+ return False
1395
+ if other.is_zero():
1396
+ return self.is_zero()
1397
+ com_charts = self.common_charts(other)
1398
+ if com_charts is None:
1399
+ raise ValueError("no common chart for the comparison")
1400
+ for chart in com_charts:
1401
+ if not (self._express[chart] == other._express[chart]):
1402
+ return False
1403
+ return True
1404
+
1405
+ def __ne__(self, other):
1406
+ r"""
1407
+ Non-equality operator.
1408
+
1409
+ INPUT:
1410
+
1411
+ - ``other`` -- a scalar field
1412
+
1413
+ OUTPUT: ``True`` if ``self`` differs from ``other``, ``False`` otherwise
1414
+
1415
+ TESTS::
1416
+
1417
+ sage: M = Manifold(2, 'M', structure='topological')
1418
+ sage: X.<x,y> = M.chart()
1419
+ sage: f = M.scalar_field({X: x+y})
1420
+ sage: f != 1
1421
+ True
1422
+ sage: f != M.zero_scalar_field()
1423
+ True
1424
+ sage: g = M.scalar_field({X: x+y})
1425
+ sage: f != g
1426
+ False
1427
+ """
1428
+ return not (self == other)
1429
+
1430
+ # ## End of required methods for an algebra element (beside arithmetic) ##
1431
+
1432
+ def _init_derived(self):
1433
+ r"""
1434
+ Initialize the derived quantities.
1435
+
1436
+ TESTS::
1437
+
1438
+ sage: M = Manifold(2, 'M', structure='topological')
1439
+ sage: X.<x,y> = M.chart()
1440
+ sage: f = M.scalar_field({X: x+y})
1441
+ sage: f._init_derived()
1442
+ """
1443
+ self._restrictions = {}
1444
+ # dict. of restrictions of ``self`` on subsets
1445
+ # of self._domain, with the subsets as keys
1446
+
1447
+ def _del_derived(self):
1448
+ r"""
1449
+ Delete the derived quantities.
1450
+
1451
+ TESTS::
1452
+
1453
+ sage: M = Manifold(2, 'M', structure='topological')
1454
+ sage: X.<x,y> = M.chart()
1455
+ sage: f = M.scalar_field({X: x+y})
1456
+ sage: U = M.open_subset('U', coord_def={X: x>0})
1457
+ sage: f.restrict(U)
1458
+ Scalar field on the Open subset U of the 2-dimensional topological
1459
+ manifold M
1460
+ sage: f._restrictions
1461
+ {Open subset U of the 2-dimensional topological manifold M:
1462
+ Scalar field on the Open subset U of the 2-dimensional topological
1463
+ manifold M}
1464
+ sage: f._del_derived()
1465
+ sage: f._restrictions # restrictions are derived quantities
1466
+ {}
1467
+ """
1468
+ self._restrictions.clear()
1469
+
1470
+ def _repr_(self):
1471
+ r"""
1472
+ String representation of the object.
1473
+
1474
+ TESTS::
1475
+
1476
+ sage: M = Manifold(2, 'M', structure='topological')
1477
+ sage: X.<x,y> = M.chart()
1478
+ sage: f = M.scalar_field({X: x+y})
1479
+ sage: f._repr_()
1480
+ 'Scalar field on the 2-dimensional topological manifold M'
1481
+ sage: f = M.scalar_field({X: x+y}, name='f')
1482
+ sage: f._repr_()
1483
+ 'Scalar field f on the 2-dimensional topological manifold M'
1484
+ sage: f
1485
+ Scalar field f on the 2-dimensional topological manifold M
1486
+ """
1487
+ description = "Scalar field"
1488
+ if self._name is not None:
1489
+ description += " " + self._name
1490
+ description += " on the {}".format(self._domain)
1491
+ return description
1492
+
1493
+ def _latex_(self):
1494
+ r"""
1495
+ LaTeX representation of the object.
1496
+
1497
+ TESTS::
1498
+
1499
+ sage: M = Manifold(2, 'M', structure='topological')
1500
+ sage: X.<x,y> = M.chart()
1501
+ sage: f = M.scalar_field({X: x+y})
1502
+ sage: f._latex_()
1503
+ '\\text{Scalar field on the 2-dimensional topological manifold M}'
1504
+ sage: f = M.scalar_field({X: x+y}, name='f')
1505
+ sage: f._latex_()
1506
+ 'f'
1507
+ sage: f = M.scalar_field({X: x+y}, name='f', latex_name=r'\Phi')
1508
+ sage: f._latex_()
1509
+ '\\Phi'
1510
+ sage: latex(f)
1511
+ \Phi
1512
+ """
1513
+ if self._latex_name is None:
1514
+ return r'\text{' + str(self) + r'}'
1515
+ return self._latex_name
1516
+
1517
+ def set_name(self, name=None, latex_name=None):
1518
+ r"""
1519
+ Set (or change) the text name and LaTeX name of the scalar field.
1520
+
1521
+ INPUT:
1522
+
1523
+ - ``name`` -- (string; default: ``None``) name given to the scalar
1524
+ field
1525
+ - ``latex_name`` -- (string; default: ``None``) LaTeX symbol to denote
1526
+ the scalar field; if ``None`` while ``name`` is provided, the LaTeX
1527
+ symbol is set to ``name``
1528
+
1529
+ EXAMPLES::
1530
+
1531
+ sage: M = Manifold(2, 'M', structure='topological')
1532
+ sage: X.<x,y> = M.chart()
1533
+ sage: f = M.scalar_field({X: x+y})
1534
+ sage: f = M.scalar_field({X: x+y}); f
1535
+ Scalar field on the 2-dimensional topological manifold M
1536
+ sage: f.set_name('f'); f
1537
+ Scalar field f on the 2-dimensional topological manifold M
1538
+ sage: latex(f)
1539
+ f
1540
+ sage: f.set_name('f', latex_name=r'\Phi'); f
1541
+ Scalar field f on the 2-dimensional topological manifold M
1542
+ sage: latex(f)
1543
+ \Phi
1544
+ """
1545
+ if self.is_immutable():
1546
+ raise ValueError("the name of an immutable element "
1547
+ "cannot be changed")
1548
+ if name is not None:
1549
+ self._name = name
1550
+ if latex_name is None:
1551
+ self._latex_name = self._name
1552
+ if latex_name is not None:
1553
+ self._latex_name = latex_name
1554
+ for rst in self._restrictions.values():
1555
+ rst.set_name(name=name, latex_name=latex_name)
1556
+
1557
+ def domain(self):
1558
+ r"""
1559
+ Return the open subset on which the scalar field is defined.
1560
+
1561
+ OUTPUT:
1562
+
1563
+ - instance of class
1564
+ :class:`~sage.manifolds.manifold.TopologicalManifold`
1565
+ representing the manifold's open subset on which the
1566
+ scalar field is defined
1567
+
1568
+ EXAMPLES::
1569
+
1570
+ sage: M = Manifold(2, 'M', structure='topological')
1571
+ sage: c_xy.<x,y> = M.chart()
1572
+ sage: f = M.scalar_field(x+2*y)
1573
+ sage: f.domain()
1574
+ 2-dimensional topological manifold M
1575
+ sage: U = M.open_subset('U', coord_def={c_xy: x<0})
1576
+ sage: g = f.restrict(U)
1577
+ sage: g.domain()
1578
+ Open subset U of the 2-dimensional topological manifold M
1579
+ """
1580
+ return self._domain
1581
+
1582
+ def codomain(self):
1583
+ r"""
1584
+ Return the codomain of the scalar field.
1585
+
1586
+ EXAMPLES::
1587
+
1588
+ sage: M = Manifold(2, 'M', structure='topological')
1589
+ sage: c_xy.<x,y> = M.chart()
1590
+ sage: f = M.scalar_field(x+2*y)
1591
+ sage: f.codomain()
1592
+ Real Field with 53 bits of precision
1593
+ """
1594
+ return self._domain.base_field()
1595
+
1596
+ def copy(self, name=None, latex_name=None):
1597
+ r"""
1598
+ Return an exact copy of the scalar field.
1599
+
1600
+ INPUT:
1601
+
1602
+ - ``name`` -- (default: ``None``) name given to the copy
1603
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
1604
+ copy; if none is provided, the LaTeX symbol is set to ``name``
1605
+
1606
+ EXAMPLES:
1607
+
1608
+ Copy on a 2-dimensional manifold::
1609
+
1610
+ sage: M = Manifold(2, 'M', structure='topological')
1611
+ sage: c_xy.<x,y> = M.chart()
1612
+ sage: f = M.scalar_field(x*y^2)
1613
+ sage: g = f.copy()
1614
+ sage: type(g)
1615
+ <class 'sage.manifolds.scalarfield_algebra.ScalarFieldAlgebra_with_category.element_class'>
1616
+ sage: g.expr()
1617
+ x*y^2
1618
+ sage: g == f
1619
+ True
1620
+ sage: g is f
1621
+ False
1622
+ """
1623
+ result = type(self)(self.parent(), name=name, latex_name=latex_name)
1624
+ for chart, funct in self._express.items():
1625
+ result._express[chart] = funct.copy()
1626
+ result._is_zero = self._is_zero
1627
+ return result
1628
+
1629
+ def copy_from(self, other):
1630
+ r"""
1631
+ Make ``self`` a copy of ``other``.
1632
+
1633
+ INPUT:
1634
+
1635
+ - ``other`` -- other scalar field, in the same module as ``self``
1636
+
1637
+ .. NOTE::
1638
+
1639
+ While the derived quantities are not copied, the name is kept.
1640
+
1641
+ .. WARNING::
1642
+
1643
+ All previous defined expressions and restrictions will be deleted!
1644
+
1645
+ EXAMPLES::
1646
+
1647
+ sage: M = Manifold(2, 'M', structure='topological')
1648
+ sage: c_xy.<x,y> = M.chart()
1649
+ sage: f = M.scalar_field(x*y^2, name='f')
1650
+ sage: f.display()
1651
+ f: M → ℝ
1652
+ (x, y) ↦ x*y^2
1653
+ sage: g = M.scalar_field(name='g')
1654
+ sage: g.copy_from(f)
1655
+ sage: g.display()
1656
+ g: M → ℝ
1657
+ (x, y) ↦ x*y^2
1658
+ sage: f == g
1659
+ True
1660
+
1661
+ While the original scalar field is modified, the copy is not::
1662
+
1663
+ sage: f.set_expr(x-y)
1664
+ sage: f.display()
1665
+ f: M → ℝ
1666
+ (x, y) ↦ x - y
1667
+ sage: g.display()
1668
+ g: M → ℝ
1669
+ (x, y) ↦ x*y^2
1670
+ sage: f == g
1671
+ False
1672
+ """
1673
+ if self.is_immutable():
1674
+ raise ValueError("the expressions of an immutable element "
1675
+ "cannot be changed")
1676
+ if other not in self.parent():
1677
+ raise TypeError("the original must be an element of "
1678
+ f"{self.parent()}")
1679
+ self._del_derived()
1680
+ for chart, funct in other._express.items():
1681
+ self._express[chart] = funct.copy()
1682
+ self._is_zero = other._is_zero
1683
+
1684
+ def coord_function(self, chart=None, from_chart=None):
1685
+ r"""
1686
+ Return the function of the coordinates representing the scalar field
1687
+ in a given chart.
1688
+
1689
+ INPUT:
1690
+
1691
+ - ``chart`` -- (default: ``None``) chart with respect to which the
1692
+ coordinate expression is to be returned; if ``None``, the
1693
+ default chart of the scalar field's domain will be used
1694
+ - ``from_chart`` -- (default: ``None``) chart from which the
1695
+ required expression is computed if it is not known already in the
1696
+ chart ``chart``; if ``None``, a chart is picked in the known
1697
+ expressions
1698
+
1699
+ OUTPUT:
1700
+
1701
+ - instance of :class:`~sage.manifolds.chart_func.ChartFunction`
1702
+ representing the coordinate function of the scalar field in the
1703
+ given chart
1704
+
1705
+ EXAMPLES:
1706
+
1707
+ Coordinate function on a 2-dimensional manifold::
1708
+
1709
+ sage: M = Manifold(2, 'M', structure='topological')
1710
+ sage: c_xy.<x,y> = M.chart()
1711
+ sage: f = M.scalar_field(x*y^2)
1712
+ sage: f.coord_function()
1713
+ x*y^2
1714
+ sage: f.coord_function(c_xy) # equivalent form (since c_xy is the default chart)
1715
+ x*y^2
1716
+ sage: type(f.coord_function())
1717
+ <class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
1718
+
1719
+ Expression via a change of coordinates::
1720
+
1721
+ sage: c_uv.<u,v> = M.chart()
1722
+ sage: c_uv.transition_map(c_xy, [u+v, u-v])
1723
+ Change of coordinates from Chart (M, (u, v)) to Chart (M, (x, y))
1724
+ sage: f._express # at this stage, f is expressed only in terms of (x,y) coordinates
1725
+ {Chart (M, (x, y)): x*y^2}
1726
+ sage: f.coord_function(c_uv) # forces the computation of the expression of f in terms of (u,v) coordinates
1727
+ u^3 - u^2*v - u*v^2 + v^3
1728
+ sage: f.coord_function(c_uv) == (u+v)*(u-v)^2 # check
1729
+ True
1730
+ sage: f._express # random (dict. output); f has now 2 coordinate expressions:
1731
+ {Chart (M, (x, y)): x*y^2, Chart (M, (u, v)): u^3 - u^2*v - u*v^2 + v^3}
1732
+
1733
+ Usage in a physical context (simple Lorentz transformation - boost in
1734
+ ``x`` direction, with relative velocity ``v`` between ``o1``
1735
+ and ``o2`` frames)::
1736
+
1737
+ sage: M = Manifold(2, 'M', structure='topological')
1738
+ sage: o1.<t,x> = M.chart()
1739
+ sage: o2.<T,X> = M.chart()
1740
+ sage: f = M.scalar_field(x^2 - t^2)
1741
+ sage: f.coord_function(o1)
1742
+ -t^2 + x^2
1743
+ sage: v = var('v'); gam = 1/sqrt(1-v^2)
1744
+ sage: o2.transition_map(o1, [gam*(T - v*X), gam*(X - v*T)])
1745
+ Change of coordinates from Chart (M, (T, X)) to Chart (M, (t, x))
1746
+ sage: f.coord_function(o2)
1747
+ -T^2 + X^2
1748
+ """
1749
+ if chart is None:
1750
+ chart = self._domain._def_chart
1751
+ else:
1752
+ if chart not in self._domain._atlas:
1753
+ raise ValueError("the {} is not a chart ".format(chart) +
1754
+ "defined on the {}".format(self._domain))
1755
+ if chart not in self._express:
1756
+ # Check whether chart corresponds to a subchart of a chart
1757
+ # where the expression of self is known:
1758
+ for known_chart in self._express:
1759
+ if chart in known_chart._subcharts:
1760
+ new_expr = self._express[known_chart].expr()
1761
+ self._express[chart] = chart.function(new_expr)
1762
+ return self._express[chart]
1763
+ # If this point is reached, the expression must be computed
1764
+ # from that in the chart from_chart, by means of a
1765
+ # change-of-coordinates formula:
1766
+ if from_chart is None:
1767
+ # from_chart in searched among the charts of known expressions
1768
+ # and subcharts of them
1769
+ known_express = self._express.copy()
1770
+ found = False
1771
+ for kchart in known_express:
1772
+ for skchart in kchart._subcharts:
1773
+ if (chart, skchart) in self._domain._coord_changes:
1774
+ from_chart = skchart
1775
+ found = True
1776
+ if skchart not in self._express:
1777
+ self._express[skchart] = skchart.function(
1778
+ self._express[kchart].expr())
1779
+ break
1780
+ if found:
1781
+ break
1782
+ if not found:
1783
+ raise ValueError("no starting chart could be found to " +
1784
+ "compute the expression in the {}".format(chart))
1785
+ change = self._domain._coord_changes[(chart, from_chart)]
1786
+ # old coordinates expressed in terms of the new ones:
1787
+ coords = [change._transf._functions[i].expr()
1788
+ for i in range(self._manifold.dim())]
1789
+ new_expr = self._express[from_chart](*coords)
1790
+ self._express[chart] = chart.function(new_expr)
1791
+ self._del_derived()
1792
+ return self._express[chart]
1793
+
1794
+ def expr(self, chart=None, from_chart=None):
1795
+ r"""
1796
+ Return the coordinate expression of the scalar field in a given
1797
+ chart.
1798
+
1799
+ INPUT:
1800
+
1801
+ - ``chart`` -- (default: ``None``) chart with respect to which the
1802
+ coordinate expression is required; if ``None``, the default
1803
+ chart of the scalar field's domain will be used
1804
+ - ``from_chart`` -- (default: ``None``) chart from which the
1805
+ required expression is computed if it is not known already in the
1806
+ chart ``chart``; if ``None``, a chart is picked in ``self._express``
1807
+
1808
+ OUTPUT:
1809
+
1810
+ - the coordinate expression of the scalar field in the given chart,
1811
+ either as a Sage's symbolic expression or as a SymPy object,
1812
+ depending on the symbolic calculus method used on the chart
1813
+
1814
+ EXAMPLES:
1815
+
1816
+ Expression of a scalar field on a 2-dimensional manifold::
1817
+
1818
+ sage: M = Manifold(2, 'M', structure='topological')
1819
+ sage: c_xy.<x,y> = M.chart()
1820
+ sage: f = M.scalar_field(x*y^2)
1821
+ sage: f.expr()
1822
+ x*y^2
1823
+ sage: f.expr(c_xy) # equivalent form (since c_xy is the default chart)
1824
+ x*y^2
1825
+
1826
+ Expression via a change of coordinates::
1827
+
1828
+ sage: c_uv.<u,v> = M.chart()
1829
+ sage: c_uv.transition_map(c_xy, [u+v, u-v])
1830
+ Change of coordinates from Chart (M, (u, v)) to Chart (M, (x, y))
1831
+ sage: f._express # at this stage, f is expressed only in terms of (x,y) coordinates
1832
+ {Chart (M, (x, y)): x*y^2}
1833
+ sage: f.expr(c_uv) # forces the computation of the expression of f in terms of (u,v) coordinates
1834
+ u^3 - u^2*v - u*v^2 + v^3
1835
+ sage: bool( f.expr(c_uv) == (u+v)*(u-v)^2 ) # check
1836
+ True
1837
+ sage: f._express # random (dict. output); f has now 2 coordinate expressions:
1838
+ {Chart (M, (x, y)): x*y^2, Chart (M, (u, v)): u^3 - u^2*v - u*v^2 + v^3}
1839
+
1840
+ Note that the object returned by ``expr()`` depends on the symbolic
1841
+ backend used for coordinate computations::
1842
+
1843
+ sage: type(f.expr())
1844
+ <class 'sage.symbolic.expression.Expression'>
1845
+ sage: M.set_calculus_method('sympy')
1846
+ sage: type(f.expr())
1847
+ <class 'sympy.core.mul.Mul'>
1848
+ sage: f.expr() # note the SymPy exponent notation
1849
+ x*y**2
1850
+ """
1851
+ return self.coord_function(chart, from_chart).expr()
1852
+
1853
+ def set_expr(self, coord_expression, chart=None):
1854
+ r"""
1855
+ Set the coordinate expression of the scalar field.
1856
+
1857
+ The expressions with respect to other charts are deleted, in order to
1858
+ avoid any inconsistency. To keep them, use :meth:`add_expr` instead.
1859
+
1860
+ INPUT:
1861
+
1862
+ - ``coord_expression`` -- coordinate expression of the scalar field
1863
+ - ``chart`` -- (default: ``None``) chart in which ``coord_expression``
1864
+ is defined; if ``None``, the default chart of the scalar field's
1865
+ domain is assumed
1866
+
1867
+ EXAMPLES:
1868
+
1869
+ Setting scalar field expressions on a 2-dimensional manifold::
1870
+
1871
+ sage: M = Manifold(2, 'M', structure='topological')
1872
+ sage: c_xy.<x,y> = M.chart()
1873
+ sage: f = M.scalar_field(x^2 + 2*x*y +1)
1874
+ sage: f._express
1875
+ {Chart (M, (x, y)): x^2 + 2*x*y + 1}
1876
+ sage: f.set_expr(3*y)
1877
+ sage: f._express # the (x,y) expression has been changed:
1878
+ {Chart (M, (x, y)): 3*y}
1879
+ sage: c_uv.<u,v> = M.chart()
1880
+ sage: f.set_expr(cos(u)-sin(v), c_uv)
1881
+ sage: f._express # the (x,y) expression has been lost:
1882
+ {Chart (M, (u, v)): cos(u) - sin(v)}
1883
+ sage: f.set_expr(3*y)
1884
+ sage: f._express # the (u,v) expression has been lost:
1885
+ {Chart (M, (x, y)): 3*y}
1886
+
1887
+ Since zero and one are special elements, their expressions cannot be
1888
+ changed::
1889
+
1890
+ sage: z = M.zero_scalar_field()
1891
+ sage: z.set_expr(3*y)
1892
+ Traceback (most recent call last):
1893
+ ...
1894
+ ValueError: the expressions of an immutable element cannot be
1895
+ changed
1896
+ sage: one = M.one_scalar_field()
1897
+ sage: one.set_expr(3*y)
1898
+ Traceback (most recent call last):
1899
+ ...
1900
+ ValueError: the expressions of an immutable element cannot be
1901
+ changed
1902
+ """
1903
+ if self.is_immutable():
1904
+ raise ValueError("the expressions of an immutable element "
1905
+ "cannot be changed")
1906
+ if chart is None:
1907
+ chart = self._domain._def_chart
1908
+ self._express.clear()
1909
+ self._express[chart] = chart.function(coord_expression)
1910
+ self._is_zero = False # a priori
1911
+ self._del_derived()
1912
+
1913
+ def add_expr(self, coord_expression, chart=None):
1914
+ r"""
1915
+ Add some coordinate expression to the scalar field.
1916
+
1917
+ The previous expressions with respect to other charts are kept. To
1918
+ clear them, use :meth:`set_expr` instead.
1919
+
1920
+ INPUT:
1921
+
1922
+ - ``coord_expression`` -- coordinate expression of the scalar field
1923
+ - ``chart`` -- (default: ``None``) chart in which ``coord_expression``
1924
+ is defined; if ``None``, the default chart of the scalar field's
1925
+ domain is assumed
1926
+
1927
+ .. WARNING::
1928
+
1929
+ If the scalar field has already expressions in other charts, it
1930
+ is the user's responsibility to make sure that the expression
1931
+ to be added is consistent with them.
1932
+
1933
+ EXAMPLES:
1934
+
1935
+ Adding scalar field expressions on a 2-dimensional manifold::
1936
+
1937
+ sage: M = Manifold(2, 'M', structure='topological')
1938
+ sage: c_xy.<x,y> = M.chart()
1939
+ sage: f = M.scalar_field(x^2 + 2*x*y +1)
1940
+ sage: f._express
1941
+ {Chart (M, (x, y)): x^2 + 2*x*y + 1}
1942
+ sage: f.add_expr(3*y)
1943
+ sage: f._express # the (x,y) expression has been changed:
1944
+ {Chart (M, (x, y)): 3*y}
1945
+ sage: c_uv.<u,v> = M.chart()
1946
+ sage: f.add_expr(cos(u)-sin(v), c_uv)
1947
+ sage: f._express # random (dict. output); f has now 2 expressions:
1948
+ {Chart (M, (x, y)): 3*y, Chart (M, (u, v)): cos(u) - sin(v)}
1949
+
1950
+ Since zero and one are special elements, their expressions cannot be
1951
+ changed::
1952
+
1953
+ sage: z = M.zero_scalar_field()
1954
+ sage: z.add_expr(cos(u)-sin(v), c_uv)
1955
+ Traceback (most recent call last):
1956
+ ...
1957
+ ValueError: the expressions of an immutable element cannot be
1958
+ changed
1959
+ sage: one = M.one_scalar_field()
1960
+ sage: one.add_expr(cos(u)-sin(v), c_uv)
1961
+ Traceback (most recent call last):
1962
+ ...
1963
+ ValueError: the expressions of an immutable element cannot be
1964
+ changed
1965
+ """
1966
+ if self.is_immutable():
1967
+ raise ValueError("the expressions of an immutable element "
1968
+ "cannot be changed")
1969
+ if chart is None:
1970
+ chart = self._domain._def_chart
1971
+ self._express[chart] = chart.function(coord_expression)
1972
+ self._is_zero = False # a priori
1973
+ self._del_derived()
1974
+
1975
+ def add_expr_by_continuation(self, chart, subdomain):
1976
+ r"""
1977
+ Set coordinate expression in a chart by continuation of the
1978
+ coordinate expression in a subchart.
1979
+
1980
+ The continuation is performed by demanding that the coordinate
1981
+ expression is identical to that in the restriction of the chart to
1982
+ a given subdomain.
1983
+
1984
+ INPUT:
1985
+
1986
+ - ``chart`` -- coordinate chart `(U,(x^i))` in which the expression of
1987
+ the scalar field is to set
1988
+ - ``subdomain`` -- open subset `V\subset U` in which the expression
1989
+ in terms of the restriction of the coordinate chart `(U,(x^i))` to
1990
+ `V` is already known or can be evaluated by a change of coordinates.
1991
+
1992
+ EXAMPLES:
1993
+
1994
+ Scalar field on the sphere `S^2`::
1995
+
1996
+ sage: M = Manifold(2, 'S^2', structure='topological')
1997
+ sage: U = M.open_subset('U') ; V = M.open_subset('V') # the complement of resp. N pole and S pole
1998
+ sage: M.declare_union(U,V) # S^2 is the union of U and V
1999
+ sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() # stereographic coordinates
2000
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)),
2001
+ ....: intersection_name='W', restrictions1= x^2+y^2!=0,
2002
+ ....: restrictions2= u^2+v^2!=0)
2003
+ sage: uv_to_xy = xy_to_uv.inverse()
2004
+ sage: W = U.intersection(V) # S^2 minus the two poles
2005
+ sage: f = M.scalar_field(atan(x^2+y^2), chart=c_xy, name='f')
2006
+
2007
+ The scalar field has been defined only on the domain covered by the
2008
+ chart ``c_xy``, i.e. `U`::
2009
+
2010
+ sage: f.display()
2011
+ f: S^2 → ℝ
2012
+ on U: (x, y) ↦ arctan(x^2 + y^2)
2013
+ on W: (u, v) ↦ arctan(1/(u^2 + v^2))
2014
+
2015
+ We note that on `W = U \cap V`, the expression of `f` in terms of
2016
+ coordinates `(u,v)` can be deduced from that in the coordinates
2017
+ `(x,y)` thanks to the transition map between the two charts::
2018
+
2019
+ sage: f.display(c_uv.restrict(W))
2020
+ f: S^2 → ℝ
2021
+ on W: (u, v) ↦ arctan(1/(u^2 + v^2))
2022
+
2023
+ We use this fact to extend the definition of `f` to the open
2024
+ subset `V`, covered by the chart ``c_uv``::
2025
+
2026
+ sage: f.add_expr_by_continuation(c_uv, W)
2027
+
2028
+ Then, `f` is known on the whole sphere::
2029
+
2030
+ sage: f.display()
2031
+ f: S^2 → ℝ
2032
+ on U: (x, y) ↦ arctan(x^2 + y^2)
2033
+ on V: (u, v) ↦ arctan(1/(u^2 + v^2))
2034
+ """
2035
+ if self.is_immutable():
2036
+ raise ValueError("the expressions of an immutable element "
2037
+ "cannot be changed")
2038
+ if not chart.domain().is_subset(self._domain):
2039
+ raise ValueError("the chart is not defined on a subset of " +
2040
+ "the scalar field domain")
2041
+ schart = chart.restrict(subdomain)
2042
+ self._express[chart] = chart.function(self.expr(schart))
2043
+ self._is_zero = False # a priori
2044
+ self._del_derived()
2045
+
2046
+ def set_restriction(self, rst):
2047
+ r"""
2048
+ Define a restriction of ``self`` to some subdomain.
2049
+
2050
+ INPUT:
2051
+
2052
+ - ``rst`` -- :class:`ScalarField` defined on a subdomain of
2053
+ the domain of ``self``
2054
+
2055
+ EXAMPLES::
2056
+
2057
+ sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2
2058
+ sage: U = M.open_subset('U') # complement of the North pole
2059
+ sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
2060
+ sage: V = M.open_subset('V') # complement of the South pole
2061
+ sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
2062
+ sage: M.declare_union(U,V) # S^2 is the union of U and V
2063
+ sage: f = M.scalar_field(name='f')
2064
+ sage: g = U.scalar_field(x^2+y)
2065
+ sage: f.set_restriction(g)
2066
+ sage: f.display()
2067
+ f: M → ℝ
2068
+ on U: (x, y) ↦ x^2 + y
2069
+ sage: f.restrict(U) == g
2070
+ True
2071
+ """
2072
+ if self.is_immutable():
2073
+ raise ValueError("the expressions of an immutable element "
2074
+ "cannot be changed")
2075
+ if not isinstance(rst, ScalarField):
2076
+ raise TypeError("the argument must be a scalar field")
2077
+ if not rst._domain.is_subset(self._domain):
2078
+ raise ValueError("the domain of the declared restriction is not " +
2079
+ "a subset of the field's domain")
2080
+ self._restrictions[rst._domain] = rst.copy(name=self._name,
2081
+ latex_name=self._latex_name)
2082
+ for chart, expr in rst._express.items():
2083
+ intersection = chart.domain().intersection(rst._domain)
2084
+ self._express[chart.restrict(intersection)] = expr
2085
+ self._is_zero = False # a priori
2086
+
2087
+ def display(self, chart: Optional[Chart] = None) -> FormattedExpansion:
2088
+ r"""
2089
+ Display the expression of the scalar field in a given chart.
2090
+
2091
+ Without any argument, this function displays all known, distinct
2092
+ expressions.
2093
+
2094
+ INPUT:
2095
+
2096
+ - ``chart`` -- (default: ``None``) chart with respect to which
2097
+ the coordinate expression is to be displayed; if ``None``, the
2098
+ display is performed in all the greatest charts in which the
2099
+ coordinate expression is known
2100
+
2101
+ The output is either text-formatted (console mode) or LaTeX-formatted
2102
+ (notebook mode).
2103
+
2104
+ EXAMPLES:
2105
+
2106
+ Various displays::
2107
+
2108
+ sage: M = Manifold(2, 'M', structure='topological')
2109
+ sage: c_xy.<x,y> = M.chart()
2110
+ sage: f = M.scalar_field(sqrt(x+1), name='f')
2111
+ sage: f.display()
2112
+ f: M → ℝ
2113
+ (x, y) ↦ sqrt(x + 1)
2114
+ sage: latex(f.display())
2115
+ \begin{array}{llcl} f:& M & \longrightarrow & \mathbb{R} \\ & \left(x, y\right) & \longmapsto & \sqrt{x + 1} \end{array}
2116
+ sage: g = M.scalar_field(function('G')(x, y), name='g')
2117
+ sage: g.display()
2118
+ g: M → ℝ
2119
+ (x, y) ↦ G(x, y)
2120
+ sage: latex(g.display())
2121
+ \begin{array}{llcl} g:& M & \longrightarrow & \mathbb{R} \\ & \left(x, y\right) & \longmapsto & G\left(x, y\right) \end{array}
2122
+
2123
+ A shortcut of ``display()`` is ``disp()``::
2124
+
2125
+ sage: f.disp()
2126
+ f: M → ℝ
2127
+ (x, y) ↦ sqrt(x + 1)
2128
+
2129
+ In case the scalar field is piecewise-defined, the ``display()``
2130
+ command still outputs all expressions. Each expression displayed
2131
+ corresponds to the chart on the greatest domain where this particular
2132
+ expression is known::
2133
+
2134
+ sage: U = M.open_subset('U')
2135
+ sage: f.set_expr(y^2, c_xy.restrict(U))
2136
+ sage: f.display()
2137
+ f: M → ℝ
2138
+ on U: (x, y) ↦ y^2
2139
+ sage: latex(f.display())
2140
+ \begin{array}{llcl} f:& M & \longrightarrow & \mathbb{R} \\ \text{on}\ U : & \left(x, y\right) & \longmapsto & y^{2} \end{array}
2141
+ """
2142
+ from sage.misc.latex import latex
2143
+ from sage.tensor.modules.format_utilities import FormattedExpansion
2144
+ from sage.typeset.unicode_characters import (
2145
+ unicode_mapsto,
2146
+ unicode_mathbbC,
2147
+ unicode_mathbbR,
2148
+ unicode_to,
2149
+ )
2150
+
2151
+ def _display_expression(self, chart, result):
2152
+ r"""
2153
+ Helper function for :meth:`display`.
2154
+ """
2155
+ try:
2156
+ # get coordinate expression
2157
+ expression = self.coord_function(chart)
2158
+ except (TypeError, ValueError):
2159
+ pass
2160
+ # if that succeeds, proceed:
2161
+ coords = chart[:]
2162
+ if len(coords) == 1:
2163
+ coords = coords[0]
2164
+ if chart.domain() == self._domain:
2165
+ if self._name is not None:
2166
+ result._txt += " "
2167
+ result._latex += " & "
2168
+ else:
2169
+ result._txt += "on " + chart.domain()._name + ": "
2170
+ result._latex += r"\text{on}\ " + latex(chart.domain()) \
2171
+ + r": & "
2172
+ result._txt += repr(coords) + " " + unicode_mapsto + " " \
2173
+ + repr(expression) + "\n"
2174
+ result._latex += latex(coords) + r"& \longmapsto & " \
2175
+ + latex(expression) + r"\\"
2176
+
2177
+ # Name of the base field:
2178
+ field = self._domain.base_field()
2179
+ field_type = self._domain.base_field_type()
2180
+ if field_type == 'real':
2181
+ field_name = unicode_mathbbR
2182
+ field_latex_name = r'\mathbb{R}'
2183
+ elif field_type == 'complex':
2184
+ field_name = unicode_mathbbC
2185
+ field_latex_name = r'\mathbb{C}'
2186
+ else:
2187
+ field_name = str(field)
2188
+ field_latex_name = latex(field)
2189
+
2190
+ result = FormattedExpansion()
2191
+ if self._name is None:
2192
+ symbol = ""
2193
+ else:
2194
+ symbol = self._name + ": "
2195
+ result._txt = symbol + self._domain._name + " " + unicode_to + " " \
2196
+ + field_name + "\n"
2197
+ if self._latex_name is None:
2198
+ symbol = ""
2199
+ else:
2200
+ symbol = self._latex_name + ":"
2201
+ result._latex = r"\begin{array}{llcl} " + symbol + r"&" + \
2202
+ latex(self._domain) + r"& \longrightarrow & " + \
2203
+ field_latex_name + r" \\"
2204
+ if chart is None:
2205
+ for ch in self._domain._top_charts:
2206
+ ###
2207
+ # Get the greatest domain of top chart restrictions where the
2208
+ # expression is known:
2209
+ max_dom = None
2210
+ for sch in ch._subcharts:
2211
+ if max_dom is None:
2212
+ try:
2213
+ self.coord_function(sch)
2214
+ max_dom = sch.domain()
2215
+ except (TypeError, ValueError):
2216
+ pass
2217
+ elif max_dom.is_subset(sch.domain()):
2218
+ try:
2219
+ self.coord_function(sch)
2220
+ max_dom = sch.domain()
2221
+ except (TypeError, ValueError):
2222
+ pass
2223
+ if max_dom is not None:
2224
+ _display_expression(self, ch.restrict(max_dom), result)
2225
+ else:
2226
+ _display_expression(self, chart, result)
2227
+ result._txt = result._txt[:-1]
2228
+ result._latex = result._latex[:-2] + r"\end{array}"
2229
+ return result
2230
+
2231
+ disp = display
2232
+
2233
+ def restrict(self, subdomain):
2234
+ r"""
2235
+ Restriction of the scalar field to an open subset of its domain of
2236
+ definition.
2237
+
2238
+ INPUT:
2239
+
2240
+ - ``subdomain`` -- an open subset of the scalar field's domain
2241
+
2242
+ OUTPUT:
2243
+
2244
+ - instance of :class:`ScalarField` representing the restriction of
2245
+ the scalar field to ``subdomain``
2246
+
2247
+ EXAMPLES:
2248
+
2249
+ Restriction of a scalar field defined on `\RR^2` to the
2250
+ unit open disc::
2251
+
2252
+ sage: M = Manifold(2, 'M', structure='topological')
2253
+ sage: X.<x,y> = M.chart() # Cartesian coordinates
2254
+ sage: U = M.open_subset('U', coord_def={X: x^2+y^2 < 1}) # U unit open disc
2255
+ sage: f = M.scalar_field(cos(x*y), name='f')
2256
+ sage: f_U = f.restrict(U) ; f_U
2257
+ Scalar field f on the Open subset U of the 2-dimensional
2258
+ topological manifold M
2259
+ sage: f_U.display()
2260
+ f: U → ℝ
2261
+ (x, y) ↦ cos(x*y)
2262
+ sage: f.parent()
2263
+ Algebra of scalar fields on the 2-dimensional topological
2264
+ manifold M
2265
+ sage: f_U.parent()
2266
+ Algebra of scalar fields on the Open subset U of the 2-dimensional
2267
+ topological manifold M
2268
+
2269
+ The restriction to the whole domain is the identity::
2270
+
2271
+ sage: f.restrict(M) is f
2272
+ True
2273
+ sage: f_U.restrict(U) is f_U
2274
+ True
2275
+
2276
+ Restriction of the zero scalar field::
2277
+
2278
+ sage: M.zero_scalar_field().restrict(U)
2279
+ Scalar field zero on the Open subset U of the 2-dimensional
2280
+ topological manifold M
2281
+ sage: M.zero_scalar_field().restrict(U) is U.zero_scalar_field()
2282
+ True
2283
+ """
2284
+ if subdomain == self._domain:
2285
+ return self
2286
+ if subdomain not in self._restrictions:
2287
+ if not subdomain.is_subset(self._domain):
2288
+ raise ValueError("the specified domain is not a subset of " +
2289
+ "the domain of definition of the scalar field")
2290
+ # Special case of the zero scalar field:
2291
+ if self._is_zero:
2292
+ return subdomain._zero_scalar_field
2293
+ # First one tries to get the restriction from a tighter domain:
2294
+ for dom, rst in self._restrictions.items():
2295
+ if subdomain.is_subset(dom):
2296
+ self._restrictions[subdomain] = rst.restrict(subdomain)
2297
+ break
2298
+ else:
2299
+ # If this fails, the restriction must be created from scratch:
2300
+ sexpress = {}
2301
+ for chart, funct in self._express.items():
2302
+ for schart in subdomain.atlas():
2303
+ if schart in chart._subcharts:
2304
+ sexpress[schart] = funct.expr()
2305
+ resu = type(self)(subdomain.scalar_field_algebra(),
2306
+ coord_expression=sexpress, name=self._name,
2307
+ latex_name=self._latex_name)
2308
+ if self.is_immutable():
2309
+ resu.set_immutable() # restriction must be immutable, too
2310
+ self._restrictions[subdomain] = resu
2311
+ return self._restrictions[subdomain]
2312
+
2313
+ def common_charts(self, other):
2314
+ r"""
2315
+ Find common charts for the expressions of the scalar field and
2316
+ ``other``.
2317
+
2318
+ INPUT:
2319
+
2320
+ - ``other`` -- a scalar field
2321
+
2322
+ OUTPUT:
2323
+
2324
+ - list of common charts; if no common chart is found, ``None`` is
2325
+ returned (instead of an empty list)
2326
+
2327
+ EXAMPLES:
2328
+
2329
+ Search for common charts on a 2-dimensional manifold with 2
2330
+ overlapping domains::
2331
+
2332
+ sage: M = Manifold(2, 'M', structure='topological')
2333
+ sage: U = M.open_subset('U')
2334
+ sage: c_xy.<x,y> = U.chart()
2335
+ sage: V = M.open_subset('V')
2336
+ sage: c_uv.<u,v> = V.chart()
2337
+ sage: M.declare_union(U,V) # M is the union of U and V
2338
+ sage: f = U.scalar_field(x^2)
2339
+ sage: g = M.scalar_field(x+y)
2340
+ sage: f.common_charts(g)
2341
+ [Chart (U, (x, y))]
2342
+ sage: g.add_expr(u, c_uv)
2343
+ sage: f._express
2344
+ {Chart (U, (x, y)): x^2}
2345
+ sage: g._express # random (dictionary output)
2346
+ {Chart (U, (x, y)): x + y, Chart (V, (u, v)): u}
2347
+ sage: f.common_charts(g)
2348
+ [Chart (U, (x, y))]
2349
+
2350
+ Common charts found as subcharts: the subcharts are introduced via
2351
+ a transition map between charts c_xy and c_uv on the intersecting
2352
+ subdomain `W = U\cap V`::
2353
+
2354
+ sage: trans = c_xy.transition_map(c_uv, (x+y, x-y), 'W', x<0, u+v<0)
2355
+ sage: M.atlas()
2356
+ [Chart (U, (x, y)), Chart (V, (u, v)), Chart (W, (x, y)),
2357
+ Chart (W, (u, v))]
2358
+ sage: c_xy_W = M.atlas()[2]
2359
+ sage: c_uv_W = M.atlas()[3]
2360
+ sage: trans.inverse()
2361
+ Change of coordinates from Chart (W, (u, v)) to Chart (W, (x, y))
2362
+ sage: f.common_charts(g)
2363
+ [Chart (U, (x, y))]
2364
+ sage: f.expr(c_xy_W)
2365
+ x^2
2366
+ sage: f._express # random (dictionary output)
2367
+ {Chart (U, (x, y)): x^2, Chart (W, (x, y)): x^2}
2368
+ sage: g._express # random (dictionary output)
2369
+ {Chart (U, (x, y)): x + y, Chart (V, (u, v)): u}
2370
+ sage: g.common_charts(f) # c_xy_W is not returned because it is subchart of 'xy'
2371
+ [Chart (U, (x, y))]
2372
+ sage: f.expr(c_uv_W)
2373
+ 1/4*u^2 + 1/2*u*v + 1/4*v^2
2374
+ sage: f._express # random (dictionary output)
2375
+ {Chart (U, (x, y)): x^2, Chart (W, (x, y)): x^2,
2376
+ Chart (W, (u, v)): 1/4*u^2 + 1/2*u*v + 1/4*v^2}
2377
+ sage: g._express # random (dictionary output)
2378
+ {Chart (U, (x, y)): x + y, Chart (V, (u, v)): u}
2379
+ sage: f.common_charts(g)
2380
+ [Chart (U, (x, y)), Chart (W, (u, v))]
2381
+ sage: # the expressions have been updated on the subcharts
2382
+ sage: g._express # random (dictionary output)
2383
+ {Chart (U, (x, y)): x + y, Chart (V, (u, v)): u,
2384
+ Chart (W, (u, v)): u}
2385
+
2386
+ Common charts found by computing some coordinate changes::
2387
+
2388
+ sage: W = U.intersection(V)
2389
+ sage: f = W.scalar_field(x^2, c_xy_W)
2390
+ sage: g = W.scalar_field(u+1, c_uv_W)
2391
+ sage: f._express
2392
+ {Chart (W, (x, y)): x^2}
2393
+ sage: g._express
2394
+ {Chart (W, (u, v)): u + 1}
2395
+ sage: f.common_charts(g)
2396
+ [Chart (W, (x, y)), Chart (W, (u, v))]
2397
+ sage: f._express # random (dictionary output)
2398
+ {Chart (W, (u, v)): 1/4*u^2 + 1/2*u*v + 1/4*v^2,
2399
+ Chart (W, (x, y)): x^2}
2400
+ sage: g._express # random (dictionary output)
2401
+ {Chart (W, (u, v)): u + 1, Chart (W, (x, y)): x + y + 1}
2402
+
2403
+ TESTS:
2404
+
2405
+ Check that :issue:`28072` has been fixed::
2406
+
2407
+ sage: c_ab.<a,b> = W.chart()
2408
+ sage: xy_to_ab = c_xy_W.transition_map(c_ab, (3*y, x-y))
2409
+ sage: h = W.scalar_field(a+b, chart=c_ab)
2410
+ sage: f.common_charts(h)
2411
+ [Chart (W, (x, y))]
2412
+ sage: h.expr(c_xy_W)
2413
+ x + 2*y
2414
+ """
2415
+ if not isinstance(other, ScalarField):
2416
+ raise TypeError("the second argument must be a scalar field")
2417
+ coord_changes = self._manifold._coord_changes
2418
+ resu = []
2419
+ #
2420
+ # 1/ Search for common charts among the existing expressions, i.e.
2421
+ # without performing any expression transformation.
2422
+ # -------------------------------------------------------------
2423
+ for chart1 in self._express:
2424
+ if chart1 in other._express:
2425
+ resu.append(chart1)
2426
+ # Search for a subchart:
2427
+ known_expr1 = self._express.copy()
2428
+ known_expr2 = other._express.copy()
2429
+ for chart1 in known_expr1:
2430
+ if chart1 not in resu:
2431
+ for chart2 in known_expr2:
2432
+ if chart2 not in resu:
2433
+ if chart2 in chart1._subcharts:
2434
+ self.expr(chart2)
2435
+ resu.append(chart2)
2436
+ if chart1 in chart2._subcharts:
2437
+ other.expr(chart1)
2438
+ resu.append(chart1)
2439
+ #
2440
+ # 2/ Search for common charts via one expression transformation
2441
+ # ----------------------------------------------------------
2442
+ for chart1 in known_expr1:
2443
+ if chart1 not in resu:
2444
+ for chart2 in known_expr2:
2445
+ if chart2 not in resu:
2446
+ if (chart1, chart2) in coord_changes:
2447
+ other.coord_function(chart1, from_chart=chart2)
2448
+ resu.append(chart1)
2449
+ if (chart2, chart1) in coord_changes:
2450
+ self.coord_function(chart2, from_chart=chart1)
2451
+ resu.append(chart2)
2452
+ if not resu:
2453
+ return None
2454
+ else:
2455
+ return resu
2456
+
2457
+ def __call__(self, p, chart=None):
2458
+ r"""
2459
+ Compute the value of the scalar field at a given point.
2460
+
2461
+ INPUT:
2462
+
2463
+ - ``p`` -- point in the scalar field's domain
2464
+ - ``chart`` -- (default: ``None``) chart in which the coordinates
2465
+ of ``p`` are to be considered; if ``None``, a chart in which
2466
+ both ``p``'s coordinates and the expression of the scalar field
2467
+ are known is searched, starting from the default chart
2468
+ of ``self._domain``
2469
+
2470
+ OUTPUT: value at ``p``
2471
+
2472
+ EXAMPLES::
2473
+
2474
+ sage: M = Manifold(2, 'M', structure='topological')
2475
+ sage: X.<x,y> = M.chart()
2476
+ sage: f = M.scalar_field({X: x+y}, name='f')
2477
+ sage: p = M((2,-5), name='p'); p
2478
+ Point p on the 2-dimensional topological manifold M
2479
+ sage: f.__call__(p)
2480
+ -3
2481
+ sage: f(p)
2482
+ -3
2483
+ sage: M.zero_scalar_field()(p)
2484
+ 0
2485
+ sage: M.one_scalar_field()(p)
2486
+ 1
2487
+
2488
+ Example with a change of chart::
2489
+
2490
+ sage: Y.<u,v> = M.chart()
2491
+ sage: X_to_Y = X.transition_map(Y, [x+y, x-y])
2492
+ sage: Y_to_X = X_to_Y.inverse()
2493
+ sage: g = M.scalar_field({Y: u*v}, name='g')
2494
+ sage: g(p)
2495
+ -21
2496
+ sage: p.coord(Y)
2497
+ (-3, 7)
2498
+ """
2499
+ # ! # it should be "if p not in self_domain:" instead, but this test is
2500
+ # skipped for efficiency
2501
+ if p not in self._manifold:
2502
+ raise ValueError("the {} ".format(p) + "does not belong " +
2503
+ "to the {}".format(self._manifold))
2504
+ if self._is_zero:
2505
+ return 0
2506
+ if chart is None:
2507
+ # A common chart is searched:
2508
+ def_chart = self._domain._def_chart
2509
+ if def_chart in p._coordinates and def_chart in self._express:
2510
+ chart = def_chart
2511
+ else:
2512
+ for chart_p in p._coordinates:
2513
+ if chart_p in self._express:
2514
+ chart = chart_p
2515
+ break
2516
+ if chart is None:
2517
+ # A change of coordinates is attempted for p:
2518
+ for chart_s in self._express:
2519
+ try:
2520
+ p.coord(chart_s)
2521
+ chart = chart_s
2522
+ break
2523
+ except ValueError:
2524
+ pass
2525
+ else:
2526
+ # A change of coordinates is attempted on the scalar field
2527
+ # expressions:
2528
+ for chart_p in p._coordinates:
2529
+ try:
2530
+ self.coord_function(chart_p)
2531
+ chart = chart_p
2532
+ break
2533
+ except (TypeError, ValueError):
2534
+ pass
2535
+ if chart is None:
2536
+ raise ValueError("no common chart has been found to evaluate " +
2537
+ "the action of {} on the {}".format(self, p))
2538
+ return self._express[chart](*(p._coordinates[chart]))
2539
+
2540
+ def preimage(self, codomain_subset, name=None, latex_name=None):
2541
+ r"""
2542
+ Return the preimage of ``codomain_subset``.
2543
+
2544
+ An alias is :meth:`pullback`.
2545
+
2546
+ INPUT:
2547
+
2548
+ - ``codomain_subset`` -- an instance of
2549
+ :class:`~sage.sets.real_set.RealSet`
2550
+ - ``name`` -- string; name (symbol) given to the subset
2551
+ - ``latex_name`` -- string (default: ``None``); LaTeX symbol to
2552
+ denote the subset; if none are provided, it is set to ``name``
2553
+
2554
+ OUTPUT:
2555
+
2556
+ - either a :class:`~sage.manifolds.manifold.TopologicalManifold` or
2557
+ a :class:`~sage.manifolds.subsets.pullback.ManifoldSubsetPullback`
2558
+
2559
+ EXAMPLES::
2560
+
2561
+ sage: M = Manifold(2, 'M', structure='topological')
2562
+ sage: X.<x,y> = M.chart()
2563
+ sage: f = M.scalar_field({X: x+y}, name='f')
2564
+ sage: L = f.pullback(RealSet.point(1)); latex(L)
2565
+ f^{-1}(\{1\})
2566
+ sage: M((-1, 1)) in L
2567
+ False
2568
+ sage: M((0, 1)) in L
2569
+ True
2570
+
2571
+ sage: M.zero_scalar_field().preimage(RealSet.point(0)) is M
2572
+ True
2573
+ """
2574
+ if self.is_trivial_zero() and 0 in codomain_subset:
2575
+ return self.domain()
2576
+ from sage.manifolds.subsets.pullback import ManifoldSubsetPullback
2577
+ return ManifoldSubsetPullback(self, codomain_subset,
2578
+ name=name, latex_name=latex_name)
2579
+
2580
+ pullback = preimage
2581
+
2582
+ def __pos__(self):
2583
+ r"""
2584
+ Unary plus operator.
2585
+
2586
+ OUTPUT: an exact copy of the scalar field
2587
+
2588
+ TESTS::
2589
+
2590
+ sage: M = Manifold(2, 'M', structure='topological')
2591
+ sage: X.<x,y> = M.chart()
2592
+ sage: f = M.scalar_field({X: x+y}, name='f')
2593
+ sage: g = f.__pos__(); g
2594
+ Scalar field +f on the 2-dimensional topological manifold M
2595
+ sage: g == f
2596
+ True
2597
+ """
2598
+ result = type(self)(self.parent())
2599
+ for chart in self._express:
2600
+ result._express[chart] = + self._express[chart]
2601
+ if self._name is not None:
2602
+ result._name = '+' + self._name
2603
+ if self._latex_name is not None:
2604
+ result._latex_name = '+' + self._latex_name
2605
+ return result
2606
+
2607
+ def __neg__(self):
2608
+ r"""
2609
+ Unary minus operator.
2610
+
2611
+ OUTPUT: the negative of the scalar field
2612
+
2613
+ TESTS::
2614
+
2615
+ sage: M = Manifold(2, 'M', structure='topological')
2616
+ sage: X.<x,y> = M.chart()
2617
+ sage: f = M.scalar_field({X: x+y}, name='f')
2618
+ sage: g = f.__neg__(); g
2619
+ Scalar field -f on the 2-dimensional topological manifold M
2620
+ sage: g.display()
2621
+ -f: M → ℝ
2622
+ (x, y) ↦ -x - y
2623
+ sage: g.__neg__() == f
2624
+ True
2625
+ """
2626
+ result = type(self)(self.parent())
2627
+ for chart in self._express:
2628
+ result._express[chart] = - self._express[chart]
2629
+ if self._name is not None:
2630
+ result._name = '-' + self._name
2631
+ if self._latex_name is not None:
2632
+ result._latex_name = '-' + self._latex_name
2633
+ return result
2634
+
2635
+ # ### CommutativeAlgebraElement arithmetic operators ###
2636
+
2637
+ def _add_(self, other):
2638
+ r"""
2639
+ Scalar field addition.
2640
+
2641
+ INPUT:
2642
+
2643
+ - ``other`` -- a scalar field (in the same algebra as ``self``)
2644
+
2645
+ OUTPUT:
2646
+
2647
+ - the scalar field resulting from the addition of ``self`` and
2648
+ ``other``
2649
+
2650
+ TESTS::
2651
+
2652
+ sage: M = Manifold(2, 'M', structure='topological')
2653
+ sage: X.<x,y> = M.chart()
2654
+ sage: f = M.scalar_field({X: x+y}, name='f')
2655
+ sage: g = M.scalar_field({X: x*y}, name='g')
2656
+ sage: s = f._add_(g); s
2657
+ Scalar field f+g on the 2-dimensional topological manifold M
2658
+ sage: s.display()
2659
+ f+g: M → ℝ
2660
+ (x, y) ↦ (x + 1)*y + x
2661
+ sage: s == f+g
2662
+ True
2663
+ sage: f._add_(M.zero_scalar_field()) == f
2664
+ True
2665
+ """
2666
+ # Trivial cases:
2667
+ if self.is_trivial_zero():
2668
+ return other
2669
+ if other.is_trivial_zero():
2670
+ return self
2671
+ # Generic case:
2672
+ com_charts = self.common_charts(other)
2673
+ if com_charts is None:
2674
+ raise ValueError("no common chart for the addition")
2675
+ result = type(self)(self.parent())
2676
+ for chart in com_charts:
2677
+ # ChartFunction addition:
2678
+ result._express[chart] = self._express[chart] + other._express[chart]
2679
+ if self._name is not None and other._name is not None:
2680
+ result._name = self._name + '+' + other._name
2681
+ if self._latex_name is not None and other._latex_name is not None:
2682
+ result._latex_name = self._latex_name + '+' + other._latex_name
2683
+ return result
2684
+
2685
+ def _sub_(self, other):
2686
+ r"""
2687
+ Scalar field subtraction.
2688
+
2689
+ INPUT:
2690
+
2691
+ - ``other`` -- a scalar field (in the same algebra as ``self``)
2692
+
2693
+ OUTPUT:
2694
+
2695
+ - the scalar field resulting from the subtraction of ``other`` from
2696
+ ``self``
2697
+
2698
+ TESTS::
2699
+
2700
+ sage: M = Manifold(2, 'M', structure='topological')
2701
+ sage: X.<x,y> = M.chart()
2702
+ sage: f = M.scalar_field({X: x+y}, name='f')
2703
+ sage: g = M.scalar_field({X: x*y}, name='g')
2704
+ sage: s = f._sub_(g); s
2705
+ Scalar field f-g on the 2-dimensional topological manifold M
2706
+ sage: s.display()
2707
+ f-g: M → ℝ
2708
+ (x, y) ↦ -(x - 1)*y + x
2709
+ sage: s == f-g
2710
+ True
2711
+ sage: f._sub_(M.zero_scalar_field()) == f
2712
+ True
2713
+ """
2714
+ # Trivial cases:
2715
+ if self.is_trivial_zero():
2716
+ return -other
2717
+ if other.is_trivial_zero():
2718
+ return self
2719
+ if self is other:
2720
+ return self.parent().zero()
2721
+ # Generic case:
2722
+ com_charts = self.common_charts(other)
2723
+ if com_charts is None:
2724
+ raise ValueError("no common chart for the subtraction")
2725
+ result = type(self)(self.parent())
2726
+ for chart in com_charts:
2727
+ # ChartFunction subtraction:
2728
+ result._express[chart] = self._express[chart] - other._express[chart]
2729
+ if self._name is not None and other._name is not None:
2730
+ result._name = self._name + '-' + other._name
2731
+ if self._latex_name is not None and other._latex_name is not None:
2732
+ result._latex_name = self._latex_name + '-' + other._latex_name
2733
+ return result
2734
+
2735
+ def _mul_(self, other):
2736
+ r"""
2737
+ Scalar field multiplication.
2738
+
2739
+ INPUT:
2740
+
2741
+ - ``other`` -- a scalar field (in the same algebra as ``self``)
2742
+
2743
+ OUTPUT:
2744
+
2745
+ - the scalar field resulting from the multiplication of ``self`` by
2746
+ ``other``
2747
+
2748
+ TESTS::
2749
+
2750
+ sage: M = Manifold(2, 'M', structure='topological')
2751
+ sage: X.<x,y> = M.chart()
2752
+ sage: f = M.scalar_field({X: x+y}, name='f')
2753
+ sage: g = M.scalar_field({X: x*y}, name='g')
2754
+ sage: s = f._mul_(g); s
2755
+ Scalar field f*g on the 2-dimensional topological manifold M
2756
+ sage: s.display()
2757
+ f*g: M → ℝ
2758
+ (x, y) ↦ x^2*y + x*y^2
2759
+ sage: s == f*g
2760
+ True
2761
+ sage: f._mul_(M.zero_scalar_field()) == M.zero_scalar_field()
2762
+ True
2763
+ sage: f._mul_(M.one_scalar_field()) == f
2764
+ True
2765
+ """
2766
+ # Trivial cases:
2767
+ if self.is_trivial_zero() or other.is_trivial_zero():
2768
+ return self._domain.zero_scalar_field()
2769
+ if self.is_trivial_one():
2770
+ return other
2771
+ if other.is_trivial_one():
2772
+ return self
2773
+ # Generic case:
2774
+ from sage.tensor.modules.format_utilities import (
2775
+ format_mul_latex,
2776
+ format_mul_txt,
2777
+ )
2778
+ com_charts = self.common_charts(other)
2779
+ if com_charts is None:
2780
+ raise ValueError("no common chart for the multiplication")
2781
+ result = type(self)(self.parent())
2782
+ for chart in com_charts:
2783
+ # ChartFunction multiplication:
2784
+ result._express[chart] = self._express[chart] * other._express[chart]
2785
+ result._name = format_mul_txt(self._name, '*', other._name)
2786
+ result._latex_name = format_mul_latex(self._latex_name, r' \cdot ',
2787
+ other._latex_name)
2788
+ return result
2789
+
2790
+ def _div_(self, other):
2791
+ r"""
2792
+ Scalar field division.
2793
+
2794
+ INPUT:
2795
+
2796
+ - ``other`` -- a scalar field (in the same algebra as self)
2797
+
2798
+ OUTPUT:
2799
+
2800
+ - the scalar field resulting from the division of ``self`` by
2801
+ ``other``
2802
+
2803
+ TESTS::
2804
+
2805
+ sage: M = Manifold(2, 'M', structure='topological')
2806
+ sage: X.<x,y> = M.chart()
2807
+ sage: f = M.scalar_field({X: x+y}, name='f')
2808
+ sage: g = M.scalar_field({X: x*y}, name='g')
2809
+ sage: s = f._div_(g); s
2810
+ Scalar field f/g on the 2-dimensional topological manifold M
2811
+ sage: s.display()
2812
+ f/g: M → ℝ
2813
+ (x, y) ↦ (x + y)/(x*y)
2814
+ sage: s == f/g
2815
+ True
2816
+ sage: f._div_(M.zero_scalar_field())
2817
+ Traceback (most recent call last):
2818
+ ...
2819
+ ZeroDivisionError: division of a scalar field by zero
2820
+ """
2821
+ from sage.tensor.modules.format_utilities import (
2822
+ format_mul_latex,
2823
+ format_mul_txt,
2824
+ )
2825
+ # Trivial cases:
2826
+ if other.is_trivial_zero():
2827
+ raise ZeroDivisionError("division of a scalar field by zero")
2828
+ if self.is_trivial_zero():
2829
+ return self._domain.zero_scalar_field()
2830
+ # Generic case:
2831
+ com_charts = self.common_charts(other)
2832
+ if com_charts is None:
2833
+ raise ValueError("no common chart for the division")
2834
+ result = type(self)(self.parent())
2835
+ for chart in com_charts:
2836
+ # ChartFunction division:
2837
+ result._express[chart] = self._express[chart] / other._express[chart]
2838
+ result._name = format_mul_txt(self._name, '/', other._name)
2839
+ result._latex_name = format_mul_latex(self._latex_name, '/',
2840
+ other._latex_name)
2841
+ return result
2842
+
2843
+ def _lmul_(self, number):
2844
+ r"""
2845
+ Scalar multiplication operator: return ``number * self`` or
2846
+ ``self * number``.
2847
+
2848
+ This differs from ``_mul_(self, other)`` by the fact that ``number``
2849
+ is not assumed to be a scalar field defined on the same domain as
2850
+ ``self``, contrary to ``other`` in ``_mul_(self, other)``. In
2851
+ practice, ``number`` is an element of the field on which the
2852
+ scalar field algebra is defined.
2853
+
2854
+ INPUT:
2855
+
2856
+ - ``number`` -- an element of the ring on which the scalar field
2857
+ algebra is defined; this should be an element of the topological
2858
+ field on which the manifold is constructed (possibly represented
2859
+ by a symbolic expression)
2860
+
2861
+ OUTPUT: the scalar field ``number * self``
2862
+
2863
+ TESTS::
2864
+
2865
+ sage: M = Manifold(2, 'M', structure='topological')
2866
+ sage: X.<x,y> = M.chart()
2867
+ sage: f = M.scalar_field({X: x+y}, name='f')
2868
+ sage: s = f._lmul_(2); s
2869
+ Scalar field on the 2-dimensional topological manifold M
2870
+ sage: s.display()
2871
+ M → ℝ
2872
+ (x, y) ↦ 2*x + 2*y
2873
+ sage: s == 2 * f
2874
+ True
2875
+ sage: s == f * 2
2876
+ True
2877
+ sage: f._lmul_(pi).display()
2878
+ M → ℝ
2879
+ (x, y) ↦ pi*(x + y)
2880
+ sage: f._lmul_(pi) == pi*f
2881
+ True
2882
+ sage: f._lmul_(0) == M.zero_scalar_field()
2883
+ True
2884
+ sage: f._lmul_(1) == f
2885
+ True
2886
+ """
2887
+ # Trivial cases:
2888
+ try:
2889
+ if number.is_trivial_zero():
2890
+ return self.parent().zero()
2891
+ if (number - 1).is_trivial_zero():
2892
+ return self
2893
+ except AttributeError:
2894
+ # in case base ring is not SR:
2895
+ if number == 0:
2896
+ return self.parent().zero()
2897
+ if number == 1:
2898
+ return self
2899
+ # Generic case:
2900
+ result = type(self)(self.parent())
2901
+ if isinstance(number, Expression):
2902
+ var = number.variables() # possible symbolic variables in number
2903
+ if var:
2904
+ # There are symbolic variables in number
2905
+ # Are any of them a chart coordinate ?
2906
+ chart_var = False
2907
+ for chart in self._express:
2908
+ if any(s in chart[:] for s in var):
2909
+ chart_var = True
2910
+ break
2911
+ if chart_var:
2912
+ # Some symbolic variables in number are chart coordinates
2913
+ for chart, expr in self._express.items():
2914
+ # The multiplication is performed only if
2915
+ # either
2916
+ # (i) all the symbolic variables in number are
2917
+ # coordinates of this chart
2918
+ # or (ii) no symbolic variable in number belongs to a
2919
+ # different chart
2920
+ chart_coords = chart[:]
2921
+ var_not_in_chart = [s for s in var
2922
+ if s not in chart_coords]
2923
+ any_in_other_chart = False
2924
+ if var_not_in_chart:
2925
+ for other_chart in self._domain.atlas():
2926
+ other_chart_coords = other_chart[:]
2927
+ for s in var_not_in_chart:
2928
+ if s in other_chart_coords:
2929
+ any_in_other_chart = True
2930
+ break
2931
+ if any_in_other_chart:
2932
+ break
2933
+ if not any_in_other_chart:
2934
+ result._express[chart] = number * expr
2935
+ return result
2936
+ # General case: the multiplication is performed on all charts:
2937
+ for chart, expr in self._express.items():
2938
+ result._express[chart] = number * expr
2939
+ return result
2940
+
2941
+ # ### End of CommutativeAlgebraElement arithmetic operators ###
2942
+
2943
+ def _function_name(self, func, func_latex, parentheses=True):
2944
+ r"""
2945
+ Helper function to set the symbol of a function applied to the
2946
+ scalar field.
2947
+
2948
+ TESTS::
2949
+
2950
+ sage: M = Manifold(2, 'M', structure='topological')
2951
+ sage: X.<x,y> = M.chart()
2952
+ sage: f = M.scalar_field({X: x+y}, name='f', latex_name=r"\Phi")
2953
+ sage: f._function_name("cos", r"\cos")
2954
+ ('cos(f)', '\\cos\\left(\\Phi\\right)')
2955
+ sage: f._function_name("sqrt", r"\sqrt", parentheses=False)
2956
+ ('sqrt(f)', '\\sqrt{\\Phi}')
2957
+ sage: f = M.scalar_field({X: x+y}) # no name given to f
2958
+ sage: f._function_name("cos", r"\cos")
2959
+ (None, None)
2960
+ """
2961
+ if self._name is None:
2962
+ name = None
2963
+ else:
2964
+ name = func + "(" + self._name + ")"
2965
+ if self._latex_name is None:
2966
+ latex_name = None
2967
+ elif parentheses:
2968
+ latex_name = func_latex + r"\left(" + self._latex_name + r"\right)"
2969
+ else:
2970
+ latex_name = func_latex + r"{" + self._latex_name + r"}"
2971
+ return name, latex_name
2972
+
2973
+ def exp(self):
2974
+ r"""
2975
+ Exponential of the scalar field.
2976
+
2977
+ OUTPUT: the scalar field `\exp f`, where `f` is the current scalar field
2978
+
2979
+ EXAMPLES::
2980
+
2981
+ sage: M = Manifold(2, 'M', structure='topological')
2982
+ sage: X.<x,y> = M.chart()
2983
+ sage: f = M.scalar_field({X: x+y}, name='f', latex_name=r"\Phi")
2984
+ sage: g = exp(f) ; g
2985
+ Scalar field exp(f) on the 2-dimensional topological manifold M
2986
+ sage: g.display()
2987
+ exp(f): M → ℝ
2988
+ (x, y) ↦ e^(x + y)
2989
+ sage: latex(g)
2990
+ \exp\left(\Phi\right)
2991
+
2992
+ Automatic simplifications occur::
2993
+
2994
+ sage: f = M.scalar_field({X: 2*ln(1+x^2)}, name='f')
2995
+ sage: exp(f).display()
2996
+ exp(f): M → ℝ
2997
+ (x, y) ↦ x^4 + 2*x^2 + 1
2998
+
2999
+ The inverse function is :meth:`log`::
3000
+
3001
+ sage: log(exp(f)) == f
3002
+ True
3003
+
3004
+ Some tests::
3005
+
3006
+ sage: exp(M.zero_scalar_field()) == M.constant_scalar_field(1)
3007
+ True
3008
+ sage: exp(M.constant_scalar_field(1)) == M.constant_scalar_field(e)
3009
+ True
3010
+ """
3011
+ name, latex_name = self._function_name("exp", r"\exp")
3012
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3013
+ for chart, func in self._express.items():
3014
+ resu._express[chart] = func.exp()
3015
+ return resu
3016
+
3017
+ def log(self):
3018
+ r"""
3019
+ Natural logarithm of the scalar field.
3020
+
3021
+ OUTPUT: the scalar field `\ln f`, where `f` is the current scalar field
3022
+
3023
+ EXAMPLES::
3024
+
3025
+ sage: M = Manifold(2, 'M', structure='topological')
3026
+ sage: X.<x,y> = M.chart()
3027
+ sage: f = M.scalar_field({X: x+y}, name='f', latex_name=r"\Phi")
3028
+ sage: g = log(f) ; g
3029
+ Scalar field ln(f) on the 2-dimensional topological manifold M
3030
+ sage: g.display()
3031
+ ln(f): M → ℝ
3032
+ (x, y) ↦ log(x + y)
3033
+ sage: latex(g)
3034
+ \ln\left(\Phi\right)
3035
+
3036
+ The inverse function is :meth:`exp`::
3037
+
3038
+ sage: exp(log(f)) == f
3039
+ True
3040
+ """
3041
+ name, latex_name = self._function_name("ln", r"\ln")
3042
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3043
+ for chart, func in self._express.items():
3044
+ resu._express[chart] = func.log()
3045
+ return resu
3046
+
3047
+ def __pow__(self, exponent):
3048
+ r"""
3049
+ The scalar field to a given power.
3050
+
3051
+ INPUT:
3052
+
3053
+ - ``exponent`` -- the exponent
3054
+
3055
+ OUTPUT:
3056
+
3057
+ - the scalar field `f^a`, where `f` is the current scalar field and
3058
+ `a` the exponent
3059
+
3060
+ EXAMPLES::
3061
+
3062
+ sage: M = Manifold(2, 'M', structure='topological')
3063
+ sage: X.<x,y> = M.chart()
3064
+ sage: f = M.scalar_field({X: x+y}, name='f', latex_name=r'\Phi')
3065
+ sage: g = f.__pow__(pi) ; g
3066
+ Scalar field f^pi on the 2-dimensional topological manifold M
3067
+ sage: latex(g)
3068
+ {\Phi}^{ \pi }
3069
+ sage: g.display()
3070
+ f^pi: M → ℝ
3071
+ (x, y) ↦ (x + y)^pi
3072
+
3073
+ The global function ``pow`` can be used::
3074
+
3075
+ sage: pow(f, pi) == f.__pow__(pi)
3076
+ True
3077
+
3078
+ as well as the exponent notation::
3079
+
3080
+ sage: f^pi == f.__pow__(pi)
3081
+ True
3082
+
3083
+ Some checks::
3084
+
3085
+ sage: pow(f, 2) == f*f
3086
+ True
3087
+ sage: pow(pow(f, 1/2), 2) == f
3088
+ True
3089
+ """
3090
+ from sage.misc.latex import latex
3091
+ if self._name is None:
3092
+ name = None
3093
+ else:
3094
+ name = self._name + "^{}".format(exponent)
3095
+ if self._latex_name is None:
3096
+ latex_name = None
3097
+ else:
3098
+ latex_name = r"{" + self._latex_name + r"}^{" + \
3099
+ latex(exponent) + r"}"
3100
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3101
+ for chart, func in self._express.items():
3102
+ resu._express[chart] = func.__pow__(exponent)
3103
+ return resu
3104
+
3105
+ def sqrt(self):
3106
+ r"""
3107
+ Square root of the scalar field.
3108
+
3109
+ OUTPUT: the scalar field `\sqrt f`, where `f` is the current scalar field
3110
+
3111
+ EXAMPLES::
3112
+
3113
+ sage: M = Manifold(2, 'M', structure='topological')
3114
+ sage: X.<x,y> = M.chart()
3115
+ sage: f = M.scalar_field({X: 1+x^2+y^2}, name='f',
3116
+ ....: latex_name=r"\Phi")
3117
+ sage: g = sqrt(f) ; g
3118
+ Scalar field sqrt(f) on the 2-dimensional topological manifold M
3119
+ sage: latex(g)
3120
+ \sqrt{\Phi}
3121
+ sage: g.display()
3122
+ sqrt(f): M → ℝ
3123
+ (x, y) ↦ sqrt(x^2 + y^2 + 1)
3124
+
3125
+ Some tests::
3126
+
3127
+ sage: g^2 == f
3128
+ True
3129
+ sage: sqrt(M.zero_scalar_field()) == M.zero_scalar_field()
3130
+ True
3131
+ """
3132
+ name, latex_name = self._function_name("sqrt", r"\sqrt",
3133
+ parentheses=False)
3134
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3135
+ for chart, func in self._express.items():
3136
+ resu._express[chart] = func.sqrt()
3137
+ return resu
3138
+
3139
+ def cos(self):
3140
+ r"""
3141
+ Cosine of the scalar field.
3142
+
3143
+ OUTPUT: the scalar field `\cos f`, where `f` is the current scalar field
3144
+
3145
+ EXAMPLES::
3146
+
3147
+ sage: M = Manifold(2, 'M', structure='topological')
3148
+ sage: X.<x,y> = M.chart()
3149
+ sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
3150
+ sage: g = cos(f) ; g
3151
+ Scalar field cos(f) on the 2-dimensional topological manifold M
3152
+ sage: latex(g)
3153
+ \cos\left(\Phi\right)
3154
+ sage: g.display()
3155
+ cos(f): M → ℝ
3156
+ (x, y) ↦ cos(x*y)
3157
+
3158
+ Some tests::
3159
+
3160
+ sage: cos(M.zero_scalar_field()) == M.constant_scalar_field(1)
3161
+ True
3162
+ sage: cos(M.constant_scalar_field(pi/2)) == M.zero_scalar_field()
3163
+ True
3164
+ """
3165
+ name, latex_name = self._function_name("cos", r"\cos")
3166
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3167
+ for chart, func in self._express.items():
3168
+ resu._express[chart] = func.cos()
3169
+ return resu
3170
+
3171
+ def sin(self):
3172
+ r"""
3173
+ Sine of the scalar field.
3174
+
3175
+ OUTPUT: the scalar field `\sin f`, where `f` is the current scalar field
3176
+
3177
+ EXAMPLES::
3178
+
3179
+ sage: M = Manifold(2, 'M', structure='topological')
3180
+ sage: X.<x,y> = M.chart()
3181
+ sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
3182
+ sage: g = sin(f) ; g
3183
+ Scalar field sin(f) on the 2-dimensional topological manifold M
3184
+ sage: latex(g)
3185
+ \sin\left(\Phi\right)
3186
+ sage: g.display()
3187
+ sin(f): M → ℝ
3188
+ (x, y) ↦ sin(x*y)
3189
+
3190
+ Some tests::
3191
+
3192
+ sage: sin(M.zero_scalar_field()) == M.zero_scalar_field()
3193
+ True
3194
+ sage: sin(M.constant_scalar_field(pi/2)) == M.constant_scalar_field(1)
3195
+ True
3196
+ """
3197
+ name, latex_name = self._function_name("sin", r"\sin")
3198
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3199
+ for chart, func in self._express.items():
3200
+ resu._express[chart] = func.sin()
3201
+ return resu
3202
+
3203
+ def tan(self):
3204
+ r"""
3205
+ Tangent of the scalar field.
3206
+
3207
+ OUTPUT: the scalar field `\tan f`, where `f` is the current scalar field
3208
+
3209
+ EXAMPLES::
3210
+
3211
+ sage: M = Manifold(2, 'M', structure='topological')
3212
+ sage: X.<x,y> = M.chart()
3213
+ sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
3214
+ sage: g = tan(f) ; g
3215
+ Scalar field tan(f) on the 2-dimensional topological manifold M
3216
+ sage: latex(g)
3217
+ \tan\left(\Phi\right)
3218
+ sage: g.display()
3219
+ tan(f): M → ℝ
3220
+ (x, y) ↦ sin(x*y)/cos(x*y)
3221
+
3222
+ Some tests::
3223
+
3224
+ sage: tan(f) == sin(f) / cos(f)
3225
+ True
3226
+ sage: tan(M.zero_scalar_field()) == M.zero_scalar_field()
3227
+ True
3228
+ sage: tan(M.constant_scalar_field(pi/4)) == M.constant_scalar_field(1)
3229
+ True
3230
+ """
3231
+ name, latex_name = self._function_name("tan", r"\tan")
3232
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3233
+ for chart, func in self._express.items():
3234
+ resu._express[chart] = func.tan()
3235
+ return resu
3236
+
3237
+ def arccos(self):
3238
+ r"""
3239
+ Arc cosine of the scalar field.
3240
+
3241
+ OUTPUT: the scalar field `\arccos f`, where `f` is the current scalar field
3242
+
3243
+ EXAMPLES::
3244
+
3245
+ sage: M = Manifold(2, 'M', structure='topological')
3246
+ sage: X.<x,y> = M.chart()
3247
+ sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
3248
+ sage: g = arccos(f) ; g
3249
+ Scalar field arccos(f) on the 2-dimensional topological manifold M
3250
+ sage: latex(g)
3251
+ \arccos\left(\Phi\right)
3252
+ sage: g.display()
3253
+ arccos(f): M → ℝ
3254
+ (x, y) ↦ arccos(x*y)
3255
+
3256
+ The notation ``acos`` can be used as well::
3257
+
3258
+ sage: acos(f)
3259
+ Scalar field arccos(f) on the 2-dimensional topological manifold M
3260
+ sage: acos(f) == g
3261
+ True
3262
+
3263
+ Some tests::
3264
+
3265
+ sage: cos(g) == f
3266
+ True
3267
+ sage: arccos(M.constant_scalar_field(1)) == M.zero_scalar_field()
3268
+ True
3269
+ sage: arccos(M.zero_scalar_field()) == M.constant_scalar_field(pi/2)
3270
+ True
3271
+ """
3272
+ name, latex_name = self._function_name("arccos", r"\arccos")
3273
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3274
+ for chart, func in self._express.items():
3275
+ resu._express[chart] = func.arccos()
3276
+ return resu
3277
+
3278
+ def arcsin(self):
3279
+ r"""
3280
+ Arc sine of the scalar field.
3281
+
3282
+ OUTPUT: the scalar field `\arcsin f`, where `f` is the current scalar field
3283
+
3284
+ EXAMPLES::
3285
+
3286
+ sage: M = Manifold(2, 'M', structure='topological')
3287
+ sage: X.<x,y> = M.chart()
3288
+ sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
3289
+ sage: g = arcsin(f) ; g
3290
+ Scalar field arcsin(f) on the 2-dimensional topological manifold M
3291
+ sage: latex(g)
3292
+ \arcsin\left(\Phi\right)
3293
+ sage: g.display()
3294
+ arcsin(f): M → ℝ
3295
+ (x, y) ↦ arcsin(x*y)
3296
+
3297
+ The notation ``asin`` can be used as well::
3298
+
3299
+ sage: asin(f)
3300
+ Scalar field arcsin(f) on the 2-dimensional topological manifold M
3301
+ sage: asin(f) == g
3302
+ True
3303
+
3304
+ Some tests::
3305
+
3306
+ sage: sin(g) == f
3307
+ True
3308
+ sage: arcsin(M.zero_scalar_field()) == M.zero_scalar_field()
3309
+ True
3310
+ sage: arcsin(M.constant_scalar_field(1)) == M.constant_scalar_field(pi/2)
3311
+ True
3312
+ """
3313
+ name, latex_name = self._function_name("arcsin", r"\arcsin")
3314
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3315
+ for chart, func in self._express.items():
3316
+ resu._express[chart] = func.arcsin()
3317
+ return resu
3318
+
3319
+ def arctan(self):
3320
+ r"""
3321
+ Arc tangent of the scalar field.
3322
+
3323
+ OUTPUT: the scalar field `\arctan f`, where `f` is the current scalar field
3324
+
3325
+ EXAMPLES::
3326
+
3327
+ sage: M = Manifold(2, 'M', structure='topological')
3328
+ sage: X.<x,y> = M.chart()
3329
+ sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
3330
+ sage: g = arctan(f) ; g
3331
+ Scalar field arctan(f) on the 2-dimensional topological manifold M
3332
+ sage: latex(g)
3333
+ \arctan\left(\Phi\right)
3334
+ sage: g.display()
3335
+ arctan(f): M → ℝ
3336
+ (x, y) ↦ arctan(x*y)
3337
+
3338
+ The notation ``atan`` can be used as well::
3339
+
3340
+ sage: atan(f)
3341
+ Scalar field arctan(f) on the 2-dimensional topological manifold M
3342
+ sage: atan(f) == g
3343
+ True
3344
+
3345
+ Some tests::
3346
+
3347
+ sage: tan(g) == f
3348
+ True
3349
+ sage: arctan(M.zero_scalar_field()) == M.zero_scalar_field()
3350
+ True
3351
+ sage: arctan(M.constant_scalar_field(1)) == M.constant_scalar_field(pi/4)
3352
+ True
3353
+ """
3354
+ name, latex_name = self._function_name("arctan", r"\arctan")
3355
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3356
+ for chart, func in self._express.items():
3357
+ resu._express[chart] = func.arctan()
3358
+ return resu
3359
+
3360
+ def cosh(self):
3361
+ r"""
3362
+ Hyperbolic cosine of the scalar field.
3363
+
3364
+ OUTPUT: the scalar field `\cosh f`, where `f` is the current scalar field
3365
+
3366
+ EXAMPLES::
3367
+
3368
+ sage: M = Manifold(2, 'M', structure='topological')
3369
+ sage: X.<x,y> = M.chart()
3370
+ sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
3371
+ sage: g = cosh(f) ; g
3372
+ Scalar field cosh(f) on the 2-dimensional topological manifold M
3373
+ sage: latex(g)
3374
+ \cosh\left(\Phi\right)
3375
+ sage: g.display()
3376
+ cosh(f): M → ℝ
3377
+ (x, y) ↦ cosh(x*y)
3378
+
3379
+ Some test::
3380
+
3381
+ sage: cosh(M.zero_scalar_field()) == M.constant_scalar_field(1)
3382
+ True
3383
+ """
3384
+ name, latex_name = self._function_name("cosh", r"\cosh")
3385
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3386
+ for chart, func in self._express.items():
3387
+ resu._express[chart] = func.cosh()
3388
+ return resu
3389
+
3390
+ def sinh(self):
3391
+ r"""
3392
+ Hyperbolic sine of the scalar field.
3393
+
3394
+ OUTPUT: the scalar field `\sinh f`, where `f` is the current scalar field
3395
+
3396
+ EXAMPLES::
3397
+
3398
+ sage: M = Manifold(2, 'M', structure='topological')
3399
+ sage: X.<x,y> = M.chart()
3400
+ sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
3401
+ sage: g = sinh(f) ; g
3402
+ Scalar field sinh(f) on the 2-dimensional topological manifold M
3403
+ sage: latex(g)
3404
+ \sinh\left(\Phi\right)
3405
+ sage: g.display()
3406
+ sinh(f): M → ℝ
3407
+ (x, y) ↦ sinh(x*y)
3408
+
3409
+ Some test::
3410
+
3411
+ sage: sinh(M.zero_scalar_field()) == M.zero_scalar_field()
3412
+ True
3413
+ """
3414
+ name, latex_name = self._function_name("sinh", r"\sinh")
3415
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3416
+ for chart, func in self._express.items():
3417
+ resu._express[chart] = func.sinh()
3418
+ return resu
3419
+
3420
+ def tanh(self):
3421
+ r"""
3422
+ Hyperbolic tangent of the scalar field.
3423
+
3424
+ OUTPUT: the scalar field `\tanh f`, where `f` is the current scalar field
3425
+
3426
+ EXAMPLES::
3427
+
3428
+ sage: M = Manifold(2, 'M', structure='topological')
3429
+ sage: X.<x,y> = M.chart()
3430
+ sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
3431
+ sage: g = tanh(f) ; g
3432
+ Scalar field tanh(f) on the 2-dimensional topological manifold M
3433
+ sage: latex(g)
3434
+ \tanh\left(\Phi\right)
3435
+ sage: g.display()
3436
+ tanh(f): M → ℝ
3437
+ (x, y) ↦ sinh(x*y)/cosh(x*y)
3438
+
3439
+ Some tests::
3440
+
3441
+ sage: tanh(f) == sinh(f) / cosh(f)
3442
+ True
3443
+ sage: tanh(M.zero_scalar_field()) == M.zero_scalar_field()
3444
+ True
3445
+ """
3446
+ name, latex_name = self._function_name("tanh", r"\tanh")
3447
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3448
+ for chart, func in self._express.items():
3449
+ resu._express[chart] = func.tanh()
3450
+ return resu
3451
+
3452
+ def arccosh(self):
3453
+ r"""
3454
+ Inverse hyperbolic cosine of the scalar field.
3455
+
3456
+ OUTPUT:
3457
+
3458
+ - the scalar field `\mathrm{arccosh}\, f`, where `f` is the current
3459
+ scalar field
3460
+
3461
+ EXAMPLES::
3462
+
3463
+ sage: M = Manifold(2, 'M', structure='topological')
3464
+ sage: X.<x,y> = M.chart()
3465
+ sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
3466
+ sage: g = arccosh(f) ; g
3467
+ Scalar field arccosh(f) on the 2-dimensional topological manifold M
3468
+ sage: latex(g)
3469
+ \,\mathrm{arccosh}\left(\Phi\right)
3470
+ sage: g.display()
3471
+ arccosh(f): M → ℝ
3472
+ (x, y) ↦ arccosh(x*y)
3473
+
3474
+ The notation ``acosh`` can be used as well::
3475
+
3476
+ sage: acosh(f)
3477
+ Scalar field arccosh(f) on the 2-dimensional topological manifold M
3478
+ sage: acosh(f) == g
3479
+ True
3480
+
3481
+ Some tests::
3482
+
3483
+ sage: cosh(g) == f
3484
+ True
3485
+ sage: arccosh(M.constant_scalar_field(1)) == M.zero_scalar_field()
3486
+ True
3487
+ """
3488
+ name, latex_name = self._function_name("arccosh", r"\,\mathrm{arccosh}")
3489
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3490
+ for chart, func in self._express.items():
3491
+ resu._express[chart] = func.arccosh()
3492
+ return resu
3493
+
3494
+ def arcsinh(self):
3495
+ r"""
3496
+ Inverse hyperbolic sine of the scalar field.
3497
+
3498
+ OUTPUT:
3499
+
3500
+ - the scalar field `\mathrm{arcsinh}\, f`, where `f` is the current
3501
+ scalar field
3502
+
3503
+ EXAMPLES::
3504
+
3505
+ sage: M = Manifold(2, 'M', structure='topological')
3506
+ sage: X.<x,y> = M.chart()
3507
+ sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
3508
+ sage: g = arcsinh(f) ; g
3509
+ Scalar field arcsinh(f) on the 2-dimensional topological manifold M
3510
+ sage: latex(g)
3511
+ \,\mathrm{arcsinh}\left(\Phi\right)
3512
+ sage: g.display()
3513
+ arcsinh(f): M → ℝ
3514
+ (x, y) ↦ arcsinh(x*y)
3515
+
3516
+ The notation ``asinh`` can be used as well::
3517
+
3518
+ sage: asinh(f)
3519
+ Scalar field arcsinh(f) on the 2-dimensional topological manifold M
3520
+ sage: asinh(f) == g
3521
+ True
3522
+
3523
+ Some tests::
3524
+
3525
+ sage: sinh(g) == f
3526
+ True
3527
+ sage: arcsinh(M.zero_scalar_field()) == M.zero_scalar_field()
3528
+ True
3529
+ """
3530
+ name, latex_name = self._function_name("arcsinh", r"\,\mathrm{arcsinh}")
3531
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3532
+ for chart, func in self._express.items():
3533
+ resu._express[chart] = func.arcsinh()
3534
+ return resu
3535
+
3536
+ def arctanh(self):
3537
+ r"""
3538
+ Inverse hyperbolic tangent of the scalar field.
3539
+
3540
+ OUTPUT:
3541
+
3542
+ - the scalar field `\mathrm{arctanh}\, f`, where `f` is the current
3543
+ scalar field
3544
+
3545
+ EXAMPLES::
3546
+
3547
+ sage: M = Manifold(2, 'M', structure='topological')
3548
+ sage: X.<x,y> = M.chart()
3549
+ sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
3550
+ sage: g = arctanh(f) ; g
3551
+ Scalar field arctanh(f) on the 2-dimensional topological manifold M
3552
+ sage: latex(g)
3553
+ \,\mathrm{arctanh}\left(\Phi\right)
3554
+ sage: g.display()
3555
+ arctanh(f): M → ℝ
3556
+ (x, y) ↦ arctanh(x*y)
3557
+
3558
+ The notation ``atanh`` can be used as well::
3559
+
3560
+ sage: atanh(f)
3561
+ Scalar field arctanh(f) on the 2-dimensional topological manifold M
3562
+ sage: atanh(f) == g
3563
+ True
3564
+
3565
+ Some tests::
3566
+
3567
+ sage: tanh(g) == f
3568
+ True
3569
+ sage: arctanh(M.zero_scalar_field()) == M.zero_scalar_field()
3570
+ True
3571
+ sage: arctanh(M.constant_scalar_field(1/2)) == M.constant_scalar_field(log(3)/2)
3572
+ True
3573
+ """
3574
+ name, latex_name = self._function_name("arctanh", r"\,\mathrm{arctanh}")
3575
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3576
+ for chart, func in self._express.items():
3577
+ resu._express[chart] = func.arctanh()
3578
+ return resu
3579
+
3580
+ def __abs__(self):
3581
+ r"""
3582
+ Absolute value of the scalar field.
3583
+
3584
+ OUTPUT:
3585
+
3586
+ - the scalar field `\mathrm{Abs}\, f`, where `f` is the current
3587
+ scalar field
3588
+
3589
+ EXAMPLES::
3590
+
3591
+ sage: M = Manifold(2, 'M', structure='topological')
3592
+ sage: X.<x,y> = M.chart()
3593
+ sage: f = M.scalar_field({X: x*y}, name='f', latex_name=r"\Phi")
3594
+ sage: g = abs(f) ; g
3595
+ Scalar field abs(f) on the 2-dimensional topological manifold M
3596
+ sage: latex(g)
3597
+ \,\mathrm{abs}\left(\Phi\right)
3598
+ sage: g.display()
3599
+ abs(f): M → ℝ
3600
+ (x, y) ↦ abs(x)*abs(y)
3601
+ """
3602
+ name, latex_name = self._function_name("abs", r"\,\mathrm{abs}")
3603
+ resu = type(self)(self.parent(), name=name, latex_name=latex_name)
3604
+ for chart, func in self._express.items():
3605
+ resu._express[chart] = func.abs()
3606
+ return resu
3607
+
3608
+ def set_calc_order(self, symbol, order, truncate=False):
3609
+ r"""
3610
+ Trigger a power series expansion with respect to a small parameter in
3611
+ computations involving the scalar field.
3612
+
3613
+ This property is propagated by usual operations. The internal
3614
+ representation must be ``SR`` for this to take effect.
3615
+
3616
+ If the small parameter is `\epsilon` and `f` is ``self``, the
3617
+ power series expansion to order `n` is
3618
+
3619
+ .. MATH::
3620
+
3621
+ f = f_0 + \epsilon f_1 + \epsilon^2 f_2 + \cdots + \epsilon^n f_n
3622
+ + O(\epsilon^{n+1}),
3623
+
3624
+ where `f_0, f_1, \ldots, f_n` are `n+1` scalar fields that do not
3625
+ depend upon `\epsilon`.
3626
+
3627
+ INPUT:
3628
+
3629
+ - ``symbol`` -- symbolic variable (the "small parameter" `\epsilon`)
3630
+ with respect to which the coordinate expressions of ``self`` in
3631
+ various charts are expanded in power series (around the zero value of
3632
+ this variable)
3633
+ - ``order`` -- integer; the order `n` of the expansion, defined as the
3634
+ degree of the polynomial representing the truncated power series in
3635
+ ``symbol``
3636
+
3637
+ .. WARNING::
3638
+
3639
+ The order of the big `O` in the power series expansion is `n+1`,
3640
+ where `n` is ``order``.
3641
+
3642
+ - ``truncate`` -- boolean (default: ``False``); determines whether the
3643
+ coordinate expressions of ``self`` are replaced by their expansions
3644
+ to the given order
3645
+
3646
+ EXAMPLES::
3647
+
3648
+ sage: M = Manifold(2, 'M', structure='topological')
3649
+ sage: X.<x,y> = M.chart()
3650
+ sage: t = var('t') # the small parameter
3651
+ sage: f = M.scalar_field(exp(-t*x))
3652
+ sage: f.expr()
3653
+ e^(-t*x)
3654
+ sage: f.set_calc_order(t, 2, truncate=True)
3655
+ sage: f.expr()
3656
+ 1/2*t^2*x^2 - t*x + 1
3657
+ """
3658
+ for expr in self._express.values():
3659
+ expr._expansion_symbol = symbol
3660
+ expr._order = order
3661
+ if truncate:
3662
+ expr.simplify()
3663
+ self._del_derived()
3664
+
3665
+ def set_immutable(self):
3666
+ r"""
3667
+ Set ``self`` and all restrictions of ``self`` immutable.
3668
+
3669
+ EXAMPLES::
3670
+
3671
+ sage: M = Manifold(2, 'M')
3672
+ sage: X.<x,y> = M.chart()
3673
+ sage: U = M.open_subset('U', coord_def={X: x^2+y^2<1}) # disk
3674
+ sage: V = M.open_subset('U', coord_def={X: x>0}) # half plane
3675
+ sage: f = M.scalar_field(x^2, name='f')
3676
+ sage: fU = f.restrict(U)
3677
+ sage: f.set_immutable()
3678
+ sage: fU.is_immutable()
3679
+ True
3680
+ sage: f.restrict(V).is_immutable()
3681
+ True
3682
+ """
3683
+ for rst in self._restrictions.values():
3684
+ rst.set_immutable()
3685
+ for func in self._express.values():
3686
+ func.set_immutable()
3687
+ super().set_immutable()
3688
+
3689
+ @cached_method
3690
+ def __hash__(self):
3691
+ r"""
3692
+ Hash function.
3693
+
3694
+ TESTS::
3695
+
3696
+ sage: M = Manifold(2, 'M')
3697
+ sage: X.<x,y> = M.chart()
3698
+ sage: f = M.scalar_field(x^2, name='f')
3699
+ sage: f.set_immutable()
3700
+ sage: g = M.scalar_field(x^2, name='g')
3701
+ sage: g.set_immutable()
3702
+
3703
+ Check whether equality implies equality of hash::
3704
+
3705
+ sage: f == g
3706
+ True
3707
+ sage: hash(f) == hash(g)
3708
+ True
3709
+
3710
+ Let us check that ``f`` can be used as a dictionary key::
3711
+
3712
+ sage: {f: 1}[f]
3713
+ 1
3714
+ """
3715
+ if self.is_mutable():
3716
+ raise ValueError('element must be immutable in order to be '
3717
+ 'hashable')
3718
+ return hash((type(self).__name__, self._domain))