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,3090 @@
1
+ # sage_setup: distribution = sagemath-symbolics
2
+ r"""
3
+ Topological Manifolds
4
+
5
+ Given a topological field `K` (in most applications, `K = \RR` or
6
+ `K = \CC`) and a nonnegative integer `n`, a *topological manifold of
7
+ dimension* `n` *over K* is a topological space `M` such that
8
+
9
+ - `M` is a Hausdorff space,
10
+ - `M` is second countable,
11
+ - every point in `M` has a neighborhood homeomorphic to `K^n`.
12
+
13
+ Topological manifolds are implemented via the class
14
+ :class:`TopologicalManifold`. Open subsets of topological manifolds
15
+ are also implemented via :class:`TopologicalManifold`, since they are
16
+ topological manifolds by themselves.
17
+
18
+ In the current setting, topological manifolds are mostly described by
19
+ means of charts (see :class:`~sage.manifolds.chart.Chart`).
20
+
21
+ :class:`TopologicalManifold` serves as a base class for more specific
22
+ manifold classes.
23
+
24
+ The user interface is provided by the generic function
25
+ :func:`~sage.manifolds.manifold.Manifold`, with
26
+ with the argument ``structure`` set to ``'topological'``.
27
+
28
+ .. RUBRIC:: Example 1: the 2-sphere as a topological manifold of dimension
29
+ 2 over `\RR`
30
+
31
+ One starts by declaring `S^2` as a 2-dimensional topological manifold::
32
+
33
+ sage: M = Manifold(2, 'S^2', structure='topological')
34
+ sage: M
35
+ 2-dimensional topological manifold S^2
36
+
37
+ Since the base topological field has not been specified in the argument list
38
+ of ``Manifold``, `\RR` is assumed::
39
+
40
+ sage: M.base_field()
41
+ Real Field with 53 bits of precision
42
+ sage: dim(M)
43
+ 2
44
+
45
+ Let us consider the complement of a point, the "North pole" say; this is an
46
+ open subset of `S^2`, which we call `U`::
47
+
48
+ sage: U = M.open_subset('U'); U
49
+ Open subset U of the 2-dimensional topological manifold S^2
50
+
51
+ A standard chart on `U` is provided by the stereographic projection from the
52
+ North pole to the equatorial plane::
53
+
54
+ sage: stereoN.<x,y> = U.chart(); stereoN
55
+ Chart (U, (x, y))
56
+
57
+ Thanks to the operator ``<x,y>`` on the left-hand side, the coordinates
58
+ declared in a chart (here `x` and `y`), are accessible by their names;
59
+ they are Sage's symbolic variables::
60
+
61
+ sage: y
62
+ y
63
+ sage: type(y)
64
+ <class 'sage.symbolic.expression.Expression'>
65
+
66
+ The South pole is the point of coordinates `(x, y) = (0, 0)` in the above
67
+ chart::
68
+
69
+ sage: S = U.point((0,0), chart=stereoN, name='S'); S
70
+ Point S on the 2-dimensional topological manifold S^2
71
+
72
+ Let us call `V` the open subset that is the complement of the South pole and
73
+ let us introduce on it the chart induced by the stereographic projection from
74
+ the South pole to the equatorial plane::
75
+
76
+ sage: V = M.open_subset('V'); V
77
+ Open subset V of the 2-dimensional topological manifold S^2
78
+ sage: stereoS.<u,v> = V.chart(); stereoS
79
+ Chart (V, (u, v))
80
+
81
+ The North pole is the point of coordinates `(u, v) = (0, 0)` in this chart::
82
+
83
+ sage: N = V.point((0,0), chart=stereoS, name='N'); N
84
+ Point N on the 2-dimensional topological manifold S^2
85
+
86
+ To fully construct the manifold, we declare that it is the union of `U`
87
+ and `V`::
88
+
89
+ sage: M.declare_union(U,V)
90
+
91
+ and we provide the transition map between the charts ``stereoN`` =
92
+ `(U, (x, y))` and ``stereoS`` = `(V, (u, v))`, denoting by `W` the
93
+ intersection of `U` and `V` (`W` is the subset of `U` defined by
94
+ `x^2 + y^2 \neq 0`, as well as the subset of `V` defined by
95
+ `u^2 + v^2 \neq 0`)::
96
+
97
+ sage: stereoN_to_S = stereoN.transition_map(stereoS, [x/(x^2+y^2), y/(x^2+y^2)],
98
+ ....: intersection_name='W', restrictions1= x^2+y^2!=0,
99
+ ....: restrictions2= u^2+v^2!=0)
100
+ sage: stereoN_to_S
101
+ Change of coordinates from Chart (W, (x, y)) to Chart (W, (u, v))
102
+ sage: stereoN_to_S.display()
103
+ u = x/(x^2 + y^2)
104
+ v = y/(x^2 + y^2)
105
+
106
+ We give the name ``W`` to the Python variable representing `W = U \cap V`::
107
+
108
+ sage: W = U.intersection(V)
109
+
110
+ The inverse of the transition map is computed by the method
111
+ :meth:`sage.manifolds.chart.CoordChange.inverse`::
112
+
113
+ sage: stereoN_to_S.inverse()
114
+ Change of coordinates from Chart (W, (u, v)) to Chart (W, (x, y))
115
+ sage: stereoN_to_S.inverse().display()
116
+ x = u/(u^2 + v^2)
117
+ y = v/(u^2 + v^2)
118
+
119
+ At this stage, we have four open subsets on `S^2`::
120
+
121
+ sage: M.subset_family()
122
+ Set {S^2, U, V, W} of open subsets of the 2-dimensional topological manifold S^2
123
+
124
+ `W` is the open subset that is the complement of the two poles::
125
+
126
+ sage: N in W or S in W
127
+ False
128
+
129
+ The North pole lies in `V` and the South pole in `U`::
130
+
131
+ sage: N in V, N in U
132
+ (True, False)
133
+ sage: S in U, S in V
134
+ (True, False)
135
+
136
+ The manifold's (user) atlas contains four charts, two of them
137
+ being restrictions of charts to a smaller domain::
138
+
139
+ sage: M.atlas()
140
+ [Chart (U, (x, y)), Chart (V, (u, v)),
141
+ Chart (W, (x, y)), Chart (W, (u, v))]
142
+
143
+ Let us consider the point of coordinates `(1, 2)` in the chart ``stereoN``::
144
+
145
+ sage: p = M.point((1,2), chart=stereoN, name='p'); p
146
+ Point p on the 2-dimensional topological manifold S^2
147
+ sage: p.parent()
148
+ 2-dimensional topological manifold S^2
149
+ sage: p in W
150
+ True
151
+
152
+ The coordinates of `p` in the chart ``stereoS`` are computed by letting
153
+ the chart act on the point::
154
+
155
+ sage: stereoS(p)
156
+ (1/5, 2/5)
157
+
158
+ Given the definition of `p`, we have of course::
159
+
160
+ sage: stereoN(p)
161
+ (1, 2)
162
+
163
+ Similarly::
164
+
165
+ sage: stereoS(N)
166
+ (0, 0)
167
+ sage: stereoN(S)
168
+ (0, 0)
169
+
170
+ A continuous map `S^2 \to \RR` (scalar field)::
171
+
172
+ sage: f = M.scalar_field({stereoN: atan(x^2+y^2), stereoS: pi/2-atan(u^2+v^2)},
173
+ ....: name='f')
174
+ sage: f
175
+ Scalar field f on the 2-dimensional topological manifold S^2
176
+ sage: f.display()
177
+ f: S^2 → ℝ
178
+ on U: (x, y) ↦ arctan(x^2 + y^2)
179
+ on V: (u, v) ↦ 1/2*pi - arctan(u^2 + v^2)
180
+ sage: f(p)
181
+ arctan(5)
182
+ sage: f(N)
183
+ 1/2*pi
184
+ sage: f(S)
185
+ 0
186
+ sage: f.parent()
187
+ Algebra of scalar fields on the 2-dimensional topological manifold S^2
188
+ sage: f.parent().category()
189
+ Join of Category of commutative algebras over Symbolic Ring and Category of homsets of topological spaces
190
+
191
+
192
+ .. RUBRIC:: Example 2: the Riemann sphere as a topological manifold of
193
+ dimension 1 over `\CC`
194
+
195
+ We declare the Riemann sphere `\CC^*` as a 1-dimensional topological manifold
196
+ over `\CC`::
197
+
198
+ sage: M = Manifold(1, 'ℂ*', structure='topological', field='complex'); M
199
+ Complex 1-dimensional topological manifold ℂ*
200
+
201
+ We introduce a first open subset, which is actually
202
+ `\CC = \CC^*\setminus\{\infty\}` if we interpret `\CC^*` as the
203
+ Alexandroff one-point compactification of `\CC`::
204
+
205
+ sage: U = M.open_subset('U')
206
+
207
+ A natural chart on `U` is then nothing but the identity map of `\CC`, hence
208
+ we denote the associated coordinate by `z`::
209
+
210
+ sage: Z.<z> = U.chart()
211
+
212
+ The origin of the complex plane is the point of coordinate `z = 0`::
213
+
214
+ sage: O = U.point((0,), chart=Z, name='O'); O
215
+ Point O on the Complex 1-dimensional topological manifold ℂ*
216
+
217
+ Another open subset of `\CC^*` is `V = \CC^*\setminus\{O\}`::
218
+
219
+ sage: V = M.open_subset('V')
220
+
221
+ We define a chart on `V` such that the point at infinity is the point of
222
+ coordinate `0` in this chart::
223
+
224
+ sage: W.<w> = V.chart(); W
225
+ Chart (V, (w,))
226
+ sage: inf = M.point((0,), chart=W, name='inf', latex_name=r'\infty')
227
+ sage: inf
228
+ Point inf on the Complex 1-dimensional topological manifold ℂ*
229
+
230
+ To fully construct the Riemann sphere, we declare that it is the union
231
+ of `U` and `V`::
232
+
233
+ sage: M.declare_union(U,V)
234
+
235
+ and we provide the transition map between the two charts as `w = 1 / z`
236
+ on `A = U \cap V`::
237
+
238
+ sage: Z_to_W = Z.transition_map(W, 1/z, intersection_name='A',
239
+ ....: restrictions1= z!=0, restrictions2= w!=0)
240
+ sage: Z_to_W
241
+ Change of coordinates from Chart (A, (z,)) to Chart (A, (w,))
242
+ sage: Z_to_W.display()
243
+ w = 1/z
244
+ sage: Z_to_W.inverse()
245
+ Change of coordinates from Chart (A, (w,)) to Chart (A, (z,))
246
+ sage: Z_to_W.inverse().display()
247
+ z = 1/w
248
+
249
+ Let consider the complex number `i` as a point of the Riemann sphere::
250
+
251
+ sage: i = M((I,), chart=Z, name='i'); i
252
+ Point i on the Complex 1-dimensional topological manifold ℂ*
253
+
254
+ Its coordinates w.r.t. the charts ``Z`` and ``W`` are::
255
+
256
+ sage: Z(i)
257
+ (I,)
258
+ sage: W(i)
259
+ (-I,)
260
+
261
+ and we have::
262
+
263
+ sage: i in U
264
+ True
265
+ sage: i in V
266
+ True
267
+
268
+ The following subsets and charts have been defined::
269
+
270
+ sage: M.subset_family()
271
+ Set {A, U, V, ℂ*} of open subsets of the Complex 1-dimensional topological manifold ℂ*
272
+ sage: M.atlas()
273
+ [Chart (U, (z,)), Chart (V, (w,)), Chart (A, (z,)), Chart (A, (w,))]
274
+
275
+ A constant map `\CC^* \rightarrow \CC`::
276
+
277
+ sage: f = M.constant_scalar_field(3+2*I, name='f'); f
278
+ Scalar field f on the Complex 1-dimensional topological manifold ℂ*
279
+ sage: f.display()
280
+ f: ℂ* → ℂ
281
+ on U: z ↦ 2*I + 3
282
+ on V: w ↦ 2*I + 3
283
+ sage: f(O)
284
+ 2*I + 3
285
+ sage: f(i)
286
+ 2*I + 3
287
+ sage: f(inf)
288
+ 2*I + 3
289
+ sage: f.parent()
290
+ Algebra of scalar fields on the Complex 1-dimensional topological
291
+ manifold ℂ*
292
+ sage: f.parent().category()
293
+ Join of Category of commutative algebras over Symbolic Ring and Category of homsets of topological spaces
294
+
295
+ AUTHORS:
296
+
297
+ - Eric Gourgoulhon (2015): initial version
298
+ - Travis Scrimshaw (2015): structure described via
299
+ :class:`~sage.manifolds.structure.TopologicalStructure` or
300
+ :class:`~sage.manifolds.structure.RealTopologicalStructure`
301
+ - Michael Jung (2020): topological vector bundles and orientability
302
+
303
+
304
+ REFERENCES:
305
+
306
+ - [Lee2011]_
307
+ - [Lee2013]_
308
+ - [KN1963]_
309
+ - [Huy2005]_
310
+ """
311
+
312
+ # ****************************************************************************
313
+ # Copyright (C) 2015-2020 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
314
+ # Copyright (C) 2015 Travis Scrimshaw <tscrimsh@umn.edu>
315
+ # Copyright (C) 2016 Andrew Mathas
316
+ # Copyright (C) 2018 Florentin Jaffredo
317
+ # Copyright (C) 2019 Hans Fotsing Tetsing
318
+ # Copyright (C) 2019-2020 Michael Jung
319
+ # Copyright (C) 2021 Matthias Koeppe <mkoeppe@math.ucdavis.edu>
320
+ #
321
+ # This program is free software: you can redistribute it and/or modify
322
+ # it under the terms of the GNU General Public License as published by
323
+ # the Free Software Foundation, either version 2 of the License, or
324
+ # (at your option) any later version.
325
+ # https://www.gnu.org/licenses/
326
+ # ****************************************************************************
327
+
328
+ from __future__ import annotations
329
+
330
+ from typing import TYPE_CHECKING, Optional, Union, overload
331
+
332
+ import sage.rings.abc
333
+ from sage.categories.fields import Fields
334
+ from sage.categories.homset import Hom
335
+ from sage.categories.manifolds import Manifolds
336
+ from sage.manifolds.structure import (
337
+ DifferentialStructure,
338
+ RealDifferentialStructure,
339
+ RealTopologicalStructure,
340
+ TopologicalStructure,
341
+ )
342
+ from sage.manifolds.subset import ManifoldSubset
343
+ from sage.misc.cachefunc import cached_method
344
+ from sage.misc.prandom import getrandbits
345
+ from sage.rings.cc import CC
346
+ from sage.rings.integer import Integer
347
+ from sage.rings.real_mpfr import RR
348
+ from sage.structure.global_options import GlobalOptions
349
+
350
+ if TYPE_CHECKING:
351
+ from sage.manifolds.chart import Chart
352
+ from sage.manifolds.continuous_map import ContinuousMap
353
+ from sage.manifolds.differentiable.diff_map import DiffMap
354
+ from sage.manifolds.differentiable.manifold import DifferentiableManifold
355
+ from sage.manifolds.scalarfield import ScalarField
356
+
357
+
358
+ #############################################################################
359
+ # Global options
360
+
361
+ #############################################################################
362
+ # Class
363
+
364
+ class TopologicalManifold(ManifoldSubset):
365
+ r"""
366
+ Topological manifold over a topological field `K`.
367
+
368
+ Given a topological field `K` (in most applications, `K = \RR` or
369
+ `K = \CC`) and a nonnegative integer `n`, a *topological manifold of
370
+ dimension* `n` *over K* is a topological space `M` such that
371
+
372
+ - `M` is a Hausdorff space,
373
+ - `M` is second countable, and
374
+ - every point in `M` has a neighborhood homeomorphic to `K^n`.
375
+
376
+ This is a Sage *parent* class, the corresponding *element*
377
+ class being :class:`~sage.manifolds.point.ManifoldPoint`.
378
+
379
+ INPUT:
380
+
381
+ - ``n`` -- positive integer; dimension of the manifold
382
+ - ``name`` -- string; name (symbol) given to the manifold
383
+ - ``field`` -- field `K` on which the manifold is
384
+ defined; allowed values are
385
+
386
+ - ``'real'`` or an object of type ``RealField`` (e.g., ``RR``) for
387
+ a manifold over `\RR`
388
+ - ``'complex'`` or an object of type ``ComplexField`` (e.g., ``CC``)
389
+ for a manifold over `\CC`
390
+ - an object in the category of topological fields (see
391
+ :class:`~sage.categories.fields.Fields` and
392
+ :class:`~sage.categories.topological_spaces.TopologicalSpaces`)
393
+ for other types of manifolds
394
+
395
+ - ``structure`` -- manifold structure (see
396
+ :class:`~sage.manifolds.structure.TopologicalStructure` or
397
+ :class:`~sage.manifolds.structure.RealTopologicalStructure`)
398
+ - ``base_manifold`` -- (default: ``None``) if not ``None``, must be a
399
+ topological manifold; the created object is then an open subset of
400
+ ``base_manifold``
401
+ - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to
402
+ denote the manifold; if none are provided, it is set to ``name``
403
+ - ``start_index`` -- (default: 0) integer; lower value of the range of
404
+ indices used for "indexed objects" on the manifold, e.g., coordinates
405
+ in a chart
406
+ - ``category`` -- (default: ``None``) to specify the category; if
407
+ ``None``, ``Manifolds(field)`` is assumed (see the category
408
+ :class:`~sage.categories.manifolds.Manifolds`)
409
+ - ``unique_tag`` -- (default: ``None``) tag used to force the construction
410
+ of a new object when all the other arguments have been used previously
411
+ (without ``unique_tag``, the
412
+ :class:`~sage.structure.unique_representation.UniqueRepresentation`
413
+ behavior inherited from
414
+ :class:`~sage.manifolds.subset.ManifoldSubset`
415
+ would return the previously constructed object corresponding to these
416
+ arguments)
417
+
418
+ EXAMPLES:
419
+
420
+ A 4-dimensional topological manifold (over `\RR`)::
421
+
422
+ sage: M = Manifold(4, 'M', latex_name=r'\mathcal{M}', structure='topological')
423
+ sage: M
424
+ 4-dimensional topological manifold M
425
+ sage: latex(M)
426
+ \mathcal{M}
427
+ sage: type(M)
428
+ <class 'sage.manifolds.manifold.TopologicalManifold_with_category'>
429
+ sage: M.base_field()
430
+ Real Field with 53 bits of precision
431
+ sage: dim(M)
432
+ 4
433
+
434
+ The input parameter ``start_index`` defines the range of indices
435
+ on the manifold::
436
+
437
+ sage: M = Manifold(4, 'M', structure='topological')
438
+ sage: list(M.irange())
439
+ [0, 1, 2, 3]
440
+ sage: M = Manifold(4, 'M', structure='topological', start_index=1)
441
+ sage: list(M.irange())
442
+ [1, 2, 3, 4]
443
+ sage: list(Manifold(4, 'M', structure='topological', start_index=-2).irange())
444
+ [-2, -1, 0, 1]
445
+
446
+ A complex manifold::
447
+
448
+ sage: N = Manifold(3, 'N', structure='topological', field='complex'); N
449
+ Complex 3-dimensional topological manifold N
450
+
451
+ A manifold over `\QQ`::
452
+
453
+ sage: N = Manifold(6, 'N', structure='topological', field=QQ); N
454
+ 6-dimensional topological manifold N over the Rational Field
455
+
456
+ A manifold over `\QQ_5`, the field of 5-adic numbers::
457
+
458
+ sage: N = Manifold(2, 'N', structure='topological', field=Qp(5)); N # needs sage.rings.padics
459
+ 2-dimensional topological manifold N over the 5-adic Field with capped
460
+ relative precision 20
461
+
462
+ A manifold is a Sage *parent* object, in the category of topological
463
+ manifolds over a given topological field (see
464
+ :class:`~sage.categories.manifolds.Manifolds`)::
465
+
466
+ sage: isinstance(M, Parent)
467
+ True
468
+ sage: M.category()
469
+ Category of manifolds over Real Field with 53 bits of precision
470
+ sage: from sage.categories.manifolds import Manifolds
471
+ sage: M.category() is Manifolds(RR)
472
+ True
473
+ sage: M.category() is Manifolds(M.base_field())
474
+ True
475
+ sage: M in Manifolds(RR)
476
+ True
477
+ sage: N in Manifolds(Qp(5)) # needs sage.rings.padics
478
+ True
479
+
480
+ The corresponding Sage *elements* are points::
481
+
482
+ sage: X.<t, x, y, z> = M.chart()
483
+ sage: p = M.an_element(); p
484
+ Point on the 4-dimensional topological manifold M
485
+ sage: p.parent()
486
+ 4-dimensional topological manifold M
487
+ sage: M.is_parent_of(p)
488
+ True
489
+ sage: p in M
490
+ True
491
+
492
+ The manifold's points are instances of class
493
+ :class:`~sage.manifolds.point.ManifoldPoint`::
494
+
495
+ sage: isinstance(p, sage.manifolds.point.ManifoldPoint)
496
+ True
497
+
498
+ Since an open subset of a topological manifold `M` is itself a
499
+ topological manifold, open subsets of `M` are instances of the class
500
+ :class:`TopologicalManifold`::
501
+
502
+ sage: U = M.open_subset('U'); U
503
+ Open subset U of the 4-dimensional topological manifold M
504
+ sage: isinstance(U, sage.manifolds.manifold.TopologicalManifold)
505
+ True
506
+ sage: U.base_field() == M.base_field()
507
+ True
508
+ sage: dim(U) == dim(M)
509
+ True
510
+ sage: U.category()
511
+ Join of Category of subobjects of sets and Category of manifolds over
512
+ Real Field with 53 bits of precision
513
+
514
+ The manifold passes all the tests of the test suite relative to its
515
+ category::
516
+
517
+ sage: TestSuite(M).run()
518
+
519
+ .. SEEALSO::
520
+
521
+ :mod:`sage.manifolds.manifold`
522
+ """
523
+ _dim: int
524
+
525
+ def __init__(self, n, name, field, structure, base_manifold=None,
526
+ latex_name=None, start_index=0, category=None,
527
+ unique_tag=None):
528
+ r"""
529
+ Construct a topological manifold.
530
+
531
+ TESTS::
532
+
533
+ sage: M = Manifold(3, 'M', latex_name=r'\mathbb{M}',
534
+ ....: structure='topological', start_index=1)
535
+ sage: M
536
+ 3-dimensional topological manifold M
537
+ sage: latex(M)
538
+ \mathbb{M}
539
+ sage: dim(M)
540
+ 3
541
+ sage: X.<x,y,z> = M.chart()
542
+ sage: TestSuite(M).run()
543
+
544
+ Tests for open subsets::
545
+
546
+ sage: U = M.open_subset('U', coord_def={X: x>0})
547
+ sage: TestSuite(U).run()
548
+ sage: U.category() is M.category().Subobjects()
549
+ True
550
+ """
551
+ # Initialization of the attributes _dim, _field, _field_type:
552
+ if not isinstance(n, (int, Integer)):
553
+ raise TypeError("the manifold dimension must be an integer")
554
+ if n < 1:
555
+ raise ValueError("the manifold dimension must be strictly positive")
556
+ self._dim = n
557
+ if field == 'real':
558
+ self._field = RR
559
+ self._field_type = 'real'
560
+ elif field == 'complex':
561
+ self._field = CC
562
+ self._field_type = 'complex'
563
+ else:
564
+ if field not in Fields():
565
+ raise TypeError("the argument 'field' must be a field")
566
+ self._field = field
567
+ if isinstance(field, sage.rings.abc.RealField):
568
+ self._field_type = 'real'
569
+ elif isinstance(field, sage.rings.abc.ComplexField):
570
+ self._field_type = 'complex'
571
+ else:
572
+ self._field_type = 'neither_real_nor_complex'
573
+ # Structure and category:
574
+ self._structure = structure
575
+ if base_manifold is None:
576
+ base_manifold = self
577
+ category = Manifolds(self._field).or_subcategory(category)
578
+ category = self._structure.subcategory(category)
579
+ else:
580
+ category = base_manifold.category().Subobjects()
581
+ # Initialization as a manifold set:
582
+ ManifoldSubset.__init__(self, base_manifold, name, latex_name=latex_name,
583
+ category=category)
584
+ self._is_open = True
585
+ self._open_covers.append([self]) # list of open covers of self
586
+
587
+ if not isinstance(start_index, (int, Integer)):
588
+ raise TypeError("the starting index must be an integer")
589
+ self._sindex = start_index
590
+
591
+ self._atlas = [] # list of charts defined on subsets of self
592
+ self._top_charts = [] # list of charts defined on subsets of self
593
+ # that are not subcharts of charts on larger subsets
594
+ self._def_chart = None # default chart
595
+ self._orientation = [] # set no orientation a priori
596
+ self._charts_by_coord = {} # dictionary of charts whose domain is self
597
+ # (key: string formed by the coordinate
598
+ # symbols separated by a white space)
599
+ self._coord_changes = {} # dictionary of transition maps (key: pair of
600
+ # of charts)
601
+ # List of charts that individually cover self, i.e. whose
602
+ # domains are self (if non-empty, self is a coordinate domain):
603
+ self._covering_charts = []
604
+ # Algebra of scalar fields defined on self:
605
+ self._scalar_field_algebra = self._structure.scalar_field_algebra(self)
606
+ # The zero scalar field:
607
+ self._zero_scalar_field = self._scalar_field_algebra.zero()
608
+ # The unit scalar field:
609
+ self._one_scalar_field = self._scalar_field_algebra.one()
610
+ # The current calculus method on the manifold
611
+ # (to be changed by set_calculus_method)
612
+ self._calculus_method = 'SR'
613
+
614
+ def _repr_(self):
615
+ r"""
616
+ Return a string representation of the manifold.
617
+
618
+ TESTS::
619
+
620
+ sage: M = Manifold(3, 'M', structure='topological')
621
+ sage: M._repr_()
622
+ '3-dimensional topological manifold M'
623
+ sage: repr(M) # indirect doctest
624
+ '3-dimensional topological manifold M'
625
+ sage: M # indirect doctest
626
+ 3-dimensional topological manifold M
627
+ sage: M = Manifold(3, 'M', structure='topological', field='complex')
628
+ sage: M._repr_()
629
+ 'Complex 3-dimensional topological manifold M'
630
+ sage: M = Manifold(3, 'M', structure='topological', field=QQ)
631
+ sage: M._repr_()
632
+ '3-dimensional topological manifold M over the Rational Field'
633
+
634
+ If the manifold is actually an open subset of a larger manifold, the
635
+ string representation is different::
636
+
637
+ sage: U = M.open_subset('U')
638
+ sage: U._repr_()
639
+ 'Open subset U of the 3-dimensional topological manifold M
640
+ over the Rational Field'
641
+ """
642
+ if self is self._manifold:
643
+ if self._field_type == 'real':
644
+ return "{}-dimensional {} manifold {}".format(self._dim,
645
+ self._structure.name,
646
+ self._name)
647
+ elif self._field_type == 'complex':
648
+ if isinstance(self._structure, DifferentialStructure):
649
+ return "{}-dimensional complex manifold {}".format(
650
+ self._dim,
651
+ self._name)
652
+ else:
653
+ return "Complex {}-dimensional {} manifold {}".format(
654
+ self._dim,
655
+ self._structure.name,
656
+ self._name)
657
+ return "{}-dimensional {} manifold {} over the {}".format(
658
+ self._dim,
659
+ self._structure.name,
660
+ self._name,
661
+ self._field)
662
+ else:
663
+ return "Open subset {} of the {}".format(self._name, self._manifold)
664
+
665
+ def _an_element_(self):
666
+ r"""
667
+ Construct some point on the manifold.
668
+
669
+ EXAMPLES::
670
+
671
+ sage: M = Manifold(2, 'M', structure='topological')
672
+ sage: X.<x,y> = M.chart()
673
+ sage: p = M._an_element_(); p
674
+ Point on the 2-dimensional topological manifold M
675
+ sage: p.coord()
676
+ (0, 0)
677
+ sage: U = M.open_subset('U', coord_def={X: y>1}); U
678
+ Open subset U of the 2-dimensional topological manifold M
679
+ sage: p = U._an_element_(); p
680
+ Point on the 2-dimensional topological manifold M
681
+ sage: p in U
682
+ True
683
+ sage: p.coord()
684
+ (0, 2)
685
+ sage: V = U.open_subset('V', coord_def={X.restrict(U): x<-pi})
686
+ sage: p = V._an_element_(); p
687
+ Point on the 2-dimensional topological manifold M
688
+ sage: p in V
689
+ True
690
+ sage: p.coord()
691
+ (-pi - 1, 2)
692
+ """
693
+ from sage.rings.infinity import Infinity
694
+ if self._def_chart is None:
695
+ return self.element_class(self)
696
+ # Attempt to construct a point in the domain of the default chart
697
+ chart = self._def_chart
698
+ if self._field_type == 'real':
699
+ coords = []
700
+ for coord_range in chart._bounds:
701
+ xmin = coord_range[0][0]
702
+ xmax = coord_range[1][0]
703
+ if xmin == -Infinity:
704
+ if xmax == Infinity:
705
+ x = 0
706
+ else:
707
+ x = xmax - 1
708
+ else:
709
+ if xmax == Infinity:
710
+ x = xmin + 1
711
+ else:
712
+ x = (xmin + xmax)/2
713
+ coords.append(x)
714
+ else:
715
+ coords = self._dim*[0]
716
+ if not chart.valid_coordinates(*coords):
717
+ # Attempt to construct a point in the domain of other charts
718
+ if self._field_type == 'real':
719
+ for ch in self._atlas:
720
+ if ch is self._def_chart:
721
+ continue # since this case has already been attempted
722
+ coords = []
723
+ for coord_range in ch._bounds:
724
+ xmin = coord_range[0][0]
725
+ xmax = coord_range[1][0]
726
+ if xmin == -Infinity:
727
+ if xmax == Infinity:
728
+ x = 0
729
+ else:
730
+ x = xmax - 1
731
+ else:
732
+ if xmax == Infinity:
733
+ x = xmin + 1
734
+ else:
735
+ x = (xmin + xmax)/2
736
+ coords.append(x)
737
+ if ch.valid_coordinates(*coords):
738
+ chart = ch
739
+ break
740
+ else:
741
+ # A generic element with specific coordinates could not be
742
+ # automatically generated, due to too complex coordinate
743
+ # conditions. An element without any coordinate set is
744
+ # returned instead:
745
+ return self.element_class(self)
746
+ else:
747
+ # Case of manifolds over a field different from R
748
+ for ch in self._atlas:
749
+ if ch is self._def_chart:
750
+ continue # since this case has already been attempted
751
+ if ch.valid_coordinates(*coords):
752
+ chart = ch
753
+ break
754
+ else:
755
+ return self.element_class(self)
756
+ # The point is constructed with check_coords=False since the check
757
+ # has just been performed above:
758
+ return self.element_class(self, coords=coords, chart=chart,
759
+ check_coords=False)
760
+
761
+ def __contains__(self, point):
762
+ r"""
763
+ Check whether a point is contained in the manifold.
764
+
765
+ EXAMPLES::
766
+
767
+ sage: M = Manifold(2, 'M', structure='topological')
768
+ sage: X.<x,y> = M.chart()
769
+ sage: p = M.point((1,2), chart=X)
770
+ sage: M.__contains__(p)
771
+ True
772
+ sage: p in M # indirect doctest
773
+ True
774
+ sage: U = M.open_subset('U', coord_def={X: x>0})
775
+ sage: U.__contains__(p)
776
+ True
777
+ sage: p in U # indirect doctest
778
+ True
779
+ sage: V = U.open_subset('V', coord_def={X.restrict(U): y<0})
780
+ sage: V.__contains__(p)
781
+ False
782
+ sage: p in V # indirect doctest
783
+ False
784
+ """
785
+ # for efficiency, a quick test first:
786
+ if point.parent() is self:
787
+ return True
788
+ if point.parent().is_subset(self):
789
+ return True
790
+ for chart in self._atlas:
791
+ if chart in point._coordinates:
792
+ if chart.valid_coordinates( *(point._coordinates[chart]) ):
793
+ return True
794
+ for chart in point._coordinates:
795
+ for schart in chart._subcharts:
796
+ if schart in self._atlas and schart.valid_coordinates(
797
+ *(point._coordinates[chart]) ):
798
+ return True
799
+ return False
800
+
801
+ def open_subset(self, name, latex_name=None, coord_def={}, supersets=None):
802
+ r"""
803
+ Create an open subset of the manifold.
804
+
805
+ An open subset is a set that is (i) included in the manifold and (ii)
806
+ open with respect to the manifold's topology. It is a topological
807
+ manifold by itself. Hence the returned object is an instance of
808
+ :class:`TopologicalManifold`.
809
+
810
+ INPUT:
811
+
812
+ - ``name`` -- name given to the open subset
813
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote
814
+ the subset; if none are provided, it is set to ``name``
815
+ - ``coord_def`` -- (default: {}) definition of the subset in
816
+ terms of coordinates; ``coord_def`` must a be dictionary with keys
817
+ charts on the manifold and values the symbolic expressions formed
818
+ by the coordinates to define the subset
819
+ - ``supersets`` -- (default: only ``self``) list of sets that the
820
+ new open subset is a subset of
821
+
822
+ OUTPUT: the open subset, as an instance of :class:`TopologicalManifold`
823
+
824
+ EXAMPLES:
825
+
826
+ Creating an open subset of a 2-dimensional manifold::
827
+
828
+ sage: M = Manifold(2, 'M', structure='topological')
829
+ sage: A = M.open_subset('A'); A
830
+ Open subset A of the 2-dimensional topological manifold M
831
+
832
+ As an open subset of a topological manifold, ``A`` is itself a
833
+ topological manifold, on the same topological field and of the same
834
+ dimension as ``M``::
835
+
836
+ sage: isinstance(A, sage.manifolds.manifold.TopologicalManifold)
837
+ True
838
+ sage: A.base_field() == M.base_field()
839
+ True
840
+ sage: dim(A) == dim(M)
841
+ True
842
+ sage: A.category() is M.category().Subobjects()
843
+ True
844
+
845
+ Creating an open subset of ``A``::
846
+
847
+ sage: B = A.open_subset('B'); B
848
+ Open subset B of the 2-dimensional topological manifold M
849
+
850
+ We have then::
851
+
852
+ sage: frozenset(A.subsets()) # random (set output)
853
+ {Open subset B of the 2-dimensional topological manifold M,
854
+ Open subset A of the 2-dimensional topological manifold M}
855
+ sage: B.is_subset(A)
856
+ True
857
+ sage: B.is_subset(M)
858
+ True
859
+
860
+ Defining an open subset by some coordinate restrictions: the open
861
+ unit disk in `\RR^2`::
862
+
863
+ sage: M = Manifold(2, 'R^2', structure='topological')
864
+ sage: c_cart.<x,y> = M.chart() # Cartesian coordinates on R^2
865
+ sage: U = M.open_subset('U', coord_def={c_cart: x^2+y^2<1}); U
866
+ Open subset U of the 2-dimensional topological manifold R^2
867
+
868
+ Since the argument ``coord_def`` has been set, ``U`` is automatically
869
+ provided with a chart, which is the restriction of the Cartesian one
870
+ to ``U``::
871
+
872
+ sage: U.atlas()
873
+ [Chart (U, (x, y))]
874
+
875
+ Therefore, one can immediately check whether a point belongs
876
+ to ``U``::
877
+
878
+ sage: M.point((0,0)) in U
879
+ True
880
+ sage: M.point((1/2,1/3)) in U
881
+ True
882
+ sage: M.point((1,2)) in U
883
+ False
884
+ """
885
+ resu = TopologicalManifold(self._dim, name, self._field,
886
+ self._structure,
887
+ base_manifold=self._manifold,
888
+ latex_name=latex_name,
889
+ start_index=self._sindex)
890
+ if supersets is None:
891
+ supersets = [self]
892
+ for superset in supersets:
893
+ superset._init_open_subset(resu, coord_def=coord_def)
894
+ return resu
895
+
896
+ def _init_open_subset(self, resu, coord_def):
897
+ r"""
898
+ Initialize ``resu`` as an open subset of ``self``.
899
+
900
+ INPUT:
901
+
902
+ - ``resu`` -- an instance of :class:`TopologicalManifold` or
903
+ a subclass
904
+
905
+ - ``coord_def`` -- (default: ``{}``) definition of the subset in
906
+ terms of coordinates; ``coord_def`` must a be dictionary with keys
907
+ charts on the manifold and values the symbolic expressions formed
908
+ by the coordinates to define the subset
909
+
910
+ EXAMPLES::
911
+
912
+ sage: M = Manifold(2, 'R^2', structure='topological')
913
+ sage: c_cart.<x,y> = M.chart() # Cartesian coordinates on R^2
914
+ sage: from sage.manifolds.manifold import TopologicalManifold
915
+ sage: U = TopologicalManifold(2, 'U', field=M._field, structure=M._structure, base_manifold=M)
916
+ sage: M._init_open_subset(U, coord_def={c_cart: x^2+y^2<1})
917
+ sage: U
918
+ Open subset U of the 2-dimensional topological manifold R^2
919
+ """
920
+ resu._calculus_method = self._calculus_method
921
+ if self.is_empty():
922
+ self.declare_equal(resu)
923
+ else:
924
+ self.declare_superset(resu)
925
+ self._top_subsets.add(resu)
926
+ # Charts on the result from the coordinate definition:
927
+ for chart, restrictions in coord_def.items():
928
+ if chart not in self._atlas:
929
+ raise ValueError("the {} does not belong to ".format(chart) +
930
+ "the atlas of {}".format(self))
931
+ chart.restrict(resu, restrictions)
932
+ # Transition maps on the result inferred from those of self:
933
+ for chart1 in coord_def:
934
+ for chart2 in coord_def:
935
+ if chart2 != chart1 and (chart1, chart2) in self._coord_changes:
936
+ self._coord_changes[(chart1, chart2)].restrict(resu)
937
+
938
+ def get_chart(self, coordinates, domain=None):
939
+ r"""
940
+ Get a chart from its coordinates.
941
+
942
+ The chart must have been previously created by the method
943
+ :meth:`chart`.
944
+
945
+ INPUT:
946
+
947
+ - ``coordinates`` -- single string composed of the coordinate symbols
948
+ separated by a space
949
+ - ``domain`` -- (default: ``None``) string containing the name of the
950
+ chart's domain, which must be a subset of the current manifold; if
951
+ ``None``, the current manifold is assumed
952
+
953
+ OUTPUT:
954
+
955
+ - instance of
956
+ :class:`~sage.manifolds.chart.Chart` (or of the subclass
957
+ :class:`~sage.manifolds.chart.RealChart`) representing the chart
958
+ corresponding to the above specifications
959
+
960
+ EXAMPLES::
961
+
962
+ sage: M = Manifold(2, 'M', structure='topological')
963
+ sage: X.<x,y> = M.chart()
964
+ sage: M.get_chart('x y')
965
+ Chart (M, (x, y))
966
+ sage: M.get_chart('x y') is X
967
+ True
968
+ sage: U = M.open_subset('U', coord_def={X: (y!=0,x<0)})
969
+ sage: Y.<r, ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi')
970
+ sage: M.atlas()
971
+ [Chart (M, (x, y)), Chart (U, (x, y)), Chart (U, (r, ph))]
972
+ sage: M.get_chart('x y', domain='U')
973
+ Chart (U, (x, y))
974
+ sage: M.get_chart('x y', domain='U') is X.restrict(U)
975
+ True
976
+ sage: U.get_chart('r ph')
977
+ Chart (U, (r, ph))
978
+ sage: M.get_chart('r ph', domain='U')
979
+ Chart (U, (r, ph))
980
+ sage: M.get_chart('r ph', domain='U') is Y
981
+ True
982
+ """
983
+ if domain is None:
984
+ dom = self
985
+ else:
986
+ dom = self.get_subset(domain)
987
+ try:
988
+ return dom._charts_by_coord[coordinates]
989
+ except KeyError:
990
+ raise KeyError("the coordinates '{}' ".format(coordinates) +
991
+ "do not correspond to any chart with " +
992
+ "the {} as domain".format(dom))
993
+
994
+ def dimension(self):
995
+ r"""
996
+ Return the dimension of the manifold over its base field.
997
+
998
+ EXAMPLES::
999
+
1000
+ sage: M = Manifold(2, 'M', structure='topological')
1001
+ sage: M.dimension()
1002
+ 2
1003
+
1004
+ A shortcut is ``dim()``::
1005
+
1006
+ sage: M.dim()
1007
+ 2
1008
+
1009
+ The Sage global function ``dim`` can also be used::
1010
+
1011
+ sage: dim(M)
1012
+ 2
1013
+ """
1014
+ return self._dim
1015
+
1016
+ dim = dimension
1017
+
1018
+ def base_field(self):
1019
+ r"""
1020
+ Return the field on which the manifold is defined.
1021
+
1022
+ OUTPUT: a topological field
1023
+
1024
+ EXAMPLES::
1025
+
1026
+ sage: M = Manifold(3, 'M', structure='topological')
1027
+ sage: M.base_field()
1028
+ Real Field with 53 bits of precision
1029
+ sage: M = Manifold(3, 'M', structure='topological', field='complex')
1030
+ sage: M.base_field()
1031
+ Complex Field with 53 bits of precision
1032
+ sage: M = Manifold(3, 'M', structure='topological', field=QQ)
1033
+ sage: M.base_field()
1034
+ Rational Field
1035
+ """
1036
+ return self._field
1037
+
1038
+ def base_field_type(self):
1039
+ r"""
1040
+ Return the type of topological field on which the manifold is defined.
1041
+
1042
+ OUTPUT:
1043
+
1044
+ A string describing the field, with three possible values:
1045
+
1046
+ - ``'real'`` for the real field `\RR`
1047
+ - ``'complex'`` for the complex field `\CC`
1048
+ - ``'neither_real_nor_complex'`` for a field different from `\RR` and `\CC`
1049
+
1050
+ EXAMPLES::
1051
+
1052
+ sage: M = Manifold(3, 'M', structure='topological')
1053
+ sage: M.base_field_type()
1054
+ 'real'
1055
+ sage: M = Manifold(3, 'M', structure='topological', field='complex')
1056
+ sage: M.base_field_type()
1057
+ 'complex'
1058
+ sage: M = Manifold(3, 'M', structure='topological', field=QQ)
1059
+ sage: M.base_field_type()
1060
+ 'neither_real_nor_complex'
1061
+ """
1062
+ return self._field_type
1063
+
1064
+ def start_index(self):
1065
+ r"""
1066
+ Return the first value of the index range used on the manifold.
1067
+
1068
+ This is the parameter ``start_index`` passed at the construction of
1069
+ the manifold.
1070
+
1071
+ OUTPUT:
1072
+
1073
+ - the integer `i_0` such that all indices of indexed objects on the
1074
+ manifold range from `i_0` to `i_0 + n - 1`, where `n` is the
1075
+ manifold's dimension
1076
+
1077
+ EXAMPLES::
1078
+
1079
+ sage: M = Manifold(3, 'M', structure='topological')
1080
+ sage: M.start_index()
1081
+ 0
1082
+ sage: M = Manifold(3, 'M', structure='topological', start_index=1)
1083
+ sage: M.start_index()
1084
+ 1
1085
+ """
1086
+ return self._sindex
1087
+
1088
+ def irange(self, start=None, end=None):
1089
+ r"""
1090
+ Single index generator.
1091
+
1092
+ INPUT:
1093
+
1094
+ - ``start`` -- (default: ``None``) initial value `i_0` of the index;
1095
+ if ``None``, the value returned by :meth:`start_index()` is assumed
1096
+ - ``end`` -- (default: ``None``) final value `i_n` of the index;
1097
+ if ``None``, the value returned by :meth:`start_index()` plus
1098
+ `n - 1`, where `n` is the manifold dimension, is assumed
1099
+
1100
+ OUTPUT: an iterable index, starting from `i_0` and ending at `i_0 + i_n`
1101
+
1102
+ EXAMPLES:
1103
+
1104
+ Index range on a 4-dimensional manifold::
1105
+
1106
+ sage: M = Manifold(4, 'M', structure='topological')
1107
+ sage: list(M.irange())
1108
+ [0, 1, 2, 3]
1109
+ sage: list(M.irange(start=2))
1110
+ [2, 3]
1111
+ sage: list(M.irange(end=2))
1112
+ [0, 1, 2]
1113
+ sage: list(M.irange(start=1, end=2))
1114
+ [1, 2]
1115
+
1116
+ Index range on a 4-dimensional manifold with starting index=1::
1117
+
1118
+ sage: M = Manifold(4, 'M', structure='topological', start_index=1)
1119
+ sage: list(M.irange())
1120
+ [1, 2, 3, 4]
1121
+ sage: list(M.irange(start=2))
1122
+ [2, 3, 4]
1123
+ sage: list(M.irange(end=2))
1124
+ [1, 2]
1125
+ sage: list(M.irange(start=2, end=3))
1126
+ [2, 3]
1127
+
1128
+ In general, one has always::
1129
+
1130
+ sage: next(M.irange()) == M.start_index()
1131
+ True
1132
+ """
1133
+ si = self._sindex
1134
+ if start is None:
1135
+ i = si
1136
+ else:
1137
+ i = start
1138
+ if end is None:
1139
+ imax = self._dim + si
1140
+ else:
1141
+ imax = end + 1
1142
+ while i < imax:
1143
+ yield i
1144
+ i += 1
1145
+
1146
+ def index_generator(self, nb_indices):
1147
+ r"""
1148
+ Generator of index series.
1149
+
1150
+ INPUT:
1151
+
1152
+ - ``nb_indices`` -- number of indices in a series
1153
+
1154
+ OUTPUT:
1155
+
1156
+ - an iterable index series for a generic component with the specified
1157
+ number of indices
1158
+
1159
+ EXAMPLES:
1160
+
1161
+ Indices on a 2-dimensional manifold::
1162
+
1163
+ sage: M = Manifold(2, 'M', structure='topological', start_index=1)
1164
+ sage: list(M.index_generator(2))
1165
+ [(1, 1), (1, 2), (2, 1), (2, 2)]
1166
+
1167
+ Loops can be nested::
1168
+
1169
+ sage: for ind1 in M.index_generator(2):
1170
+ ....: print("{} : {}".format(ind1, list(M.index_generator(2))))
1171
+ (1, 1) : [(1, 1), (1, 2), (2, 1), (2, 2)]
1172
+ (1, 2) : [(1, 1), (1, 2), (2, 1), (2, 2)]
1173
+ (2, 1) : [(1, 1), (1, 2), (2, 1), (2, 2)]
1174
+ (2, 2) : [(1, 1), (1, 2), (2, 1), (2, 2)]
1175
+ """
1176
+ si = self._sindex
1177
+ imax = self._dim - 1 + si
1178
+ ind = [si for k in range(nb_indices)]
1179
+ ind_end = [si for k in range(nb_indices)]
1180
+ ind_end[0] = imax+1
1181
+ while ind != ind_end:
1182
+ yield tuple(ind)
1183
+ ret = 1
1184
+ for pos in range(nb_indices-1, -1, -1):
1185
+ if ind[pos] != imax:
1186
+ ind[pos] += ret
1187
+ ret = 0
1188
+ elif ret == 1:
1189
+ if pos == 0:
1190
+ ind[pos] = imax + 1 # end point reached
1191
+ else:
1192
+ ind[pos] = si
1193
+ ret = 1
1194
+
1195
+ def atlas(self) -> list[Chart]:
1196
+ r"""
1197
+ Return the list of charts that have been defined on the manifold.
1198
+
1199
+ EXAMPLES:
1200
+
1201
+ Let us consider `\RR^2` as a 2-dimensional manifold::
1202
+
1203
+ sage: M = Manifold(2, 'R^2', structure='topological')
1204
+
1205
+ Immediately after the manifold creation, the atlas is empty, since no
1206
+ chart has been defined yet::
1207
+
1208
+ sage: M.atlas()
1209
+ []
1210
+
1211
+ Let us introduce the chart of Cartesian coordinates::
1212
+
1213
+ sage: c_cart.<x,y> = M.chart()
1214
+ sage: M.atlas()
1215
+ [Chart (R^2, (x, y))]
1216
+
1217
+ The complement of the half line `\{y = 0, x \geq 0\}`::
1218
+
1219
+ sage: U = M.open_subset('U', coord_def={c_cart: (y!=0,x<0)})
1220
+ sage: U.atlas()
1221
+ [Chart (U, (x, y))]
1222
+ sage: M.atlas()
1223
+ [Chart (R^2, (x, y)), Chart (U, (x, y))]
1224
+
1225
+ Spherical (polar) coordinates on ``U``::
1226
+
1227
+ sage: c_spher.<r, ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi')
1228
+ sage: U.atlas()
1229
+ [Chart (U, (x, y)), Chart (U, (r, ph))]
1230
+ sage: M.atlas()
1231
+ [Chart (R^2, (x, y)), Chart (U, (x, y)), Chart (U, (r, ph))]
1232
+
1233
+ .. SEEALSO::
1234
+
1235
+ :meth:`top_charts`
1236
+ """
1237
+ return list(self._atlas) # Make a (shallow) copy
1238
+
1239
+ def top_charts(self):
1240
+ r"""
1241
+ Return the list of charts defined on subsets of the current manifold
1242
+ that are not subcharts of charts on larger subsets.
1243
+
1244
+ OUTPUT:
1245
+
1246
+ - list of charts defined on open subsets of the manifold but not on
1247
+ larger subsets
1248
+
1249
+ EXAMPLES:
1250
+
1251
+ Charts on a 2-dimensional manifold::
1252
+
1253
+ sage: M = Manifold(2, 'M', structure='topological')
1254
+ sage: X.<x,y> = M.chart()
1255
+ sage: U = M.open_subset('U', coord_def={X: x>0})
1256
+ sage: Y.<u,v> = U.chart()
1257
+ sage: M.top_charts()
1258
+ [Chart (M, (x, y)), Chart (U, (u, v))]
1259
+
1260
+ Note that the (user) atlas contains one more chart: ``(U, (x,y))``,
1261
+ which is not a "top" chart::
1262
+
1263
+ sage: M.atlas()
1264
+ [Chart (M, (x, y)), Chart (U, (x, y)), Chart (U, (u, v))]
1265
+
1266
+ .. SEEALSO::
1267
+
1268
+ :meth:`atlas` for the complete list of charts defined on the
1269
+ manifold.
1270
+ """
1271
+ return list(self._top_charts) # Make a (shallow) copy
1272
+
1273
+ def default_chart(self):
1274
+ r"""
1275
+ Return the default chart defined on the manifold.
1276
+
1277
+ Unless changed via :meth:`set_default_chart`, the *default chart*
1278
+ is the first one defined on a subset of the manifold (possibly itself).
1279
+
1280
+ OUTPUT:
1281
+
1282
+ - instance of :class:`~sage.manifolds.chart.Chart`
1283
+ representing the default chart
1284
+
1285
+ EXAMPLES:
1286
+
1287
+ Default chart on a 2-dimensional manifold and on some subsets::
1288
+
1289
+ sage: M = Manifold(2, 'M', structure='topological')
1290
+ sage: M.chart('x y')
1291
+ Chart (M, (x, y))
1292
+ sage: M.chart('u v')
1293
+ Chart (M, (u, v))
1294
+ sage: M.default_chart()
1295
+ Chart (M, (x, y))
1296
+ sage: A = M.open_subset('A')
1297
+ sage: A.chart('t z')
1298
+ Chart (A, (t, z))
1299
+ sage: A.default_chart()
1300
+ Chart (A, (t, z))
1301
+ """
1302
+ return self._def_chart
1303
+
1304
+ def set_default_chart(self, chart):
1305
+ r"""
1306
+ Changing the default chart on ``self``.
1307
+
1308
+ INPUT:
1309
+
1310
+ - ``chart`` -- a chart (must be defined on some subset ``self``)
1311
+
1312
+ EXAMPLES:
1313
+
1314
+ Charts on a 2-dimensional manifold::
1315
+
1316
+ sage: M = Manifold(2, 'M', structure='topological')
1317
+ sage: c_xy.<x,y> = M.chart()
1318
+ sage: c_uv.<u,v> = M.chart()
1319
+ sage: M.default_chart()
1320
+ Chart (M, (x, y))
1321
+ sage: M.set_default_chart(c_uv)
1322
+ sage: M.default_chart()
1323
+ Chart (M, (u, v))
1324
+ """
1325
+ from sage.manifolds.chart import Chart
1326
+ if not isinstance(chart, Chart):
1327
+ raise TypeError("{} is not a chart".format(chart))
1328
+ if chart not in self._atlas:
1329
+ raise ValueError("the chart must be defined on the {}".format(self))
1330
+ self._def_chart = chart
1331
+
1332
+ def coord_change(self, chart1, chart2):
1333
+ r"""
1334
+ Return the change of coordinates (transition map) between two charts
1335
+ defined on the manifold.
1336
+
1337
+ The change of coordinates must have been defined previously, for
1338
+ instance by the method
1339
+ :meth:`~sage.manifolds.chart.Chart.transition_map`.
1340
+
1341
+ INPUT:
1342
+
1343
+ - ``chart1`` -- chart 1
1344
+ - ``chart2`` -- chart 2
1345
+
1346
+ OUTPUT:
1347
+
1348
+ - instance of :class:`~sage.manifolds.chart.CoordChange`
1349
+ representing the transition map from chart 1 to chart 2
1350
+
1351
+ EXAMPLES:
1352
+
1353
+ Change of coordinates on a 2-dimensional manifold::
1354
+
1355
+ sage: M = Manifold(2, 'M', structure='topological')
1356
+ sage: c_xy.<x,y> = M.chart()
1357
+ sage: c_uv.<u,v> = M.chart()
1358
+ sage: c_xy.transition_map(c_uv, (x+y, x-y)) # defines the coord. change
1359
+ Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v))
1360
+ sage: M.coord_change(c_xy, c_uv) # returns the coord. change defined above
1361
+ Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v))
1362
+ """
1363
+ if (chart1, chart2) not in self._coord_changes:
1364
+ raise TypeError("the change of coordinates from " +
1365
+ "{} to {}".format(chart1, chart2) + " has not " +
1366
+ "been defined on the {}".format(self))
1367
+ return self._coord_changes[(chart1, chart2)]
1368
+
1369
+ def coord_changes(self):
1370
+ r"""
1371
+ Return the changes of coordinates (transition maps) defined on
1372
+ subsets of the manifold.
1373
+
1374
+ OUTPUT: dictionary of changes of coordinates, with pairs of charts as keys
1375
+
1376
+ EXAMPLES:
1377
+
1378
+ Various changes of coordinates on a 2-dimensional manifold::
1379
+
1380
+ sage: M = Manifold(2, 'M', structure='topological')
1381
+ sage: c_xy.<x,y> = M.chart()
1382
+ sage: c_uv.<u,v> = M.chart()
1383
+ sage: xy_to_uv = c_xy.transition_map(c_uv, [x+y, x-y])
1384
+ sage: M.coord_changes()
1385
+ {(Chart (M, (x, y)),
1386
+ Chart (M, (u, v))): Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v))}
1387
+ sage: uv_to_xy = xy_to_uv.inverse()
1388
+ sage: M.coord_changes() # random (dictionary output)
1389
+ {(Chart (M, (u, v)),
1390
+ Chart (M, (x, y))): Change of coordinates from Chart (M, (u, v)) to Chart (M, (x, y)),
1391
+ (Chart (M, (x, y)),
1392
+ Chart (M, (u, v))): Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v))}
1393
+ sage: c_rs.<r,s> = M.chart()
1394
+ sage: uv_to_rs = c_uv.transition_map(c_rs, [-u+2*v, 3*u-v])
1395
+ sage: M.coord_changes() # random (dictionary output)
1396
+ {(Chart (M, (u, v)),
1397
+ Chart (M, (r, s))): Change of coordinates from Chart (M, (u, v)) to Chart (M, (r, s)),
1398
+ (Chart (M, (u, v)),
1399
+ Chart (M, (x, y))): Change of coordinates from Chart (M, (u, v)) to Chart (M, (x, y)),
1400
+ (Chart (M, (x, y)),
1401
+ Chart (M, (u, v))): Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v))}
1402
+ sage: xy_to_rs = uv_to_rs * xy_to_uv
1403
+ sage: M.coord_changes() # random (dictionary output)
1404
+ {(Chart (M, (u, v)),
1405
+ Chart (M, (r, s))): Change of coordinates from Chart (M, (u, v)) to Chart (M, (r, s)),
1406
+ (Chart (M, (u, v)),
1407
+ Chart (M, (x, y))): Change of coordinates from Chart (M, (u, v)) to Chart (M, (x, y)),
1408
+ (Chart (M, (x, y)),
1409
+ Chart (M, (u, v))): Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v)),
1410
+ (Chart (M, (x, y)),
1411
+ Chart (M, (r, s))): Change of coordinates from Chart (M, (x, y)) to Chart (M, (r, s))}
1412
+ """
1413
+ return self._coord_changes.copy()
1414
+
1415
+ def is_manifestly_coordinate_domain(self):
1416
+ r"""
1417
+ Return ``True`` if the manifold is known to be the domain of some
1418
+ coordinate chart and ``False`` otherwise.
1419
+
1420
+ If ``False`` is returned, either the manifold cannot be the domain of
1421
+ some coordinate chart or no such chart has been declared yet.
1422
+
1423
+ EXAMPLES::
1424
+
1425
+ sage: M = Manifold(2, 'M', structure='topological')
1426
+ sage: U = M.open_subset('U')
1427
+ sage: X.<x,y> = U.chart()
1428
+ sage: U.is_manifestly_coordinate_domain()
1429
+ True
1430
+ sage: M.is_manifestly_coordinate_domain()
1431
+ False
1432
+ sage: Y.<u,v> = M.chart()
1433
+ sage: M.is_manifestly_coordinate_domain()
1434
+ True
1435
+ """
1436
+ return bool(self._covering_charts)
1437
+
1438
+ def chart(
1439
+ self,
1440
+ coordinates: str = "",
1441
+ names=None,
1442
+ calc_method=None,
1443
+ coord_restrictions=None,
1444
+ ) -> Chart:
1445
+ r"""
1446
+ Define a chart, the domain of which is the manifold.
1447
+
1448
+ A *chart* is a pair `(U, \varphi)`, where `U` is the current
1449
+ manifold and `\varphi: U \rightarrow V \subset K^n`
1450
+ is a homeomorphism from `U` to an open subset `V` of `K^n`, `K`
1451
+ being the field on which the manifold is defined.
1452
+
1453
+ The components `(x^1, \ldots, x^n)` of `\varphi`, defined by
1454
+ `\varphi(p) = (x^1(p), \ldots, x^n(p)) \in K^n` for any point
1455
+ `p \in U`, are called the *coordinates* of the chart `(U, \varphi)`.
1456
+
1457
+ See :class:`~sage.manifolds.chart.Chart` for a complete
1458
+ documentation.
1459
+
1460
+ INPUT:
1461
+
1462
+ - ``coordinates`` -- (default: ``''`` (empty string)) string
1463
+ defining the coordinate symbols, ranges and possible periodicities,
1464
+ see below
1465
+ - ``names`` -- (default: ``None``) unused argument, except if
1466
+ ``coordinates`` is not provided; it must then be a tuple containing
1467
+ the coordinate symbols (this is guaranteed if the shortcut operator
1468
+ ``<,>`` is used)
1469
+ - ``calc_method`` -- (default: ``None``) string defining the calculus
1470
+ method to be used on this chart; must be one of
1471
+
1472
+ - ``'SR'``: Sage's default symbolic engine (Symbolic Ring)
1473
+ - ``'sympy'``: SymPy
1474
+ - ``None``: the current calculus method defined on the manifold is
1475
+ used (cf. :meth:`set_calculus_method`)
1476
+ - ``coord_restrictions`` -- additional restrictions on the coordinates.
1477
+ See below.
1478
+
1479
+ The coordinates declared in the string ``coordinates`` are
1480
+ separated by ``' '`` (whitespace) and each coordinate has at most four
1481
+ fields, separated by a colon (``':'``):
1482
+
1483
+ 1. The coordinate symbol (a letter or a few letters).
1484
+ 2. (optional, only for manifolds over `\RR`) The interval `I`
1485
+ defining the coordinate range: if not provided, the coordinate
1486
+ is assumed to span all `\RR`; otherwise `I` must be provided
1487
+ in the form ``(a,b)`` (or equivalently ``]a,b[``)
1488
+ The bounds ``a`` and ``b`` can be ``+/-Infinity``, ``Inf``,
1489
+ ``infinity``, ``inf`` or ``oo``. For *singular* coordinates,
1490
+ non-open intervals such as ``[a,b]`` and
1491
+ ``(a,b]`` (or equivalently ``]a,b]``) are allowed. Note that
1492
+ the interval declaration must not contain any space character.
1493
+ 3. (optional) Indicator of the periodic character of the coordinate,
1494
+ either as ``period=T``, where ``T`` is the period, or, for manifolds
1495
+ over `\RR` only, as the keyword ``periodic`` (the value of the
1496
+ period is then deduced from the interval `I` declared in field 2;
1497
+ see the example below)
1498
+ 4. (optional) The LaTeX spelling of the coordinate; if not provided
1499
+ the coordinate symbol given in the first field will be used.
1500
+
1501
+ The order of fields 2 to 4 does not matter and each of them can
1502
+ be omitted. If it contains any LaTeX expression, the string
1503
+ ``coordinates`` must be declared with the prefix 'r' (for "raw") to
1504
+ allow for a proper treatment of the backslash character (see
1505
+ examples below). If no interval range, no period and no LaTeX spelling
1506
+ is to be set for any coordinate, the argument ``coordinates`` can be
1507
+ omitted when the shortcut operator ``<,>`` is used to declare the
1508
+ chart (see examples below).
1509
+
1510
+ Additional restrictions on the coordinates can be set using the
1511
+ argument ``coord_restrictions``.
1512
+
1513
+ A restriction can be any symbolic equality or inequality involving
1514
+ the coordinates, such as ``x > y`` or ``x^2 + y^2 != 0``. The items
1515
+ of the list (or set or frozenset) ``coord_restrictions`` are combined
1516
+ with the ``and`` operator; if some restrictions are to be combined with
1517
+ the ``or`` operator instead, they have to be passed as a tuple in some
1518
+ single item of the list (or set or frozenset) ``coord_restrictions``.
1519
+ For example::
1520
+
1521
+ coord_restrictions=[x > y, (x != 0, y != 0), z^2 < x]
1522
+
1523
+ means ``(x > y) and ((x != 0) or (y != 0)) and (z^2 < x)``.
1524
+ If the list ``coord_restrictions`` contains only one item, this
1525
+ item can be passed as such, i.e. writing ``x > y`` instead
1526
+ of the single element list ``[x > y]``. If the chart variables have
1527
+ not been declared as variables yet, ``coord_restrictions`` must
1528
+ be ``lambda``-quoted.
1529
+
1530
+ OUTPUT:
1531
+
1532
+ - the created chart, as an instance of
1533
+ :class:`~sage.manifolds.chart.Chart` or one of its subclasses, like
1534
+ :class:`~sage.manifolds.differentiable.chart.RealDiffChart` for
1535
+ differentiable manifolds over `\RR`.
1536
+
1537
+ EXAMPLES:
1538
+
1539
+ Chart on a 2-dimensional manifold::
1540
+
1541
+ sage: M = Manifold(2, 'M', structure='topological')
1542
+ sage: X = M.chart('x y'); X
1543
+ Chart (M, (x, y))
1544
+ sage: X[0]
1545
+ x
1546
+ sage: X[1]
1547
+ y
1548
+ sage: X[:]
1549
+ (x, y)
1550
+
1551
+ The declared coordinates are not known at the global level::
1552
+
1553
+ sage: y
1554
+ Traceback (most recent call last):
1555
+ ...
1556
+ NameError: name 'y' is not defined
1557
+
1558
+ They can be recovered by the operator ``[:]`` applied to the chart::
1559
+
1560
+ sage: (x, y) = X[:]
1561
+ sage: y
1562
+ y
1563
+ sage: type(y)
1564
+ <class 'sage.symbolic.expression.Expression'>
1565
+
1566
+ But a shorter way to proceed is to use the operator ``<,>`` in the
1567
+ left-hand side of the chart declaration (there is then no need to
1568
+ pass the string 'x y' to chart())::
1569
+
1570
+ sage: M = Manifold(2, 'M', structure='topological')
1571
+ sage: X.<x,y> = M.chart(); X
1572
+ Chart (M, (x, y))
1573
+
1574
+ Indeed, the declared coordinates are then known at the global level::
1575
+
1576
+ sage: y
1577
+ y
1578
+ sage: (x,y) == X[:]
1579
+ True
1580
+
1581
+ Actually the instruction ``X.<x,y> = M.chart()`` is
1582
+ equivalent to the combination of the two instructions
1583
+ ``X = M.chart('x y')`` and ``(x,y) = X[:]``.
1584
+
1585
+ As an example of coordinate ranges and LaTeX symbols passed via the
1586
+ string ``coordinates`` to ``chart()``, let us introduce polar
1587
+ coordinates::
1588
+
1589
+ sage: U = M.open_subset('U', coord_def={X: x^2+y^2 != 0})
1590
+ sage: P.<r,ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):periodic:\phi'); P
1591
+ Chart (U, (r, ph))
1592
+ sage: P.coord_range()
1593
+ r: (0, +oo); ph: [0, 2*pi] (periodic)
1594
+ sage: latex(P)
1595
+ \left(U,(r, {\phi})\right)
1596
+
1597
+ Using ``coord_restrictions``::
1598
+
1599
+ sage: D = Manifold(2, 'D', structure='topological')
1600
+ sage: X.<x,y> = D.chart(coord_restrictions=lambda x,y: [x^2+y^2<1, x>0]); X
1601
+ Chart (D, (x, y))
1602
+ sage: X.valid_coordinates(0, 0)
1603
+ False
1604
+ sage: X.valid_coordinates(1/2, 0)
1605
+ True
1606
+
1607
+ See the documentation of classes
1608
+ :class:`~sage.manifolds.chart.Chart` and
1609
+ :class:`~sage.manifolds.chart.RealChart` for more examples,
1610
+ especially regarding the coordinates ranges and restrictions.
1611
+ """
1612
+ if calc_method is None:
1613
+ calc_method = self._calculus_method
1614
+ return self._structure.chart(self, coordinates=coordinates,
1615
+ names=names, calc_method=calc_method,
1616
+ coord_restrictions=coord_restrictions)
1617
+
1618
+ def is_open(self):
1619
+ """
1620
+ Return if ``self`` is an open set.
1621
+
1622
+ In the present case (manifold or open subset of it), always
1623
+ return ``True``.
1624
+
1625
+ TESTS::
1626
+
1627
+ sage: M = Manifold(2, 'M', structure='topological')
1628
+ sage: M.is_open()
1629
+ True
1630
+ """
1631
+ return True
1632
+
1633
+ def set_orientation(self, orientation):
1634
+ r"""
1635
+ Set the preferred orientation of ``self``.
1636
+
1637
+ INPUT:
1638
+
1639
+ - ``orientation`` -- a chart or a list of charts
1640
+
1641
+ .. WARNING::
1642
+
1643
+ It is the user's responsibility that the orientation set here
1644
+ is indeed an orientation. There is no check going on in the
1645
+ background. See :meth:`orientation` for the definition of an
1646
+ orientation.
1647
+
1648
+ EXAMPLES:
1649
+
1650
+ Set an orientation on a manifold::
1651
+
1652
+ sage: M = Manifold(2, 'M', structure='top')
1653
+ sage: c_xy.<x,y> = M.chart(); c_uv.<u,v> = M.chart()
1654
+ sage: M.set_orientation(c_uv)
1655
+ sage: M.orientation()
1656
+ [Chart (M, (u, v))]
1657
+
1658
+ Set an orientation in the non-trivial case::
1659
+
1660
+ sage: M = Manifold(2, 'M', structure='top')
1661
+ sage: U = M.open_subset('U'); V = M.open_subset('V')
1662
+ sage: M.declare_union(U, V)
1663
+ sage: c_xy.<x,y> = U.chart(); c_uv.<u,v> = V.chart()
1664
+ sage: M.set_orientation([c_xy, c_uv])
1665
+ sage: M.orientation()
1666
+ [Chart (U, (x, y)), Chart (V, (u, v))]
1667
+ """
1668
+ chart_type = self._structure.chart
1669
+ if isinstance(orientation, chart_type):
1670
+ orientation = [orientation]
1671
+ elif isinstance(orientation, (tuple, list)):
1672
+ orientation = list(orientation)
1673
+ else:
1674
+ raise TypeError("orientation must be a chart or a list/tuple of "
1675
+ "charts")
1676
+ dom_union = None
1677
+ for c in orientation:
1678
+ if not isinstance(c, chart_type):
1679
+ raise ValueError("orientation must consist of charts")
1680
+ dom = c._domain
1681
+ if not dom.is_subset(self):
1682
+ raise ValueError("{} must be defined ".format(c) +
1683
+ "on a subset of {}".format(self))
1684
+ if dom_union is not None:
1685
+ dom_union = dom.union(dom_union)
1686
+ else:
1687
+ dom_union = dom
1688
+ if dom_union != self:
1689
+ raise ValueError("chart domains must cover {}".format(self))
1690
+ self._orientation = orientation
1691
+
1692
+ def orientation(self):
1693
+ r"""
1694
+ Get the preferred orientation of ``self`` if available.
1695
+
1696
+ An *orientation* of an `n`-dimensional topological manifold is an
1697
+ atlas of charts whose transition maps are orientation preserving. A
1698
+ homeomorphism `f \colon U \to V` for open subsets `U, V \subset \RR^n`
1699
+ is called *orientation preserving* if for each `x \in U` the
1700
+ following map between singular homologies is the identity:
1701
+
1702
+ .. MATH::
1703
+
1704
+ H_n(\RR^n, \RR^n - 0; \ZZ) \cong H_n(U, U - x; \ZZ)
1705
+ \xrightarrow{f_*} H_n(V, V - f(x)) \cong H_n(\RR^n, \RR^n - 0; \ZZ)
1706
+
1707
+ See `this link
1708
+ <http://www.map.mpim-bonn.mpg.de/Orientation_of_manifolds>`_
1709
+ for details.
1710
+
1711
+ .. NOTE::
1712
+
1713
+ Notice that for differentiable manifolds, the notion of
1714
+ orientability does not need homology theory at all. See
1715
+ :meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.orientation`
1716
+ for details
1717
+
1718
+ The trivial case corresponds to the manifold being covered by
1719
+ one chart. In that case, if no preferred orientation has been manually
1720
+ set before, one of those charts (usually the default chart) is
1721
+ set to the preferred orientation and returned here.
1722
+
1723
+ EXAMPLES:
1724
+
1725
+ If the manifold is covered by only one chart, it certainly admits an
1726
+ orientation::
1727
+
1728
+ sage: M = Manifold(3, 'M', structure='top')
1729
+ sage: c.<x,y,z> = M.chart()
1730
+ sage: M.orientation()
1731
+ [Chart (M, (x, y, z))]
1732
+
1733
+ Usually, an orientation cannot be obtained so easily::
1734
+
1735
+ sage: M = Manifold(2, 'M', structure='top')
1736
+ sage: U = M.open_subset('U'); V = M.open_subset('V')
1737
+ sage: M.declare_union(U, V)
1738
+ sage: c_xy.<x,y> = U.chart(); c_uv.<u,v> = V.chart()
1739
+ sage: M.orientation()
1740
+ []
1741
+
1742
+ In that case, the orientation can be set by the user manually::
1743
+
1744
+ sage: M.set_orientation([c_xy, c_uv])
1745
+ sage: M.orientation()
1746
+ [Chart (U, (x, y)), Chart (V, (u, v))]
1747
+
1748
+ The orientation on submanifolds are inherited from the ambient
1749
+ manifold::
1750
+
1751
+ sage: W = U.intersection(V, name='W')
1752
+ sage: W.orientation()
1753
+ [Chart (W, (x, y))]
1754
+ """
1755
+ if not self._orientation:
1756
+ # try to get an orientation from super domains:
1757
+ for sdom in self._supersets:
1758
+ sorient = sdom._orientation
1759
+ if sorient:
1760
+ rst_orient = [c.restrict(self) for c in sorient]
1761
+ # clear duplicated domains:
1762
+ rst_orient = list(self._get_min_covering(rst_orient))
1763
+ self._orientation = rst_orient
1764
+ break
1765
+ else:
1766
+ # Trivial case:
1767
+ if self.is_manifestly_coordinate_domain():
1768
+ # Try the default chart:
1769
+ def_chart = self._def_chart
1770
+ if def_chart is not None:
1771
+ if def_chart.domain() is self:
1772
+ self._orientation = [self._def_chart]
1773
+ # Still no orientation? Choose arbitrary chart:
1774
+ if not self._orientation:
1775
+ for chart in self._covering_charts:
1776
+ self._orientation = [chart]
1777
+ break
1778
+ return list(self._orientation)
1779
+
1780
+ def has_orientation(self) -> bool:
1781
+ r"""
1782
+ Check whether ``self`` admits an obvious or by user set orientation.
1783
+
1784
+ .. SEEALSO::
1785
+
1786
+ Consult :meth:`orientation` for details about orientations.
1787
+
1788
+ .. NOTE::
1789
+
1790
+ Notice that if :meth:`has_orientation` returns ``False`` this
1791
+ does not necessarily mean that the manifold admits no orientation.
1792
+ It just means that the user has to set an orientation manually
1793
+ in that case, see :meth:`set_orientation`.
1794
+
1795
+ EXAMPLES:
1796
+
1797
+ The trivial case::
1798
+
1799
+ sage: M = Manifold(3, 'M', structure='top')
1800
+ sage: c.<x,y,z> = M.chart()
1801
+ sage: M.has_orientation()
1802
+ True
1803
+
1804
+ The non-trivial case::
1805
+
1806
+ sage: M = Manifold(2, 'M', structure='top')
1807
+ sage: U = M.open_subset('U'); V = M.open_subset('V')
1808
+ sage: M.declare_union(U, V)
1809
+ sage: c_xy.<x,y> = U.chart(); c_uv.<u,v> = V.chart()
1810
+ sage: M.has_orientation()
1811
+ False
1812
+ sage: M.set_orientation([c_xy, c_uv])
1813
+ sage: M.has_orientation()
1814
+ True
1815
+ """
1816
+ return bool(self.orientation())
1817
+
1818
+ def _get_min_covering(self, object_list):
1819
+ r"""
1820
+ Helper method to return the minimal amount of objects necessary to
1821
+ cover the union of all their domains.
1822
+
1823
+ INPUT:
1824
+
1825
+ - list of objects having an `domain` method
1826
+
1827
+ OUTPUT: set of objects
1828
+
1829
+ TESTS::
1830
+
1831
+ sage: M = Manifold(1, 'M', structure='top')
1832
+ sage: U = M.open_subset('U'); V = M.open_subset('V')
1833
+ sage: c1.<x> = U.chart(); c2.<y> = V.chart()
1834
+ sage: c3.<z> = M.chart()
1835
+ sage: M._get_min_covering([c1, c2, c3])
1836
+ {Chart (M, (z,))}
1837
+ """
1838
+ min_obj_set = set()
1839
+ for obj in object_list:
1840
+ redund_obj_set = set()
1841
+ for oobj in min_obj_set:
1842
+ if obj.domain().is_subset(oobj.domain()):
1843
+ break
1844
+ elif oobj.domain().is_subset(obj.domain()):
1845
+ redund_obj_set.add(oobj)
1846
+ else:
1847
+ min_obj_set.add(obj)
1848
+ min_obj_set.difference_update(redund_obj_set)
1849
+ return min_obj_set
1850
+
1851
+ def vector_bundle(self, rank, name, field='real', latex_name=None):
1852
+ r"""
1853
+ Return a topological vector bundle over the given field with given rank
1854
+ over this topological manifold.
1855
+
1856
+ INPUT:
1857
+
1858
+ - ``rank`` -- rank of the vector bundle
1859
+ - ``name`` -- name given to the total space
1860
+ - ``field`` -- (default: ``'real'``) topological field giving the
1861
+ vector space structure to the fibers
1862
+ - ``latex_name`` -- (optional) LaTeX name for the total space
1863
+
1864
+ OUTPUT:
1865
+
1866
+ - a topological vector bundle as an instance of
1867
+ :class:`~sage.manifolds.vector_bundle.TopologicalVectorBundle`
1868
+
1869
+ EXAMPLES::
1870
+
1871
+ sage: M = Manifold(2, 'M', structure='top')
1872
+ sage: M.vector_bundle(2, 'E')
1873
+ Topological real vector bundle E -> M of rank 2 over the base space
1874
+ 2-dimensional topological manifold M
1875
+ """
1876
+ from sage.manifolds.vector_bundle import TopologicalVectorBundle
1877
+ return TopologicalVectorBundle(rank, name, self, field=field,
1878
+ latex_name=latex_name)
1879
+
1880
+ def scalar_field_algebra(self):
1881
+ r"""
1882
+ Return the algebra of scalar fields defined the manifold.
1883
+
1884
+ See :class:`~sage.manifolds.scalarfield_algebra.ScalarFieldAlgebra`
1885
+ for a complete documentation.
1886
+
1887
+ OUTPUT:
1888
+
1889
+ - instance of
1890
+ :class:`~sage.manifolds.scalarfield_algebra.ScalarFieldAlgebra`
1891
+ representing the algebra `C^0(U)` of all scalar fields defined
1892
+ on `U` = ``self``
1893
+
1894
+ EXAMPLES:
1895
+
1896
+ Scalar algebra of a 3-dimensional open subset::
1897
+
1898
+ sage: M = Manifold(3, 'M', structure='topological')
1899
+ sage: U = M.open_subset('U')
1900
+ sage: CU = U.scalar_field_algebra() ; CU
1901
+ Algebra of scalar fields on the Open subset U of the 3-dimensional topological manifold M
1902
+ sage: CU.category()
1903
+ Join of Category of commutative algebras over Symbolic Ring and Category of homsets of topological spaces
1904
+ sage: CU.zero()
1905
+ Scalar field zero on the Open subset U of the 3-dimensional topological manifold M
1906
+
1907
+ The output is cached::
1908
+
1909
+ sage: U.scalar_field_algebra() is CU
1910
+ True
1911
+ """
1912
+ return self._scalar_field_algebra
1913
+
1914
+ def scalar_field(
1915
+ self, coord_expression=None, chart=None, name=None, latex_name=None
1916
+ ) -> ScalarField:
1917
+ r"""
1918
+ Define a scalar field on the manifold.
1919
+
1920
+ See :class:`~sage.manifolds.scalarfield.ScalarField` (or
1921
+ :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField`
1922
+ if the manifold is differentiable) for a complete documentation.
1923
+
1924
+ INPUT:
1925
+
1926
+ - ``coord_expression`` -- (default: ``None``) coordinate expression(s)
1927
+ of the scalar field; this can be either
1928
+
1929
+ * a single coordinate expression; if the argument ``chart`` is
1930
+ ``'all'``, this expression is set to all the charts defined
1931
+ on the open set; otherwise, the expression is set in the
1932
+ specific chart provided by the argument ``chart``
1933
+ * a dictionary of coordinate expressions, with the charts as keys
1934
+
1935
+ - ``chart`` -- (default: ``None``) chart defining the coordinates
1936
+ used in ``coord_expression`` when the latter is a single
1937
+ coordinate expression; if ``None``, the default chart of the
1938
+ open set is assumed; if ``chart=='all'``, ``coord_expression`` is
1939
+ assumed to be independent of the chart (constant scalar field)
1940
+
1941
+ - ``name`` -- (default: ``None``) name given to the scalar field
1942
+
1943
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
1944
+ scalar field; if ``None``, the LaTeX symbol is set to ``name``
1945
+
1946
+ If ``coord_expression`` is ``None`` or does not fully specified the
1947
+ scalar field, other coordinate expressions can be added subsequently
1948
+ by means of the methods
1949
+ :meth:`~sage.manifolds.scalarfield.ScalarField.add_expr`,
1950
+ :meth:`~sage.manifolds.scalarfield.ScalarField.add_expr_by_continuation`,
1951
+ or :meth:`~sage.manifolds.scalarfield.ScalarField.set_expr`
1952
+
1953
+ OUTPUT:
1954
+
1955
+ - instance of :class:`~sage.manifolds.scalarfield.ScalarField`
1956
+ (or of the subclass
1957
+ :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField`
1958
+ if the manifold is differentiable) representing the defined scalar
1959
+ field
1960
+
1961
+ EXAMPLES:
1962
+
1963
+ A scalar field defined by its coordinate expression in the open
1964
+ set's default chart::
1965
+
1966
+ sage: M = Manifold(3, 'M', structure='topological')
1967
+ sage: U = M.open_subset('U')
1968
+ sage: c_xyz.<x,y,z> = U.chart()
1969
+ sage: f = U.scalar_field(sin(x)*cos(y) + z, name='F'); f
1970
+ Scalar field F on the Open subset U of the 3-dimensional topological manifold M
1971
+ sage: f.display()
1972
+ F: U → ℝ
1973
+ (x, y, z) ↦ cos(y)*sin(x) + z
1974
+ sage: f.parent()
1975
+ Algebra of scalar fields on the Open subset U of the 3-dimensional topological manifold M
1976
+ sage: f in U.scalar_field_algebra()
1977
+ True
1978
+
1979
+ Equivalent definition with the chart specified::
1980
+
1981
+ sage: f = U.scalar_field(sin(x)*cos(y) + z, chart=c_xyz, name='F')
1982
+ sage: f.display()
1983
+ F: U → ℝ
1984
+ (x, y, z) ↦ cos(y)*sin(x) + z
1985
+
1986
+ Equivalent definition with a dictionary of coordinate expression(s)::
1987
+
1988
+ sage: f = U.scalar_field({c_xyz: sin(x)*cos(y) + z}, name='F')
1989
+ sage: f.display()
1990
+ F: U → ℝ
1991
+ (x, y, z) ↦ cos(y)*sin(x) + z
1992
+
1993
+ See the documentation of class
1994
+ :class:`~sage.manifolds.scalarfield.ScalarField` for more
1995
+ examples.
1996
+
1997
+ .. SEEALSO::
1998
+
1999
+ :meth:`constant_scalar_field`, :meth:`zero_scalar_field`,
2000
+ :meth:`one_scalar_field`
2001
+ """
2002
+ if isinstance(coord_expression, dict):
2003
+ # check validity of entry
2004
+ for chart in coord_expression:
2005
+ if not chart.domain().is_subset(self):
2006
+ raise ValueError("the {} is not defined ".format(chart) +
2007
+ "on some subset of the " + str(self))
2008
+ alg = self.scalar_field_algebra()
2009
+ return alg.element_class(alg, coord_expression=coord_expression,
2010
+ name=name, latex_name=latex_name, chart=chart)
2011
+
2012
+ def constant_scalar_field(self, value, name=None, latex_name=None):
2013
+ r"""
2014
+ Define a constant scalar field on the manifold.
2015
+
2016
+ INPUT:
2017
+
2018
+ - ``value`` -- constant value of the scalar field, either a numerical
2019
+ value or a symbolic expression not involving any chart coordinates
2020
+ - ``name`` -- (default: ``None``) name given to the scalar field
2021
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
2022
+ scalar field; if ``None``, the LaTeX symbol is set to ``name``
2023
+
2024
+ OUTPUT:
2025
+
2026
+ - instance of :class:`~sage.manifolds.scalarfield.ScalarField`
2027
+ representing the scalar field whose constant value is ``value``
2028
+
2029
+ EXAMPLES:
2030
+
2031
+ A constant scalar field on the 2-sphere::
2032
+
2033
+ sage: M = Manifold(2, 'M', structure='topological') # the 2-dimensional sphere S^2
2034
+ sage: U = M.open_subset('U') # complement of the North pole
2035
+ sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
2036
+ sage: V = M.open_subset('V') # complement of the South pole
2037
+ sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
2038
+ sage: M.declare_union(U,V) # S^2 is the union of U and V
2039
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)),
2040
+ ....: intersection_name='W',
2041
+ ....: restrictions1= x^2+y^2!=0,
2042
+ ....: restrictions2= u^2+v^2!=0)
2043
+ sage: uv_to_xy = xy_to_uv.inverse()
2044
+ sage: f = M.constant_scalar_field(-1) ; f
2045
+ Scalar field on the 2-dimensional topological manifold M
2046
+ sage: f.display()
2047
+ M → ℝ
2048
+ on U: (x, y) ↦ -1
2049
+ on V: (u, v) ↦ -1
2050
+
2051
+ We have::
2052
+
2053
+ sage: f.restrict(U) == U.constant_scalar_field(-1)
2054
+ True
2055
+ sage: M.constant_scalar_field(0) is M.zero_scalar_field()
2056
+ True
2057
+
2058
+ .. SEEALSO::
2059
+
2060
+ :meth:`zero_scalar_field`, :meth:`one_scalar_field`
2061
+ """
2062
+ if value == 0:
2063
+ return self.zero_scalar_field()
2064
+ alg = self.scalar_field_algebra()
2065
+ return alg.element_class(alg, coord_expression=value, name=name,
2066
+ latex_name=latex_name, chart='all')
2067
+
2068
+ def zero_scalar_field(self):
2069
+ r"""
2070
+ Return the zero scalar field defined on ``self``.
2071
+
2072
+ OUTPUT:
2073
+
2074
+ - a :class:`~sage.manifolds.scalarfield.ScalarField`
2075
+ representing the constant scalar field with value `0`
2076
+
2077
+ EXAMPLES::
2078
+
2079
+ sage: M = Manifold(2, 'M', structure='topological')
2080
+ sage: X.<x,y> = M.chart()
2081
+ sage: f = M.zero_scalar_field() ; f
2082
+ Scalar field zero on the 2-dimensional topological manifold M
2083
+ sage: f.display()
2084
+ zero: M → ℝ
2085
+ (x, y) ↦ 0
2086
+ sage: f.parent()
2087
+ Algebra of scalar fields on the 2-dimensional topological manifold M
2088
+ sage: f is M.scalar_field_algebra().zero()
2089
+ True
2090
+ """
2091
+ return self._zero_scalar_field
2092
+
2093
+ def one_scalar_field(self):
2094
+ r"""
2095
+ Return the constant scalar field with value the unit element
2096
+ of the base field of ``self``.
2097
+
2098
+ OUTPUT:
2099
+
2100
+ - a :class:`~sage.manifolds.scalarfield.ScalarField` representing
2101
+ the constant scalar field with value the unit element
2102
+ of the base field of ``self``
2103
+
2104
+ EXAMPLES::
2105
+
2106
+ sage: M = Manifold(2, 'M', structure='topological')
2107
+ sage: X.<x,y> = M.chart()
2108
+ sage: f = M.one_scalar_field(); f
2109
+ Scalar field 1 on the 2-dimensional topological manifold M
2110
+ sage: f.display()
2111
+ 1: M → ℝ
2112
+ (x, y) ↦ 1
2113
+ sage: f.parent()
2114
+ Algebra of scalar fields on the 2-dimensional topological manifold M
2115
+ sage: f is M.scalar_field_algebra().one()
2116
+ True
2117
+ """
2118
+ return self._one_scalar_field
2119
+
2120
+ class options(GlobalOptions):
2121
+ r"""
2122
+ Set and displays the options for manifolds. If no parameters
2123
+ are set, then the function returns a copy of the options dictionary.
2124
+
2125
+ The ``options`` to manifolds can be accessed as the method
2126
+ :obj:`Manifold.options`.
2127
+
2128
+ @OPTIONS@
2129
+
2130
+ EXAMPLES::
2131
+
2132
+ sage: M = Manifold(2, 'M', structure='topological')
2133
+ sage: X.<x,y> = M.chart()
2134
+ sage: g = function('g')(x, y)
2135
+
2136
+ For coordinate functions, the display is more "textbook" like::
2137
+
2138
+ sage: f = X.function(diff(g, x) + diff(g, y))
2139
+ sage: f
2140
+ d(g)/dx + d(g)/dy
2141
+ sage: latex(f)
2142
+ \frac{\partial\,g}{\partial x} + \frac{\partial\,g}{\partial y}
2143
+
2144
+ One can switch to Pynac notation by changing ``textbook_output``
2145
+ to ``False``::
2146
+
2147
+ sage: Manifold.options.textbook_output=False
2148
+ sage: f
2149
+ diff(g(x, y), x) + diff(g(x, y), y)
2150
+ sage: latex(f)
2151
+ \frac{\partial}{\partial x}g\left(x, y\right)
2152
+ + \frac{\partial}{\partial y}g\left(x, y\right)
2153
+ sage: Manifold.options._reset()
2154
+
2155
+ If there is a clear understanding that `u` and `v` are functions of
2156
+ `(x,y)`, the explicit mention of the latter can be cumbersome in lengthy
2157
+ tensor expressions::
2158
+
2159
+ sage: f = X.function(function('u')(x, y) * function('v')(x, y))
2160
+ sage: f
2161
+ u(x, y)*v(x, y)
2162
+
2163
+ We can switch it off by::
2164
+
2165
+ sage: M.options.omit_function_arguments=True
2166
+ sage: f
2167
+ u*v
2168
+ sage: M.options._reset()
2169
+ """
2170
+ NAME = 'manifolds'
2171
+ module = 'sage.manifolds.manifold'
2172
+ option_class = 'TopologicalManifold'
2173
+ textbook_output = dict(default=True,
2174
+ description='textbook-like output instead of the Pynac output for derivatives',
2175
+ checker=lambda x: isinstance(x, bool))
2176
+ omit_function_arguments = dict(default=False,
2177
+ description='Determine whether the arguments of symbolic functions are printed',
2178
+ checker=lambda x: isinstance(x, bool))
2179
+
2180
+ def _Hom_(self, other, category=None):
2181
+ r"""
2182
+ Construct the set of morphisms (i.e. continuous maps)
2183
+ ``self`` to ``other``.
2184
+
2185
+ INPUT:
2186
+
2187
+ - ``other`` -- an open subset of some topological manifold over the
2188
+ same field as ``self``
2189
+ - ``category`` -- (default: ``None``) not used here (to ensure
2190
+ compatibility with generic hook ``_Hom_``)
2191
+
2192
+ OUTPUT:
2193
+
2194
+ - the homset `\mathrm{Hom}(U,V)`, where `U` is ``self``
2195
+ and `V` is ``other``
2196
+
2197
+ .. SEEALSO::
2198
+
2199
+ For more documentation, see
2200
+ :class:`~sage.manifolds.manifold_homset.TopologicalManifoldHomset`.
2201
+
2202
+ EXAMPLES::
2203
+
2204
+ sage: M = Manifold(2, 'M', structure='topological')
2205
+ sage: N = Manifold(3, 'N', structure='topological')
2206
+ sage: H = M._Hom_(N); H
2207
+ Set of Morphisms from 2-dimensional topological manifold M to
2208
+ 3-dimensional topological manifold N in Category of manifolds over
2209
+ Real Field with 53 bits of precision
2210
+
2211
+ The result is cached::
2212
+
2213
+ sage: H is Hom(M, N)
2214
+ True
2215
+ """
2216
+ return self._structure.homset(self, other)
2217
+
2218
+ def continuous_map(self, codomain, coord_functions=None, chart1=None,
2219
+ chart2=None, name=None, latex_name=None):
2220
+ r"""
2221
+ Define a continuous map from ``self`` to ``codomain``.
2222
+
2223
+ INPUT:
2224
+
2225
+ - ``codomain`` -- :class:`TopologicalManifold`; the map's codomain
2226
+ - ``coord_functions`` -- (default: ``None``) if not ``None``,
2227
+ must be either
2228
+
2229
+ - (i) a dictionary of the coordinate expressions (as lists
2230
+ (or tuples) of the coordinates of the image expressed in
2231
+ terms of the coordinates of the considered point) with the
2232
+ pairs of charts ``(chart1, chart2)`` as keys (``chart1`` being
2233
+ a chart on ``self`` and ``chart2`` a chart on ``codomain``);
2234
+ - (ii) a single coordinate expression in a given pair of charts, the
2235
+ latter being provided by the arguments ``chart1`` and ``chart2``;
2236
+
2237
+ in both cases, if the dimension of the codomain is `1`, a single
2238
+ coordinate expression can be passed instead of a tuple with
2239
+ a single element
2240
+ - ``chart1`` -- (default: ``None``; used only in case (ii) above)
2241
+ chart on ``self`` defining the start coordinates involved in
2242
+ ``coord_functions`` for case (ii); if ``None``, the coordinates
2243
+ are assumed to refer to the default chart of ``self``
2244
+ - ``chart2`` -- (default: ``None``; used only in case (ii) above)
2245
+ chart on ``codomain`` defining the target coordinates involved in
2246
+ ``coord_functions`` for case (ii); if ``None``, the coordinates
2247
+ are assumed to refer to the default chart of ``codomain``
2248
+ - ``name`` -- (default: ``None``) name given to the continuous map
2249
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
2250
+ continuous map; if ``None``, the LaTeX symbol is set to ``name``
2251
+
2252
+ OUTPUT:
2253
+
2254
+ - the continuous map as an instance of
2255
+ :class:`~sage.manifolds.continuous_map.ContinuousMap`
2256
+
2257
+ EXAMPLES:
2258
+
2259
+ A continuous map between an open subset of `S^2` covered by regular
2260
+ spherical coordinates and `\RR^3`::
2261
+
2262
+ sage: M = Manifold(2, 'S^2', structure='topological')
2263
+ sage: U = M.open_subset('U')
2264
+ sage: c_spher.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
2265
+ sage: N = Manifold(3, 'R^3', latex_name=r'\RR^3', structure='topological')
2266
+ sage: c_cart.<x,y,z> = N.chart() # Cartesian coord. on R^3
2267
+ sage: Phi = U.continuous_map(N, (sin(th)*cos(ph), sin(th)*sin(ph), cos(th)),
2268
+ ....: name='Phi', latex_name=r'\Phi')
2269
+ sage: Phi
2270
+ Continuous map Phi from the Open subset U of the 2-dimensional topological manifold S^2 to the 3-dimensional topological manifold R^3
2271
+
2272
+ The same definition, but with a dictionary with pairs of charts as
2273
+ keys (case (i) above)::
2274
+
2275
+ sage: Phi1 = U.continuous_map(N,
2276
+ ....: {(c_spher, c_cart): (sin(th)*cos(ph), sin(th)*sin(ph), cos(th))},
2277
+ ....: name='Phi', latex_name=r'\Phi')
2278
+ sage: Phi1 == Phi
2279
+ True
2280
+
2281
+ The continuous map acting on a point::
2282
+
2283
+ sage: p = U.point((pi/2, pi)) ; p
2284
+ Point on the 2-dimensional topological manifold S^2
2285
+ sage: Phi(p)
2286
+ Point on the 3-dimensional topological manifold R^3
2287
+ sage: Phi(p).coord(c_cart)
2288
+ (-1, 0, 0)
2289
+ sage: Phi1(p) == Phi(p)
2290
+ True
2291
+
2292
+ TESTS::
2293
+
2294
+ sage: M = Manifold(2, 'M', structure='topological')
2295
+ sage: M.continuous_map(ZZ)
2296
+ Traceback (most recent call last):
2297
+ ...
2298
+ ValueError: Integer Ring is not a manifold
2299
+ over Real Field with 53 bits of precision
2300
+
2301
+ .. SEEALSO::
2302
+
2303
+ See :class:`~sage.manifolds.continuous_map.ContinuousMap`
2304
+ for the complete documentation and more examples.
2305
+
2306
+ .. TODO::
2307
+
2308
+ Allow the construction of continuous maps from ``self`` to the
2309
+ base field (considered as a trivial 1-dimensional manifold).
2310
+ """
2311
+ if (not isinstance(codomain, TopologicalManifold)
2312
+ or codomain.base_field() != self.base_field()):
2313
+ raise ValueError("{} is not a manifold over {}".format(codomain, self.base_field()))
2314
+ homset = Hom(self, codomain)
2315
+ if coord_functions is None:
2316
+ coord_functions = {}
2317
+ if not isinstance(coord_functions, dict):
2318
+ # Turn coord_functions into a dictionary:
2319
+ if chart1 is None:
2320
+ chart1 = self._def_chart
2321
+ elif chart1 not in self._atlas:
2322
+ raise ValueError("{} is not a chart ".format(chart1) +
2323
+ "defined on the {}".format(self))
2324
+ if chart2 is None:
2325
+ chart2 = codomain._def_chart
2326
+ elif chart2 not in codomain._atlas:
2327
+ raise ValueError("{} is not a chart ".format(chart2) +
2328
+ " defined on the {}".format(codomain))
2329
+ coord_functions = {(chart1, chart2): coord_functions}
2330
+ return homset(coord_functions, name=name, latex_name=latex_name)
2331
+
2332
+ def homeomorphism(self, codomain, coord_functions=None, chart1=None,
2333
+ chart2=None, name=None, latex_name=None):
2334
+ r"""
2335
+ Define a homeomorphism between the current manifold and another one.
2336
+
2337
+ See :class:`~sage.manifolds.continuous_map.ContinuousMap` for a
2338
+ complete documentation.
2339
+
2340
+ INPUT:
2341
+
2342
+ - ``codomain`` -- :class:`TopologicalManifold`; codomain of
2343
+ the homeomorphism
2344
+ - ``coord_functions`` -- (default: ``None``) if not ``None``,
2345
+ must be either
2346
+
2347
+ - (i) a dictionary of the coordinate expressions (as lists
2348
+ (or tuples) of the coordinates of the image expressed in
2349
+ terms of the coordinates of the considered point) with the
2350
+ pairs of charts ``(chart1, chart2)`` as keys (``chart1`` being
2351
+ a chart on ``self`` and ``chart2`` a chart on ``codomain``);
2352
+ - (ii) a single coordinate expression in a given pair of charts, the
2353
+ latter being provided by the arguments ``chart1`` and ``chart2``;
2354
+
2355
+ in both cases, if the dimension of the codomain is `1`, a single
2356
+ coordinate expression can be passed instead of a tuple with
2357
+ a single element
2358
+ - ``chart1`` -- (default: ``None``; used only in case (ii) above)
2359
+ chart on ``self`` defining the start coordinates involved in
2360
+ ``coord_functions`` for case (ii); if ``None``, the coordinates
2361
+ are assumed to refer to the default chart of ``self``
2362
+ - ``chart2`` -- (default: ``None``; used only in case (ii) above)
2363
+ chart on ``codomain`` defining the target coordinates involved in
2364
+ ``coord_functions`` for case (ii); if ``None``, the coordinates
2365
+ are assumed to refer to the default chart of ``codomain``
2366
+ - ``name`` -- (default: ``None``) name given to the homeomorphism
2367
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
2368
+ homeomorphism; if ``None``, the LaTeX symbol is set to ``name``
2369
+
2370
+ OUTPUT:
2371
+
2372
+ - the homeomorphism, as an instance of
2373
+ :class:`~sage.manifolds.continuous_map.ContinuousMap`
2374
+
2375
+ EXAMPLES:
2376
+
2377
+ Homeomorphism between the open unit disk in `\RR^2` and `\RR^2`::
2378
+
2379
+ sage: forget() # for doctests only
2380
+ sage: M = Manifold(2, 'M', structure='topological') # the open unit disk
2381
+ sage: c_xy.<x,y> = M.chart('x:(-1,1) y:(-1,1)', coord_restrictions=lambda x,y: x^2+y^2<1)
2382
+ ....: # Cartesian coord on M
2383
+ sage: N = Manifold(2, 'N', structure='topological') # R^2
2384
+ sage: c_XY.<X,Y> = N.chart() # canonical coordinates on R^2
2385
+ sage: Phi = M.homeomorphism(N, [x/sqrt(1-x^2-y^2), y/sqrt(1-x^2-y^2)],
2386
+ ....: name='Phi', latex_name=r'\Phi')
2387
+ sage: Phi
2388
+ Homeomorphism Phi from the 2-dimensional topological manifold M to
2389
+ the 2-dimensional topological manifold N
2390
+ sage: Phi.display()
2391
+ Phi: M → N
2392
+ (x, y) ↦ (X, Y) = (x/sqrt(-x^2 - y^2 + 1), y/sqrt(-x^2 - y^2 + 1))
2393
+
2394
+ The inverse homeomorphism::
2395
+
2396
+ sage: Phi^(-1)
2397
+ Homeomorphism Phi^(-1) from the 2-dimensional topological
2398
+ manifold N to the 2-dimensional topological manifold M
2399
+ sage: (Phi^(-1)).display()
2400
+ Phi^(-1): N → M
2401
+ (X, Y) ↦ (x, y) = (X/sqrt(X^2 + Y^2 + 1), Y/sqrt(X^2 + Y^2 + 1))
2402
+
2403
+ See the documentation of
2404
+ :class:`~sage.manifolds.continuous_map.ContinuousMap` for more
2405
+ examples.
2406
+ """
2407
+ homset = Hom(self, codomain)
2408
+ if coord_functions is None:
2409
+ coord_functions = {}
2410
+ if not isinstance(coord_functions, dict):
2411
+ # Turn coord_functions into a dictionary:
2412
+ if chart1 is None:
2413
+ chart1 = self._def_chart
2414
+ elif chart1 not in self._atlas:
2415
+ raise ValueError("{} is not a chart ".format(chart1) +
2416
+ "defined on the {}".format(self))
2417
+ if chart2 is None:
2418
+ chart2 = codomain._def_chart
2419
+ elif chart2 not in codomain._atlas:
2420
+ raise ValueError("{} is not a chart ".format(chart2) +
2421
+ " defined on the {}".format(codomain))
2422
+ coord_functions = {(chart1, chart2): coord_functions}
2423
+ return homset(coord_functions, name=name, latex_name=latex_name,
2424
+ is_isomorphism=True)
2425
+
2426
+ @overload
2427
+ def identity_map(self: TopologicalManifold) -> ContinuousMap: ...
2428
+ @overload
2429
+ def identity_map(self: DifferentiableManifold) -> DiffMap: ...
2430
+ @cached_method
2431
+ def identity_map(self):
2432
+ r"""
2433
+ Identity map of ``self``.
2434
+
2435
+ The identity map of a topological manifold `M` is the trivial
2436
+ homeomorphism:
2437
+
2438
+ .. MATH::
2439
+
2440
+ \begin{array}{cccc}
2441
+ \mathrm{Id}_M: & M & \longrightarrow & M \\
2442
+ & p & \longmapsto & p
2443
+ \end{array}
2444
+
2445
+ OUTPUT:
2446
+
2447
+ - the identity map as an instance of
2448
+ :class:`~sage.manifolds.continuous_map.ContinuousMap`
2449
+
2450
+ EXAMPLES:
2451
+
2452
+ Identity map of a complex manifold::
2453
+
2454
+ sage: M = Manifold(2, 'M', structure='topological', field='complex')
2455
+ sage: X.<x,y> = M.chart()
2456
+ sage: id = M.identity_map(); id
2457
+ Identity map Id_M of the Complex 2-dimensional topological manifold M
2458
+ sage: id.parent()
2459
+ Set of Morphisms from Complex 2-dimensional topological manifold M
2460
+ to Complex 2-dimensional topological manifold M in Category of
2461
+ manifolds over Complex Field with 53 bits of precision
2462
+ sage: id.display()
2463
+ Id_M: M → M
2464
+ (x, y) ↦ (x, y)
2465
+
2466
+ The identity map acting on a point::
2467
+
2468
+ sage: p = M((1+I, 3-I), name='p'); p
2469
+ Point p on the Complex 2-dimensional topological manifold M
2470
+ sage: id(p)
2471
+ Point p on the Complex 2-dimensional topological manifold M
2472
+ sage: id(p) == p
2473
+ True
2474
+
2475
+ .. SEEALSO::
2476
+
2477
+ See :class:`~sage.manifolds.continuous_map.ContinuousMap`
2478
+ for the complete documentation.
2479
+ """
2480
+ return Hom(self, self).one()
2481
+
2482
+ def set_calculus_method(self, method):
2483
+ r"""
2484
+ Set the calculus method to be used for coordinate computations on this
2485
+ manifold.
2486
+
2487
+ The provided method is transmitted to all coordinate charts defined on
2488
+ the manifold.
2489
+
2490
+ INPUT:
2491
+
2492
+ - ``method`` -- string specifying the method to be used for
2493
+ coordinate computations on this manifold; one of
2494
+
2495
+ - ``'SR'``: Sage's default symbolic engine (Symbolic Ring)
2496
+ - ``'sympy'``: SymPy
2497
+
2498
+ EXAMPLES:
2499
+
2500
+ Let us consider a scalar field ``f`` on a 2-dimensional manifold::
2501
+
2502
+ sage: M = Manifold(2, 'M', structure='topological')
2503
+ sage: X.<x,y> = M.chart()
2504
+ sage: f = M.scalar_field(x^2 + cos(y)*sin(x), name='F')
2505
+
2506
+ By default, the coordinate expression of ``f`` returned by
2507
+ :meth:`~sage.manifolds.scalarfield.ScalarField.expr` is a Sage's
2508
+ symbolic expression::
2509
+
2510
+ sage: f.expr()
2511
+ x^2 + cos(y)*sin(x)
2512
+ sage: type(f.expr())
2513
+ <class 'sage.symbolic.expression.Expression'>
2514
+ sage: parent(f.expr())
2515
+ Symbolic Ring
2516
+ sage: f.display()
2517
+ F: M → ℝ
2518
+ (x, y) ↦ x^2 + cos(y)*sin(x)
2519
+
2520
+ If we change the calculus method to SymPy, it becomes a SymPy object
2521
+ instead::
2522
+
2523
+ sage: M.set_calculus_method('sympy')
2524
+ sage: f.expr()
2525
+ x**2 + sin(x)*cos(y)
2526
+ sage: type(f.expr())
2527
+ <class 'sympy.core.add.Add'>
2528
+ sage: parent(f.expr())
2529
+ <class 'sympy.core.add.Add'>
2530
+ sage: f.display()
2531
+ F: M → ℝ
2532
+ (x, y) ↦ x**2 + sin(x)*cos(y)
2533
+
2534
+ Back to the Symbolic Ring::
2535
+
2536
+ sage: M.set_calculus_method('SR')
2537
+ sage: f.display()
2538
+ F: M → ℝ
2539
+ (x, y) ↦ x^2 + cos(y)*sin(x)
2540
+
2541
+ The calculus method chosen via ``set_calculus_method()`` applies to any
2542
+ chart defined subsequently on the manifold::
2543
+
2544
+ sage: M.set_calculus_method('sympy')
2545
+ sage: Y.<u,v> = M.chart() # a new chart
2546
+ sage: Y.calculus_method()
2547
+ Available calculus methods (* = current):
2548
+ - SR (default)
2549
+ - sympy (*)
2550
+
2551
+ .. SEEALSO::
2552
+
2553
+ :meth:`~sage.manifolds.chart.Chart.calculus_method` for a
2554
+ control of the calculus method chart by chart
2555
+ """
2556
+ self._calculus_method = method
2557
+ for chart in self._atlas:
2558
+ chart.calculus_method().set(method)
2559
+
2560
+ def set_simplify_function(self, simplifying_func, method=None):
2561
+ r"""
2562
+ Set the simplifying function associated to a given coordinate
2563
+ calculus method in all the charts defined on ``self``.
2564
+
2565
+ INPUT:
2566
+
2567
+ - ``simplifying_func`` -- either the string ``'default'`` for restoring
2568
+ the default simplifying function or a function ``f`` of a single
2569
+ argument ``expr`` such that ``f(expr)`` returns an object of the same
2570
+ type as ``expr`` (hopefully the simplified version of ``expr``), this
2571
+ type being
2572
+
2573
+ - :class:`~sage.symbolic.expression.Expression` if ``method`` = ``'SR'``
2574
+ - a SymPy type if ``method`` = ``'sympy'``
2575
+
2576
+ - ``method`` -- (default: ``None``) string defining the calculus method
2577
+ for which ``simplifying_func`` is provided; must be one of
2578
+
2579
+ - ``'SR'``: Sage's default symbolic engine (Symbolic Ring)
2580
+ - ``'sympy'``: SymPy
2581
+ - ``None``: the currently active calculus method on each chart is
2582
+ assumed
2583
+
2584
+ .. SEEALSO::
2585
+
2586
+ :meth:`~sage.manifolds.chart.Chart.calculus_method`
2587
+ and :meth:`sage.manifolds.calculus_method.CalculusMethod.simplify`
2588
+ for a control of the calculus method chart by chart
2589
+
2590
+ EXAMPLES:
2591
+
2592
+ Les us add two scalar fields on a 2-dimensional manifold::
2593
+
2594
+ sage: M = Manifold(2, 'M', structure='topological')
2595
+ sage: X.<x,y> = M.chart()
2596
+ sage: f = M.scalar_field((x+y)^2 + cos(x)^2)
2597
+ sage: g = M.scalar_field(-x^2-2*x*y-y^2 + sin(x)^2)
2598
+ sage: f.expr()
2599
+ (x + y)^2 + cos(x)^2
2600
+ sage: g.expr()
2601
+ -x^2 - 2*x*y - y^2 + sin(x)^2
2602
+ sage: s = f + g
2603
+
2604
+ The outcome is automatically simplified::
2605
+
2606
+ sage: s.expr()
2607
+ 1
2608
+
2609
+ The simplification is performed thanks to the default simplifying
2610
+ function on chart ``X``, which is
2611
+ :func:`~sage.manifolds.utilities.simplify_chain_real` in the present
2612
+ case (real manifold and ``SR`` calculus)::
2613
+
2614
+ sage: X.calculus_method().simplify_function() is \
2615
+ ....: sage.manifolds.utilities.simplify_chain_real
2616
+ True
2617
+
2618
+ Let us change it to the generic Sage function
2619
+ :func:`~sage.calculus.functional.simplify`::
2620
+
2621
+ sage: M.set_simplify_function(simplify)
2622
+ sage: X.calculus_method().simplify_function() is simplify
2623
+ True
2624
+
2625
+ :func:`~sage.calculus.functional.simplify` is faster, but it does not
2626
+ do much::
2627
+
2628
+ sage: s = f + g
2629
+ sage: s.expr()
2630
+ (x + y)^2 - x^2 - 2*x*y - y^2 + cos(x)^2 + sin(x)^2
2631
+
2632
+ We can replaced it by any user defined function, for instance::
2633
+
2634
+ sage: def simpl_trig(a):
2635
+ ....: return a.simplify_trig()
2636
+ sage: M.set_simplify_function(simpl_trig)
2637
+ sage: s = f + g
2638
+ sage: s.expr()
2639
+ 1
2640
+
2641
+ The default simplifying function is restored via::
2642
+
2643
+ sage: M.set_simplify_function('default')
2644
+
2645
+ Then we are back to::
2646
+
2647
+ sage: X.calculus_method().simplify_function() is \
2648
+ ....: sage.manifolds.utilities.simplify_chain_real
2649
+ True
2650
+
2651
+ Thanks to the argument ``method``, one can specify a simplifying
2652
+ function for a calculus method distinct from the current one. For
2653
+ instance, let us define a simplifying function for SymPy (note that
2654
+ ``trigsimp()`` is a SymPy method only)::
2655
+
2656
+ sage: def simpl_trig_sympy(a):
2657
+ ....: return a.trigsimp()
2658
+ sage: M.set_simplify_function(simpl_trig_sympy, method='sympy')
2659
+
2660
+ Then, it becomes active as soon as we change the calculus engine to
2661
+ SymPy::
2662
+
2663
+ sage: M.set_calculus_method('sympy')
2664
+ sage: X.calculus_method().simplify_function() is simpl_trig_sympy
2665
+ True
2666
+
2667
+ We have then::
2668
+
2669
+ sage: s = f + g
2670
+ sage: s.expr()
2671
+ 1
2672
+ sage: type(s.expr())
2673
+ <class 'sympy.core.numbers.One'>
2674
+ """
2675
+ for chart in self._atlas:
2676
+ chart.calculus_method().set_simplify_function(simplifying_func,
2677
+ method=method)
2678
+
2679
+
2680
+ ###########################################################
2681
+ # Constructor function
2682
+
2683
+ _manifold_id = Integer(0)
2684
+
2685
+
2686
+ def Manifold(
2687
+ dim: int,
2688
+ name: Optional[str],
2689
+ latex_name: Optional[str] = None,
2690
+ field: str = "real",
2691
+ structure: Optional[str] = None,
2692
+ start_index: int = 0,
2693
+ **extra_kwds,
2694
+ ) -> Union[TopologicalManifold, DifferentiableManifold]:
2695
+ r"""
2696
+ Construct a manifold of a given type over a topological field.
2697
+
2698
+ Given a topological field `K` (in most applications, `K = \RR` or
2699
+ `K = \CC`) and a nonnegative integer `n`, a *topological manifold of
2700
+ dimension* `n` *over K* is a topological space `M` such that
2701
+
2702
+ - `M` is a Hausdorff space,
2703
+ - `M` is second countable, and
2704
+ - every point in `M` has a neighborhood homeomorphic to `K^n`.
2705
+
2706
+ A *real manifold* is a manifold over `\RR`. A *differentiable* (resp.
2707
+ *smooth*, resp. *analytic*) *manifold* is a manifold such that all
2708
+ transition maps are *differentiable* (resp. *smooth*, resp. *analytic*). A
2709
+ *pseudo-Riemannian manifold* is a real differentiable manifold equipped
2710
+ with a metric tensor `g` (i.e. a field of non-degenerate symmetric bilinear
2711
+ forms), with the two subcases of *Riemannian manifold* (`g`
2712
+ positive-definite) and *Lorentzian manifold* (`g` has signature `n-2` or
2713
+ `2-n`).
2714
+
2715
+ INPUT:
2716
+
2717
+ - ``dim`` -- positive integer; dimension of the manifold
2718
+ - ``name`` -- string; name (symbol) given to the manifold
2719
+ - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to
2720
+ denote the manifold; if none are provided, it is set to ``name``
2721
+ - ``field`` -- (default: ``'real'``) field `K` on which the
2722
+ manifold is defined; allowed values are
2723
+
2724
+ - ``'real'`` or an object of type ``RealField`` (e.g. ``RR``) for a
2725
+ manifold over `\RR`
2726
+ - ``'complex'`` or an object of type ``ComplexField`` (e.g. ``CC``)
2727
+ for a manifold over `\CC`
2728
+ - an object in the category of topological fields (see
2729
+ :class:`~sage.categories.fields.Fields` and
2730
+ :class:`~sage.categories.topological_spaces.TopologicalSpaces`)
2731
+ for other types of manifolds
2732
+
2733
+ - ``structure`` -- (default: ``'smooth'``) to specify the structure or
2734
+ type of manifold; allowed values are
2735
+
2736
+ - ``'topological'`` or ``'top'`` for a topological manifold
2737
+ - ``'differentiable'`` or ``'diff'`` for a differentiable manifold
2738
+ - ``'smooth'`` for a smooth manifold
2739
+ - ``'analytic'`` for an analytic manifold
2740
+ - ``'pseudo-Riemannian'`` for a real differentiable manifold equipped
2741
+ with a pseudo-Riemannian metric; the signature is specified via the
2742
+ keyword argument ``signature`` (see below)
2743
+ - ``'Riemannian'`` for a real differentiable manifold equipped with a
2744
+ Riemannian (i.e. positive definite) metric
2745
+ - ``'Lorentzian'`` for a real differentiable manifold equipped with a
2746
+ Lorentzian metric; the signature convention is specified by the
2747
+ keyword argument ``signature='positive'`` (default) or ``'negative'``
2748
+
2749
+ - ``start_index`` -- (default: 0) integer; lower value of the range of
2750
+ indices used for "indexed objects" on the manifold, e.g. coordinates
2751
+ in a chart
2752
+ - ``extra_kwds`` -- keywords meaningful only for some specific types
2753
+ of manifolds:
2754
+
2755
+ - ``diff_degree`` -- (only for differentiable manifolds; default:
2756
+ ``infinity``): the degree of differentiability
2757
+ - ``ambient`` -- (only to construct a submanifold): the ambient manifold
2758
+ - ``metric_name`` -- (only for pseudo-Riemannian manifolds; default:
2759
+ ``'g'``) string; name (symbol) given to the metric
2760
+ - ``metric_latex_name`` -- (only for pseudo-Riemannian manifolds;
2761
+ default: ``None``) string; LaTeX symbol to denote the metric; if none
2762
+ is provided, the symbol is set to ``metric_name``
2763
+ - ``signature`` -- (only for pseudo-Riemannian manifolds; default:
2764
+ ``None``) signature `S` of the metric as a single integer:
2765
+ `S = n_+ - n_-`, where `n_+` (resp. `n_-`) is the number of positive
2766
+ terms (resp. negative terms) in any diagonal writing of the
2767
+ metric components; if ``signature`` is not provided, `S` is set to the
2768
+ manifold's dimension (Riemannian signature); for Lorentzian manifolds
2769
+ the values ``signature='positive'`` (default) or
2770
+ ``signature='negative'`` are allowed to indicate the chosen signature
2771
+ convention.
2772
+
2773
+ OUTPUT:
2774
+
2775
+ - a manifold of the specified type, as an instance of
2776
+ :class:`~sage.manifolds.manifold.TopologicalManifold` or one of its
2777
+ subclasses
2778
+ :class:`~sage.manifolds.differentiable.manifold.DifferentiableManifold`
2779
+ or
2780
+ :class:`~sage.manifolds.differentiable.pseudo_riemannian.PseudoRiemannianManifold`,
2781
+ or, if the keyword ``ambient`` is used, one of the subclasses
2782
+ :class:`~sage.manifolds.topological_submanifold.TopologicalSubmanifold`,
2783
+ :class:`~sage.manifolds.differentiable.differentiable_submanifold.DifferentiableSubmanifold`,
2784
+ or
2785
+ :class:`~sage.manifolds.differentiable.pseudo_riemannian_submanifold.PseudoRiemannianSubmanifold`.
2786
+
2787
+ EXAMPLES:
2788
+
2789
+ A 3-dimensional real topological manifold::
2790
+
2791
+ sage: M = Manifold(3, 'M', structure='topological'); M
2792
+ 3-dimensional topological manifold M
2793
+
2794
+ Given the default value of the parameter ``field``, the above is
2795
+ equivalent to::
2796
+
2797
+ sage: M = Manifold(3, 'M', structure='topological', field='real'); M
2798
+ 3-dimensional topological manifold M
2799
+
2800
+ A complex topological manifold::
2801
+
2802
+ sage: M = Manifold(3, 'M', structure='topological', field='complex'); M
2803
+ Complex 3-dimensional topological manifold M
2804
+
2805
+ A topological manifold over `\QQ`::
2806
+
2807
+ sage: M = Manifold(3, 'M', structure='topological', field=QQ); M
2808
+ 3-dimensional topological manifold M over the Rational Field
2809
+
2810
+ A 3-dimensional real differentiable manifold of class `C^4`::
2811
+
2812
+ sage: M = Manifold(3, 'M', field='real', structure='differentiable',
2813
+ ....: diff_degree=4); M
2814
+ 3-dimensional differentiable manifold M
2815
+
2816
+ Since the default value of the parameter ``field`` is ``'real'``, the above
2817
+ is equivalent to::
2818
+
2819
+ sage: M = Manifold(3, 'M', structure='differentiable', diff_degree=4)
2820
+ sage: M
2821
+ 3-dimensional differentiable manifold M
2822
+ sage: M.base_field_type()
2823
+ 'real'
2824
+
2825
+ A 3-dimensional real smooth manifold::
2826
+
2827
+ sage: M = Manifold(3, 'M', structure='differentiable', diff_degree=+oo)
2828
+ sage: M
2829
+ 3-dimensional differentiable manifold M
2830
+
2831
+ Instead of ``structure='differentiable', diff_degree=+oo``, it suffices to
2832
+ use ``structure='smooth'`` to get the same result::
2833
+
2834
+ sage: M = Manifold(3, 'M', structure='smooth'); M
2835
+ 3-dimensional differentiable manifold M
2836
+ sage: M.diff_degree()
2837
+ +Infinity
2838
+
2839
+ Actually, since ``'smooth'`` is the default value of the parameter
2840
+ ``structure``, the creation of a real smooth manifold can be shortened to::
2841
+
2842
+ sage: M = Manifold(3, 'M'); M
2843
+ 3-dimensional differentiable manifold M
2844
+ sage: M.diff_degree()
2845
+ +Infinity
2846
+
2847
+ Other parameters can change the default of the parameter ``structure``::
2848
+
2849
+ sage: M = Manifold(3, 'M', diff_degree=0); M
2850
+ 3-dimensional topological manifold M
2851
+ sage: M = Manifold(3, 'M', diff_degree=2); M
2852
+ 3-dimensional differentiable manifold M
2853
+ sage: M = Manifold(3, 'M', metric_name='g'); M
2854
+ 3-dimensional Riemannian manifold M
2855
+
2856
+ For a complex smooth manifold, we have to set the parameter ``field``::
2857
+
2858
+ sage: M = Manifold(3, 'M', field='complex'); M
2859
+ 3-dimensional complex manifold M
2860
+ sage: M.diff_degree()
2861
+ +Infinity
2862
+
2863
+ Submanifolds are constructed by means of the keyword ``ambient``::
2864
+
2865
+ sage: N = Manifold(2, 'N', field='complex', ambient=M); N
2866
+ 2-dimensional differentiable submanifold N immersed in the
2867
+ 3-dimensional complex manifold M
2868
+
2869
+ The immersion `N\to M` has to be specified in a second stage, via the
2870
+ method
2871
+ :meth:`~sage.manifolds.topological_submanifold.TopologicalSubmanifold.set_immersion`
2872
+ or
2873
+ :meth:`~sage.manifolds.topological_submanifold.TopologicalSubmanifold.set_embedding`.
2874
+
2875
+ For more detailed examples, see the documentation of
2876
+ :class:`~sage.manifolds.manifold.TopologicalManifold`,
2877
+ :class:`~sage.manifolds.differentiable.manifold.DifferentiableManifold`
2878
+ and
2879
+ :class:`~sage.manifolds.differentiable.pseudo_riemannian.PseudoRiemannianManifold`,
2880
+ or the documentation of
2881
+ :class:`~sage.manifolds.topological_submanifold.TopologicalSubmanifold`,
2882
+ :class:`~sage.manifolds.differentiable.differentiable_submanifold.DifferentiableSubmanifold`
2883
+ and
2884
+ :class:`~sage.manifolds.differentiable.pseudo_riemannian_submanifold.PseudoRiemannianSubmanifold`
2885
+ for submanifolds.
2886
+
2887
+ .. RUBRIC:: Uniqueness of manifold objects
2888
+
2889
+ Suppose we construct a manifold named `M`::
2890
+
2891
+ sage: M = Manifold(2, 'M', structure='topological')
2892
+ sage: X.<x,y> = M.chart()
2893
+
2894
+ At some point, we change our mind and would like to restart with a new
2895
+ manifold, using the same name `M` and keeping the previous manifold for
2896
+ reference::
2897
+
2898
+ sage: M_old = M # for reference
2899
+ sage: M = Manifold(2, 'M', structure='topological')
2900
+
2901
+ This results in a brand new object::
2902
+
2903
+ sage: M.atlas()
2904
+ []
2905
+
2906
+ The object ``M_old`` is intact::
2907
+
2908
+ sage: M_old.atlas()
2909
+ [Chart (M, (x, y))]
2910
+
2911
+ Both objects have the same display::
2912
+
2913
+ sage: M
2914
+ 2-dimensional topological manifold M
2915
+ sage: M_old
2916
+ 2-dimensional topological manifold M
2917
+
2918
+ but they are different::
2919
+
2920
+ sage: M != M_old
2921
+ True
2922
+
2923
+ Let us introduce a chart on ``M``, using the same coordinate symbols
2924
+ as for ``M_old``::
2925
+
2926
+ sage: X.<x,y> = M.chart()
2927
+
2928
+ The charts are displayed in the same way::
2929
+
2930
+ sage: M.atlas()
2931
+ [Chart (M, (x, y))]
2932
+ sage: M_old.atlas()
2933
+ [Chart (M, (x, y))]
2934
+
2935
+ but they are actually different::
2936
+
2937
+ sage: M.atlas()[0] != M_old.atlas()[0]
2938
+ True
2939
+
2940
+ Moreover, the two manifolds ``M`` and ``M_old`` are still considered
2941
+ distinct::
2942
+
2943
+ sage: M != M_old
2944
+ True
2945
+
2946
+ This reflects the fact that the equality of manifold objects holds only
2947
+ for identical objects, i.e. one has ``M1 == M2`` if, and only if,
2948
+ ``M1 is M2``. Actually, the manifold classes inherit from
2949
+ :class:`~sage.misc.fast_methods.WithEqualityById`::
2950
+
2951
+ sage: isinstance(M, sage.misc.fast_methods.WithEqualityById)
2952
+ True
2953
+ """
2954
+ from sage.manifolds.differentiable.degenerate import DegenerateManifold
2955
+ from sage.manifolds.differentiable.degenerate_submanifold import (
2956
+ DegenerateSubmanifold,
2957
+ )
2958
+ from sage.manifolds.differentiable.differentiable_submanifold import (
2959
+ DifferentiableSubmanifold,
2960
+ )
2961
+ from sage.manifolds.differentiable.manifold import DifferentiableManifold
2962
+ from sage.manifolds.differentiable.pseudo_riemannian import PseudoRiemannianManifold
2963
+ from sage.manifolds.differentiable.pseudo_riemannian_submanifold import (
2964
+ PseudoRiemannianSubmanifold,
2965
+ )
2966
+ from sage.manifolds.topological_submanifold import TopologicalSubmanifold
2967
+ from sage.rings.infinity import infinity
2968
+
2969
+ global _manifold_id
2970
+
2971
+ _manifold_id += 1
2972
+ unique_tag = lambda: getrandbits(128)*_manifold_id
2973
+
2974
+ if structure is None:
2975
+ if any(extra_kwds.get(x, None) is not None
2976
+ for x in ('metric_name', 'metric_latex_name', 'signature')):
2977
+ structure = 'pseudo-Riemannian'
2978
+
2979
+ if structure is None:
2980
+ diff_degree = extra_kwds.get('diff_degree', infinity)
2981
+ if diff_degree == infinity:
2982
+ structure = 'smooth'
2983
+ elif diff_degree > 0:
2984
+ structure = 'differentiable'
2985
+ else:
2986
+ structure = 'topological'
2987
+
2988
+ if structure in ['topological', 'top']:
2989
+ if field == 'real' or isinstance(field, sage.rings.abc.RealField):
2990
+ structure = RealTopologicalStructure()
2991
+ else:
2992
+ structure = TopologicalStructure()
2993
+ if 'ambient' in extra_kwds:
2994
+ ambient = extra_kwds['ambient']
2995
+ return TopologicalSubmanifold(dim, name, field, structure,
2996
+ ambient=ambient,
2997
+ latex_name=latex_name,
2998
+ start_index=start_index,
2999
+ unique_tag=unique_tag())
3000
+ return TopologicalManifold(dim, name, field, structure,
3001
+ latex_name=latex_name,
3002
+ start_index=start_index,
3003
+ unique_tag=unique_tag())
3004
+ elif structure in ['differentiable', 'diff', 'smooth']:
3005
+ if 'diff_degree' in extra_kwds:
3006
+ diff_degree = extra_kwds['diff_degree']
3007
+ if structure == 'smooth' and diff_degree != infinity:
3008
+ raise ValueError("diff_degree = {} is ".format(diff_degree) +
3009
+ "not compatible with a smooth structure")
3010
+ else:
3011
+ diff_degree = infinity
3012
+ if field == 'real' or isinstance(field, sage.rings.abc.RealField):
3013
+ structure = RealDifferentialStructure()
3014
+ else:
3015
+ structure = DifferentialStructure()
3016
+ if 'ambient' in extra_kwds:
3017
+ ambient = extra_kwds['ambient']
3018
+ return DifferentiableSubmanifold(dim, name, field, structure,
3019
+ ambient=ambient,
3020
+ diff_degree=diff_degree,
3021
+ latex_name=latex_name,
3022
+ start_index=start_index,
3023
+ unique_tag=unique_tag())
3024
+ return DifferentiableManifold(dim, name, field, structure,
3025
+ diff_degree=diff_degree,
3026
+ latex_name=latex_name,
3027
+ start_index=start_index,
3028
+ unique_tag=unique_tag())
3029
+ elif structure in ['pseudo-Riemannian', 'Riemannian', 'Lorentzian','degenerate_metric']:
3030
+ diff_degree = extra_kwds.get('diff_degree', infinity)
3031
+ metric_name = extra_kwds.get('metric_name', None)
3032
+ metric_latex_name = extra_kwds.get('metric_latex_name', None)
3033
+ if structure == 'pseudo-Riemannian':
3034
+ signature = extra_kwds.get('signature', None)
3035
+ elif structure == 'Riemannian':
3036
+ signature = dim
3037
+ elif structure == 'degenerate_metric':
3038
+ signature = (0, dim-1, 1)
3039
+ elif structure == 'Lorentzian':
3040
+ if 'signature' in extra_kwds:
3041
+ signat = extra_kwds['signature']
3042
+ if signat == 'positive' or signat == dim - 2:
3043
+ signature = dim - 2
3044
+ elif signat == 'negative' or signat == 2 - dim:
3045
+ signature = 2 - dim
3046
+ else:
3047
+ raise ValueError("signature {} not ".format(signat) +
3048
+ "compatible with a Lorentzian " +
3049
+ "manifold of dimension {}".format(dim))
3050
+ else:
3051
+ signature = dim - 2 # default value for a Lorentzian manifold
3052
+ if 'ambient' in extra_kwds:
3053
+ ambient = extra_kwds['ambient']
3054
+ if structure == 'degenerate_metric':
3055
+ return DegenerateSubmanifold(dim, name, ambient=ambient,
3056
+ metric_name=metric_name,
3057
+ signature=signature,
3058
+ diff_degree=diff_degree,
3059
+ latex_name=latex_name,
3060
+ metric_latex_name=metric_latex_name,
3061
+ start_index=start_index,
3062
+ unique_tag=unique_tag())
3063
+ return PseudoRiemannianSubmanifold(dim, name, ambient=ambient,
3064
+ metric_name=metric_name,
3065
+ signature=signature,
3066
+ diff_degree=diff_degree,
3067
+ latex_name=latex_name,
3068
+ metric_latex_name=metric_latex_name,
3069
+ start_index=start_index,
3070
+ unique_tag=unique_tag())
3071
+ if structure == 'degenerate_metric':
3072
+ return DegenerateManifold(dim, name, metric_name=metric_name,
3073
+ signature=signature,
3074
+ diff_degree=diff_degree,
3075
+ latex_name=latex_name,
3076
+ metric_latex_name=metric_latex_name,
3077
+ start_index=start_index,
3078
+ unique_tag=unique_tag())
3079
+ return PseudoRiemannianManifold(dim, name, metric_name=metric_name,
3080
+ signature=signature,
3081
+ diff_degree=diff_degree,
3082
+ latex_name=latex_name,
3083
+ metric_latex_name=metric_latex_name,
3084
+ start_index=start_index,
3085
+ unique_tag=unique_tag())
3086
+ raise NotImplementedError("manifolds of type {} are ".format(structure) +
3087
+ "not implemented")
3088
+
3089
+
3090
+ Manifold.options = TopologicalManifold.options