passagemath-symbolics 10.6.40__cp314-cp314t-macosx_13_0_x86_64.whl

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

Potentially problematic release.


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

Files changed (172) hide show
  1. passagemath_symbolics/.dylibs/libgmp.10.dylib +0 -0
  2. passagemath_symbolics/__init__.py +3 -0
  3. passagemath_symbolics-10.6.40.dist-info/METADATA +187 -0
  4. passagemath_symbolics-10.6.40.dist-info/RECORD +172 -0
  5. passagemath_symbolics-10.6.40.dist-info/WHEEL +6 -0
  6. passagemath_symbolics-10.6.40.dist-info/top_level.txt +3 -0
  7. sage/all__sagemath_symbolics.py +17 -0
  8. sage/calculus/all.py +14 -0
  9. sage/calculus/calculus.py +2826 -0
  10. sage/calculus/desolvers.py +1866 -0
  11. sage/calculus/predefined.py +51 -0
  12. sage/calculus/tests.py +225 -0
  13. sage/calculus/var.cpython-314t-darwin.so +0 -0
  14. sage/calculus/var.pyx +401 -0
  15. sage/dynamics/all__sagemath_symbolics.py +6 -0
  16. sage/dynamics/complex_dynamics/all.py +5 -0
  17. sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
  18. sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-314t-darwin.so +0 -0
  19. sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1035 -0
  20. sage/ext/all__sagemath_symbolics.py +1 -0
  21. sage/ext_data/kenzo/CP2.txt +45 -0
  22. sage/ext_data/kenzo/CP3.txt +349 -0
  23. sage/ext_data/kenzo/CP4.txt +4774 -0
  24. sage/ext_data/kenzo/README.txt +49 -0
  25. sage/ext_data/kenzo/S4.txt +20 -0
  26. sage/ext_data/magma/latex/latex.m +1021 -0
  27. sage/ext_data/magma/latex/latex.spec +1 -0
  28. sage/ext_data/magma/sage/basic.m +356 -0
  29. sage/ext_data/magma/sage/sage.spec +1 -0
  30. sage/ext_data/magma/spec +9 -0
  31. sage/geometry/all__sagemath_symbolics.py +8 -0
  32. sage/geometry/hyperbolic_space/all.py +5 -0
  33. sage/geometry/hyperbolic_space/hyperbolic_coercion.py +743 -0
  34. sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
  35. sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2409 -0
  36. sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
  37. sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1082 -0
  38. sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
  39. sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
  40. sage/geometry/riemannian_manifolds/all.py +7 -0
  41. sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
  42. sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
  43. sage/interfaces/all__sagemath_symbolics.py +1 -0
  44. sage/interfaces/magma.py +3017 -0
  45. sage/interfaces/magma_free.py +92 -0
  46. sage/interfaces/maple.py +1397 -0
  47. sage/interfaces/mathematica.py +1345 -0
  48. sage/interfaces/mathics.py +1312 -0
  49. sage/interfaces/sympy.py +1398 -0
  50. sage/interfaces/sympy_wrapper.py +197 -0
  51. sage/interfaces/tides.py +938 -0
  52. sage/libs/all__sagemath_symbolics.py +6 -0
  53. sage/manifolds/all.py +7 -0
  54. sage/manifolds/calculus_method.py +555 -0
  55. sage/manifolds/catalog.py +437 -0
  56. sage/manifolds/chart.py +4019 -0
  57. sage/manifolds/chart_func.py +3419 -0
  58. sage/manifolds/continuous_map.py +2183 -0
  59. sage/manifolds/continuous_map_image.py +155 -0
  60. sage/manifolds/differentiable/affine_connection.py +2475 -0
  61. sage/manifolds/differentiable/all.py +1 -0
  62. sage/manifolds/differentiable/automorphismfield.py +1383 -0
  63. sage/manifolds/differentiable/automorphismfield_group.py +604 -0
  64. sage/manifolds/differentiable/bundle_connection.py +1445 -0
  65. sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
  66. sage/manifolds/differentiable/chart.py +1241 -0
  67. sage/manifolds/differentiable/curve.py +1028 -0
  68. sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
  69. sage/manifolds/differentiable/degenerate.py +559 -0
  70. sage/manifolds/differentiable/degenerate_submanifold.py +1671 -0
  71. sage/manifolds/differentiable/diff_form.py +1658 -0
  72. sage/manifolds/differentiable/diff_form_module.py +1062 -0
  73. sage/manifolds/differentiable/diff_map.py +1315 -0
  74. sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
  75. sage/manifolds/differentiable/examples/all.py +1 -0
  76. sage/manifolds/differentiable/examples/euclidean.py +2517 -0
  77. sage/manifolds/differentiable/examples/real_line.py +897 -0
  78. sage/manifolds/differentiable/examples/sphere.py +1186 -0
  79. sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
  80. sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
  81. sage/manifolds/differentiable/integrated_curve.py +4035 -0
  82. sage/manifolds/differentiable/levi_civita_connection.py +841 -0
  83. sage/manifolds/differentiable/manifold.py +4254 -0
  84. sage/manifolds/differentiable/manifold_homset.py +1826 -0
  85. sage/manifolds/differentiable/metric.py +3032 -0
  86. sage/manifolds/differentiable/mixed_form.py +1507 -0
  87. sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
  88. sage/manifolds/differentiable/multivector_module.py +800 -0
  89. sage/manifolds/differentiable/multivectorfield.py +1520 -0
  90. sage/manifolds/differentiable/poisson_tensor.py +268 -0
  91. sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
  92. sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
  93. sage/manifolds/differentiable/scalarfield.py +1343 -0
  94. sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
  95. sage/manifolds/differentiable/symplectic_form.py +910 -0
  96. sage/manifolds/differentiable/symplectic_form_test.py +220 -0
  97. sage/manifolds/differentiable/tangent_space.py +412 -0
  98. sage/manifolds/differentiable/tangent_vector.py +616 -0
  99. sage/manifolds/differentiable/tensorfield.py +4665 -0
  100. sage/manifolds/differentiable/tensorfield_module.py +963 -0
  101. sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
  102. sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
  103. sage/manifolds/differentiable/vector_bundle.py +1728 -0
  104. sage/manifolds/differentiable/vectorfield.py +1717 -0
  105. sage/manifolds/differentiable/vectorfield_module.py +2445 -0
  106. sage/manifolds/differentiable/vectorframe.py +1832 -0
  107. sage/manifolds/family.py +270 -0
  108. sage/manifolds/local_frame.py +1490 -0
  109. sage/manifolds/manifold.py +3090 -0
  110. sage/manifolds/manifold_homset.py +452 -0
  111. sage/manifolds/operators.py +359 -0
  112. sage/manifolds/point.py +994 -0
  113. sage/manifolds/scalarfield.py +3718 -0
  114. sage/manifolds/scalarfield_algebra.py +629 -0
  115. sage/manifolds/section.py +3111 -0
  116. sage/manifolds/section_module.py +831 -0
  117. sage/manifolds/structure.py +229 -0
  118. sage/manifolds/subset.py +2764 -0
  119. sage/manifolds/subsets/all.py +1 -0
  120. sage/manifolds/subsets/closure.py +131 -0
  121. sage/manifolds/subsets/pullback.py +885 -0
  122. sage/manifolds/topological_submanifold.py +891 -0
  123. sage/manifolds/trivialization.py +733 -0
  124. sage/manifolds/utilities.py +1348 -0
  125. sage/manifolds/vector_bundle.py +1342 -0
  126. sage/manifolds/vector_bundle_fiber.py +332 -0
  127. sage/manifolds/vector_bundle_fiber_element.py +111 -0
  128. sage/matrix/all__sagemath_symbolics.py +1 -0
  129. sage/matrix/matrix_symbolic_dense.cpython-314t-darwin.so +0 -0
  130. sage/matrix/matrix_symbolic_dense.pxd +6 -0
  131. sage/matrix/matrix_symbolic_dense.pyx +1022 -0
  132. sage/matrix/matrix_symbolic_sparse.cpython-314t-darwin.so +0 -0
  133. sage/matrix/matrix_symbolic_sparse.pxd +6 -0
  134. sage/matrix/matrix_symbolic_sparse.pyx +1029 -0
  135. sage/modules/all__sagemath_symbolics.py +1 -0
  136. sage/modules/vector_callable_symbolic_dense.py +105 -0
  137. sage/modules/vector_symbolic_dense.py +116 -0
  138. sage/modules/vector_symbolic_sparse.py +118 -0
  139. sage/rings/all__sagemath_symbolics.py +4 -0
  140. sage/rings/asymptotic/all.py +6 -0
  141. sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
  142. sage/rings/asymptotic/asymptotic_ring.py +4858 -0
  143. sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4153 -0
  144. sage/rings/asymptotic/growth_group.py +5373 -0
  145. sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
  146. sage/rings/asymptotic/term_monoid.py +5237 -0
  147. sage/rings/function_field/all__sagemath_symbolics.py +2 -0
  148. sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
  149. sage/symbolic/all.py +15 -0
  150. sage/symbolic/assumptions.py +985 -0
  151. sage/symbolic/benchmark.py +93 -0
  152. sage/symbolic/callable.py +459 -0
  153. sage/symbolic/complexity_measures.py +35 -0
  154. sage/symbolic/constants.py +1287 -0
  155. sage/symbolic/expression_conversion_algebraic.py +310 -0
  156. sage/symbolic/expression_conversion_sympy.py +317 -0
  157. sage/symbolic/expression_conversions.py +1713 -0
  158. sage/symbolic/function_factory.py +355 -0
  159. sage/symbolic/integration/all.py +1 -0
  160. sage/symbolic/integration/external.py +270 -0
  161. sage/symbolic/integration/integral.py +1115 -0
  162. sage/symbolic/maxima_wrapper.py +162 -0
  163. sage/symbolic/operators.py +267 -0
  164. sage/symbolic/random_tests.py +462 -0
  165. sage/symbolic/relation.py +1907 -0
  166. sage/symbolic/ring.cpython-314t-darwin.so +0 -0
  167. sage/symbolic/ring.pxd +5 -0
  168. sage/symbolic/ring.pyx +1396 -0
  169. sage/symbolic/subring.py +1025 -0
  170. sage/symbolic/symengine.py +19 -0
  171. sage/symbolic/tests.py +40 -0
  172. sage/symbolic/units.py +1470 -0
@@ -0,0 +1,3032 @@
1
+ # sage_setup: distribution = sagemath-symbolics
2
+ r"""
3
+ Pseudo-Riemannian Metrics and Degenerate Metrics
4
+
5
+ The class :class:`PseudoRiemannianMetric` implements pseudo-Riemannian metrics
6
+ on differentiable manifolds over `\RR`. The derived class
7
+ :class:`PseudoRiemannianMetricParal` is devoted to metrics with values on a
8
+ parallelizable manifold.
9
+
10
+ The class :class:`DegenerateMetric` implements degenerate (or null or lightlike)
11
+ metrics on differentiable manifolds over `\RR`. The derived class
12
+ :class:`DegenerateMetricParal` is devoted to metrics with values on a
13
+ parallelizable manifold.
14
+
15
+ AUTHORS:
16
+
17
+ - Eric Gourgoulhon, Michal Bejger (2013-2015) : initial version
18
+ - Pablo Angulo (2016) : Schouten, Cotton and Cotton-York tensors
19
+ - Florentin Jaffredo (2018) : series expansion for the inverse metric
20
+ - Hans Fotsing Tetsing (2019) : degenerate metrics
21
+ - Marius Gerbershagen (2022) : compute volume forms with contravariant indices
22
+ only as needed
23
+
24
+ REFERENCES:
25
+
26
+ - [KN1963]_
27
+ - [Lee1997]_
28
+ - [ONe1983]_
29
+ - [DB1996]_
30
+ - [DS2010]_
31
+ """
32
+ # *****************************************************************************
33
+ # Copyright (C) 2015 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
34
+ # Copyright (C) 2015 Michal Bejger <bejger@camk.edu.pl>
35
+ # Copyright (C) 2016 Pablo Angulo <pang@cancamusa.net>
36
+ # Copyright (C) 2018 Florentin Jaffredo <florentin.jaffredo@polytechnique.edu>
37
+ # Copyright (C) 2019 Hans Fotsing Tetsing <hans.fotsing@aims-cameroon.org>
38
+ #
39
+ # Distributed under the terms of the GNU General Public License (GPL)
40
+ # as published by the Free Software Foundation; either version 2 of
41
+ # the License, or (at your option) any later version.
42
+ # https://www.gnu.org/licenses/
43
+ # *****************************************************************************
44
+ from __future__ import annotations
45
+
46
+ from typing import TYPE_CHECKING, overload
47
+
48
+ from sage.manifolds.differentiable.tensorfield import TensorField
49
+ from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal
50
+ from sage.rings.integer import Integer
51
+
52
+ if TYPE_CHECKING:
53
+ from sage.manifolds.differentiable.diff_form import DiffForm
54
+
55
+
56
+ class PseudoRiemannianMetric(TensorField):
57
+ r"""
58
+ Pseudo-Riemannian metric with values on an open subset of a
59
+ differentiable manifold.
60
+
61
+ An instance of this class is a field of nondegenerate symmetric bilinear
62
+ forms (metric field) along a differentiable manifold `U` with
63
+ values on a differentiable manifold `M` over `\RR`, via a differentiable
64
+ mapping `\Phi: U \rightarrow M`.
65
+ The standard case of a metric field *on* a manifold corresponds to `U=M`
66
+ and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi` being an
67
+ immersion and `\Phi` being a curve in `M` (`U` is then an open interval
68
+ of `\RR`).
69
+
70
+ A *metric* `g` is a field on `U`, such that at each point `p\in U`, `g(p)`
71
+ is a bilinear map of the type:
72
+
73
+ .. MATH::
74
+
75
+ g(p):\ T_q M\times T_q M \longrightarrow \RR
76
+
77
+ where `T_q M` stands for the tangent space to the
78
+ manifold `M` at the point `q=\Phi(p)`, such that `g(p)` is symmetric:
79
+ `\forall (u,v)\in T_q M\times T_q M, \ g(p)(v,u) = g(p)(u,v)`
80
+ and nondegenerate:
81
+ `(\forall v\in T_q M,\ \ g(p)(u,v) = 0) \Longrightarrow u=0`.
82
+
83
+ .. NOTE::
84
+
85
+ If `M` is parallelizable, the class :class:`PseudoRiemannianMetricParal`
86
+ should be used instead.
87
+
88
+ INPUT:
89
+
90
+ - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector
91
+ fields along `U` with values on `\Phi(U)\subset M`
92
+ - ``name`` -- name given to the metric
93
+ - ``signature`` -- (default: ``None``) signature `S` of the metric as a
94
+ single integer: `S = n_+ - n_-`, where `n_+` (resp. `n_-`) is the number
95
+ of positive terms (resp. number of negative terms) in any diagonal
96
+ writing of the metric components; if ``signature`` is ``None``, `S` is
97
+ set to the dimension of manifold `M` (Riemannian signature)
98
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the metric;
99
+ if ``None``, it is formed from ``name``
100
+
101
+ EXAMPLES:
102
+
103
+ Let us construct the standard metric on the sphere `S^2`, described in
104
+ terms of stereographic coordinates, from the North pole (open subset `U`)
105
+ and from the South pole (open subset `V`)::
106
+
107
+ sage: M = Manifold(2, 'S^2', start_index=1)
108
+ sage: U = M.open_subset('U') ; V = M.open_subset('V')
109
+ sage: M.declare_union(U,V) # S^2 is the union of U and V
110
+ sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() # stereographic coord
111
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)),
112
+ ....: intersection_name='W', restrictions1= x^2+y^2!=0,
113
+ ....: restrictions2= u^2+v^2!=0)
114
+ sage: uv_to_xy = xy_to_uv.inverse()
115
+ sage: eU = c_xy.frame() ; eV = c_uv.frame()
116
+ sage: g = M.metric('g') ; g
117
+ Riemannian metric g on the 2-dimensional differentiable manifold S^2
118
+
119
+ The metric is considered as a tensor field of type (0,2) on `S^2`::
120
+
121
+ sage: g.parent()
122
+ Module T^(0,2)(S^2) of type-(0,2) tensors fields on the 2-dimensional
123
+ differentiable manifold S^2
124
+
125
+ We define `g` by its components on domain `U`::
126
+
127
+ sage: g[eU,1,1], g[eU,2,2] = 4/(1+x^2+y^2)^2, 4/(1+x^2+y^2)^2
128
+ sage: g.display(eU)
129
+ g = 4/(x^2 + y^2 + 1)^2 dx⊗dx + 4/(x^2 + y^2 + 1)^2 dy⊗dy
130
+
131
+ A matrix view of the components::
132
+
133
+ sage: g[eU,:]
134
+ [4/(x^2 + y^2 + 1)^2 0]
135
+ [ 0 4/(x^2 + y^2 + 1)^2]
136
+
137
+ The components of `g` on domain `V` expressed in terms of coordinates
138
+ `(u,v)` are obtained by applying (i) the tensor transformation law on
139
+ `W = U\cap V` and (ii) some analytical continuation::
140
+
141
+ sage: W = U.intersection(V)
142
+ sage: g.add_comp_by_continuation(eV, W, chart=c_uv)
143
+ sage: g.apply_map(factor, frame=eV, keep_other_components=True) # for a nicer display
144
+ sage: g.display(eV)
145
+ g = 4/(u^2 + v^2 + 1)^2 du⊗du + 4/(u^2 + v^2 + 1)^2 dv⊗dv
146
+
147
+ At this stage, the metric is fully defined on the whole sphere. Its
148
+ restriction to some subdomain is itself a metric (by default, it bears the
149
+ same symbol)::
150
+
151
+ sage: g.restrict(U)
152
+ Riemannian metric g on the Open subset U of the 2-dimensional
153
+ differentiable manifold S^2
154
+ sage: g.restrict(U).parent()
155
+ Free module T^(0,2)(U) of type-(0,2) tensors fields on the Open subset
156
+ U of the 2-dimensional differentiable manifold S^2
157
+
158
+ The parent of `g|_U` is a free module because is `U` is a parallelizable
159
+ domain, contrary to `S^2`. Actually, `g` and `g|_U` have different Python
160
+ type::
161
+
162
+ sage: type(g)
163
+ <class 'sage.manifolds.differentiable.metric.PseudoRiemannianMetric'>
164
+ sage: type(g.restrict(U))
165
+ <class 'sage.manifolds.differentiable.metric.PseudoRiemannianMetricParal'>
166
+
167
+ As a field of bilinear forms, the metric acts on pairs of vector fields,
168
+ yielding a scalar field::
169
+
170
+ sage: a = M.vector_field({eU: [x, 2+y]}, name='a')
171
+ sage: a.add_comp_by_continuation(eV, W, chart=c_uv)
172
+ sage: b = M.vector_field({eU: [-y, x]}, name='b')
173
+ sage: b.add_comp_by_continuation(eV, W, chart=c_uv)
174
+ sage: s = g(a,b) ; s
175
+ Scalar field g(a,b) on the 2-dimensional differentiable manifold S^2
176
+ sage: s.display()
177
+ g(a,b): S^2 → ℝ
178
+ on U: (x, y) ↦ 8*x/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1)
179
+ on V: (u, v) ↦ 8*(u^3 + u*v^2)/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1)
180
+
181
+ The inverse metric is::
182
+
183
+ sage: ginv = g.inverse() ; ginv
184
+ Tensor field inv_g of type (2,0) on the 2-dimensional differentiable
185
+ manifold S^2
186
+ sage: ginv.parent()
187
+ Module T^(2,0)(S^2) of type-(2,0) tensors fields on the 2-dimensional
188
+ differentiable manifold S^2
189
+ sage: latex(ginv)
190
+ g^{-1}
191
+ sage: ginv.display(eU)
192
+ inv_g = (1/4*x^4 + 1/4*y^4 + 1/2*(x^2 + 1)*y^2 + 1/2*x^2 + 1/4) ∂/∂x⊗∂/∂x
193
+ + (1/4*x^4 + 1/4*y^4 + 1/2*(x^2 + 1)*y^2 + 1/2*x^2 + 1/4) ∂/∂y⊗∂/∂y
194
+ sage: ginv.display(eV)
195
+ inv_g = (1/4*u^4 + 1/4*v^4 + 1/2*(u^2 + 1)*v^2 + 1/2*u^2 + 1/4) ∂/∂u⊗∂/∂u
196
+ + (1/4*u^4 + 1/4*v^4 + 1/2*(u^2 + 1)*v^2 + 1/2*u^2 + 1/4) ∂/∂v⊗∂/∂v
197
+
198
+ We have::
199
+
200
+ sage: ginv.restrict(U) is g.restrict(U).inverse()
201
+ True
202
+ sage: ginv.restrict(V) is g.restrict(V).inverse()
203
+ True
204
+ sage: ginv.restrict(W) is g.restrict(W).inverse()
205
+ True
206
+
207
+ To get the volume form (Levi-Civita tensor) associated with `g`, we have
208
+ first to define an orientation on `S^2`. The standard orientation is that
209
+ in which ``eV`` is right-handed; indeed, once supplemented by the outward
210
+ unit normal, ``eV`` give birth to a right-handed frame with respect to the
211
+ standard orientation of the ambient Euclidean space `E^3`. With such an
212
+ orientation, ``eU`` is then left-handed and in order to define an
213
+ orientation on the whole of `S^2`, we introduce a vector frame
214
+ on `U` by swapping ``eU``'s vectors::
215
+
216
+ sage: f = U.vector_frame('f', (eU[2], eU[1]))
217
+ sage: M.set_orientation([eV, f])
218
+
219
+ We have then, factorizing the components for a nicer display::
220
+
221
+ sage: eps = g.volume_form() ; eps
222
+ 2-form eps_g on the 2-dimensional differentiable manifold S^2
223
+ sage: eps.apply_map(factor, frame=eU, keep_other_components=True)
224
+ sage: eps.apply_map(factor, frame=eV, keep_other_components=True)
225
+ sage: eps.display(eU)
226
+ eps_g = -4/(x^2 + y^2 + 1)^2 dx∧dy
227
+ sage: eps.display(eV)
228
+ eps_g = 4/(u^2 + v^2 + 1)^2 du∧dv
229
+
230
+ The unique non-trivial component of the volume form is, up to a sign
231
+ depending of the chosen orientation, nothing but the square root of the
232
+ determinant of `g` in the corresponding frame::
233
+
234
+ sage: eps[[eU,1,2]] == -g.sqrt_abs_det(eU)
235
+ True
236
+ sage: eps[[eV,1,2]] == g.sqrt_abs_det(eV)
237
+ True
238
+
239
+ The Levi-Civita connection associated with the metric `g`::
240
+
241
+ sage: nabla = g.connection() ; nabla
242
+ Levi-Civita connection nabla_g associated with the Riemannian metric g
243
+ on the 2-dimensional differentiable manifold S^2
244
+ sage: latex(nabla)
245
+ \nabla_{g}
246
+
247
+ The Christoffel symbols `\Gamma^i_{\ \, jk}` associated with some
248
+ coordinates::
249
+
250
+ sage: g.christoffel_symbols(c_xy)
251
+ 3-indices components w.r.t. Coordinate frame (U, (∂/∂x,∂/∂y)), with
252
+ symmetry on the index positions (1, 2)
253
+ sage: g.christoffel_symbols(c_xy)[:]
254
+ [[[-2*x/(x^2 + y^2 + 1), -2*y/(x^2 + y^2 + 1)],
255
+ [-2*y/(x^2 + y^2 + 1), 2*x/(x^2 + y^2 + 1)]],
256
+ [[2*y/(x^2 + y^2 + 1), -2*x/(x^2 + y^2 + 1)],
257
+ [-2*x/(x^2 + y^2 + 1), -2*y/(x^2 + y^2 + 1)]]]
258
+ sage: g.christoffel_symbols(c_uv)[:]
259
+ [[[-2*u/(u^2 + v^2 + 1), -2*v/(u^2 + v^2 + 1)],
260
+ [-2*v/(u^2 + v^2 + 1), 2*u/(u^2 + v^2 + 1)]],
261
+ [[2*v/(u^2 + v^2 + 1), -2*u/(u^2 + v^2 + 1)],
262
+ [-2*u/(u^2 + v^2 + 1), -2*v/(u^2 + v^2 + 1)]]]
263
+
264
+ The Christoffel symbols are nothing but the connection coefficients w.r.t.
265
+ the coordinate frame::
266
+
267
+ sage: g.christoffel_symbols(c_xy) is nabla.coef(c_xy.frame())
268
+ True
269
+ sage: g.christoffel_symbols(c_uv) is nabla.coef(c_uv.frame())
270
+ True
271
+
272
+ Test that `\nabla` is the connection compatible with `g`::
273
+
274
+ sage: t = nabla(g) ; t
275
+ Tensor field nabla_g(g) of type (0,3) on the 2-dimensional
276
+ differentiable manifold S^2
277
+ sage: t.display(eU)
278
+ nabla_g(g) = 0
279
+ sage: t.display(eV)
280
+ nabla_g(g) = 0
281
+ sage: t == 0
282
+ True
283
+
284
+ The Riemann curvature tensor of `g`::
285
+
286
+ sage: riem = g.riemann() ; riem
287
+ Tensor field Riem(g) of type (1,3) on the 2-dimensional differentiable
288
+ manifold S^2
289
+ sage: riem.display(eU)
290
+ Riem(g) = 4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) ∂/∂x⊗dy⊗dx⊗dy
291
+ - 4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) ∂/∂x⊗dy⊗dy⊗dx
292
+ - 4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) ∂/∂y⊗dx⊗dx⊗dy
293
+ + 4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) ∂/∂y⊗dx⊗dy⊗dx
294
+ sage: riem.display(eV)
295
+ Riem(g) = 4/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) ∂/∂u⊗dv⊗du⊗dv
296
+ - 4/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) ∂/∂u⊗dv⊗dv⊗du
297
+ - 4/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) ∂/∂v⊗du⊗du⊗dv
298
+ + 4/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) ∂/∂v⊗du⊗dv⊗du
299
+
300
+ The Ricci tensor of `g`::
301
+
302
+ sage: ric = g.ricci() ; ric
303
+ Field of symmetric bilinear forms Ric(g) on the 2-dimensional
304
+ differentiable manifold S^2
305
+ sage: ric.display(eU)
306
+ Ric(g) = 4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dx⊗dx
307
+ + 4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dy⊗dy
308
+ sage: ric.display(eV)
309
+ Ric(g) = 4/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) du⊗du
310
+ + 4/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) dv⊗dv
311
+ sage: ric == g
312
+ True
313
+
314
+ The Ricci scalar of `g`::
315
+
316
+ sage: r = g.ricci_scalar() ; r
317
+ Scalar field r(g) on the 2-dimensional differentiable manifold S^2
318
+ sage: r.display()
319
+ r(g): S^2 → ℝ
320
+ on U: (x, y) ↦ 2
321
+ on V: (u, v) ↦ 2
322
+
323
+ In dimension 2, the Riemann tensor can be expressed entirely in terms of
324
+ the Ricci scalar `r`:
325
+
326
+ .. MATH::
327
+
328
+ R^i_{\ \, jlk} = \frac{r}{2} \left( \delta^i_{\ \, k} g_{jl}
329
+ - \delta^i_{\ \, l} g_{jk} \right)
330
+
331
+ This formula can be checked here, with the r.h.s. rewritten as
332
+ `-r g_{j[k} \delta^i_{\ \, l]}`::
333
+
334
+ sage: delta = M.tangent_identity_field()
335
+ sage: riem == - r*(g*delta).antisymmetrize(2,3)
336
+ True
337
+ """
338
+ _derived_objects = ('_connection', '_ricci_scalar', '_weyl',
339
+ '_schouten', '_cotton', '_cotton_york')
340
+
341
+ def __init__(self, vector_field_module, name, signature=None,
342
+ latex_name=None):
343
+ r"""
344
+ Construct a metric.
345
+
346
+ TESTS::
347
+
348
+ sage: M = Manifold(2, 'M')
349
+ sage: U = M.open_subset('U') ; V = M.open_subset('V')
350
+ sage: M.declare_union(U,V) # M is the union of U and V
351
+ sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
352
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y),
353
+ ....: intersection_name='W', restrictions1= x>0,
354
+ ....: restrictions2= u+v>0)
355
+ sage: uv_to_xy = xy_to_uv.inverse()
356
+ sage: W = U.intersection(V)
357
+ sage: e_xy = c_xy.frame() ; e_uv = c_uv.frame()
358
+ sage: XM = M.vector_field_module()
359
+ sage: from sage.manifolds.differentiable.metric import \
360
+ ....: PseudoRiemannianMetric
361
+ sage: g = PseudoRiemannianMetric(XM, 'g', signature=0); g
362
+ Lorentzian metric g on the 2-dimensional differentiable
363
+ manifold M
364
+ sage: g[e_xy,0,0], g[e_xy,1,1] = -(1+x^2), 1+y^2
365
+ sage: g.add_comp_by_continuation(e_uv, W, c_uv)
366
+ sage: TestSuite(g).run(skip=['_test_category', '_test_pickling'])
367
+
368
+ .. TODO::
369
+
370
+ - fix _test_pickling (in the superclass TensorField)
371
+ - add a specific parent to the metrics, to fit with the category
372
+ framework
373
+ """
374
+ TensorField.__init__(self, vector_field_module, (0,2),
375
+ name=name, latex_name=latex_name, sym=(0,1))
376
+ # signature:
377
+ ndim = self._ambient_domain.dimension()
378
+ if signature is None:
379
+ signature = ndim
380
+ else:
381
+ if not isinstance(signature, (int, Integer)):
382
+ raise TypeError("the metric signature must be an integer")
383
+ if (signature < - ndim) or (signature > ndim):
384
+ raise ValueError("metric signature out of range")
385
+ if (signature+ndim) % 2 == 1:
386
+ if ndim % 2 == 0:
387
+ raise ValueError("the metric signature must be even")
388
+ else:
389
+ raise ValueError("the metric signature must be odd")
390
+ self._signature = signature
391
+ # the pair (n_+, n_-):
392
+ self._signature_pm = ((ndim+signature)//2, (ndim-signature)//2)
393
+ self._indic_signat = 1 - 2*(self._signature_pm[1] % 2) # (-1)^n_-
394
+ # Initialization of derived quantities:
395
+ PseudoRiemannianMetric._init_derived(self)
396
+
397
+ def _repr_(self):
398
+ r"""
399
+ String representation of the object.
400
+
401
+ TESTS::
402
+
403
+ sage: M = Manifold(5, 'M')
404
+ sage: g = M.metric('g')
405
+ sage: g._repr_()
406
+ 'Riemannian metric g on the 5-dimensional differentiable manifold M'
407
+ sage: g = M.metric('g', signature=3)
408
+ sage: g._repr_()
409
+ 'Lorentzian metric g on the 5-dimensional differentiable manifold M'
410
+ sage: g = M.metric('g', signature=1)
411
+ sage: g._repr_()
412
+ 'Pseudo-Riemannian metric g on the 5-dimensional differentiable manifold M'
413
+ """
414
+ n = self._ambient_domain.dimension()
415
+ s = self._signature
416
+ if s == n:
417
+ description = "Riemannian metric "
418
+ elif s == n-2 or s == 2-n:
419
+ description = "Lorentzian metric "
420
+ else:
421
+ description = "Pseudo-Riemannian metric "
422
+ description += self._name + " "
423
+ return self._final_repr(description)
424
+
425
+ def _new_instance(self):
426
+ r"""
427
+ Create an instance of the same class as ``self`` with the same
428
+ signature.
429
+
430
+ TESTS::
431
+
432
+ sage: M = Manifold(5, 'M')
433
+ sage: g = M.metric('g', signature=3)
434
+ sage: g1 = g._new_instance(); g1
435
+ Lorentzian metric unnamed metric on the 5-dimensional
436
+ differentiable manifold M
437
+ sage: type(g1) == type(g)
438
+ True
439
+ sage: g1.parent() is g.parent()
440
+ True
441
+ sage: g1.signature() == g.signature()
442
+ True
443
+ """
444
+ return type(self)(self._vmodule, 'unnamed metric',
445
+ signature=self._signature,
446
+ latex_name=r'\text{unnamed metric}')
447
+
448
+ def _init_derived(self):
449
+ r"""
450
+ Initialize the derived quantities.
451
+
452
+ TESTS::
453
+
454
+ sage: M = Manifold(5, 'M')
455
+ sage: g = M.metric('g')
456
+ sage: g._init_derived()
457
+ """
458
+ # Initialization of quantities pertaining to the mother class:
459
+ TensorField._init_derived(self)
460
+ # inverse metric:
461
+ inv_name = 'inv_' + self._name
462
+ inv_latex_name = self._latex_name + r'^{-1}'
463
+ self._inverse = self._vmodule.tensor((2,0), name=inv_name,
464
+ latex_name=inv_latex_name,
465
+ sym=(0,1))
466
+ for attr in self._derived_objects:
467
+ self.__setattr__(attr, None)
468
+ self._determinants = {} # determinants in various frames
469
+ self._sqrt_abs_dets = {} # sqrt(abs(det g)) in various frames
470
+ self._vol_forms = [] # volume form and associated tensors
471
+
472
+ def _del_derived(self):
473
+ r"""
474
+ Delete the derived quantities.
475
+
476
+ TESTS::
477
+
478
+ sage: M = Manifold(5, 'M')
479
+ sage: g = M.metric('g')
480
+ sage: g._del_derived()
481
+ """
482
+ # First the derived quantities from the mother class are deleted:
483
+ TensorField._del_derived(self)
484
+ # The inverse metric is cleared:
485
+ self._del_inverse()
486
+ # The connection, Ricci scalar and Weyl tensor are reset to None:
487
+ # The Schouten, Cotton and Cotton-York tensors are reset to None:
488
+ for attr in self._derived_objects:
489
+ self.__setattr__(attr, None)
490
+ # The dictionary of determinants over the various frames is cleared:
491
+ self._determinants.clear()
492
+ self._sqrt_abs_dets.clear()
493
+ # The volume form and the associated tensors is deleted:
494
+ del self._vol_forms[:]
495
+
496
+ def _del_inverse(self):
497
+ r"""
498
+ Delete the inverse metric.
499
+
500
+ TESTS::
501
+
502
+ sage: M = Manifold(5, 'M')
503
+ sage: g = M.metric('g')
504
+ sage: g._del_inverse()
505
+ """
506
+ self._inverse._restrictions.clear()
507
+ self._inverse._del_derived()
508
+
509
+ def signature(self):
510
+ r"""
511
+ Signature of the metric.
512
+
513
+ OUTPUT:
514
+
515
+ - signature `S` of the metric, defined as the integer
516
+ `S = n_+ - n_-`, where `n_+` (resp. `n_-`) is the number of
517
+ positive terms (resp. number of negative terms) in any diagonal
518
+ writing of the metric components
519
+
520
+ EXAMPLES:
521
+
522
+ Signatures on a 2-dimensional manifold::
523
+
524
+ sage: M = Manifold(2, 'M')
525
+ sage: g = M.metric('g') # if not specified, the signature is Riemannian
526
+ sage: g.signature()
527
+ 2
528
+ sage: h = M.metric('h', signature=0)
529
+ sage: h.signature()
530
+ 0
531
+ """
532
+ return self._signature
533
+
534
+ def restrict(self, subdomain, dest_map=None):
535
+ r"""
536
+ Return the restriction of the metric to some subdomain.
537
+
538
+ If the restriction has not been defined yet, it is constructed here.
539
+
540
+ INPUT:
541
+
542
+ - ``subdomain`` -- open subset `U` of the metric's domain (must be an
543
+ instance of :class:`~sage.manifolds.differentiable.manifold.DifferentiableManifold`)
544
+ - ``dest_map`` -- (default: ``None``) destination map
545
+ `\Phi:\ U \rightarrow V`, where `V` is a subdomain of
546
+ ``self._codomain``
547
+ (type: :class:`~sage.manifolds.differentiable.diff_map.DiffMap`)
548
+ If ``None``, the restriction of ``self._vmodule._dest_map`` to `U` is
549
+ used.
550
+
551
+ OUTPUT:
552
+
553
+ - instance of :class:`PseudoRiemannianMetric` representing the
554
+ restriction.
555
+
556
+ EXAMPLES::
557
+
558
+ sage: M = Manifold(5, 'M')
559
+ sage: g = M.metric('g', signature=3)
560
+ sage: U = M.open_subset('U')
561
+ sage: g.restrict(U)
562
+ Lorentzian metric g on the Open subset U of the
563
+ 5-dimensional differentiable manifold M
564
+ sage: g.restrict(U).signature()
565
+ 3
566
+
567
+ See the top documentation of :class:`PseudoRiemannianMetric` for more
568
+ examples.
569
+ """
570
+ if subdomain == self._domain:
571
+ return self
572
+ if subdomain not in self._restrictions:
573
+ # Construct the restriction at the tensor field level:
574
+ resu = TensorField.restrict(self, subdomain, dest_map=dest_map)
575
+ # the type is correctly handled by TensorField.restrict, i.e.
576
+ # resu is of type self.__class__, but the signature is not handled
577
+ # by TensorField.restrict; we have to set it here:
578
+ resu._signature = self._signature
579
+ resu._signature_pm = self._signature_pm
580
+ resu._indic_signat = self._indic_signat
581
+ # Restrictions of derived quantities:
582
+ resu._inverse = self.inverse().restrict(subdomain)
583
+ for attr in self._derived_objects:
584
+ derived = self.__getattribute__(attr)
585
+ if derived is not None:
586
+ resu.__setattr__(attr, derived.restrict(subdomain))
587
+ if self._vol_forms != []:
588
+ for eps in self._vol_forms:
589
+ resu._vol_forms.append(eps.restrict(subdomain))
590
+ # NB: no initialization of resu._determinants nor
591
+ # resu._sqrt_abs_dets
592
+ # The restriction is ready:
593
+ self._restrictions[subdomain] = resu
594
+ return self._restrictions[subdomain]
595
+
596
+ def set(self, symbiform):
597
+ r"""
598
+ Define the metric from a field of symmetric bilinear forms.
599
+
600
+ INPUT:
601
+
602
+ - ``symbiform`` -- instance of
603
+ :class:`~sage.manifolds.differentiable.tensorfield.TensorField`
604
+ representing a field of symmetric bilinear forms
605
+
606
+ EXAMPLES:
607
+
608
+ Metric defined from a field of symmetric bilinear forms on a
609
+ non-parallelizable 2-dimensional manifold::
610
+
611
+ sage: M = Manifold(2, 'M')
612
+ sage: U = M.open_subset('U') ; V = M.open_subset('V')
613
+ sage: M.declare_union(U,V) # M is the union of U and V
614
+ sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
615
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), intersection_name='W',
616
+ ....: restrictions1= x>0, restrictions2= u+v>0)
617
+ sage: uv_to_xy = xy_to_uv.inverse()
618
+ sage: W = U.intersection(V)
619
+ sage: eU = c_xy.frame() ; eV = c_uv.frame()
620
+ sage: h = M.sym_bilin_form_field(name='h')
621
+ sage: h[eU,0,0], h[eU,0,1], h[eU,1,1] = 1+x, x*y, 1-y
622
+ sage: h.add_comp_by_continuation(eV, W, c_uv)
623
+ sage: h.display(eU)
624
+ h = (x + 1) dx⊗dx + x*y dx⊗dy + x*y dy⊗dx + (-y + 1) dy⊗dy
625
+ sage: h.display(eV)
626
+ h = (1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2) du⊗du + 1/4*u du⊗dv
627
+ + 1/4*u dv⊗du + (-1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2) dv⊗dv
628
+ sage: g = M.metric('g')
629
+ sage: g.set(h)
630
+ sage: g.display(eU)
631
+ g = (x + 1) dx⊗dx + x*y dx⊗dy + x*y dy⊗dx + (-y + 1) dy⊗dy
632
+ sage: g.display(eV)
633
+ g = (1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2) du⊗du + 1/4*u du⊗dv
634
+ + 1/4*u dv⊗du + (-1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2) dv⊗dv
635
+ """
636
+ if not isinstance(symbiform, TensorField):
637
+ raise TypeError("the argument must be a tensor field")
638
+ if symbiform._tensor_type != (0,2):
639
+ raise TypeError("the argument must be of tensor type (0,2)")
640
+ if symbiform._sym != ((0,1),):
641
+ raise TypeError("the argument must be symmetric")
642
+ if not symbiform._domain.is_subset(self._domain):
643
+ raise TypeError("the symmetric bilinear form is not defined " +
644
+ "on the metric domain")
645
+ self._del_derived()
646
+ self._restrictions.clear()
647
+ if isinstance(symbiform, TensorFieldParal):
648
+ rst = self.restrict(symbiform._domain)
649
+ rst.set(symbiform)
650
+ else:
651
+ for dom, symbiform_rst in symbiform._restrictions.items():
652
+ rst = self.restrict(dom)
653
+ rst.set(symbiform_rst)
654
+
655
+ def inverse(self, expansion_symbol=None, order=1):
656
+ r"""
657
+ Return the inverse metric.
658
+
659
+ INPUT:
660
+
661
+ - ``expansion_symbol`` -- (default: ``None``) symbolic variable; if
662
+ specified, the inverse will be expanded in power series with respect
663
+ to this variable (around its zero value)
664
+ - ``order`` -- integer (default: 1); the order of the expansion
665
+ if ``expansion_symbol`` is not ``None``; the *order* is defined as
666
+ the degree of the polynomial representing the truncated power series
667
+ in ``expansion_symbol``; currently only first order inverse is
668
+ supported
669
+
670
+ If ``expansion_symbol`` is set, then the zeroth order metric must be
671
+ invertible. Moreover, subsequent calls to this method will return
672
+ a cached value, even when called with the default value (to enable
673
+ computation of derived quantities). To reset, use :meth:`_del_derived`.
674
+
675
+ OUTPUT:
676
+
677
+ - instance of
678
+ :class:`~sage.manifolds.differentiable.tensorfield.TensorField`
679
+ with ``tensor_type`` = (2,0) representing the inverse metric
680
+
681
+ EXAMPLES:
682
+
683
+ Inverse of the standard metric on the 2-sphere::
684
+
685
+ sage: M = Manifold(2, 'S^2', start_index=1)
686
+ sage: U = M.open_subset('U') ; V = M.open_subset('V')
687
+ sage: M.declare_union(U,V) # S^2 is the union of U and V
688
+ sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() # stereographic coord.
689
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)),
690
+ ....: intersection_name='W', restrictions1= x^2+y^2!=0,
691
+ ....: restrictions2= u^2+v^2!=0)
692
+ sage: uv_to_xy = xy_to_uv.inverse()
693
+ sage: W = U.intersection(V) # the complement of the two poles
694
+ sage: eU = c_xy.frame() ; eV = c_uv.frame()
695
+ sage: g = M.metric('g')
696
+ sage: g[eU,1,1], g[eU,2,2] = 4/(1+x^2+y^2)^2, 4/(1+x^2+y^2)^2
697
+ sage: g.add_comp_by_continuation(eV, W, c_uv)
698
+ sage: ginv = g.inverse(); ginv
699
+ Tensor field inv_g of type (2,0) on the 2-dimensional differentiable manifold S^2
700
+ sage: ginv.display(eU)
701
+ inv_g = (1/4*x^4 + 1/4*y^4 + 1/2*(x^2 + 1)*y^2 + 1/2*x^2 + 1/4) ∂/∂x⊗∂/∂x
702
+ + (1/4*x^4 + 1/4*y^4 + 1/2*(x^2 + 1)*y^2 + 1/2*x^2 + 1/4) ∂/∂y⊗∂/∂y
703
+ sage: ginv.display(eV)
704
+ inv_g = (1/4*u^4 + 1/4*v^4 + 1/2*(u^2 + 1)*v^2 + 1/2*u^2 + 1/4) ∂/∂u⊗∂/∂u
705
+ + (1/4*u^4 + 1/4*v^4 + 1/2*(u^2 + 1)*v^2 + 1/2*u^2 + 1/4) ∂/∂v⊗∂/∂v
706
+
707
+ Let us check that ``ginv`` is indeed the inverse of ``g``::
708
+
709
+ sage: s = g.contract(ginv); s # contraction of last index of g with first index of ginv
710
+ Tensor field of type (1,1) on the 2-dimensional differentiable manifold S^2
711
+ sage: s == M.tangent_identity_field()
712
+ True
713
+ """
714
+ # Is the inverse metric up to date?
715
+ for dom, rst in self._restrictions.items():
716
+ self._inverse._restrictions[dom] = rst.inverse(
717
+ expansion_symbol=expansion_symbol,
718
+ order=order) # forces the update
719
+ # of the restriction
720
+ return self._inverse
721
+
722
+ def connection(self, name=None, latex_name=None, init_coef=True):
723
+ r"""
724
+ Return the unique torsion-free affine connection compatible with
725
+ ``self``.
726
+
727
+ This is the so-called Levi-Civita connection.
728
+
729
+ INPUT:
730
+
731
+ - ``name`` -- (default: ``None``) name given to the Levi-Civita
732
+ connection; if ``None``, it is formed from the metric name
733
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
734
+ Levi-Civita connection; if ``None``, it is set to ``name``, or if the
735
+ latter is None as well, it formed from the symbol `\nabla` and the
736
+ metric symbol
737
+ - ``init_coef`` -- boolean (default: ``True``); determines whether the
738
+ connection coefficients are initialized, as Christoffel symbols
739
+ in the top charts of the domain of ``self`` (i.e. disregarding
740
+ the subcharts)
741
+
742
+ OUTPUT:
743
+
744
+ - the Levi-Civita connection, as an instance of
745
+ :class:`~sage.manifolds.differentiable.levi_civita_connection.LeviCivitaConnection`
746
+
747
+ EXAMPLES:
748
+
749
+ Levi-Civita connection associated with the Euclidean metric on
750
+ `\RR^3`::
751
+
752
+ sage: M = Manifold(3, 'R^3', start_index=1)
753
+
754
+ Let us use spherical coordinates on `\RR^3`::
755
+
756
+ sage: U = M.open_subset('U') # the complement of the half-plane (y=0, x>=0)
757
+ sage: c_spher.<r,th,ph> = U.chart(r'r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi')
758
+ sage: g = U.metric('g')
759
+ sage: g[1,1], g[2,2], g[3,3] = 1, r^2 , (r*sin(th))^2 # the Euclidean metric
760
+ sage: g.connection()
761
+ Levi-Civita connection nabla_g associated with the Riemannian
762
+ metric g on the Open subset U of the 3-dimensional differentiable
763
+ manifold R^3
764
+ sage: g.connection().display() # Nonzero connection coefficients
765
+ Gam^r_th,th = -r
766
+ Gam^r_ph,ph = -r*sin(th)^2
767
+ Gam^th_r,th = 1/r
768
+ Gam^th_th,r = 1/r
769
+ Gam^th_ph,ph = -cos(th)*sin(th)
770
+ Gam^ph_r,ph = 1/r
771
+ Gam^ph_th,ph = cos(th)/sin(th)
772
+ Gam^ph_ph,r = 1/r
773
+ Gam^ph_ph,th = cos(th)/sin(th)
774
+
775
+ Test of compatibility with the metric::
776
+
777
+ sage: Dg = g.connection()(g) ; Dg
778
+ Tensor field nabla_g(g) of type (0,3) on the Open subset U of the
779
+ 3-dimensional differentiable manifold R^3
780
+ sage: Dg == 0
781
+ True
782
+ sage: Dig = g.connection()(g.inverse()) ; Dig
783
+ Tensor field nabla_g(inv_g) of type (2,1) on the Open subset U of
784
+ the 3-dimensional differentiable manifold R^3
785
+ sage: Dig == 0
786
+ True
787
+ """
788
+ from sage.manifolds.differentiable.levi_civita_connection import (
789
+ LeviCivitaConnection,
790
+ )
791
+ if self._connection is None:
792
+ if latex_name is None:
793
+ if name is None:
794
+ latex_name = r'\nabla_{' + self._latex_name + '}'
795
+ else:
796
+ latex_name = name
797
+ if name is None:
798
+ name = 'nabla_' + self._name
799
+ self._connection = LeviCivitaConnection(self, name,
800
+ latex_name=latex_name,
801
+ init_coef=init_coef)
802
+ return self._connection
803
+
804
+ def christoffel_symbols(self, chart=None):
805
+ r"""
806
+ Christoffel symbols of ``self`` with respect to a chart.
807
+
808
+ INPUT:
809
+
810
+ - ``chart`` -- (default: ``None``) chart with respect to which the
811
+ Christoffel symbols are required; if none is provided, the
812
+ default chart of the metric's domain is assumed.
813
+
814
+ OUTPUT:
815
+
816
+ - the set of Christoffel symbols in the given chart, as an instance of
817
+ :class:`~sage.tensor.modules.comp.CompWithSym`
818
+
819
+ EXAMPLES:
820
+
821
+ Christoffel symbols of the flat metric on `\RR^3` with respect to
822
+ spherical coordinates::
823
+
824
+ sage: M = Manifold(3, 'R3', r'\RR^3', start_index=1)
825
+ sage: U = M.open_subset('U') # the complement of the half-plane (y=0, x>=0)
826
+ sage: X.<r,th,ph> = U.chart(r'r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi')
827
+ sage: g = U.metric('g')
828
+ sage: g[1,1], g[2,2], g[3,3] = 1, r^2, r^2*sin(th)^2
829
+ sage: g.display() # the standard flat metric expressed in spherical coordinates
830
+ g = dr⊗dr + r^2 dth⊗dth + r^2*sin(th)^2 dph⊗dph
831
+ sage: Gam = g.christoffel_symbols() ; Gam
832
+ 3-indices components w.r.t. Coordinate frame (U, (∂/∂r,∂/∂th,∂/∂ph)),
833
+ with symmetry on the index positions (1, 2)
834
+ sage: type(Gam)
835
+ <class 'sage.tensor.modules.comp.CompWithSym'>
836
+ sage: Gam[:]
837
+ [[[0, 0, 0], [0, -r, 0], [0, 0, -r*sin(th)^2]],
838
+ [[0, 1/r, 0], [1/r, 0, 0], [0, 0, -cos(th)*sin(th)]],
839
+ [[0, 0, 1/r], [0, 0, cos(th)/sin(th)], [1/r, cos(th)/sin(th), 0]]]
840
+ sage: Gam[1,2,2]
841
+ -r
842
+ sage: Gam[2,1,2]
843
+ 1/r
844
+ sage: Gam[3,1,3]
845
+ 1/r
846
+ sage: Gam[3,2,3]
847
+ cos(th)/sin(th)
848
+ sage: Gam[2,3,3]
849
+ -cos(th)*sin(th)
850
+
851
+ Note that a better display of the Christoffel symbols is provided by
852
+ the method :meth:`christoffel_symbols_display`::
853
+
854
+ sage: g.christoffel_symbols_display()
855
+ Gam^r_th,th = -r
856
+ Gam^r_ph,ph = -r*sin(th)^2
857
+ Gam^th_r,th = 1/r
858
+ Gam^th_ph,ph = -cos(th)*sin(th)
859
+ Gam^ph_r,ph = 1/r
860
+ Gam^ph_th,ph = cos(th)/sin(th)
861
+ """
862
+ if chart is None:
863
+ frame = self._domain._def_chart._frame
864
+ else:
865
+ frame = chart._frame
866
+ return self.connection().coef(frame)
867
+
868
+ def christoffel_symbols_display(self, chart=None, symbol=None,
869
+ latex_symbol=None, index_labels=None, index_latex_labels=None,
870
+ coordinate_labels=True, only_nonzero=True,
871
+ only_nonredundant=True):
872
+ r"""
873
+ Display the Christoffel symbols w.r.t. to a given chart, one
874
+ per line.
875
+
876
+ The output is either text-formatted (console mode) or LaTeX-formatted
877
+ (notebook mode).
878
+
879
+ INPUT:
880
+
881
+ - ``chart`` -- (default: ``None``) chart with respect to which the
882
+ Christoffel symbols are defined; if none is provided, the
883
+ default chart of the metric's domain is assumed.
884
+ - ``symbol`` -- (default: ``None``) string specifying the
885
+ symbol of the connection coefficients; if ``None``, 'Gam' is used
886
+ - ``latex_symbol`` -- (default: ``None``) string specifying the LaTeX
887
+ symbol for the components; if ``None``, '\\Gamma' is used
888
+ - ``index_labels`` -- (default: ``None``) list of strings representing
889
+ the labels of each index; if ``None``, coordinate symbols are used
890
+ except if ``coordinate_symbols`` is set to ``False``, in which case
891
+ integer labels are used
892
+ - ``index_latex_labels`` -- (default: ``None``) list of strings
893
+ representing the LaTeX labels of each index; if ``None``, coordinate
894
+ LaTeX symbols are used, except if ``coordinate_symbols`` is set to
895
+ ``False``, in which case integer labels are used
896
+ - ``coordinate_labels`` -- boolean (default: ``True``); if ``True``,
897
+ coordinate symbols are used by default (instead of integers)
898
+ - ``only_nonzero`` -- boolean (default: ``True``); if ``True``, only
899
+ nonzero connection coefficients are displayed
900
+ - ``only_nonredundant`` -- boolean (default: ``True``); if ``True``,
901
+ only nonredundant (w.r.t. the symmetry of the last two indices)
902
+ connection coefficients are displayed
903
+
904
+ EXAMPLES:
905
+
906
+ Christoffel symbols of the flat metric on `\RR^3` with respect to
907
+ spherical coordinates::
908
+
909
+ sage: M = Manifold(3, 'R3', r'\RR^3', start_index=1)
910
+ sage: U = M.open_subset('U') # the complement of the half-plane (y=0, x>=0)
911
+ sage: X.<r,th,ph> = U.chart(r'r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi')
912
+ sage: g = U.metric('g')
913
+ sage: g[1,1], g[2,2], g[3,3] = 1, r^2, r^2*sin(th)^2
914
+ sage: g.display() # the standard flat metric expressed in spherical coordinates
915
+ g = dr⊗dr + r^2 dth⊗dth + r^2*sin(th)^2 dph⊗dph
916
+ sage: g.christoffel_symbols_display()
917
+ Gam^r_th,th = -r
918
+ Gam^r_ph,ph = -r*sin(th)^2
919
+ Gam^th_r,th = 1/r
920
+ Gam^th_ph,ph = -cos(th)*sin(th)
921
+ Gam^ph_r,ph = 1/r
922
+ Gam^ph_th,ph = cos(th)/sin(th)
923
+
924
+ To list all nonzero Christoffel symbols, including those that can be
925
+ deduced by symmetry, use ``only_nonredundant=False``::
926
+
927
+ sage: g.christoffel_symbols_display(only_nonredundant=False)
928
+ Gam^r_th,th = -r
929
+ Gam^r_ph,ph = -r*sin(th)^2
930
+ Gam^th_r,th = 1/r
931
+ Gam^th_th,r = 1/r
932
+ Gam^th_ph,ph = -cos(th)*sin(th)
933
+ Gam^ph_r,ph = 1/r
934
+ Gam^ph_th,ph = cos(th)/sin(th)
935
+ Gam^ph_ph,r = 1/r
936
+ Gam^ph_ph,th = cos(th)/sin(th)
937
+
938
+ Listing all Christoffel symbols (except those that can be deduced by
939
+ symmetry), including the vanishing one::
940
+
941
+ sage: g.christoffel_symbols_display(only_nonzero=False)
942
+ Gam^r_r,r = 0
943
+ Gam^r_r,th = 0
944
+ Gam^r_r,ph = 0
945
+ Gam^r_th,th = -r
946
+ Gam^r_th,ph = 0
947
+ Gam^r_ph,ph = -r*sin(th)^2
948
+ Gam^th_r,r = 0
949
+ Gam^th_r,th = 1/r
950
+ Gam^th_r,ph = 0
951
+ Gam^th_th,th = 0
952
+ Gam^th_th,ph = 0
953
+ Gam^th_ph,ph = -cos(th)*sin(th)
954
+ Gam^ph_r,r = 0
955
+ Gam^ph_r,th = 0
956
+ Gam^ph_r,ph = 1/r
957
+ Gam^ph_th,th = 0
958
+ Gam^ph_th,ph = cos(th)/sin(th)
959
+ Gam^ph_ph,ph = 0
960
+
961
+ Using integer labels::
962
+
963
+ sage: g.christoffel_symbols_display(coordinate_labels=False)
964
+ Gam^1_22 = -r
965
+ Gam^1_33 = -r*sin(th)^2
966
+ Gam^2_12 = 1/r
967
+ Gam^2_33 = -cos(th)*sin(th)
968
+ Gam^3_13 = 1/r
969
+ Gam^3_23 = cos(th)/sin(th)
970
+ """
971
+ if chart is None:
972
+ chart = self._domain.default_chart()
973
+ return self.connection().display(frame=chart.frame(), chart=chart,
974
+ symbol=symbol, latex_symbol=latex_symbol,
975
+ index_labels=index_labels, index_latex_labels=index_latex_labels,
976
+ coordinate_labels=coordinate_labels, only_nonzero=only_nonzero,
977
+ only_nonredundant=only_nonredundant)
978
+
979
+ def riemann(self, name=None, latex_name=None):
980
+ r"""
981
+ Return the Riemann curvature tensor associated with the metric.
982
+
983
+ This method is actually a shortcut for ``self.connection().riemann()``
984
+
985
+ The Riemann curvature tensor is the tensor field `R` of type (1,3)
986
+ defined by
987
+
988
+ .. MATH::
989
+
990
+ R(\omega, u, v, w) = \left\langle \omega, \nabla_u \nabla_v w
991
+ - \nabla_v \nabla_u w - \nabla_{[u, v]} w \right\rangle
992
+
993
+ for any 1-form `\omega` and any vector fields `u`, `v` and `w`.
994
+
995
+ INPUT:
996
+
997
+ - ``name`` -- (default: ``None``) name given to the Riemann tensor;
998
+ if none, it is set to "Riem(g)", where "g" is the metric's name
999
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
1000
+ Riemann tensor; if none, it is set to "\\mathrm{Riem}(g)", where "g"
1001
+ is the metric's name
1002
+
1003
+ OUTPUT:
1004
+
1005
+ - the Riemann curvature tensor `R`, as an instance of
1006
+ :class:`~sage.manifolds.differentiable.tensorfield.TensorField`
1007
+
1008
+ EXAMPLES:
1009
+
1010
+ Riemann tensor of the standard metric on the 2-sphere::
1011
+
1012
+ sage: M = Manifold(2, 'S^2', start_index=1)
1013
+ sage: U = M.open_subset('U') # the complement of a meridian (domain of spherical coordinates)
1014
+ sage: c_spher.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
1015
+ sage: a = var('a') # the sphere radius
1016
+ sage: g = U.metric('g')
1017
+ sage: g[1,1], g[2,2] = a^2, a^2*sin(th)^2
1018
+ sage: g.display() # standard metric on the 2-sphere of radius a:
1019
+ g = a^2 dth⊗dth + a^2*sin(th)^2 dph⊗dph
1020
+ sage: g.riemann()
1021
+ Tensor field Riem(g) of type (1,3) on the Open subset U of the
1022
+ 2-dimensional differentiable manifold S^2
1023
+ sage: g.riemann()[:]
1024
+ [[[[0, 0], [0, 0]], [[0, sin(th)^2], [-sin(th)^2, 0]]],
1025
+ [[[0, -1], [1, 0]], [[0, 0], [0, 0]]]]
1026
+
1027
+ In dimension 2, the Riemann tensor can be expressed entirely in terms of
1028
+ the Ricci scalar `r`:
1029
+
1030
+ .. MATH::
1031
+
1032
+ R^i_{\ \, jlk} = \frac{r}{2} \left( \delta^i_{\ \, k} g_{jl}
1033
+ - \delta^i_{\ \, l} g_{jk} \right)
1034
+
1035
+ This formula can be checked here, with the r.h.s. rewritten as
1036
+ `-r g_{j[k} \delta^i_{\ \, l]}`::
1037
+
1038
+ sage: g.riemann() == \
1039
+ ....: -g.ricci_scalar()*(g*U.tangent_identity_field()).antisymmetrize(2,3)
1040
+ True
1041
+
1042
+ Using SymPy as symbolic engine::
1043
+
1044
+ sage: M.set_calculus_method('sympy')
1045
+ sage: g = U.metric('g')
1046
+ sage: g[1,1], g[2,2] = a**2, a**2*sin(th)**2
1047
+ sage: g.riemann()[:]
1048
+ [[[[0, 0], [0, 0]],
1049
+ [[0, sin(2*th)/(2*tan(th)) - cos(2*th)],
1050
+ [-sin(2*th)/(2*tan(th)) + cos(2*th), 0]]],
1051
+ [[[0, -1], [1, 0]], [[0, 0], [0, 0]]]]
1052
+ """
1053
+ return self.connection().riemann(name, latex_name)
1054
+
1055
+ def ricci(self, name=None, latex_name=None):
1056
+ r"""
1057
+ Return the Ricci tensor associated with the metric.
1058
+
1059
+ This method is actually a shortcut for ``self.connection().ricci()``
1060
+
1061
+ The Ricci tensor is the tensor field `Ric` of type (0,2)
1062
+ defined from the Riemann curvature tensor `R` by
1063
+
1064
+ .. MATH::
1065
+
1066
+ Ric(u, v) = R(e^i, u, e_i, v)
1067
+
1068
+ for any vector fields `u` and `v`, `(e_i)` being any vector frame and
1069
+ `(e^i)` the dual coframe.
1070
+
1071
+ INPUT:
1072
+
1073
+ - ``name`` -- (default: ``None``) name given to the Ricci tensor;
1074
+ if none, it is set to "Ric(g)", where "g" is the metric's name
1075
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
1076
+ Ricci tensor; if none, it is set to "\\mathrm{Ric}(g)", where "g"
1077
+ is the metric's name
1078
+
1079
+ OUTPUT:
1080
+
1081
+ - the Ricci tensor `Ric`, as an instance of
1082
+ :class:`~sage.manifolds.differentiable.tensorfield.TensorField` of tensor
1083
+ type (0,2) and symmetric
1084
+
1085
+ EXAMPLES:
1086
+
1087
+ Ricci tensor of the standard metric on the 2-sphere::
1088
+
1089
+ sage: M = Manifold(2, 'S^2', start_index=1)
1090
+ sage: U = M.open_subset('U') # the complement of a meridian (domain of spherical coordinates)
1091
+ sage: c_spher.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
1092
+ sage: a = var('a') # the sphere radius
1093
+ sage: g = U.metric('g')
1094
+ sage: g[1,1], g[2,2] = a^2, a^2*sin(th)^2
1095
+ sage: g.display() # standard metric on the 2-sphere of radius a:
1096
+ g = a^2 dth⊗dth + a^2*sin(th)^2 dph⊗dph
1097
+ sage: g.ricci()
1098
+ Field of symmetric bilinear forms Ric(g) on the Open subset U of
1099
+ the 2-dimensional differentiable manifold S^2
1100
+ sage: g.ricci()[:]
1101
+ [ 1 0]
1102
+ [ 0 sin(th)^2]
1103
+ sage: g.ricci() == a^(-2) * g
1104
+ True
1105
+ """
1106
+ return self.connection().ricci(name, latex_name)
1107
+
1108
+ def ricci_scalar(self, name=None, latex_name=None):
1109
+ r"""
1110
+ Return the Ricci scalar associated with the metric.
1111
+
1112
+ The Ricci scalar is the scalar field `r` defined from the Ricci tensor
1113
+ `Ric` and the metric tensor `g` by
1114
+
1115
+ .. MATH::
1116
+
1117
+ r = g^{ij} Ric_{ij}
1118
+
1119
+ INPUT:
1120
+
1121
+ - ``name`` -- (default: ``None``) name given to the Ricci scalar;
1122
+ if none, it is set to "r(g)", where "g" is the metric's name
1123
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
1124
+ Ricci scalar; if none, it is set to "\\mathrm{r}(g)", where "g"
1125
+ is the metric's name
1126
+
1127
+ OUTPUT:
1128
+
1129
+ - the Ricci scalar `r`, as an instance of
1130
+ :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField`
1131
+
1132
+ EXAMPLES:
1133
+
1134
+ Ricci scalar of the standard metric on the 2-sphere::
1135
+
1136
+ sage: M = Manifold(2, 'S^2', start_index=1)
1137
+ sage: U = M.open_subset('U') # the complement of a meridian (domain of spherical coordinates)
1138
+ sage: c_spher.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
1139
+ sage: a = var('a') # the sphere radius
1140
+ sage: g = U.metric('g')
1141
+ sage: g[1,1], g[2,2] = a^2, a^2*sin(th)^2
1142
+ sage: g.display() # standard metric on the 2-sphere of radius a:
1143
+ g = a^2 dth⊗dth + a^2*sin(th)^2 dph⊗dph
1144
+ sage: g.ricci_scalar()
1145
+ Scalar field r(g) on the Open subset U of the 2-dimensional
1146
+ differentiable manifold S^2
1147
+ sage: g.ricci_scalar().display() # The Ricci scalar is constant:
1148
+ r(g): U → ℝ
1149
+ (th, ph) ↦ 2/a^2
1150
+
1151
+ """
1152
+ if self._ricci_scalar is None:
1153
+ resu = self.inverse().contract(0, 1, self.ricci(), 0, 1)
1154
+ if name is None:
1155
+ name = "r(" + self._name + ")"
1156
+ if latex_name is None:
1157
+ latex_name = r"\mathrm{r}\left(" + self._latex_name + \
1158
+ r"\right)"
1159
+ resu._name = name
1160
+ resu._latex_name = latex_name
1161
+ self._ricci_scalar = resu
1162
+ return self._ricci_scalar
1163
+
1164
+ def weyl(self, name=None, latex_name=None):
1165
+ r"""
1166
+ Return the Weyl conformal tensor associated with the metric.
1167
+
1168
+ The Weyl conformal tensor is the tensor field `C` of type (1,3)
1169
+ defined as the trace-free part of the Riemann curvature tensor `R`
1170
+
1171
+ INPUT:
1172
+
1173
+ - ``name`` -- (default: ``None``) name given to the Weyl conformal
1174
+ tensor; if ``None``, it is set to "C(g)", where "g" is the metric's
1175
+ name
1176
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
1177
+ Weyl conformal tensor; if ``None``, it is set to "\\mathrm{C}(g)",
1178
+ where "g" is the metric's name
1179
+
1180
+ OUTPUT:
1181
+
1182
+ - the Weyl conformal tensor `C`, as an instance of
1183
+ :class:`~sage.manifolds.differentiable.tensorfield.TensorField`
1184
+
1185
+ EXAMPLES:
1186
+
1187
+ Checking that the Weyl tensor identically vanishes on a 3-dimensional
1188
+ manifold, for instance the hyperbolic space `H^3`::
1189
+
1190
+ sage: M = Manifold(3, 'H^3', start_index=1)
1191
+ sage: U = M.open_subset('U') # the complement of the half-plane (y=0, x>=0)
1192
+ sage: X.<rh,th,ph> = U.chart(r'rh:(0,+oo):\rho th:(0,pi):\theta ph:(0,2*pi):\phi')
1193
+ sage: g = U.metric('g')
1194
+ sage: b = var('b')
1195
+ sage: g[1,1], g[2,2], g[3,3] = b^2, (b*sinh(rh))^2, (b*sinh(rh)*sin(th))^2
1196
+ sage: g.display() # standard metric on H^3:
1197
+ g = b^2 drh⊗drh + b^2*sinh(rh)^2 dth⊗dth
1198
+ + b^2*sin(th)^2*sinh(rh)^2 dph⊗dph
1199
+ sage: C = g.weyl() ; C
1200
+ Tensor field C(g) of type (1,3) on the Open subset U of the
1201
+ 3-dimensional differentiable manifold H^3
1202
+ sage: C == 0
1203
+ True
1204
+ """
1205
+ if self._weyl is None:
1206
+ n = self._ambient_domain.dimension()
1207
+ if n < 3:
1208
+ raise ValueError("the Weyl tensor is not defined for a " +
1209
+ "manifold of dimension n <= 2")
1210
+ delta = self._domain.tangent_identity_field(dest_map=self._vmodule._dest_map)
1211
+ riem = self.riemann()
1212
+ ric = self.ricci()
1213
+ rscal = self.ricci_scalar()
1214
+ # First index of the Ricci tensor raised with the metric
1215
+ ricup = ric.up(self, 0)
1216
+ aux = self*ricup + ric*delta - rscal/(n-1) * self*delta
1217
+ self._weyl = riem + 2/(n-2) * aux.antisymmetrize(2,3)
1218
+ if name is None:
1219
+ name = "C(" + self._name + ")"
1220
+ if latex_name is None:
1221
+ latex_name = r"\mathrm{C}\left(" + self._latex_name + r"\right)"
1222
+ self._weyl.set_name(name=name, latex_name=latex_name)
1223
+ return self._weyl
1224
+
1225
+ def schouten(self, name=None, latex_name=None):
1226
+ r"""
1227
+ Return the Schouten tensor associated with the metric.
1228
+
1229
+ The Schouten tensor is the tensor field `Sc` of type (0,2) defined
1230
+ from the Ricci curvature tensor `Ric` (see :meth:`ricci`) and the
1231
+ scalar curvature `r` (see :meth:`ricci_scalar`) and the metric `g` by
1232
+
1233
+ .. MATH::
1234
+
1235
+ Sc(u, v) = \frac{1}{n-2}\left(Ric(u, v) + \frac{r}{2(n-1)}g(u,v)
1236
+ \right)
1237
+
1238
+ for any vector fields `u` and `v`.
1239
+
1240
+ INPUT:
1241
+
1242
+ - ``name`` -- (default: ``None``) name given to the Schouten tensor;
1243
+ if none, it is set to "Schouten(g)", where "g" is the metric's name
1244
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
1245
+ Schouten tensor; if none, it is set to "\\mathrm{Schouten}(g)",
1246
+ where "g" is the metric's name
1247
+
1248
+ OUTPUT:
1249
+
1250
+ - the Schouten tensor `Sc`, as an instance of
1251
+ :class:`~sage.manifolds.differentiable.tensorfield.TensorField` of tensor
1252
+ type (0,2) and symmetric
1253
+
1254
+ EXAMPLES:
1255
+
1256
+ Schouten tensor of the left invariant metric of Heisenberg's
1257
+ Nil group::
1258
+
1259
+ sage: M = Manifold(3, 'Nil', start_index=1)
1260
+ sage: X.<x,y,z> = M.chart()
1261
+ sage: g = M.riemannian_metric('g')
1262
+ sage: g[1,1], g[2,2], g[2,3], g[3,3] = 1, 1+x^2, -x, 1
1263
+ sage: g.display()
1264
+ g = dx⊗dx + (x^2 + 1) dy⊗dy - x dy⊗dz - x dz⊗dy + dz⊗dz
1265
+ sage: g.schouten()
1266
+ Field of symmetric bilinear forms Schouten(g) on the 3-dimensional
1267
+ differentiable manifold Nil
1268
+ sage: g.schouten().display()
1269
+ Schouten(g) = -3/8 dx⊗dx + (5/8*x^2 - 3/8) dy⊗dy - 5/8*x dy⊗dz
1270
+ - 5/8*x dz⊗dy + 5/8 dz⊗dz
1271
+ """
1272
+ n = self._ambient_domain.dimension()
1273
+ if n < 3:
1274
+ raise ValueError("the Schouten tensor is only defined for a " +
1275
+ "manifold of dimension >= 3")
1276
+ if self._schouten is None:
1277
+ s = (1/(n-2))*self.ricci() - (self.ricci_scalar()/(2*(n-1)*(n-2)))*self
1278
+ name = name or 'Schouten(' + self._name + ')'
1279
+ latex_name = latex_name or r'\mathrm{Schouten}(' + self._latex_name + ')'
1280
+ s.set_name(name=name, latex_name=latex_name)
1281
+ self._schouten = s
1282
+ return self._schouten
1283
+
1284
+ def cotton(self, name=None, latex_name=None):
1285
+ r"""
1286
+ Return the Cotton conformal tensor associated with the metric.
1287
+ The tensor has type (0,3) and is defined in terms of the Schouten
1288
+ tensor `S` (see :meth:`schouten`):
1289
+
1290
+ .. MATH::
1291
+
1292
+ C_{ijk} = (n-2) \left(\nabla_k S_{ij}
1293
+ - \nabla_j S_{ik}\right)
1294
+
1295
+ INPUT:
1296
+
1297
+ - ``name`` -- (default: ``None``) name given to the Cotton conformal
1298
+ tensor; if ``None``, it is set to "Cot(g)", where "g" is the metric's
1299
+ name
1300
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
1301
+ Cotton conformal tensor; if ``None``, it is set to "\\mathrm{Cot}(g)",
1302
+ where "g" is the metric's name
1303
+
1304
+ OUTPUT:
1305
+
1306
+ - the Cotton conformal tensor `Cot`, as an instance of
1307
+ :class:`~sage.manifolds.differentiable.tensorfield.TensorField`
1308
+
1309
+ EXAMPLES:
1310
+
1311
+ Checking that the Cotton tensor identically vanishes on a conformally flat
1312
+ 3-dimensional manifold, for instance the hyperbolic space `H^3`::
1313
+
1314
+ sage: M = Manifold(3, 'H^3', start_index=1)
1315
+ sage: U = M.open_subset('U') # the complement of the half-plane (y=0, x>=0)
1316
+ sage: X.<rh,th,ph> = U.chart(r'rh:(0,+oo):\rho th:(0,pi):\theta ph:(0,2*pi):\phi')
1317
+ sage: g = U.metric('g')
1318
+ sage: b = var('b')
1319
+ sage: g[1,1], g[2,2], g[3,3] = b^2, (b*sinh(rh))^2, (b*sinh(rh)*sin(th))^2
1320
+ sage: g.display() # standard metric on H^3:
1321
+ g = b^2 drh⊗drh + b^2*sinh(rh)^2 dth⊗dth
1322
+ + b^2*sin(th)^2*sinh(rh)^2 dph⊗dph
1323
+ sage: Cot = g.cotton() ; Cot # long time
1324
+ Tensor field Cot(g) of type (0,3) on the Open subset U of the
1325
+ 3-dimensional differentiable manifold H^3
1326
+ sage: Cot == 0 # long time
1327
+ True
1328
+ """
1329
+ n = self._ambient_domain.dimension()
1330
+ if n < 3:
1331
+ raise ValueError("the Cotton tensor is only defined for a " +
1332
+ "manifold of dimension >= 3")
1333
+ if self._cotton is None:
1334
+ nabla = self.connection()
1335
+ s = self.schouten()
1336
+ cot = 2*(n-2)*nabla(s).antisymmetrize(1,2)
1337
+ name = name or 'Cot(' + self._name + ')'
1338
+ latex_name = latex_name or r'\mathrm{Cot}(' + self._latex_name + ')'
1339
+ cot.set_name(name=name, latex_name=latex_name)
1340
+ self._cotton = cot
1341
+ return self._cotton
1342
+
1343
+ def cotton_york(self, name=None, latex_name=None):
1344
+ r"""
1345
+ Return the Cotton-York conformal tensor associated with the metric.
1346
+ The tensor has type (0,2) and is only defined for manifolds of
1347
+ dimension 3. It is defined in terms of the Cotton tensor `C`
1348
+ (see :meth:`cotton`) or the Schouten tensor `S` (see :meth:`schouten`):
1349
+
1350
+ .. MATH::
1351
+
1352
+ CY_{ij} = \frac{1}{2} \epsilon^{kl}_{\ \ \, i} C_{jlk}
1353
+ = \epsilon^{kl}_{\ \ \, i} \nabla_k S_{lj}
1354
+
1355
+ INPUT:
1356
+
1357
+ - ``name`` -- (default: ``None``) name given to the Cotton-York
1358
+ tensor; if ``None``, it is set to "CY(g)", where "g" is the metric's
1359
+ name
1360
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
1361
+ Cotton-York tensor; if ``None``, it is set to "\\mathrm{CY}(g)",
1362
+ where "g" is the metric's name
1363
+
1364
+ OUTPUT:
1365
+
1366
+ - the Cotton-York conformal tensor `CY`, as an instance of
1367
+ :class:`~sage.manifolds.differentiable.tensorfield.TensorField`
1368
+
1369
+ EXAMPLES:
1370
+
1371
+ Compute the determinant of the Cotton-York tensor for the Heisenberg
1372
+ group with the left invariant metric::
1373
+
1374
+ sage: M = Manifold(3, 'Nil', start_index=1)
1375
+ sage: X.<x,y,z> = M.chart()
1376
+ sage: g = M.riemannian_metric('g')
1377
+ sage: g[1,1], g[2,2], g[2,3], g[3,3] = 1, 1+x^2, -x, 1
1378
+ sage: g.display()
1379
+ g = dx⊗dx + (x^2 + 1) dy⊗dy - x dy⊗dz - x dz⊗dy + dz⊗dz
1380
+ sage: CY = g.cotton_york() ; CY # long time
1381
+ Tensor field CY(g) of type (0,2) on the 3-dimensional
1382
+ differentiable manifold Nil
1383
+ sage: CY.display() # long time
1384
+ CY(g) = 1/2 dx⊗dx + (-x^2 + 1/2) dy⊗dy + x dy⊗dz + x dz⊗dy - dz⊗dz
1385
+ sage: det(CY[:]) # long time
1386
+ -1/4
1387
+ """
1388
+ n = self._ambient_domain.dimension()
1389
+ if n != 3:
1390
+ raise ValueError("the Cotton-York tensor is only defined for a " +
1391
+ "manifold of dimension 3")
1392
+ if self._cotton_york is None:
1393
+ cot = self.cotton()
1394
+ eps = self.volume_form(2)
1395
+ cy = eps.contract(0, 1, cot, 2, 1)/2
1396
+ name = name or 'CY(' + self._name + ')'
1397
+ latex_name = latex_name or r'\mathrm{CY}(' + self._latex_name + ')'
1398
+ cy.set_name(name=name, latex_name=latex_name)
1399
+ self._cotton_york = cy
1400
+ return self._cotton_york
1401
+
1402
+ def determinant(self, frame=None):
1403
+ r"""
1404
+ Determinant of the metric components in the specified frame.
1405
+
1406
+ INPUT:
1407
+
1408
+ - ``frame`` -- (default: ``None``) vector frame with
1409
+ respect to which the components `g_{ij}` of the metric are defined;
1410
+ if ``None``, the default frame of the metric's domain is used. If a
1411
+ chart is provided instead of a frame, the associated coordinate
1412
+ frame is used
1413
+
1414
+ OUTPUT:
1415
+
1416
+ - the determinant `\det (g_{ij})`, as an instance of
1417
+ :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField`
1418
+
1419
+ EXAMPLES:
1420
+
1421
+ Metric determinant on a 2-dimensional manifold::
1422
+
1423
+ sage: M = Manifold(2, 'M', start_index=1)
1424
+ sage: X.<x,y> = M.chart()
1425
+ sage: g = M.metric('g')
1426
+ sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y
1427
+ sage: g[:]
1428
+ [ x + 1 x*y]
1429
+ [ x*y -y + 1]
1430
+ sage: s = g.determinant() # determinant in M's default frame
1431
+ sage: s.expr()
1432
+ -x^2*y^2 - (x + 1)*y + x + 1
1433
+
1434
+ A shortcut is ``det()``::
1435
+
1436
+ sage: g.det() == g.determinant()
1437
+ True
1438
+
1439
+ The notation ``det(g)`` can be used::
1440
+
1441
+ sage: det(g) == g.determinant()
1442
+ True
1443
+
1444
+ Determinant in a frame different from the default's one::
1445
+
1446
+ sage: Y.<u,v> = M.chart()
1447
+ sage: ch_X_Y = X.transition_map(Y, [x+y, x-y])
1448
+ sage: ch_X_Y.inverse()
1449
+ Change of coordinates from Chart (M, (u, v)) to Chart (M, (x, y))
1450
+ sage: g.comp(Y.frame())[:, Y]
1451
+ [ 1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2 1/4*u]
1452
+ [ 1/4*u -1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2]
1453
+ sage: g.determinant(Y.frame()).expr()
1454
+ -1/4*x^2*y^2 - 1/4*(x + 1)*y + 1/4*x + 1/4
1455
+ sage: g.determinant(Y.frame()).expr(Y)
1456
+ -1/64*u^4 - 1/64*v^4 + 1/32*(u^2 + 2)*v^2 - 1/16*u^2 + 1/4*v + 1/4
1457
+
1458
+ A chart can be passed instead of a frame::
1459
+
1460
+ sage: g.determinant(X) is g.determinant(X.frame())
1461
+ True
1462
+ sage: g.determinant(Y) is g.determinant(Y.frame())
1463
+ True
1464
+
1465
+ The metric determinant depends on the frame::
1466
+
1467
+ sage: g.determinant(X.frame()) == g.determinant(Y.frame())
1468
+ False
1469
+
1470
+ Using SymPy as symbolic engine::
1471
+
1472
+ sage: M.set_calculus_method('sympy')
1473
+ sage: g = M.metric('g')
1474
+ sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y
1475
+ sage: s = g.determinant() # determinant in M's default frame
1476
+ sage: s.expr()
1477
+ -x**2*y**2 + x - y*(x + 1) + 1
1478
+ """
1479
+ from sage.matrix.constructor import matrix
1480
+ dom = self._domain
1481
+ if frame is None:
1482
+ frame = dom._def_frame
1483
+ if frame in dom._atlas:
1484
+ # frame is actually a chart and is changed to the associated
1485
+ # coordinate frame:
1486
+ frame = frame._frame
1487
+ if frame not in self._determinants:
1488
+ # a new computation is necessary
1489
+ resu = frame._domain.scalar_field()
1490
+ manif = self._ambient_domain
1491
+ gg = self.comp(frame)
1492
+ i1 = manif.start_index()
1493
+ for chart in gg[[i1, i1]]._express:
1494
+ # TODO: do the computation without the 'SR' enforcement
1495
+ gm = matrix( [[ gg[i, j, chart].expr(method='SR')
1496
+ for j in manif.irange()] for i in manif.irange()] )
1497
+ detgm = chart.simplify(gm.det(), method='SR')
1498
+ resu.add_expr(detgm, chart=chart)
1499
+ self._determinants[frame] = resu
1500
+ return self._determinants[frame]
1501
+
1502
+ det = determinant
1503
+
1504
+ def sqrt_abs_det(self, frame=None):
1505
+ r"""
1506
+ Square root of the absolute value of the determinant of the metric
1507
+ components in the specified frame.
1508
+
1509
+ INPUT:
1510
+
1511
+ - ``frame`` -- (default: ``None``) vector frame with
1512
+ respect to which the components `g_{ij}` of ``self`` are defined;
1513
+ if ``None``, the domain's default frame is used. If a chart is
1514
+ provided, the associated coordinate frame is used
1515
+
1516
+ OUTPUT:
1517
+
1518
+ - `\sqrt{|\det (g_{ij})|}`, as an instance of
1519
+ :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField`
1520
+
1521
+ EXAMPLES:
1522
+
1523
+ Standard metric in the Euclidean space `\RR^3` with spherical
1524
+ coordinates::
1525
+
1526
+ sage: M = Manifold(3, 'M', start_index=1)
1527
+ sage: U = M.open_subset('U') # the complement of the half-plane (y=0, x>=0)
1528
+ sage: c_spher.<r,th,ph> = U.chart(r'r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi')
1529
+ sage: g = U.metric('g')
1530
+ sage: g[1,1], g[2,2], g[3,3] = 1, r^2, (r*sin(th))^2
1531
+ sage: g.display()
1532
+ g = dr⊗dr + r^2 dth⊗dth + r^2*sin(th)^2 dph⊗dph
1533
+ sage: g.sqrt_abs_det().expr()
1534
+ r^2*sin(th)
1535
+
1536
+ Metric determinant on a 2-dimensional manifold::
1537
+
1538
+ sage: M = Manifold(2, 'M', start_index=1)
1539
+ sage: X.<x,y> = M.chart()
1540
+ sage: g = M.metric('g')
1541
+ sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y
1542
+ sage: g[:]
1543
+ [ x + 1 x*y]
1544
+ [ x*y -y + 1]
1545
+ sage: s = g.sqrt_abs_det() ; s
1546
+ Scalar field on the 2-dimensional differentiable manifold M
1547
+ sage: s.expr()
1548
+ sqrt(-x^2*y^2 - (x + 1)*y + x + 1)
1549
+
1550
+ Determinant in a frame different from the default's one::
1551
+
1552
+ sage: Y.<u,v> = M.chart()
1553
+ sage: ch_X_Y = X.transition_map(Y, [x+y, x-y])
1554
+ sage: ch_X_Y.inverse()
1555
+ Change of coordinates from Chart (M, (u, v)) to Chart (M, (x, y))
1556
+ sage: g[Y.frame(),:,Y]
1557
+ [ 1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2 1/4*u]
1558
+ [ 1/4*u -1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2]
1559
+ sage: g.sqrt_abs_det(Y.frame()).expr()
1560
+ 1/2*sqrt(-x^2*y^2 - (x + 1)*y + x + 1)
1561
+ sage: g.sqrt_abs_det(Y.frame()).expr(Y)
1562
+ 1/8*sqrt(-u^4 - v^4 + 2*(u^2 + 2)*v^2 - 4*u^2 + 16*v + 16)
1563
+
1564
+ A chart can be passed instead of a frame::
1565
+
1566
+ sage: g.sqrt_abs_det(Y) is g.sqrt_abs_det(Y.frame())
1567
+ True
1568
+
1569
+ The metric determinant depends on the frame::
1570
+
1571
+ sage: g.sqrt_abs_det(X.frame()) == g.sqrt_abs_det(Y.frame())
1572
+ False
1573
+
1574
+ Using SymPy as symbolic engine::
1575
+
1576
+ sage: M.set_calculus_method('sympy')
1577
+ sage: g = M.metric('g')
1578
+ sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y
1579
+ sage: g.sqrt_abs_det().expr()
1580
+ sqrt(-x**2*y**2 - x*y + x - y + 1)
1581
+ sage: g.sqrt_abs_det(Y.frame()).expr()
1582
+ sqrt(-x**2*y**2 - x*y + x - y + 1)/2
1583
+ sage: g.sqrt_abs_det(Y.frame()).expr(Y)
1584
+ sqrt(-u**4 + 2*u**2*v**2 - 4*u**2 - v**4 + 4*v**2 + 16*v + 16)/8
1585
+ """
1586
+ dom = self._domain
1587
+ if frame is None:
1588
+ frame = dom._def_frame
1589
+ if frame in dom._atlas:
1590
+ # frame is actually a chart and is changed to the associated
1591
+ # coordinate frame:
1592
+ frame = frame._frame
1593
+ if frame not in self._sqrt_abs_dets:
1594
+ # a new computation is necessary
1595
+ detg = self.determinant(frame)
1596
+ resu = frame._domain.scalar_field()
1597
+ for chart, funct in detg._express.items():
1598
+ x = (self._indic_signat * funct).sqrt().expr()
1599
+ resu.add_expr(x, chart=chart)
1600
+ self._sqrt_abs_dets[frame] = resu
1601
+ return self._sqrt_abs_dets[frame]
1602
+
1603
+ @overload
1604
+ def volume_form(self) -> DiffForm: ...
1605
+ @overload
1606
+ def volume_form(self, contra: int) -> TensorField: ...
1607
+ def volume_form(self, contra=0):
1608
+ r"""
1609
+ Volume form (Levi-Civita tensor) `\epsilon` associated with the metric.
1610
+
1611
+ The volume form `\epsilon` is an `n`-form (`n` being the manifold's
1612
+ dimension) such that for any oriented vector basis `(e_i)` which is
1613
+ orthonormal with respect to the metric, the condition
1614
+
1615
+ .. MATH::
1616
+
1617
+ \epsilon(e_1,\ldots,e_n) = 1
1618
+
1619
+ holds.
1620
+
1621
+ Notice that a volume form requires an orientable manifold with
1622
+ a preferred orientation, see
1623
+ :meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.orientation`
1624
+ for details.
1625
+
1626
+ INPUT:
1627
+
1628
+ - ``contra`` -- (default: 0) number of contravariant indices of the
1629
+ returned tensor
1630
+
1631
+ OUTPUT:
1632
+
1633
+ - if ``contra = 0`` (default value): the volume `n`-form `\epsilon`, as
1634
+ an instance of
1635
+ :class:`~sage.manifolds.differentiable.diff_form.DiffForm`
1636
+ - if ``contra = k``, with `1\leq k \leq n`, the tensor field of type
1637
+ (k,n-k) formed from `\epsilon` by raising the first k indices with
1638
+ the metric (see method
1639
+ :meth:`~sage.manifolds.differentiable.tensorfield.TensorField.up`);
1640
+ the output is then an instance of
1641
+ :class:`~sage.manifolds.differentiable.tensorfield.TensorField`, with
1642
+ the appropriate antisymmetries, or of the subclass
1643
+ :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField`
1644
+ if `k=n`
1645
+
1646
+ EXAMPLES:
1647
+
1648
+ Volume form on `\RR^3` with spherical coordinates, using the standard
1649
+ orientation, which is predefined::
1650
+
1651
+ sage: M = Manifold(3, 'M', start_index=1)
1652
+ sage: U = M.open_subset('U') # the complement of the half-plane (y=0, x>=0)
1653
+ sage: c_spher.<r,th,ph> = U.chart(r'r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi')
1654
+ sage: g = U.metric('g')
1655
+ sage: g[1,1], g[2,2], g[3,3] = 1, r^2, (r*sin(th))^2
1656
+ sage: g.display()
1657
+ g = dr⊗dr + r^2 dth⊗dth + r^2*sin(th)^2 dph⊗dph
1658
+ sage: eps = g.volume_form() ; eps
1659
+ 3-form eps_g on the Open subset U of the 3-dimensional
1660
+ differentiable manifold M
1661
+ sage: eps.display()
1662
+ eps_g = r^2*sin(th) dr∧dth∧dph
1663
+ sage: eps[[1,2,3]] == g.sqrt_abs_det()
1664
+ True
1665
+ sage: latex(eps)
1666
+ \epsilon_{g}
1667
+
1668
+ The tensor field of components `\epsilon^i_{\ \, jk}` (``contra=1``)::
1669
+
1670
+ sage: eps1 = g.volume_form(1) ; eps1
1671
+ Tensor field of type (1,2) on the Open subset U of the
1672
+ 3-dimensional differentiable manifold M
1673
+ sage: eps1.symmetries()
1674
+ no symmetry; antisymmetry: (1, 2)
1675
+ sage: eps1[:]
1676
+ [[[0, 0, 0], [0, 0, r^2*sin(th)], [0, -r^2*sin(th), 0]],
1677
+ [[0, 0, -sin(th)], [0, 0, 0], [sin(th), 0, 0]],
1678
+ [[0, 1/sin(th), 0], [-1/sin(th), 0, 0], [0, 0, 0]]]
1679
+
1680
+ The tensor field of components `\epsilon^{ij}_{\ \ k}` (``contra=2``)::
1681
+
1682
+ sage: eps2 = g.volume_form(2) ; eps2
1683
+ Tensor field of type (2,1) on the Open subset U of the
1684
+ 3-dimensional differentiable manifold M
1685
+ sage: eps2.symmetries()
1686
+ no symmetry; antisymmetry: (0, 1)
1687
+ sage: eps2[:]
1688
+ [[[0, 0, 0], [0, 0, sin(th)], [0, -1/sin(th), 0]],
1689
+ [[0, 0, -sin(th)], [0, 0, 0], [1/(r^2*sin(th)), 0, 0]],
1690
+ [[0, 1/sin(th), 0], [-1/(r^2*sin(th)), 0, 0], [0, 0, 0]]]
1691
+
1692
+ The tensor field of components `\epsilon^{ijk}` (``contra=3``)::
1693
+
1694
+ sage: eps3 = g.volume_form(3) ; eps3
1695
+ 3-vector field on the Open subset U of the 3-dimensional
1696
+ differentiable manifold M
1697
+ sage: eps3.tensor_type()
1698
+ (3, 0)
1699
+ sage: eps3.symmetries()
1700
+ no symmetry; antisymmetry: (0, 1, 2)
1701
+ sage: eps3[:]
1702
+ [[[0, 0, 0], [0, 0, 1/(r^2*sin(th))], [0, -1/(r^2*sin(th)), 0]],
1703
+ [[0, 0, -1/(r^2*sin(th))], [0, 0, 0], [1/(r^2*sin(th)), 0, 0]],
1704
+ [[0, 1/(r^2*sin(th)), 0], [-1/(r^2*sin(th)), 0, 0], [0, 0, 0]]]
1705
+ sage: eps3[1,2,3]
1706
+ 1/(r^2*sin(th))
1707
+ sage: eps3[[1,2,3]] * g.sqrt_abs_det() == 1
1708
+ True
1709
+
1710
+ If the manifold has no predefined orientation, an orientation must be
1711
+ set before invoking ``volume_form()``. For instance let consider the
1712
+ 2-sphere described by the stereographic charts from the North and
1713
+ South pole::
1714
+
1715
+ sage: M = Manifold(2, 'M', structure='Riemannian')
1716
+ sage: U = M.open_subset('U'); V = M.open_subset('V')
1717
+ sage: M.declare_union(U, V)
1718
+ sage: c_xy.<x,y> = U.chart() # stereographic chart from the North pole
1719
+ sage: c_uv.<u,v> = V.chart() # stereographic chart from the South pole
1720
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)),
1721
+ ....: intersection_name='W', restrictions1= x^2+y^2!=0,
1722
+ ....: restrictions2= u^2+v^2!=0)
1723
+ sage: uv_to_xy = xy_to_uv.inverse()
1724
+ sage: eU = c_xy.frame(); eV = c_uv.frame()
1725
+ sage: g = M.metric()
1726
+ sage: g[eU,0,0], g[eU,1,1] = 4/(1+x^2+y^2)^2, 4/(1+x^2+y^2)^2
1727
+ sage: g.add_comp_by_continuation(eV, U.intersection(V), chart=c_uv)
1728
+ sage: eps = g.volume_form()
1729
+ Traceback (most recent call last):
1730
+ ...
1731
+ ValueError: 2-dimensional Riemannian manifold M must admit an
1732
+ orientation
1733
+
1734
+ Let us define the orientation of ``M`` such that ``eU`` is
1735
+ right-handed; ``eV`` is then left-handed and in order to define an
1736
+ orientation on the whole of ``M``, we introduce a vector frame on ``V``
1737
+ by swapping ``eV``'s vectors::
1738
+
1739
+ sage: f = V.vector_frame('f', (eV[1], eV[0]))
1740
+ sage: M.set_orientation([eU, f])
1741
+
1742
+ We have then, factorizing the components for a nicer display::
1743
+
1744
+ sage: eps = g.volume_form()
1745
+ sage: eps.apply_map(factor, frame=eU, keep_other_components=True)
1746
+ sage: eps.apply_map(factor, frame=eV, keep_other_components=True)
1747
+ sage: eps.display(eU)
1748
+ eps_g = 4/(x^2 + y^2 + 1)^2 dx∧dy
1749
+ sage: eps.display(eV)
1750
+ eps_g = -4/(u^2 + v^2 + 1)^2 du∧dv
1751
+
1752
+ Note the minus sign in the above expression, reflecting the fact that
1753
+ ``eV`` is left-handed with respect to the chosen orientation.
1754
+ """
1755
+ dom = self._domain
1756
+ orient = dom.orientation()
1757
+ manif = self._ambient_domain
1758
+ ndim = manif.dimension()
1759
+ if not orient:
1760
+ raise ValueError('{} must admit an orientation'.format(dom))
1761
+ if contra > ndim:
1762
+ raise ValueError('The number of contravariant indices is greater '
1763
+ 'than the manifold dimension')
1764
+ if self._vol_forms == []:
1765
+ # a new computation is necessary
1766
+ # The result is constructed on the vector field module,
1767
+ # so that dest_map is taken automatically into account:
1768
+ eps = self._vmodule.alternating_form(ndim, name='eps_'+self._name,
1769
+ latex_name=r'\epsilon_{'+self._latex_name+r'}')
1770
+ si = manif.start_index()
1771
+ ind = tuple(range(si, si+ndim))
1772
+ for frame in orient:
1773
+ if frame.destination_map() is frame.domain().identity_map():
1774
+ eps.add_comp(frame)[[ind]] = self.sqrt_abs_det(frame)
1775
+ self._vol_forms.append(eps) # Levi-Civita tensor constructed
1776
+ if contra >= len(self._vol_forms):
1777
+ # Tensors related to the Levi-Civita one by index rising:
1778
+ for k in range(len(self._vol_forms), contra+1):
1779
+ epskm1 = self._vol_forms[k-1]
1780
+ epsk = epskm1.up(self, k-1)
1781
+ if k > 1:
1782
+ # restoring the antisymmetry after the up operation:
1783
+ epsk = epsk.antisymmetrize(*range(k))
1784
+ self._vol_forms.append(epsk)
1785
+ return self._vol_forms[contra]
1786
+
1787
+ def hodge_star(self, pform: DiffForm) -> DiffForm:
1788
+ r"""
1789
+ Compute the Hodge dual of a differential form with respect to the
1790
+ metric.
1791
+
1792
+ If the differential form is a `p`-form `A`, its *Hodge dual* with
1793
+ respect to the metric `g` is the
1794
+ `(n-p)`-form `*A` defined by
1795
+
1796
+ .. MATH::
1797
+
1798
+ *A_{i_1\ldots i_{n-p}} = \frac{1}{p!} A_{k_1\ldots k_p}
1799
+ \epsilon^{k_1\ldots k_p}_{\qquad\ i_1\ldots i_{n-p}}
1800
+
1801
+ where `n` is the manifold's dimension, `\epsilon` is the volume
1802
+ `n`-form associated with `g` (see :meth:`volume_form`) and the indices
1803
+ `k_1,\ldots, k_p` are raised with `g`.
1804
+
1805
+ Notice that the Hodge star dual requires an orientable manifold
1806
+ with a preferred orientation, see
1807
+ :meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.orientation`
1808
+ for details.
1809
+
1810
+ INPUT:
1811
+
1812
+ - ``pform`` -- a `p`-form `A`; must be an instance of
1813
+ :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField`
1814
+ for `p=0` and of
1815
+ :class:`~sage.manifolds.differentiable.diff_form.DiffForm` or
1816
+ :class:`~sage.manifolds.differentiable.diff_form.DiffFormParal`
1817
+ for `p\geq 1`.
1818
+
1819
+ OUTPUT:
1820
+
1821
+ - the `(n-p)`-form `*A`
1822
+
1823
+ EXAMPLES:
1824
+
1825
+ Hodge dual of a 1-form in the Euclidean space `R^3`::
1826
+
1827
+ sage: M = Manifold(3, 'M', start_index=1)
1828
+ sage: X.<x,y,z> = M.chart()
1829
+ sage: g = M.metric('g')
1830
+ sage: g[1,1], g[2,2], g[3,3] = 1, 1, 1
1831
+ sage: var('Ax Ay Az')
1832
+ (Ax, Ay, Az)
1833
+ sage: a = M.one_form(Ax, Ay, Az, name='A')
1834
+ sage: sa = g.hodge_star(a) ; sa
1835
+ 2-form *A on the 3-dimensional differentiable manifold M
1836
+ sage: sa.display()
1837
+ *A = Az dx∧dy - Ay dx∧dz + Ax dy∧dz
1838
+ sage: ssa = g.hodge_star(sa) ; ssa
1839
+ 1-form **A on the 3-dimensional differentiable manifold M
1840
+ sage: ssa.display()
1841
+ **A = Ax dx + Ay dy + Az dz
1842
+ sage: ssa == a # must hold for a Riemannian metric in dimension 3
1843
+ True
1844
+
1845
+ Hodge dual of a 0-form (scalar field) in `R^3`::
1846
+
1847
+ sage: f = M.scalar_field(function('F')(x,y,z), name='f')
1848
+ sage: sf = g.hodge_star(f) ; sf
1849
+ 3-form *f on the 3-dimensional differentiable manifold M
1850
+ sage: sf.display()
1851
+ *f = F(x, y, z) dx∧dy∧dz
1852
+ sage: ssf = g.hodge_star(sf) ; ssf
1853
+ Scalar field **f on the 3-dimensional differentiable manifold M
1854
+ sage: ssf.display()
1855
+ **f: M → ℝ
1856
+ (x, y, z) ↦ F(x, y, z)
1857
+ sage: ssf == f # must hold for a Riemannian metric
1858
+ True
1859
+
1860
+ Hodge dual of a 0-form in Minkowski spacetime::
1861
+
1862
+ sage: M = Manifold(4, 'M')
1863
+ sage: X.<t,x,y,z> = M.chart()
1864
+ sage: g = M.lorentzian_metric('g')
1865
+ sage: g[0,0], g[1,1], g[2,2], g[3,3] = -1, 1, 1, 1
1866
+ sage: g.display() # Minkowski metric
1867
+ g = -dt⊗dt + dx⊗dx + dy⊗dy + dz⊗dz
1868
+ sage: var('f0')
1869
+ f0
1870
+ sage: f = M.scalar_field(f0, name='f')
1871
+ sage: sf = g.hodge_star(f) ; sf
1872
+ 4-form *f on the 4-dimensional differentiable manifold M
1873
+ sage: sf.display()
1874
+ *f = f0 dt∧dx∧dy∧dz
1875
+ sage: ssf = g.hodge_star(sf) ; ssf
1876
+ Scalar field **f on the 4-dimensional differentiable manifold M
1877
+ sage: ssf.display()
1878
+ **f: M → ℝ
1879
+ (t, x, y, z) ↦ -f0
1880
+ sage: ssf == -f # must hold for a Lorentzian metric
1881
+ True
1882
+
1883
+ Hodge dual of a 1-form in Minkowski spacetime::
1884
+
1885
+ sage: var('At Ax Ay Az')
1886
+ (At, Ax, Ay, Az)
1887
+ sage: a = M.one_form(At, Ax, Ay, Az, name='A')
1888
+ sage: a.display()
1889
+ A = At dt + Ax dx + Ay dy + Az dz
1890
+ sage: sa = g.hodge_star(a) ; sa
1891
+ 3-form *A on the 4-dimensional differentiable manifold M
1892
+ sage: sa.display()
1893
+ *A = -Az dt∧dx∧dy + Ay dt∧dx∧dz - Ax dt∧dy∧dz - At dx∧dy∧dz
1894
+ sage: ssa = g.hodge_star(sa) ; ssa
1895
+ 1-form **A on the 4-dimensional differentiable manifold M
1896
+ sage: ssa.display()
1897
+ **A = At dt + Ax dx + Ay dy + Az dz
1898
+ sage: ssa == a # must hold for a Lorentzian metric in dimension 4
1899
+ True
1900
+
1901
+ Hodge dual of a 2-form in Minkowski spacetime::
1902
+
1903
+ sage: F = M.diff_form(2, name='F')
1904
+ sage: var('Ex Ey Ez Bx By Bz')
1905
+ (Ex, Ey, Ez, Bx, By, Bz)
1906
+ sage: F[0,1], F[0,2], F[0,3] = -Ex, -Ey, -Ez
1907
+ sage: F[1,2], F[1,3], F[2,3] = Bz, -By, Bx
1908
+ sage: F[:]
1909
+ [ 0 -Ex -Ey -Ez]
1910
+ [ Ex 0 Bz -By]
1911
+ [ Ey -Bz 0 Bx]
1912
+ [ Ez By -Bx 0]
1913
+ sage: sF = g.hodge_star(F) ; sF
1914
+ 2-form *F on the 4-dimensional differentiable manifold M
1915
+ sage: sF[:]
1916
+ [ 0 Bx By Bz]
1917
+ [-Bx 0 Ez -Ey]
1918
+ [-By -Ez 0 Ex]
1919
+ [-Bz Ey -Ex 0]
1920
+ sage: ssF = g.hodge_star(sF) ; ssF
1921
+ 2-form **F on the 4-dimensional differentiable manifold M
1922
+ sage: ssF[:]
1923
+ [ 0 Ex Ey Ez]
1924
+ [-Ex 0 -Bz By]
1925
+ [-Ey Bz 0 -Bx]
1926
+ [-Ez -By Bx 0]
1927
+ sage: ssF.display()
1928
+ **F = Ex dt∧dx + Ey dt∧dy + Ez dt∧dz - Bz dx∧dy + By dx∧dz
1929
+ - Bx dy∧dz
1930
+ sage: F.display()
1931
+ F = -Ex dt∧dx - Ey dt∧dy - Ez dt∧dz + Bz dx∧dy - By dx∧dz
1932
+ + Bx dy∧dz
1933
+ sage: ssF == -F # must hold for a Lorentzian metric in dimension 4
1934
+ True
1935
+
1936
+ Test of the standard identity
1937
+
1938
+ .. MATH::
1939
+
1940
+ *(A\wedge B) = \epsilon(A^\sharp, B^\sharp, ., .)
1941
+
1942
+ where `A` and `B` are any 1-forms and `A^\sharp` and `B^\sharp` the
1943
+ vectors associated to them by the metric `g` (index raising)::
1944
+
1945
+ sage: var('Bt Bx By Bz')
1946
+ (Bt, Bx, By, Bz)
1947
+ sage: b = M.one_form(Bt, Bx, By, Bz, name='B')
1948
+ sage: b.display()
1949
+ B = Bt dt + Bx dx + By dy + Bz dz
1950
+ sage: epsilon = g.volume_form()
1951
+ sage: g.hodge_star(a.wedge(b)) == epsilon.contract(0,a.up(g)).contract(0,b.up(g))
1952
+ True
1953
+ """
1954
+ return pform.hodge_dual(self)
1955
+
1956
+
1957
+ #******************************************************************************
1958
+
1959
+ class PseudoRiemannianMetricParal(PseudoRiemannianMetric, TensorFieldParal):
1960
+ r"""
1961
+ Pseudo-Riemannian metric with values on a parallelizable manifold.
1962
+
1963
+ An instance of this class is a field of nondegenerate symmetric bilinear
1964
+ forms (metric field) along a differentiable manifold `U` with values in a
1965
+ parallelizable manifold `M` over `\RR`, via a differentiable mapping
1966
+ `\Phi: U \rightarrow M`. The standard case of a metric field *on* a
1967
+ manifold corresponds to `U=M` and `\Phi = \mathrm{Id}_M`. Other common
1968
+ cases are `\Phi` being an immersion and `\Phi` being a curve in `M` (`U` is
1969
+ then an open interval of `\RR`).
1970
+
1971
+ A *metric* `g` is a field on `U`, such that at each
1972
+ point `p\in U`, `g(p)` is a bilinear map of the type:
1973
+
1974
+ .. MATH::
1975
+
1976
+ g(p):\ T_q M\times T_q M \longrightarrow \RR
1977
+
1978
+ where `T_q M` stands for the tangent space to manifold `M` at the point
1979
+ `q=\Phi(p)`, such that `g(p)` is symmetric:
1980
+ `\forall (u,v)\in T_q M\times T_q M, \ g(p)(v,u) = g(p)(u,v)`
1981
+ and nondegenerate:
1982
+ `(\forall v\in T_q M,\ \ g(p)(u,v) = 0) \Longrightarrow u=0`.
1983
+
1984
+ .. NOTE::
1985
+
1986
+ If `M` is not parallelizable, the class :class:`PseudoRiemannianMetric`
1987
+ should be used instead.
1988
+
1989
+ INPUT:
1990
+
1991
+ - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector
1992
+ fields along `U` with values on `\Phi(U)\subset M`
1993
+ - ``name`` -- name given to the metric
1994
+ - ``signature`` -- (default: ``None``) signature `S` of the metric as a
1995
+ single integer: `S = n_+ - n_-`, where `n_+` (resp. `n_-`) is the number
1996
+ of positive terms (resp. number of negative terms) in any diagonal
1997
+ writing of the metric components; if ``signature`` is ``None``, `S` is
1998
+ set to the dimension of manifold `M` (Riemannian signature)
1999
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the metric;
2000
+ if ``None``, it is formed from ``name``
2001
+
2002
+ EXAMPLES:
2003
+
2004
+ Metric on a 2-dimensional manifold::
2005
+
2006
+ sage: M = Manifold(2, 'M', start_index=1)
2007
+ sage: c_xy.<x,y> = M.chart()
2008
+ sage: g = M.metric('g') ; g
2009
+ Riemannian metric g on the 2-dimensional differentiable manifold M
2010
+ sage: latex(g)
2011
+ g
2012
+
2013
+ A metric is a special kind of tensor field and therefore inheritates all the
2014
+ properties from class
2015
+ :class:`~sage.manifolds.differentiable.tensorfield.TensorField`::
2016
+
2017
+ sage: g.parent()
2018
+ Free module T^(0,2)(M) of type-(0,2) tensors fields on the
2019
+ 2-dimensional differentiable manifold M
2020
+ sage: g.tensor_type()
2021
+ (0, 2)
2022
+ sage: g.symmetries() # g is symmetric:
2023
+ symmetry: (0, 1); no antisymmetry
2024
+
2025
+ Setting the metric components in the manifold's default frame::
2026
+
2027
+ sage: g[1,1], g[1,2], g[2,2] = 1+x, x*y, 1-x
2028
+ sage: g[:]
2029
+ [ x + 1 x*y]
2030
+ [ x*y -x + 1]
2031
+ sage: g.display()
2032
+ g = (x + 1) dx⊗dx + x*y dx⊗dy + x*y dy⊗dx + (-x + 1) dy⊗dy
2033
+
2034
+ Metric components in a frame different from the manifold's default one::
2035
+
2036
+ sage: c_uv.<u,v> = M.chart() # new chart on M
2037
+ sage: xy_to_uv = c_xy.transition_map(c_uv, [x+y, x-y]) ; xy_to_uv
2038
+ Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v))
2039
+ sage: uv_to_xy = xy_to_uv.inverse() ; uv_to_xy
2040
+ Change of coordinates from Chart (M, (u, v)) to Chart (M, (x, y))
2041
+ sage: M.atlas()
2042
+ [Chart (M, (x, y)), Chart (M, (u, v))]
2043
+ sage: M.frames()
2044
+ [Coordinate frame (M, (∂/∂x,∂/∂y)), Coordinate frame (M, (∂/∂u,∂/∂v))]
2045
+ sage: g[c_uv.frame(),:] # metric components in frame c_uv.frame() expressed in M's default chart (x,y)
2046
+ [ 1/2*x*y + 1/2 1/2*x]
2047
+ [ 1/2*x -1/2*x*y + 1/2]
2048
+ sage: g.display(c_uv.frame())
2049
+ g = (1/2*x*y + 1/2) du⊗du + 1/2*x du⊗dv + 1/2*x dv⊗du
2050
+ + (-1/2*x*y + 1/2) dv⊗dv
2051
+ sage: g[c_uv.frame(),:,c_uv] # metric components in frame c_uv.frame() expressed in chart (u,v)
2052
+ [ 1/8*u^2 - 1/8*v^2 + 1/2 1/4*u + 1/4*v]
2053
+ [ 1/4*u + 1/4*v -1/8*u^2 + 1/8*v^2 + 1/2]
2054
+ sage: g.display(c_uv.frame(), c_uv)
2055
+ g = (1/8*u^2 - 1/8*v^2 + 1/2) du⊗du + (1/4*u + 1/4*v) du⊗dv
2056
+ + (1/4*u + 1/4*v) dv⊗du + (-1/8*u^2 + 1/8*v^2 + 1/2) dv⊗dv
2057
+
2058
+ As a shortcut of the above command, on can pass just the chart ``c_uv``
2059
+ to ``display``, the vector frame being then assumed to be the coordinate
2060
+ frame associated with the chart::
2061
+
2062
+ sage: g.display(c_uv)
2063
+ g = (1/8*u^2 - 1/8*v^2 + 1/2) du⊗du + (1/4*u + 1/4*v) du⊗dv
2064
+ + (1/4*u + 1/4*v) dv⊗du + (-1/8*u^2 + 1/8*v^2 + 1/2) dv⊗dv
2065
+
2066
+ The inverse metric is obtained via :meth:`inverse`::
2067
+
2068
+ sage: ig = g.inverse() ; ig
2069
+ Tensor field inv_g of type (2,0) on the 2-dimensional differentiable
2070
+ manifold M
2071
+ sage: ig[:]
2072
+ [ (x - 1)/(x^2*y^2 + x^2 - 1) x*y/(x^2*y^2 + x^2 - 1)]
2073
+ [ x*y/(x^2*y^2 + x^2 - 1) -(x + 1)/(x^2*y^2 + x^2 - 1)]
2074
+ sage: ig.display()
2075
+ inv_g = (x - 1)/(x^2*y^2 + x^2 - 1) ∂/∂x⊗∂/∂x
2076
+ + x*y/(x^2*y^2 + x^2 - 1) ∂/∂x⊗∂/∂y + x*y/(x^2*y^2 + x^2 - 1) ∂/∂y⊗∂/∂x
2077
+ - (x + 1)/(x^2*y^2 + x^2 - 1) ∂/∂y⊗∂/∂y
2078
+ """
2079
+ def __init__(self, vector_field_module, name, signature=None,
2080
+ latex_name=None):
2081
+ r"""
2082
+ Construct a metric on a parallelizable manifold.
2083
+
2084
+ TESTS::
2085
+
2086
+ sage: M = Manifold(2, 'M')
2087
+ sage: X.<x,y> = M.chart() # makes M parallelizable
2088
+ sage: XM = M.vector_field_module()
2089
+ sage: from sage.manifolds.differentiable.metric import \
2090
+ ....: PseudoRiemannianMetricParal
2091
+ sage: g = PseudoRiemannianMetricParal(XM, 'g', signature=0); g
2092
+ Lorentzian metric g on the 2-dimensional differentiable manifold M
2093
+ sage: g[0,0], g[1,1] = -(1+x^2), 1+y^2
2094
+ sage: TestSuite(g).run(skip='_test_category')
2095
+
2096
+ .. TODO::
2097
+
2098
+ - add a specific parent to the metrics, to fit with the category
2099
+ framework
2100
+ """
2101
+ TensorFieldParal.__init__(self, vector_field_module, (0,2),
2102
+ name=name, latex_name=latex_name, sym=(0,1))
2103
+ # signature:
2104
+ ndim = self._ambient_domain.dimension()
2105
+ if signature is None:
2106
+ signature = ndim
2107
+ else:
2108
+ if not isinstance(signature, (int, Integer)):
2109
+ raise TypeError("the metric signature must be an integer")
2110
+ if (signature < - ndim) or (signature > ndim):
2111
+ raise ValueError("metric signature out of range")
2112
+ if (signature+ndim) % 2 == 1:
2113
+ if ndim % 2 == 0:
2114
+ raise ValueError("the metric signature must be even")
2115
+ else:
2116
+ raise ValueError("the metric signature must be odd")
2117
+ self._signature = signature
2118
+ # the pair (n_+, n_-):
2119
+ self._signature_pm = ((ndim+signature)//2, (ndim-signature)//2)
2120
+ self._indic_signat = 1 - 2*(self._signature_pm[1] % 2) # (-1)^n_-
2121
+ # Initialization of derived quantities:
2122
+ PseudoRiemannianMetricParal._init_derived(self)
2123
+
2124
+ def _init_derived(self):
2125
+ r"""
2126
+ Initialize the derived quantities.
2127
+
2128
+ TESTS::
2129
+
2130
+ sage: M = Manifold(3, 'M')
2131
+ sage: X.<x,y,z> = M.chart() # makes M parallelizable
2132
+ sage: g = M.metric('g')
2133
+ sage: g._init_derived()
2134
+ """
2135
+ # Initialization of quantities pertaining to the mother classes:
2136
+ TensorFieldParal._init_derived(self)
2137
+ PseudoRiemannianMetric._init_derived(self)
2138
+
2139
+ def _del_derived(self, del_restrictions=True):
2140
+ r"""
2141
+ Delete the derived quantities.
2142
+
2143
+ INPUT:
2144
+
2145
+ - ``del_restrictions`` -- boolean (default: ``True``); determines whether the
2146
+ restrictions of ``self`` to subdomains are deleted
2147
+
2148
+ TESTS::
2149
+
2150
+ sage: M = Manifold(3, 'M')
2151
+ sage: X.<x,y,z> = M.chart() # makes M parallelizable
2152
+ sage: g = M.metric('g')
2153
+ sage: g._del_derived(del_restrictions=False)
2154
+ sage: g._del_derived()
2155
+ """
2156
+ # The derived quantities from the mother classes are deleted:
2157
+ TensorFieldParal._del_derived(self, del_restrictions=del_restrictions)
2158
+ PseudoRiemannianMetric._del_derived(self)
2159
+
2160
+ def _del_inverse(self):
2161
+ r"""
2162
+ Delete the inverse metric.
2163
+
2164
+ TESTS::
2165
+
2166
+ sage: M = Manifold(3, 'M')
2167
+ sage: X.<x,y,z> = M.chart() # makes M parallelizable
2168
+ sage: g = M.metric('g')
2169
+ sage: g._del_inverse()
2170
+ """
2171
+ self._inverse._components.clear()
2172
+ self._inverse._del_derived()
2173
+
2174
+ def restrict(self, subdomain, dest_map=None):
2175
+ r"""
2176
+ Return the restriction of the metric to some subdomain.
2177
+
2178
+ If the restriction has not been defined yet, it is constructed here.
2179
+
2180
+ INPUT:
2181
+
2182
+ - ``subdomain`` -- open subset `U` of ``self._domain`` (must be an
2183
+ instance of
2184
+ :class:`~sage.manifolds.differentiable.manifold.DifferentiableManifold`)
2185
+ - ``dest_map`` -- (default: ``None``) destination map
2186
+ `\Phi:\ U \rightarrow V`, where `V` is a subdomain of
2187
+ ``self._codomain``
2188
+ (type: :class:`~sage.manifolds.differentiable.diff_map.DiffMap`)
2189
+ If ``None``, the restriction of ``self._vmodule._dest_map`` to `U` is
2190
+ used.
2191
+
2192
+ OUTPUT:
2193
+
2194
+ - instance of :class:`PseudoRiemannianMetricParal` representing the
2195
+ restriction.
2196
+
2197
+ EXAMPLES:
2198
+
2199
+ Restriction of a Lorentzian metric on `\RR^2` to the upper half plane::
2200
+
2201
+ sage: M = Manifold(2, 'M')
2202
+ sage: X.<x,y> = M.chart()
2203
+ sage: g = M.lorentzian_metric('g')
2204
+ sage: g[0,0], g[1,1] = -1, 1
2205
+ sage: U = M.open_subset('U', coord_def={X: y>0})
2206
+ sage: gU = g.restrict(U); gU
2207
+ Lorentzian metric g on the Open subset U of the 2-dimensional
2208
+ differentiable manifold M
2209
+ sage: gU.signature()
2210
+ 0
2211
+ sage: gU.display()
2212
+ g = -dx⊗dx + dy⊗dy
2213
+ """
2214
+ if subdomain == self._domain:
2215
+ return self
2216
+ if subdomain not in self._restrictions:
2217
+ # Construct the restriction at the tensor field level:
2218
+ resu = TensorFieldParal.restrict(self, subdomain, dest_map=dest_map)
2219
+ # the type is correctly handled by TensorFieldParal.restrict, i.e.
2220
+ # resu is of type self.__class__, but the signature is not handled
2221
+ # by TensorFieldParal.restrict; we have to set it here:
2222
+ resu._signature = self._signature
2223
+ resu._signature_pm = self._signature_pm
2224
+ resu._indic_signat = self._indic_signat
2225
+ # Restrictions of derived quantities:
2226
+ resu._inverse = self.inverse().restrict(subdomain)
2227
+ if self._connection is not None:
2228
+ resu._connection = self._connection.restrict(subdomain)
2229
+ if self._ricci_scalar is not None:
2230
+ resu._ricci_scalar = self._ricci_scalar.restrict(subdomain)
2231
+ if self._weyl is not None:
2232
+ resu._weyl = self._weyl.restrict(subdomain)
2233
+ if self._vol_forms != []:
2234
+ for eps in self._vol_forms:
2235
+ resu._vol_forms.append(eps.restrict(subdomain))
2236
+ # NB: no initialization of resu._determinants nor
2237
+ # resu._sqrt_abs_dets
2238
+ # The restriction is ready:
2239
+ self._restrictions[subdomain] = resu
2240
+ return self._restrictions[subdomain]
2241
+
2242
+ def set(self, symbiform):
2243
+ r"""
2244
+ Define the metric from a field of symmetric bilinear forms.
2245
+
2246
+ INPUT:
2247
+
2248
+ - ``symbiform`` -- instance of
2249
+ :class:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal`
2250
+ representing a field of symmetric bilinear forms
2251
+
2252
+ EXAMPLES::
2253
+
2254
+ sage: M = Manifold(2, 'M')
2255
+ sage: X.<x,y> = M.chart()
2256
+ sage: s = M.sym_bilin_form_field(name='s')
2257
+ sage: s[0,0], s[0,1], s[1,1] = 1+x^2, x*y, 1+y^2
2258
+ sage: g = M.metric('g')
2259
+ sage: g.set(s)
2260
+ sage: g.display()
2261
+ g = (x^2 + 1) dx⊗dx + x*y dx⊗dy + x*y dy⊗dx + (y^2 + 1) dy⊗dy
2262
+ """
2263
+ if not isinstance(symbiform, TensorFieldParal):
2264
+ raise TypeError("the argument must be a tensor field with " +
2265
+ "values on a parallelizable domain")
2266
+ if symbiform._tensor_type != (0,2):
2267
+ raise TypeError("the argument must be of tensor type (0,2)")
2268
+ if symbiform._sym != ((0,1),):
2269
+ raise TypeError("the argument must be symmetric")
2270
+ if symbiform._vmodule is not self._vmodule:
2271
+ raise TypeError("the symmetric bilinear form and the metric are " +
2272
+ "not defined on the same vector field module")
2273
+ self._del_derived()
2274
+ self._components.clear()
2275
+ for frame in symbiform._components:
2276
+ self._components[frame] = symbiform._components[frame].copy()
2277
+ for dom, symbiform_rst in symbiform._restrictions.items():
2278
+ rst = self.restrict(dom)
2279
+ rst.set(symbiform_rst)
2280
+
2281
+ def inverse(self, expansion_symbol=None, order=1):
2282
+ r"""
2283
+ Return the inverse metric.
2284
+
2285
+ INPUT:
2286
+
2287
+ - ``expansion_symbol`` -- (default: ``None``) symbolic variable; if
2288
+ specified, the inverse will be expanded in power series with respect
2289
+ to this variable (around its zero value)
2290
+ - ``order`` -- integer (default: 1); the order of the expansion
2291
+ if ``expansion_symbol`` is not ``None``; the *order* is defined as
2292
+ the degree of the polynomial representing the truncated power series
2293
+ in ``expansion_symbol``; currently only first order inverse is
2294
+ supported
2295
+
2296
+ If ``expansion_symbol`` is set, then the zeroth order metric must be
2297
+ invertible. Moreover, subsequent calls to this method will return
2298
+ a cached value, even when called with the default value (to enable
2299
+ computation of derived quantities). To reset, use :meth:`_del_derived`.
2300
+
2301
+ OUTPUT:
2302
+
2303
+ - instance of
2304
+ :class:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal`
2305
+ with ``tensor_type`` = (2,0) representing the inverse metric
2306
+
2307
+ EXAMPLES:
2308
+
2309
+ Inverse metric on a 2-dimensional manifold::
2310
+
2311
+ sage: M = Manifold(2, 'M', start_index=1)
2312
+ sage: c_xy.<x,y> = M.chart()
2313
+ sage: g = M.metric('g')
2314
+ sage: g[1,1], g[1,2], g[2,2] = 1+x, x*y, 1-x
2315
+ sage: g[:] # components in the manifold's default frame
2316
+ [ x + 1 x*y]
2317
+ [ x*y -x + 1]
2318
+ sage: ig = g.inverse() ; ig
2319
+ Tensor field inv_g of type (2,0) on the 2-dimensional
2320
+ differentiable manifold M
2321
+ sage: ig[:]
2322
+ [ (x - 1)/(x^2*y^2 + x^2 - 1) x*y/(x^2*y^2 + x^2 - 1)]
2323
+ [ x*y/(x^2*y^2 + x^2 - 1) -(x + 1)/(x^2*y^2 + x^2 - 1)]
2324
+
2325
+ If the metric is modified, the inverse metric is automatically updated::
2326
+
2327
+ sage: g[1,2] = 0 ; g[:]
2328
+ [ x + 1 0]
2329
+ [ 0 -x + 1]
2330
+ sage: g.inverse()[:]
2331
+ [ 1/(x + 1) 0]
2332
+ [ 0 -1/(x - 1)]
2333
+
2334
+ Using SymPy as symbolic engine::
2335
+
2336
+ sage: M.set_calculus_method('sympy')
2337
+ sage: g[1,1], g[1,2], g[2,2] = 1+x, x*y, 1-x
2338
+ sage: g[:] # components in the manifold's default frame
2339
+ [x + 1 x*y]
2340
+ [ x*y 1 - x]
2341
+ sage: g.inverse()[:]
2342
+ [ (x - 1)/(x**2*y**2 + x**2 - 1) x*y/(x**2*y**2 + x**2 - 1)]
2343
+ [ x*y/(x**2*y**2 + x**2 - 1) -(x + 1)/(x**2*y**2 + x**2 - 1)]
2344
+
2345
+ Demonstration of the series expansion capabilities::
2346
+
2347
+ sage: M = Manifold(4, 'M', structure='Lorentzian')
2348
+ sage: C.<t,x,y,z> = M.chart()
2349
+ sage: e = var('e')
2350
+ sage: g = M.metric()
2351
+ sage: h = M.tensor_field(0, 2, sym=(0,1))
2352
+ sage: g[0, 0], g[1, 1], g[2, 2], g[3, 3] = -1, 1, 1, 1
2353
+ sage: h[0, 1], h[1, 2], h[2, 3] = 1, 1, 1
2354
+ sage: g.set(g + e*h)
2355
+
2356
+ If ``e`` is a small parameter, ``g`` is a tridiagonal approximation of
2357
+ the Minkowski metric::
2358
+
2359
+ sage: g[:]
2360
+ [-1 e 0 0]
2361
+ [ e 1 e 0]
2362
+ [ 0 e 1 e]
2363
+ [ 0 0 e 1]
2364
+
2365
+ The inverse, truncated to first order in ``e``, is::
2366
+
2367
+ sage: g.inverse(expansion_symbol=e)[:]
2368
+ [-1 e 0 0]
2369
+ [ e 1 -e 0]
2370
+ [ 0 -e 1 -e]
2371
+ [ 0 0 -e 1]
2372
+
2373
+ If ``inverse()`` is called subsequently, the result will be the same.
2374
+ This allows for all computations to be made to first order::
2375
+
2376
+ sage: g.inverse()[:]
2377
+ [-1 e 0 0]
2378
+ [ e 1 -e 0]
2379
+ [ 0 -e 1 -e]
2380
+ [ 0 0 -e 1]
2381
+ """
2382
+ if expansion_symbol is not None:
2383
+ if (self._inverse is not None and bool(self._inverse._components)
2384
+ and self._inverse._components.values()[0][0,0]._expansion_symbol
2385
+ == expansion_symbol
2386
+ and self._inverse._components.values()[0][0,0]._order == order):
2387
+ return self._inverse
2388
+
2389
+ if order != 1:
2390
+ raise NotImplementedError("only first order inverse is implemented")
2391
+ decompo = self.series_expansion(expansion_symbol, order)
2392
+ g0 = decompo[0]
2393
+ g1 = decompo[1]
2394
+
2395
+ g0m = self._new_instance() # needed because only metrics have
2396
+ g0m.set_comp()[:] = g0[:] # an "inverse" method.
2397
+
2398
+ contraction = g1.contract(0, g0m.inverse(), 0)
2399
+ contraction = contraction.contract(1, g0m.inverse(), 1)
2400
+ self._inverse = g0m.inverse() - expansion_symbol * contraction
2401
+ self._inverse.set_calc_order(expansion_symbol, order)
2402
+ return self._inverse
2403
+
2404
+ from sage.matrix.constructor import matrix
2405
+ from sage.tensor.modules.comp import CompFullySym
2406
+ # Is the inverse metric up to date ?
2407
+ for frame in self._components:
2408
+ if frame not in self._inverse._components:
2409
+ # the computation is necessary
2410
+ fmodule = self._fmodule
2411
+ si = fmodule._sindex
2412
+ nsi = fmodule._rank + si
2413
+ dom = self._domain
2414
+ cinv = CompFullySym(fmodule._ring, frame, 2, start_index=si,
2415
+ output_formatter=fmodule._output_formatter)
2416
+ cinv_scal = {} # dict. of scalars representing the components
2417
+ # of the inverse (keys: comp. indices)
2418
+ for i in range(si, nsi):
2419
+ for j in range(i, nsi): # symmetry taken into account
2420
+ cinv_scal[(i,j)] = dom.scalar_field()
2421
+ for chart in dom.top_charts():
2422
+ # TODO: do the computation without the 'SR' enforcement
2423
+ try:
2424
+ gmat = matrix(
2425
+ [[self.comp(frame)[i, j, chart].expr(method='SR')
2426
+ for j in range(si, nsi)] for i in range(si, nsi)])
2427
+ gmat_inv = gmat.inverse()
2428
+ except (KeyError, ValueError):
2429
+ continue
2430
+ for i in range(si, nsi):
2431
+ for j in range(i, nsi):
2432
+ val = chart.simplify(gmat_inv[i-si,j-si], method='SR')
2433
+ cinv_scal[(i,j)].add_expr(val, chart=chart)
2434
+ for i in range(si, nsi):
2435
+ for j in range(i, nsi):
2436
+ cinv[i,j] = cinv_scal[(i,j)]
2437
+ self._inverse._components[frame] = cinv
2438
+ return self._inverse
2439
+
2440
+ def ricci_scalar(self, name=None, latex_name=None):
2441
+ r"""
2442
+ Return the metric's Ricci scalar.
2443
+
2444
+ The Ricci scalar is the scalar field `r` defined from the Ricci tensor
2445
+ `Ric` and the metric tensor `g` by
2446
+
2447
+ .. MATH::
2448
+
2449
+ r = g^{ij} Ric_{ij}
2450
+
2451
+ INPUT:
2452
+
2453
+ - ``name`` -- (default: ``None``) name given to the Ricci scalar;
2454
+ if none, it is set to "r(g)", where "g" is the metric's name
2455
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
2456
+ Ricci scalar; if none, it is set to "\\mathrm{r}(g)", where "g"
2457
+ is the metric's name
2458
+
2459
+ OUTPUT:
2460
+
2461
+ - the Ricci scalar `r`, as an instance of
2462
+ :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField`
2463
+
2464
+ EXAMPLES:
2465
+
2466
+ Ricci scalar of the standard metric on the 2-sphere::
2467
+
2468
+ sage: M = Manifold(2, 'S^2', start_index=1)
2469
+ sage: U = M.open_subset('U') # the complement of a meridian (domain of spherical coordinates)
2470
+ sage: c_spher.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
2471
+ sage: a = var('a') # the sphere radius
2472
+ sage: g = U.metric('g')
2473
+ sage: g[1,1], g[2,2] = a^2, a^2*sin(th)^2
2474
+ sage: g.display() # standard metric on the 2-sphere of radius a:
2475
+ g = a^2 dth⊗dth + a^2*sin(th)^2 dph⊗dph
2476
+ sage: g.ricci_scalar()
2477
+ Scalar field r(g) on the Open subset U of the 2-dimensional
2478
+ differentiable manifold S^2
2479
+ sage: g.ricci_scalar().display() # The Ricci scalar is constant:
2480
+ r(g): U → ℝ
2481
+ (th, ph) ↦ 2/a^2
2482
+
2483
+ """
2484
+ if self._ricci_scalar is None:
2485
+ manif = self._ambient_domain
2486
+ ric = self.ricci()
2487
+ ig = self.inverse()
2488
+ frame = ig.common_basis(ric)
2489
+ cric = ric._components[frame]
2490
+ cig = ig._components[frame]
2491
+ rsum1 = 0
2492
+ for i in manif.irange():
2493
+ rsum1 += cig[[i,i]] * cric[[i,i]]
2494
+ rsum2 = 0
2495
+ for i in manif.irange():
2496
+ for j in manif.irange(start=i+1):
2497
+ rsum2 += cig[[i,j]] * cric[[i,j]]
2498
+ self._ricci_scalar = rsum1 + 2*rsum2
2499
+ if name is None:
2500
+ self._ricci_scalar._name = "r(" + self._name + ")"
2501
+ else:
2502
+ self._ricci_scalar._name = name
2503
+ if latex_name is None:
2504
+ self._ricci_scalar._latex_name = r"\mathrm{r}\left(" + \
2505
+ self._latex_name + r"\right)"
2506
+ else:
2507
+ self._ricci_scalar._latex_name = latex_name
2508
+ return self._ricci_scalar
2509
+
2510
+
2511
+ #****************************************************************************************************
2512
+
2513
+
2514
+ class DegenerateMetric(TensorField):
2515
+ r"""
2516
+ Degenerate (or null or lightlike) metric with values on an open subset of a
2517
+ differentiable manifold.
2518
+
2519
+ An instance of this class is a field of degenerate symmetric bilinear
2520
+ forms (metric field) along a differentiable manifold `U` with
2521
+ values on a differentiable manifold `M` over `\RR`, via a differentiable
2522
+ mapping `\Phi: U \rightarrow M`.
2523
+ The standard case of a degenerate metric field *on* a manifold corresponds to `U=M`
2524
+ and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi` being an
2525
+ immersion and `\Phi` being a curve in `M` (`U` is then an open interval
2526
+ of `\RR`).
2527
+
2528
+ A *degenerate metric* `g` is a field on `U`, such that at each point `p\in U`, `g(p)`
2529
+ is a bilinear map of the type:
2530
+
2531
+ .. MATH::
2532
+
2533
+ g(p):\ T_q M\times T_q M \longrightarrow \RR
2534
+
2535
+ where `T_q M` stands for the tangent space to the
2536
+ manifold `M` at the point `q=\Phi(p)`, such that `g(p)` is symmetric:
2537
+ `\forall (u,v)\in T_q M\times T_q M, \ g(p)(v,u) = g(p)(u,v)`
2538
+ and degenerate:
2539
+ `\exists v\in T_q M;\ \ g(p)(u,v) = 0\ \ \forall u\in T_qM`.
2540
+
2541
+ .. NOTE::
2542
+
2543
+ If `M` is parallelizable, the class :class:`DegenerateMetricParal`
2544
+ should be used instead.
2545
+
2546
+ INPUT:
2547
+
2548
+ - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector
2549
+ fields along `U` with values on `\Phi(U)\subset M`
2550
+ - ``name`` -- name given to the metric
2551
+ - ``signature`` -- (default: ``None``) signature `S` of the metric as a
2552
+ tuple: `S = (n_+, n_-, n_0)`, where `n_+` (resp. `n_-`, resp. `n_0`) is the
2553
+ number of positive terms (resp. negative terms, resp. zero tems) in any
2554
+ diagonal writing of the metric components; if ``signature`` is not
2555
+ provided, `S` is set to `(ndim-1, 0, 1)`, being `ndim` the manifold's dimension
2556
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the metric;
2557
+ if ``None``, it is formed from ``name``
2558
+
2559
+ EXAMPLES:
2560
+
2561
+ Lightlike cone::
2562
+
2563
+ sage: M = Manifold(3, 'M'); X.<x,y,z> = M.chart()
2564
+ sage: g = M.metric('g', signature=(2,0,1)); g
2565
+ degenerate metric g on the 3-dimensional differentiable manifold M
2566
+ sage: det(g)
2567
+ Scalar field zero on the 3-dimensional differentiable manifold M
2568
+ sage: g.parent()
2569
+ Free module T^(0,2)(M) of type-(0,2) tensors fields on the
2570
+ 3-dimensional differentiable manifold M
2571
+ sage: g[0,0], g[0,1], g[0,2] = (y^2 + z^2)/(x^2 + y^2 + z^2), \
2572
+ ....: - x*y/(x^2 + y^2 + z^2), - x*z/(x^2 + y^2 + z^2)
2573
+ sage: g[1,1], g[1,2], g[2,2] = (x^2 + z^2)/(x^2 + y^2 + z^2), \
2574
+ ....: - y*z/(x^2 + y^2 + z^2), (x^2 + y^2)/(x^2 + y^2 + z^2)
2575
+ sage: g.disp()
2576
+ g = (y^2 + z^2)/(x^2 + y^2 + z^2) dx⊗dx - x*y/(x^2 + y^2 + z^2) dx⊗dy
2577
+ - x*z/(x^2 + y^2 + z^2) dx⊗dz - x*y/(x^2 + y^2 + z^2) dy⊗dx
2578
+ + (x^2 + z^2)/(x^2 + y^2 + z^2) dy⊗dy - y*z/(x^2 + y^2 + z^2) dy⊗dz
2579
+ - x*z/(x^2 + y^2 + z^2) dz⊗dx - y*z/(x^2 + y^2 + z^2) dz⊗dy
2580
+ + (x^2 + y^2)/(x^2 + y^2 + z^2) dz⊗dz
2581
+
2582
+ The position vector is a lightlike vector field::
2583
+
2584
+ sage: v = M.vector_field()
2585
+ sage: v[0], v[1], v[2] = x , y, z
2586
+ sage: g(v, v).disp()
2587
+ M → ℝ
2588
+ (x, y, z) ↦ 0
2589
+ """
2590
+
2591
+ def __init__(self, vector_field_module, name, signature=None,
2592
+ latex_name=None):
2593
+ r"""
2594
+ Construct a metric.
2595
+
2596
+ TESTS::
2597
+
2598
+ sage: M = Manifold(4, 'M', structure='Lorentzian')
2599
+ sage: var('m'); assume(m>0)
2600
+ m
2601
+ sage: Int = M.open_subset('Int')
2602
+ sage: X.<t,r,th,ph>=Int.chart(r"t r:(0,2*m) th:(0,pi):\theta ph:(0,2*pi):\phi")
2603
+ sage: XM = M.vector_field_module(); e = X.frame()
2604
+ sage: from sage.manifolds.differentiable.metric import \
2605
+ ....: DegenerateMetric
2606
+ sage: g = DegenerateMetric(XM, 'g', signature=(2,1,1)); g
2607
+ degenerate metric g on the 4-dimensional Lorentzian manifold M
2608
+ sage: g[e, 0,0], g[e, 0,1], g[e, 1,1], g[e, 2,2], \
2609
+ ....: g[e, 3,3] = -1+2*m/r, 2*m/r, 1+2*m/r, r^2, r^2*sin(th)^2
2610
+ sage: g.disp(e)
2611
+ g = (2*m/r - 1) dt⊗dt + 2*m/r dt⊗dr + 2*m/r dr⊗dt + (2*m/r + 1) dr⊗dr
2612
+ + r^2 dth⊗dth + r^2*sin(th)^2 dph⊗dph
2613
+ """
2614
+ TensorField.__init__(self, vector_field_module, (0,2),
2615
+ name=name, latex_name=latex_name, sym=(0,1))
2616
+ # signature:
2617
+ ndim = self._ambient_domain.dimension()
2618
+ if signature is None:
2619
+ signature = (ndim-1,0,1)
2620
+ else:
2621
+ try:
2622
+ for elt in signature:
2623
+ if (elt < 0) or (not isinstance(elt, (int, Integer))):
2624
+ raise ValueError("{} must be a positive integer".format(elt))
2625
+ if elt > ndim:
2626
+ raise ValueError("{} must be less than {}".format(elt,ndim))
2627
+ sign = signature[0]+signature[1]+signature[2]
2628
+ if sign != ndim:
2629
+ raise ValueError("{} is different from {}".format(sign, ndim))
2630
+ except TypeError:
2631
+ raise TypeError("signature must be an iterable")
2632
+ self._signature = (signature[0],signature[1],signature[2])
2633
+ # the tuple (n_+, n_-, n_0):
2634
+ self._signature_pm = self._signature
2635
+
2636
+ def _repr_(self):
2637
+ r"""
2638
+ String representation of the object.
2639
+
2640
+ TESTS::
2641
+
2642
+ sage: M = Manifold(3, 'M')
2643
+ sage: g = M.metric('g', signature=(1,1,1))
2644
+ sage: g._repr_()
2645
+ 'degenerate metric g on the 3-dimensional differentiable manifold M'
2646
+ """
2647
+ return self._final_repr("degenerate metric "+self._name + " ")
2648
+
2649
+ def _new_instance(self):
2650
+ r"""
2651
+ Create an instance of the same class as ``self`` with the same
2652
+ signature.
2653
+
2654
+ TESTS::
2655
+
2656
+ sage: M = Manifold(3, 'M')
2657
+ sage: g = M.metric('g', signature=(1,1,1))
2658
+ sage: g1 = g._new_instance(); g1
2659
+ degenerate metric unnamed metric on the 3-dimensional differentiable manifold M
2660
+ sage: type(g1) == type(g)
2661
+ True
2662
+ sage: g1.parent() is g.parent()
2663
+ True
2664
+ sage: g1.signature() == g.signature()
2665
+ True
2666
+ """
2667
+ return type(self)(self._vmodule, 'unnamed metric',
2668
+ signature=self._signature,
2669
+ latex_name=r'\text{unnamed metric}')
2670
+
2671
+ def signature(self):
2672
+ r"""
2673
+ Signature of the metric.
2674
+
2675
+ OUTPUT:
2676
+
2677
+ - signature of a degenerate metric is defined as the tuple
2678
+ `(n_+,n_-,n_0)`, where `n_+` (resp. `n_-`, resp. `n_0`) is the number of
2679
+ positive terms (resp. negative terms, resp. zero terms) eigenvalues
2680
+
2681
+ EXAMPLES:
2682
+
2683
+ Signatures on a 3-dimensional manifold::
2684
+
2685
+ sage: M = Manifold(3, 'M')
2686
+ sage: g = M.metric('g', signature=(1,1,1))
2687
+ sage: g.signature()
2688
+ (1, 1, 1)
2689
+ sage: M = Manifold(3, 'M', structure='degenerate_metric')
2690
+ sage: g = M.metric()
2691
+ sage: g.signature()
2692
+ (0, 2, 1)
2693
+ """
2694
+ return self._signature
2695
+
2696
+ def set(self, symbiform):
2697
+ r"""
2698
+ Define the metric from a field of symmetric bilinear forms.
2699
+
2700
+ INPUT:
2701
+
2702
+ - ``symbiform`` -- instance of
2703
+ :class:`~sage.manifolds.differentiable.tensorfield.TensorField`
2704
+ representing a field of symmetric bilinear forms
2705
+
2706
+ EXAMPLES:
2707
+
2708
+ Metric defined from a field of symmetric bilinear forms on a
2709
+ non-parallelizable 2-dimensional manifold::
2710
+
2711
+ sage: M = Manifold(2, 'M')
2712
+ sage: U = M.open_subset('U') ; V = M.open_subset('V')
2713
+ sage: M.declare_union(U,V) # M is the union of U and V
2714
+ sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
2715
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), intersection_name='W',
2716
+ ....: restrictions1= x>0, restrictions2= u+v>0)
2717
+ sage: uv_to_xy = xy_to_uv.inverse()
2718
+ sage: W = U.intersection(V)
2719
+ sage: eU = c_xy.frame() ; eV = c_uv.frame()
2720
+ sage: h = M.sym_bilin_form_field(name='h')
2721
+ sage: h[eU,0,0], h[eU,0,1], h[eU,1,1] = 1+x, x*y, 1-y
2722
+ sage: h.add_comp_by_continuation(eV, W, c_uv)
2723
+ sage: h.display(eU)
2724
+ h = (x + 1) dx⊗dx + x*y dx⊗dy + x*y dy⊗dx + (-y + 1) dy⊗dy
2725
+ sage: h.display(eV)
2726
+ h = (1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2) du⊗du + 1/4*u du⊗dv
2727
+ + 1/4*u dv⊗du + (-1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2) dv⊗dv
2728
+ sage: g = M.metric('g')
2729
+ sage: g.set(h)
2730
+ sage: g.display(eU)
2731
+ g = (x + 1) dx⊗dx + x*y dx⊗dy + x*y dy⊗dx + (-y + 1) dy⊗dy
2732
+ sage: g.display(eV)
2733
+ g = (1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2) du⊗du + 1/4*u du⊗dv
2734
+ + 1/4*u dv⊗du + (-1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2) dv⊗dv
2735
+ """
2736
+ if not isinstance(symbiform, TensorField):
2737
+ raise TypeError("the argument must be a tensor field")
2738
+ if symbiform._tensor_type != (0,2):
2739
+ raise TypeError("the argument must be of tensor type (0,2)")
2740
+ if symbiform._sym != ((0,1),):
2741
+ raise TypeError("the argument must be symmetric")
2742
+ if not symbiform._domain.is_subset(self._domain):
2743
+ raise TypeError("the symmetric bilinear form is not defined " +
2744
+ "on the metric domain")
2745
+ self._restrictions.clear()
2746
+ if isinstance(symbiform, TensorFieldParal):
2747
+ rst = self.restrict(symbiform._domain)
2748
+ rst.set(symbiform)
2749
+ else:
2750
+ for dom, symbiform_rst in symbiform._restrictions.items():
2751
+ rst = self.restrict(dom)
2752
+ rst.set(symbiform_rst)
2753
+
2754
+ def restrict(self, subdomain, dest_map=None):
2755
+ r"""
2756
+ Return the restriction of the metric to some subdomain.
2757
+
2758
+ If the restriction has not been defined yet, it is constructed here.
2759
+
2760
+ INPUT:
2761
+
2762
+ - ``subdomain`` -- open subset `U` of the metric's domain (must be an
2763
+ instance of :class:`~sage.manifolds.differentiable.manifold.DifferentiableManifold`)
2764
+ - ``dest_map`` -- (default: ``None``) destination map
2765
+ `\Phi:\ U \rightarrow V`, where `V` is a subdomain of
2766
+ ``self._codomain``
2767
+ (type: :class:`~sage.manifolds.differentiable.diff_map.DiffMap`)
2768
+ If ``None``, the restriction of ``self._vmodule._dest_map`` to `U` is
2769
+ used.
2770
+
2771
+ OUTPUT:
2772
+
2773
+ - instance of :class:`DegenerateMetric` representing the
2774
+ restriction.
2775
+
2776
+ EXAMPLES::
2777
+
2778
+ sage: M = Manifold(5, 'M')
2779
+ sage: g = M.metric('g', signature=(3,1,1))
2780
+ sage: U = M.open_subset('U')
2781
+ sage: g.restrict(U)
2782
+ degenerate metric g on the Open subset U of the 5-dimensional
2783
+ differentiable manifold M
2784
+ sage: g.restrict(U).signature()
2785
+ (3, 1, 1)
2786
+
2787
+ See the top documentation of :class:`DegenerateMetric` for more
2788
+ examples.
2789
+ """
2790
+ if subdomain == self._domain:
2791
+ return self
2792
+ if subdomain not in self._restrictions:
2793
+ # Construct the restriction at the tensor field level:
2794
+ resu = TensorField.restrict(self, subdomain, dest_map=dest_map)
2795
+ # the type is correctly handled by TensorField.restrict, i.e.
2796
+ # resu is of type self.__class__, but the signature is not handled
2797
+ # by TensorField.restrict; we have to set it here:
2798
+ resu._signature = self._signature
2799
+ resu._signature_pm = self._signature_pm
2800
+ self._restrictions[subdomain] = resu
2801
+ return self._restrictions[subdomain]
2802
+
2803
+ def determinant(self):
2804
+ r"""
2805
+ Determinant of a degenerate metric is always '0'.
2806
+
2807
+ EXAMPLES::
2808
+
2809
+ sage: S = Manifold(2, 'S')
2810
+ sage: g = S.metric('g', signature=([0,1,1]))
2811
+ sage: g.determinant()
2812
+ Scalar field zero on the 2-dimensional differentiable manifold S
2813
+ """
2814
+ return self._domain.zero_scalar_field()
2815
+
2816
+ det = determinant
2817
+
2818
+ #****************************************************************************************
2819
+
2820
+
2821
+ class DegenerateMetricParal(DegenerateMetric, TensorFieldParal):
2822
+ r"""
2823
+ Degenerate (or null or lightlike) metric with values on an open subset of a
2824
+ differentiable manifold.
2825
+
2826
+ An instance of this class is a field of degenerate symmetric bilinear
2827
+ forms (metric field) along a differentiable manifold `U` with
2828
+ values on a differentiable manifold `M` over `\RR`, via a differentiable
2829
+ mapping `\Phi: U \rightarrow M`.
2830
+ The standard case of a degenerate metric field *on* a manifold corresponds
2831
+ to `U=M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi` being an
2832
+ immersion and `\Phi` being a curve in `M` (`U` is then an open interval
2833
+ of `\RR`).
2834
+
2835
+ A *degenerate metric* `g` is a field on `U`, such that at each point
2836
+ `p\in U`, `g(p)` is a bilinear map of the type:
2837
+
2838
+ .. MATH::
2839
+
2840
+ g(p):\ T_q M\times T_q M \longrightarrow \RR
2841
+
2842
+ where `T_q M` stands for the tangent space to the
2843
+ manifold `M` at the point `q=\Phi(p)`, such that `g(p)` is symmetric:
2844
+ `\forall (u,v)\in T_q M\times T_q M, \ g(p)(v,u) = g(p)(u,v)`
2845
+ and degenerate:
2846
+ `\exists v\in T_q M;\ \ g(p)(u,v) = 0\ \ \forall u\in T_qM`.
2847
+
2848
+ .. NOTE::
2849
+
2850
+ If `M` is not parallelizable, the class :class:`DegenerateMetric`
2851
+ should be used instead.
2852
+
2853
+ INPUT:
2854
+
2855
+ - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector
2856
+ fields along `U` with values on `\Phi(U)\subset M`
2857
+ - ``name`` -- name given to the metric
2858
+ - ``signature`` -- (default: ``None``) signature `S` of the metric as a
2859
+ tuple: `S = (n_+, n_-, n_0)`, where `n_+` (resp. `n_-`, resp. `n_0`) is the
2860
+ number of positive terms (resp. negative terms, resp. zero tems) in any
2861
+ diagonal writing of the metric components; if ``signature`` is not
2862
+ provided, `S` is set to `(ndim-1, 0, 1)`, being `ndim` the manifold's dimension
2863
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the metric;
2864
+ if ``None``, it is formed from ``name``
2865
+
2866
+ EXAMPLES:
2867
+
2868
+ Lightlike cone::
2869
+
2870
+ sage: M = Manifold(3, 'M'); X.<x,y,z> = M.chart()
2871
+ sage: g = M.metric('g', signature=(2,0,1)); g
2872
+ degenerate metric g on the 3-dimensional differentiable manifold M
2873
+ sage: det(g)
2874
+ Scalar field zero on the 3-dimensional differentiable manifold M
2875
+ sage: g.parent()
2876
+ Free module T^(0,2)(M) of type-(0,2) tensors fields on the
2877
+ 3-dimensional differentiable manifold M
2878
+ sage: g[0,0], g[0,1], g[0,2] = (y^2 + z^2)/(x^2 + y^2 + z^2), \
2879
+ ....: - x*y/(x^2 + y^2 + z^2), - x*z/(x^2 + y^2 + z^2)
2880
+ sage: g[1,1], g[1,2], g[2,2] = (x^2 + z^2)/(x^2 + y^2 + z^2), \
2881
+ ....: - y*z/(x^2 + y^2 + z^2), (x^2 + y^2)/(x^2 + y^2 + z^2)
2882
+ sage: g.disp()
2883
+ g = (y^2 + z^2)/(x^2 + y^2 + z^2) dx⊗dx - x*y/(x^2 + y^2 + z^2) dx⊗dy
2884
+ - x*z/(x^2 + y^2 + z^2) dx⊗dz - x*y/(x^2 + y^2 + z^2) dy⊗dx
2885
+ + (x^2 + z^2)/(x^2 + y^2 + z^2) dy⊗dy - y*z/(x^2 + y^2 + z^2) dy⊗dz
2886
+ - x*z/(x^2 + y^2 + z^2) dz⊗dx - y*z/(x^2 + y^2 + z^2) dz⊗dy
2887
+ + (x^2 + y^2)/(x^2 + y^2 + z^2) dz⊗dz
2888
+
2889
+ The position vector is a lightlike vector field::
2890
+
2891
+ sage: v = M.vector_field()
2892
+ sage: v[0], v[1], v[2] = x , y, z
2893
+ sage: g(v, v).disp()
2894
+ M → ℝ
2895
+ (x, y, z) ↦ 0
2896
+ """
2897
+
2898
+ def __init__(self, vector_field_module, name, signature=None,
2899
+ latex_name=None):
2900
+ r"""
2901
+ Construct a metric.
2902
+
2903
+ TESTS::
2904
+
2905
+ sage: M = Manifold(3, 'M'); X.<x,y,z> = M.chart()
2906
+ sage: XM = M.vector_field_module()
2907
+ sage: from sage.manifolds.differentiable.metric import \
2908
+ ....: DegenerateMetricParal
2909
+ sage: g = DegenerateMetricParal(XM, 'g', signature=(2,0,1)); g
2910
+ degenerate metric g on the 3-dimensional differentiable manifold M
2911
+ sage: g[0,0], g[0,1], g[0,2] = (y^2 + z^2)/(x^2 + y^2 + z^2), \
2912
+ ....: - x*y/(x^2 + y^2 + z^2), - x*z/(x^2 + y^2 + z^2)
2913
+ sage: g[1,1], g[1,2], g[2,2] = (x^2 + z^2)/(x^2 + y^2 + z^2), \
2914
+ ....: - y*z/(x^2 + y^2 + z^2), (x^2 + y^2)/(x^2 + y^2 + z^2)
2915
+ sage: g.disp()
2916
+ g = (y^2 + z^2)/(x^2 + y^2 + z^2) dx⊗dx - x*y/(x^2 + y^2 + z^2) dx⊗dy
2917
+ - x*z/(x^2 + y^2 + z^2) dx⊗dz - x*y/(x^2 + y^2 + z^2) dy⊗dx
2918
+ + (x^2 + z^2)/(x^2 + y^2 + z^2) dy⊗dy - y*z/(x^2 + y^2 + z^2) dy⊗dz
2919
+ - x*z/(x^2 + y^2 + z^2) dz⊗dx - y*z/(x^2 + y^2 + z^2) dz⊗dy
2920
+ + (x^2 + y^2)/(x^2 + y^2 + z^2) dz⊗dz
2921
+ """
2922
+ TensorFieldParal.__init__(self, vector_field_module, (0,2),
2923
+ name=name, latex_name=latex_name, sym=(0,1))
2924
+ # signature:
2925
+ ndim = self._ambient_domain.dimension()
2926
+ if signature is None:
2927
+ signature = (ndim-1,0,1)
2928
+ else:
2929
+ try:
2930
+ for elt in signature:
2931
+ if (elt < 0) or (not isinstance(elt, (int, Integer))):
2932
+ raise ValueError("{} must be a positive integer".format(elt))
2933
+ sign = signature[0]+signature[1]+signature[2]
2934
+ if sign != ndim:
2935
+ raise ValueError("{} is different from {}".format(sign, ndim))
2936
+ except TypeError:
2937
+ raise TypeError("signature must be an iterable")
2938
+ self._signature = (signature[0],signature[1],signature[2])
2939
+ # the tuple (n_+, n_-, n_0):
2940
+ self._signature_pm = self._signature
2941
+
2942
+ def set(self, symbiform):
2943
+ r"""
2944
+ Define the metric from a field of symmetric bilinear forms.
2945
+
2946
+ INPUT:
2947
+
2948
+ - ``symbiform`` -- instance of
2949
+ :class:`~sage.manifolds.differentiable.tensorfield.TensorField`
2950
+ representing a field of symmetric bilinear forms
2951
+
2952
+ EXAMPLES:
2953
+
2954
+ Metric defined from a field of symmetric bilinear forms on a
2955
+ parallelizable 3-dimensional manifold::
2956
+
2957
+ sage: M = Manifold(3, 'M', start_index=1);
2958
+ sage: X.<x,y,z> = M.chart()
2959
+ sage: dx, dy = X.coframe()[1], X.coframe()[2]
2960
+ sage: b = dx*dx + dy*dy
2961
+ sage: g = M.metric('g', signature=(1,1,1)); g
2962
+ degenerate metric g on the 3-dimensional differentiable manifold M
2963
+ sage: g.set(b)
2964
+ sage: g.display()
2965
+ g = dx⊗dx + dy⊗dy
2966
+ """
2967
+ if not isinstance(symbiform, TensorFieldParal):
2968
+ raise TypeError("the argument must be a tensor field with " +
2969
+ "values on a parallelizable domain")
2970
+ if symbiform._tensor_type != (0,2):
2971
+ raise TypeError("the argument must be of tensor type (0,2)")
2972
+ if symbiform._sym != ((0,1),):
2973
+ raise TypeError("the argument must be symmetric")
2974
+ if symbiform._vmodule is not self._vmodule:
2975
+ raise TypeError("the symmetric bilinear form and the metric are " +
2976
+ "not defined on the same vector field module")
2977
+ self._components.clear()
2978
+ for frame in symbiform._components:
2979
+ self._components[frame] = symbiform._components[frame].copy()
2980
+ for dom, symbiform_rst in symbiform._restrictions.items():
2981
+ rst = self.restrict(dom)
2982
+ rst.set(symbiform_rst)
2983
+
2984
+ def restrict(self, subdomain, dest_map=None):
2985
+ r"""
2986
+ Return the restriction of the metric to some subdomain.
2987
+
2988
+ If the restriction has not been defined yet, it is constructed here.
2989
+
2990
+ INPUT:
2991
+
2992
+ - ``subdomain`` -- open subset `U` of the metric's domain (must be an
2993
+ instance of :class:`~sage.manifolds.differentiable.manifold.DifferentiableManifold`)
2994
+ - ``dest_map`` -- (default: ``None``) destination map
2995
+ `\Phi:\ U \rightarrow V`, where `V` is a subdomain of
2996
+ ``self._codomain``
2997
+ (type: :class:`~sage.manifolds.differentiable.diff_map.DiffMap`)
2998
+ If ``None``, the restriction of ``self._vmodule._dest_map`` to `U` is
2999
+ used.
3000
+
3001
+ OUTPUT:
3002
+
3003
+ - instance of :class:`DegenerateMetric` representing the
3004
+ restriction.
3005
+
3006
+ EXAMPLES::
3007
+
3008
+ sage: M = Manifold(5, 'M')
3009
+ sage: g = M.metric('g', signature=(3,1,1))
3010
+ sage: U = M.open_subset('U')
3011
+ sage: g.restrict(U)
3012
+ degenerate metric g on the Open subset U of the 5-dimensional differentiable manifold M
3013
+ sage: g.restrict(U).signature()
3014
+ (3, 1, 1)
3015
+
3016
+ See the top documentation of :class:`DegenerateMetric` for more
3017
+ examples.
3018
+ """
3019
+ if subdomain == self._domain:
3020
+ return self
3021
+ if subdomain not in self._restrictions:
3022
+ # Construct the restriction at the tensor field level:
3023
+ resu = TensorFieldParal.restrict(self, subdomain, dest_map=dest_map)
3024
+ # the type is correctly handled by TensorField.restrict, i.e.
3025
+ # resu is of type self.__class__, but the signature is not handled
3026
+ # by TensorField.restrict; we have to set it here:
3027
+ resu._signature = self._signature
3028
+ resu._signature_pm = self._signature_pm
3029
+ self._restrictions[subdomain] = resu
3030
+ return self._restrictions[subdomain]
3031
+
3032
+ #****************************************************************************************