passagemath-symbolics 10.6.37__cp310-cp310-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_symbolics/__init__.py +3 -0
- passagemath_symbolics-10.6.37.dist-info/METADATA +187 -0
- passagemath_symbolics-10.6.37.dist-info/RECORD +171 -0
- passagemath_symbolics-10.6.37.dist-info/WHEEL +5 -0
- passagemath_symbolics-10.6.37.dist-info/top_level.txt +3 -0
- sage/all__sagemath_symbolics.py +17 -0
- sage/calculus/all.py +14 -0
- sage/calculus/calculus.py +2826 -0
- sage/calculus/desolvers.py +1866 -0
- sage/calculus/predefined.py +51 -0
- sage/calculus/tests.py +225 -0
- sage/calculus/var.cpython-310-x86_64-linux-gnu.so +0 -0
- sage/calculus/var.pyx +401 -0
- sage/dynamics/all__sagemath_symbolics.py +6 -0
- sage/dynamics/complex_dynamics/all.py +5 -0
- sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-310-x86_64-linux-gnu.so +0 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1035 -0
- sage/ext/all__sagemath_symbolics.py +1 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/ext_data/magma/latex/latex.m +1021 -0
- sage/ext_data/magma/latex/latex.spec +1 -0
- sage/ext_data/magma/sage/basic.m +356 -0
- sage/ext_data/magma/sage/sage.spec +1 -0
- sage/ext_data/magma/spec +9 -0
- sage/geometry/all__sagemath_symbolics.py +8 -0
- sage/geometry/hyperbolic_space/all.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_coercion.py +743 -0
- sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2409 -0
- sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
- sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1082 -0
- sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
- sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
- sage/geometry/riemannian_manifolds/all.py +7 -0
- sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
- sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
- sage/interfaces/all__sagemath_symbolics.py +1 -0
- sage/interfaces/magma.py +3017 -0
- sage/interfaces/magma_free.py +92 -0
- sage/interfaces/maple.py +1397 -0
- sage/interfaces/mathematica.py +1345 -0
- sage/interfaces/mathics.py +1312 -0
- sage/interfaces/sympy.py +1398 -0
- sage/interfaces/sympy_wrapper.py +197 -0
- sage/interfaces/tides.py +938 -0
- sage/libs/all__sagemath_symbolics.py +6 -0
- sage/manifolds/all.py +7 -0
- sage/manifolds/calculus_method.py +555 -0
- sage/manifolds/catalog.py +437 -0
- sage/manifolds/chart.py +4019 -0
- sage/manifolds/chart_func.py +3419 -0
- sage/manifolds/continuous_map.py +2183 -0
- sage/manifolds/continuous_map_image.py +155 -0
- sage/manifolds/differentiable/affine_connection.py +2475 -0
- sage/manifolds/differentiable/all.py +1 -0
- sage/manifolds/differentiable/automorphismfield.py +1383 -0
- sage/manifolds/differentiable/automorphismfield_group.py +604 -0
- sage/manifolds/differentiable/bundle_connection.py +1445 -0
- sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
- sage/manifolds/differentiable/chart.py +1241 -0
- sage/manifolds/differentiable/curve.py +1028 -0
- sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
- sage/manifolds/differentiable/degenerate.py +559 -0
- sage/manifolds/differentiable/degenerate_submanifold.py +1671 -0
- sage/manifolds/differentiable/diff_form.py +1658 -0
- sage/manifolds/differentiable/diff_form_module.py +1062 -0
- sage/manifolds/differentiable/diff_map.py +1315 -0
- sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
- sage/manifolds/differentiable/examples/all.py +1 -0
- sage/manifolds/differentiable/examples/euclidean.py +2517 -0
- sage/manifolds/differentiable/examples/real_line.py +897 -0
- sage/manifolds/differentiable/examples/sphere.py +1186 -0
- sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
- sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
- sage/manifolds/differentiable/integrated_curve.py +4035 -0
- sage/manifolds/differentiable/levi_civita_connection.py +841 -0
- sage/manifolds/differentiable/manifold.py +4254 -0
- sage/manifolds/differentiable/manifold_homset.py +1826 -0
- sage/manifolds/differentiable/metric.py +3032 -0
- sage/manifolds/differentiable/mixed_form.py +1507 -0
- sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
- sage/manifolds/differentiable/multivector_module.py +800 -0
- sage/manifolds/differentiable/multivectorfield.py +1520 -0
- sage/manifolds/differentiable/poisson_tensor.py +268 -0
- sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
- sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
- sage/manifolds/differentiable/scalarfield.py +1343 -0
- sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
- sage/manifolds/differentiable/symplectic_form.py +910 -0
- sage/manifolds/differentiable/symplectic_form_test.py +220 -0
- sage/manifolds/differentiable/tangent_space.py +412 -0
- sage/manifolds/differentiable/tangent_vector.py +616 -0
- sage/manifolds/differentiable/tensorfield.py +4665 -0
- sage/manifolds/differentiable/tensorfield_module.py +963 -0
- sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
- sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
- sage/manifolds/differentiable/vector_bundle.py +1728 -0
- sage/manifolds/differentiable/vectorfield.py +1717 -0
- sage/manifolds/differentiable/vectorfield_module.py +2445 -0
- sage/manifolds/differentiable/vectorframe.py +1832 -0
- sage/manifolds/family.py +270 -0
- sage/manifolds/local_frame.py +1490 -0
- sage/manifolds/manifold.py +3090 -0
- sage/manifolds/manifold_homset.py +452 -0
- sage/manifolds/operators.py +359 -0
- sage/manifolds/point.py +994 -0
- sage/manifolds/scalarfield.py +3718 -0
- sage/manifolds/scalarfield_algebra.py +629 -0
- sage/manifolds/section.py +3111 -0
- sage/manifolds/section_module.py +831 -0
- sage/manifolds/structure.py +229 -0
- sage/manifolds/subset.py +2764 -0
- sage/manifolds/subsets/all.py +1 -0
- sage/manifolds/subsets/closure.py +131 -0
- sage/manifolds/subsets/pullback.py +885 -0
- sage/manifolds/topological_submanifold.py +891 -0
- sage/manifolds/trivialization.py +733 -0
- sage/manifolds/utilities.py +1348 -0
- sage/manifolds/vector_bundle.py +1342 -0
- sage/manifolds/vector_bundle_fiber.py +332 -0
- sage/manifolds/vector_bundle_fiber_element.py +111 -0
- sage/matrix/all__sagemath_symbolics.py +1 -0
- sage/matrix/matrix_symbolic_dense.cpython-310-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_symbolic_dense.pxd +6 -0
- sage/matrix/matrix_symbolic_dense.pyx +1022 -0
- sage/matrix/matrix_symbolic_sparse.cpython-310-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_symbolic_sparse.pxd +6 -0
- sage/matrix/matrix_symbolic_sparse.pyx +1029 -0
- sage/modules/all__sagemath_symbolics.py +1 -0
- sage/modules/vector_callable_symbolic_dense.py +105 -0
- sage/modules/vector_symbolic_dense.py +116 -0
- sage/modules/vector_symbolic_sparse.py +118 -0
- sage/rings/all__sagemath_symbolics.py +4 -0
- sage/rings/asymptotic/all.py +6 -0
- sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
- sage/rings/asymptotic/asymptotic_ring.py +4858 -0
- sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4153 -0
- sage/rings/asymptotic/growth_group.py +5373 -0
- sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
- sage/rings/asymptotic/term_monoid.py +5237 -0
- sage/rings/function_field/all__sagemath_symbolics.py +2 -0
- sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
- sage/symbolic/all.py +15 -0
- sage/symbolic/assumptions.py +985 -0
- sage/symbolic/benchmark.py +93 -0
- sage/symbolic/callable.py +459 -0
- sage/symbolic/complexity_measures.py +35 -0
- sage/symbolic/constants.py +1287 -0
- sage/symbolic/expression_conversion_algebraic.py +310 -0
- sage/symbolic/expression_conversion_sympy.py +317 -0
- sage/symbolic/expression_conversions.py +1713 -0
- sage/symbolic/function_factory.py +355 -0
- sage/symbolic/integration/all.py +1 -0
- sage/symbolic/integration/external.py +270 -0
- sage/symbolic/integration/integral.py +1115 -0
- sage/symbolic/maxima_wrapper.py +162 -0
- sage/symbolic/operators.py +267 -0
- sage/symbolic/random_tests.py +462 -0
- sage/symbolic/relation.py +1907 -0
- sage/symbolic/ring.cpython-310-x86_64-linux-gnu.so +0 -0
- sage/symbolic/ring.pxd +5 -0
- sage/symbolic/ring.pyx +1396 -0
- sage/symbolic/subring.py +1025 -0
- sage/symbolic/symengine.py +19 -0
- sage/symbolic/tests.py +40 -0
- sage/symbolic/units.py +1470 -0
|
@@ -0,0 +1,2475 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-symbolics
|
|
2
|
+
r"""
|
|
3
|
+
Affine Connections
|
|
4
|
+
|
|
5
|
+
The class :class:`AffineConnection` implements affine connections on
|
|
6
|
+
smooth manifolds.
|
|
7
|
+
|
|
8
|
+
AUTHORS:
|
|
9
|
+
|
|
10
|
+
- Eric Gourgoulhon, Michal Bejger (2013-2015) : initial version
|
|
11
|
+
- Marco Mancini (2015) : parallelization of some computations
|
|
12
|
+
- Florentin Jaffredo (2018) : series expansion with respect to a given
|
|
13
|
+
parameter
|
|
14
|
+
|
|
15
|
+
REFERENCES:
|
|
16
|
+
|
|
17
|
+
- [Lee1997]_
|
|
18
|
+
- [KN1963]_
|
|
19
|
+
- [ONe1983]_
|
|
20
|
+
"""
|
|
21
|
+
# *****************************************************************************
|
|
22
|
+
# Copyright (C) 2015 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
|
|
23
|
+
# Copyright (C) 2015 Michal Bejger <bejger@camk.edu.pl>
|
|
24
|
+
# Copyright (C) 2015 Marco Mancini <marco.mancini@obspm.fr>
|
|
25
|
+
#
|
|
26
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
27
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
28
|
+
# the License, or (at your option) any later version.
|
|
29
|
+
# https://www.gnu.org/licenses/
|
|
30
|
+
# *****************************************************************************
|
|
31
|
+
|
|
32
|
+
from sage.manifolds.differentiable.manifold import DifferentiableManifold
|
|
33
|
+
from sage.misc.cachefunc import cached_method
|
|
34
|
+
from sage.parallel.decorate import parallel
|
|
35
|
+
from sage.parallel.parallelism import Parallelism
|
|
36
|
+
from sage.rings.integer import Integer
|
|
37
|
+
from sage.structure.sage_object import SageObject
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class AffineConnection(SageObject):
|
|
41
|
+
r"""
|
|
42
|
+
Affine connection on a smooth manifold.
|
|
43
|
+
|
|
44
|
+
Let `M` be a differentiable manifold of class `C^\infty` (smooth manifold)
|
|
45
|
+
over a non-discrete topological field `K` (in most applications `K=\RR`
|
|
46
|
+
or `K=\CC`), let `C^\infty(M)` be the algebra of smooth functions
|
|
47
|
+
`M\rightarrow K` (cf.
|
|
48
|
+
:class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`)
|
|
49
|
+
and let `\mathfrak{X}(M)` be the `C^\infty(M)`-module of vector fields on
|
|
50
|
+
`M` (cf.
|
|
51
|
+
:class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule`).
|
|
52
|
+
An *affine connection* on `M` is an operator
|
|
53
|
+
|
|
54
|
+
.. MATH::
|
|
55
|
+
|
|
56
|
+
\begin{array}{cccc}
|
|
57
|
+
\nabla: & \mathfrak{X}(M)\times \mathfrak{X}(M) & \longrightarrow &
|
|
58
|
+
\mathfrak{X}(M) \\
|
|
59
|
+
& (u,v) & \longmapsto & \nabla_u v
|
|
60
|
+
\end{array}
|
|
61
|
+
|
|
62
|
+
that
|
|
63
|
+
|
|
64
|
+
- is `K`-bilinear, i.e. is bilinear when considering `\mathfrak{X}(M)` as a
|
|
65
|
+
vector space over `K`
|
|
66
|
+
- is `C^\infty(M)`-linear w.r.t. the first argument:
|
|
67
|
+
`\forall f\in C^\infty(M),\ \nabla_{fu} v = f\nabla_u v`
|
|
68
|
+
- obeys Leibniz rule w.r.t. the second argument:
|
|
69
|
+
`\forall f\in C^\infty(M),\ \nabla_u (f v) = \mathrm{d}f(u)\, v + f \nabla_u v`
|
|
70
|
+
|
|
71
|
+
The affine connection `\nabla` gives birth to the *covariant derivative
|
|
72
|
+
operator* acting on tensor fields, denoted by the same symbol:
|
|
73
|
+
|
|
74
|
+
.. MATH::
|
|
75
|
+
|
|
76
|
+
\begin{array}{cccc}
|
|
77
|
+
\nabla: & T^{(k,l)}(M) & \longrightarrow & T^{(k,l+1)}(M)\\
|
|
78
|
+
& t & \longmapsto & \nabla t
|
|
79
|
+
\end{array}
|
|
80
|
+
|
|
81
|
+
where `T^{(k,l)}(M)` stands for the `C^\infty(M)`-module of tensor fields
|
|
82
|
+
of type `(k,l)` on `M` (cf.
|
|
83
|
+
:class:`~sage.manifolds.differentiable.tensorfield_module.TensorFieldModule`),
|
|
84
|
+
with the convention `T^{(0,0)}(M):=C^\infty(M)`.
|
|
85
|
+
For a vector field `v`, the covariant derivative `\nabla v` is a
|
|
86
|
+
type-(1,1) tensor field such that
|
|
87
|
+
|
|
88
|
+
.. MATH::
|
|
89
|
+
|
|
90
|
+
\forall u \in\mathfrak{X}(M), \ \nabla_u v = \nabla v(., u)
|
|
91
|
+
|
|
92
|
+
More generally for any tensor field `t\in T^{(k,l)}(M)`, we have
|
|
93
|
+
|
|
94
|
+
.. MATH::
|
|
95
|
+
|
|
96
|
+
\forall u \in\mathfrak{X}(M), \ \nabla_u t = \nabla t(\ldots, u)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
.. NOTE::
|
|
100
|
+
|
|
101
|
+
The above convention means that, in terms of index notation,
|
|
102
|
+
the "derivation index" in `\nabla t` is the *last* one:
|
|
103
|
+
|
|
104
|
+
.. MATH::
|
|
105
|
+
|
|
106
|
+
\nabla_c t^{a_1\ldots a_k}_{\quad\quad b_1\ldots b_l} =
|
|
107
|
+
(\nabla t)^{a_1\ldots a_k}_{\quad\quad b_1\ldots b_l c}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
INPUT:
|
|
111
|
+
|
|
112
|
+
- ``domain`` -- the manifold on which the connection is defined
|
|
113
|
+
(must be an instance of class
|
|
114
|
+
:class:`~sage.manifolds.differentiable.manifold.DifferentiableManifold`)
|
|
115
|
+
- ``name`` -- name given to the affine connection
|
|
116
|
+
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the affine
|
|
117
|
+
connection; if ``None``, it is set to ``name``
|
|
118
|
+
|
|
119
|
+
EXAMPLES:
|
|
120
|
+
|
|
121
|
+
Affine connection on a 3-dimensional manifold::
|
|
122
|
+
|
|
123
|
+
sage: M = Manifold(3, 'M', start_index=1)
|
|
124
|
+
sage: c_xyz.<x,y,z> = M.chart()
|
|
125
|
+
sage: nab = M.affine_connection('nabla', r'\nabla') ; nab
|
|
126
|
+
Affine connection nabla on the 3-dimensional differentiable manifold M
|
|
127
|
+
|
|
128
|
+
A just-created connection has no connection coefficients::
|
|
129
|
+
|
|
130
|
+
sage: nab._coefficients
|
|
131
|
+
{}
|
|
132
|
+
|
|
133
|
+
The connection coefficients relative to the manifold's default frame
|
|
134
|
+
[here `(\partial/\partial x, \partial/\partial y, \partial/\partial z)`],
|
|
135
|
+
are created by providing the relevant indices inside square brackets::
|
|
136
|
+
|
|
137
|
+
sage: nab[1,1,2], nab[3,2,3] = x^2, y*z # Gamma^1_{12} = x^2, Gamma^3_{23} = yz
|
|
138
|
+
sage: nab._coefficients
|
|
139
|
+
{Coordinate frame (M, (∂/∂x,∂/∂y,∂/∂z)): 3-indices components w.r.t.
|
|
140
|
+
Coordinate frame (M, (∂/∂x,∂/∂y,∂/∂z))}
|
|
141
|
+
|
|
142
|
+
If not the default one, the vector frame w.r.t. which the connection
|
|
143
|
+
coefficients are defined can be specified as the first argument inside the
|
|
144
|
+
square brackets; hence the above definition is equivalent to::
|
|
145
|
+
|
|
146
|
+
sage: nab[c_xyz.frame(), 1,1,2], nab[c_xyz.frame(),3,2,3] = x^2, y*z
|
|
147
|
+
sage: nab._coefficients
|
|
148
|
+
{Coordinate frame (M, (∂/∂x,∂/∂y,∂/∂z)): 3-indices components w.r.t.
|
|
149
|
+
Coordinate frame (M, (∂/∂x,∂/∂y,∂/∂z))}
|
|
150
|
+
|
|
151
|
+
Unset components are initialized to zero::
|
|
152
|
+
|
|
153
|
+
sage: nab[:] # list of coefficients relative to the manifold's default vector frame
|
|
154
|
+
[[[0, x^2, 0], [0, 0, 0], [0, 0, 0]],
|
|
155
|
+
[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
|
|
156
|
+
[[0, 0, 0], [0, 0, y*z], [0, 0, 0]]]
|
|
157
|
+
|
|
158
|
+
The treatment of connection coefficients in a given vector frame is similar
|
|
159
|
+
to that of tensor components; see therefore the class
|
|
160
|
+
:class:`~sage.manifolds.differentiable.tensorfield.TensorField` for the
|
|
161
|
+
documentation. In particular, the square brackets return the connection
|
|
162
|
+
coefficients as instances of
|
|
163
|
+
:class:`~sage.manifolds.chart_func.ChartFunction`,
|
|
164
|
+
while the double square brackets return a scalar field::
|
|
165
|
+
|
|
166
|
+
sage: nab[1,1,2]
|
|
167
|
+
x^2
|
|
168
|
+
sage: nab[1,1,2].display()
|
|
169
|
+
(x, y, z) ↦ x^2
|
|
170
|
+
sage: type(nab[1,1,2])
|
|
171
|
+
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
|
|
172
|
+
sage: nab[[1,1,2]]
|
|
173
|
+
Scalar field on the 3-dimensional differentiable manifold M
|
|
174
|
+
sage: nab[[1,1,2]].display()
|
|
175
|
+
M → ℝ
|
|
176
|
+
(x, y, z) ↦ x^2
|
|
177
|
+
sage: nab[[1,1,2]].coord_function() is nab[1,1,2]
|
|
178
|
+
True
|
|
179
|
+
|
|
180
|
+
Action on a scalar field::
|
|
181
|
+
|
|
182
|
+
sage: f = M.scalar_field(x^2 - y^2, name='f')
|
|
183
|
+
sage: Df = nab(f) ; Df
|
|
184
|
+
1-form df on the 3-dimensional differentiable manifold M
|
|
185
|
+
sage: Df[:]
|
|
186
|
+
[2*x, -2*y, 0]
|
|
187
|
+
|
|
188
|
+
The action of an affine connection on a scalar field must
|
|
189
|
+
coincide with the differential::
|
|
190
|
+
|
|
191
|
+
sage: Df == f.differential()
|
|
192
|
+
True
|
|
193
|
+
|
|
194
|
+
A generic affine connection has some torsion::
|
|
195
|
+
|
|
196
|
+
sage: DDf = nab(Df) ; DDf
|
|
197
|
+
Tensor field nabla(df) of type (0,2) on the 3-dimensional
|
|
198
|
+
differentiable manifold M
|
|
199
|
+
sage: DDf.antisymmetrize()[:] # nabla does not commute on scalar fields:
|
|
200
|
+
[ 0 -x^3 0]
|
|
201
|
+
[ x^3 0 0]
|
|
202
|
+
[ 0 0 0]
|
|
203
|
+
|
|
204
|
+
Let us check the standard formula
|
|
205
|
+
|
|
206
|
+
.. MATH::
|
|
207
|
+
|
|
208
|
+
\nabla_j \nabla_i \, f - \nabla_i \nabla_j \, f =
|
|
209
|
+
T^k_{\ \, ij} \nabla_k \, f ,
|
|
210
|
+
|
|
211
|
+
where the `T^k_{\ \, ij}`'s are the components of the connection's
|
|
212
|
+
torsion tensor::
|
|
213
|
+
|
|
214
|
+
sage: 2*DDf.antisymmetrize() == nab.torsion().contract(0,Df)
|
|
215
|
+
True
|
|
216
|
+
|
|
217
|
+
The connection acting on a vector field::
|
|
218
|
+
|
|
219
|
+
sage: v = M.vector_field(y*z, x*z, x*y, name='v')
|
|
220
|
+
sage: Dv = nab(v) ; Dv
|
|
221
|
+
Tensor field nabla(v) of type (1,1) on the 3-dimensional differentiable
|
|
222
|
+
manifold M
|
|
223
|
+
sage: Dv[:]
|
|
224
|
+
[ 0 (x^2*y + 1)*z y]
|
|
225
|
+
[ z 0 x]
|
|
226
|
+
[ y x x*y*z^2]
|
|
227
|
+
|
|
228
|
+
Another example: connection on a non-parallelizable 2-dimensional manifold::
|
|
229
|
+
|
|
230
|
+
sage: M = Manifold(2, 'M')
|
|
231
|
+
sage: U = M.open_subset('U') ; V = M.open_subset('V')
|
|
232
|
+
sage: M.declare_union(U,V) # M is the union of U and V
|
|
233
|
+
sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
|
|
234
|
+
sage: transf = c_xy.transition_map(c_uv, (x+y, x-y), intersection_name='W',
|
|
235
|
+
....: restrictions1= x>0, restrictions2= u+v>0)
|
|
236
|
+
sage: inv = transf.inverse()
|
|
237
|
+
sage: W = U.intersection(V)
|
|
238
|
+
sage: eU = c_xy.frame() ; eV = c_uv.frame()
|
|
239
|
+
sage: c_xyW = c_xy.restrict(W) ; c_uvW = c_uv.restrict(W)
|
|
240
|
+
sage: eUW = c_xyW.frame() ; eVW = c_uvW.frame()
|
|
241
|
+
sage: nab = M.affine_connection('nabla', r'\nabla')
|
|
242
|
+
|
|
243
|
+
The connection is first defined on the open subset U by means of its
|
|
244
|
+
coefficients w.r.t. the frame eU (the manifold's default frame)::
|
|
245
|
+
|
|
246
|
+
sage: nab[0,0,0], nab[1,0,1] = x, x*y
|
|
247
|
+
|
|
248
|
+
The coefficients w.r.t the frame eV are deduced by continuation of the
|
|
249
|
+
coefficients w.r.t. the frame eVW on the open subset `W=U\cap V`::
|
|
250
|
+
|
|
251
|
+
sage: for i in M.irange():
|
|
252
|
+
....: for j in M.irange():
|
|
253
|
+
....: for k in M.irange():
|
|
254
|
+
....: nab.add_coef(eV)[i,j,k] = nab.coef(eVW)[i,j,k,c_uvW].expr()
|
|
255
|
+
|
|
256
|
+
At this stage, the connection is fully defined on all the manifold::
|
|
257
|
+
|
|
258
|
+
sage: nab.coef(eU)[:]
|
|
259
|
+
[[[x, 0], [0, 0]], [[0, x*y], [0, 0]]]
|
|
260
|
+
sage: nab.coef(eV)[:]
|
|
261
|
+
[[[1/16*u^2 - 1/16*v^2 + 1/8*u + 1/8*v, -1/16*u^2 + 1/16*v^2 + 1/8*u + 1/8*v],
|
|
262
|
+
[1/16*u^2 - 1/16*v^2 + 1/8*u + 1/8*v, -1/16*u^2 + 1/16*v^2 + 1/8*u + 1/8*v]],
|
|
263
|
+
[[-1/16*u^2 + 1/16*v^2 + 1/8*u + 1/8*v, 1/16*u^2 - 1/16*v^2 + 1/8*u + 1/8*v],
|
|
264
|
+
[-1/16*u^2 + 1/16*v^2 + 1/8*u + 1/8*v, 1/16*u^2 - 1/16*v^2 + 1/8*u + 1/8*v]]]
|
|
265
|
+
|
|
266
|
+
We may let it act on a vector field defined globally on `M`::
|
|
267
|
+
|
|
268
|
+
sage: a = M.vector_field({eU: [-y,x]}, name='a')
|
|
269
|
+
sage: a.add_comp_by_continuation(eV, W, c_uv)
|
|
270
|
+
sage: a.display(eU)
|
|
271
|
+
a = -y ∂/∂x + x ∂/∂y
|
|
272
|
+
sage: a.display(eV)
|
|
273
|
+
a = v ∂/∂u - u ∂/∂v
|
|
274
|
+
sage: da = nab(a) ; da
|
|
275
|
+
Tensor field nabla(a) of type (1,1) on the 2-dimensional differentiable
|
|
276
|
+
manifold M
|
|
277
|
+
sage: da.display(eU)
|
|
278
|
+
nabla(a) = -x*y ∂/∂x⊗dx - ∂/∂x⊗dy + ∂/∂y⊗dx - x*y^2 ∂/∂y⊗dy
|
|
279
|
+
sage: da.display(eV)
|
|
280
|
+
nabla(a) = (-1/16*u^3 + 1/16*u^2*v + 1/16*(u + 2)*v^2 - 1/16*v^3 - 1/8*u^2) ∂/∂u⊗du
|
|
281
|
+
+ (1/16*u^3 - 1/16*u^2*v - 1/16*(u - 2)*v^2 + 1/16*v^3 - 1/8*u^2 + 1) ∂/∂u⊗dv
|
|
282
|
+
+ (1/16*u^3 - 1/16*u^2*v - 1/16*(u - 2)*v^2 + 1/16*v^3 - 1/8*u^2 - 1) ∂/∂v⊗du
|
|
283
|
+
+ (-1/16*u^3 + 1/16*u^2*v + 1/16*(u + 2)*v^2 - 1/16*v^3 - 1/8*u^2) ∂/∂v⊗dv
|
|
284
|
+
|
|
285
|
+
A few tests::
|
|
286
|
+
|
|
287
|
+
sage: nab(a.restrict(V)) == da.restrict(V)
|
|
288
|
+
True
|
|
289
|
+
sage: nab.restrict(V)(a) == da.restrict(V)
|
|
290
|
+
True
|
|
291
|
+
sage: nab.restrict(V)(a.restrict(U)) == da.restrict(W)
|
|
292
|
+
True
|
|
293
|
+
sage: nab.restrict(U)(a.restrict(V)) == da.restrict(W) # long time
|
|
294
|
+
True
|
|
295
|
+
|
|
296
|
+
Same examples with SymPy as the engine for symbolic calculus::
|
|
297
|
+
|
|
298
|
+
sage: M.set_calculus_method('sympy')
|
|
299
|
+
sage: nab = M.affine_connection('nabla', r'\nabla')
|
|
300
|
+
sage: nab[0,0,0], nab[1,0,1] = x, x*y
|
|
301
|
+
sage: for i in M.irange():
|
|
302
|
+
....: for j in M.irange():
|
|
303
|
+
....: for k in M.irange():
|
|
304
|
+
....: nab.add_coef(eV)[i,j,k] = nab.coef(eVW)[i,j,k,c_uvW].expr()
|
|
305
|
+
|
|
306
|
+
At this stage, the connection is fully defined on all the manifold::
|
|
307
|
+
|
|
308
|
+
sage: nab.coef(eU)[:]
|
|
309
|
+
[[[x, 0], [0, 0]], [[0, x*y], [0, 0]]]
|
|
310
|
+
sage: nab.coef(eV)[:]
|
|
311
|
+
[[[u**2/16 + u/8 - v**2/16 + v/8, -u**2/16 + u/8 + v**2/16 + v/8],
|
|
312
|
+
[u**2/16 + u/8 - v**2/16 + v/8, -u**2/16 + u/8 + v**2/16 + v/8]],
|
|
313
|
+
[[-u**2/16 + u/8 + v**2/16 + v/8, u**2/16 + u/8 - v**2/16 + v/8],
|
|
314
|
+
[-u**2/16 + u/8 + v**2/16 + v/8, u**2/16 + u/8 - v**2/16 + v/8]]]
|
|
315
|
+
|
|
316
|
+
We may let it act on a vector field defined globally on `M`::
|
|
317
|
+
|
|
318
|
+
sage: a = M.vector_field({eU: [-y,x]}, name='a')
|
|
319
|
+
sage: a.add_comp_by_continuation(eV, W, c_uv)
|
|
320
|
+
sage: a.display(eU)
|
|
321
|
+
a = -y ∂/∂x + x ∂/∂y
|
|
322
|
+
sage: a.display(eV)
|
|
323
|
+
a = v ∂/∂u - u ∂/∂v
|
|
324
|
+
sage: da = nab(a) ; da
|
|
325
|
+
Tensor field nabla(a) of type (1,1) on the 2-dimensional differentiable
|
|
326
|
+
manifold M
|
|
327
|
+
sage: da.display(eU)
|
|
328
|
+
nabla(a) = -x*y ∂/∂x⊗dx - ∂/∂x⊗dy + ∂/∂y⊗dx - x*y**2 ∂/∂y⊗dy
|
|
329
|
+
sage: da.display(eV)
|
|
330
|
+
nabla(a) = (-u**3/16 + u**2*v/16 - u**2/8 + u*v**2/16 - v**3/16 + v**2/8) ∂/∂u⊗du
|
|
331
|
+
+ (u**3/16 - u**2*v/16 - u**2/8 - u*v**2/16 + v**3/16 + v**2/8 + 1) ∂/∂u⊗dv
|
|
332
|
+
+ (u**3/16 - u**2*v/16 - u**2/8 - u*v**2/16 + v**3/16 + v**2/8 - 1) ∂/∂v⊗du
|
|
333
|
+
+ (-u**3/16 + u**2*v/16 - u**2/8 + u*v**2/16 - v**3/16 + v**2/8) ∂/∂v⊗dv
|
|
334
|
+
|
|
335
|
+
To make affine connections hashable, they have to be set immutable before::
|
|
336
|
+
|
|
337
|
+
sage: nab.is_immutable()
|
|
338
|
+
False
|
|
339
|
+
sage: nab.set_immutable()
|
|
340
|
+
sage: nab.is_immutable()
|
|
341
|
+
True
|
|
342
|
+
|
|
343
|
+
Immutable connections cannot be changed anymore::
|
|
344
|
+
|
|
345
|
+
sage: nab.set_coef(eU)
|
|
346
|
+
Traceback (most recent call last):
|
|
347
|
+
...
|
|
348
|
+
ValueError: the coefficients of an immutable element cannot be
|
|
349
|
+
changed
|
|
350
|
+
|
|
351
|
+
However, they can now be used as keys for dictionaries::
|
|
352
|
+
|
|
353
|
+
sage: {nab: 1}[nab]
|
|
354
|
+
1
|
|
355
|
+
|
|
356
|
+
The immutability process cannot be made undone. If a connection is
|
|
357
|
+
needed to be changed again, a copy has to be created::
|
|
358
|
+
|
|
359
|
+
sage: nab_copy = nab.copy('nablo'); nab_copy
|
|
360
|
+
Affine connection nablo on the 2-dimensional differentiable manifold M
|
|
361
|
+
sage: nab_copy is nab
|
|
362
|
+
False
|
|
363
|
+
sage: nab_copy == nab
|
|
364
|
+
True
|
|
365
|
+
sage: nab_copy.is_immutable()
|
|
366
|
+
False
|
|
367
|
+
"""
|
|
368
|
+
def __init__(self, domain, name, latex_name=None):
|
|
369
|
+
r"""
|
|
370
|
+
Construct an affine connection.
|
|
371
|
+
|
|
372
|
+
TESTS::
|
|
373
|
+
|
|
374
|
+
sage: M = Manifold(3, 'M')
|
|
375
|
+
sage: from sage.manifolds.differentiable.affine_connection import \
|
|
376
|
+
....: AffineConnection
|
|
377
|
+
sage: nab = AffineConnection(M, 'nabla', latex_name=r'\nabla')
|
|
378
|
+
sage: nab
|
|
379
|
+
Affine connection nabla on the 3-dimensional differentiable
|
|
380
|
+
manifold M
|
|
381
|
+
sage: X.<x,y,z> = M.chart()
|
|
382
|
+
sage: nab[0,1,0] = x*y*z
|
|
383
|
+
sage: TestSuite(nab).run()
|
|
384
|
+
"""
|
|
385
|
+
if not isinstance(domain, DifferentiableManifold):
|
|
386
|
+
raise TypeError("the first argument must be a differentiable " +
|
|
387
|
+
"manifold")
|
|
388
|
+
self._is_immutable = False
|
|
389
|
+
self._domain = domain
|
|
390
|
+
self._name = name
|
|
391
|
+
if latex_name is None:
|
|
392
|
+
self._latex_name = self._name
|
|
393
|
+
else:
|
|
394
|
+
self._latex_name = latex_name
|
|
395
|
+
self._coefficients = {} # dict. of connection coefficients, with the
|
|
396
|
+
# vector frames as keys
|
|
397
|
+
# Initialization of derived quantities:
|
|
398
|
+
self._init_derived()
|
|
399
|
+
|
|
400
|
+
def _repr_(self):
|
|
401
|
+
r"""
|
|
402
|
+
String representation of the object.
|
|
403
|
+
|
|
404
|
+
TESTS::
|
|
405
|
+
|
|
406
|
+
sage: M = Manifold(5, 'M')
|
|
407
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
408
|
+
sage: nab._repr_()
|
|
409
|
+
'Affine connection nabla on the 5-dimensional differentiable manifold M'
|
|
410
|
+
sage: repr(nab) # indirect doctest
|
|
411
|
+
'Affine connection nabla on the 5-dimensional differentiable manifold M'
|
|
412
|
+
"""
|
|
413
|
+
description = "Affine connection"
|
|
414
|
+
if self._name is not None:
|
|
415
|
+
description += " " + self._name
|
|
416
|
+
description += " on the {}".format(self._domain)
|
|
417
|
+
return description
|
|
418
|
+
|
|
419
|
+
def _latex_(self):
|
|
420
|
+
r"""
|
|
421
|
+
LaTeX representation of the object.
|
|
422
|
+
|
|
423
|
+
TESTS::
|
|
424
|
+
|
|
425
|
+
sage: M = Manifold(5, 'M')
|
|
426
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
427
|
+
sage: nab._latex_()
|
|
428
|
+
'\\nabla'
|
|
429
|
+
sage: latex(nab) # indirect doctest
|
|
430
|
+
\nabla
|
|
431
|
+
sage: nab = M.affine_connection('D')
|
|
432
|
+
sage: nab._latex_()
|
|
433
|
+
'D'
|
|
434
|
+
sage: latex(nab) # indirect doctest
|
|
435
|
+
D
|
|
436
|
+
"""
|
|
437
|
+
return self._latex_name
|
|
438
|
+
|
|
439
|
+
def _init_derived(self):
|
|
440
|
+
r"""
|
|
441
|
+
Initialize the derived quantities.
|
|
442
|
+
|
|
443
|
+
TESTS::
|
|
444
|
+
|
|
445
|
+
sage: M = Manifold(4, 'M')
|
|
446
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
447
|
+
sage: nab._init_derived()
|
|
448
|
+
"""
|
|
449
|
+
self._restrictions = {} # dict. of restrictions of ``self`` on some
|
|
450
|
+
# subdomains, with the subdomains as keys
|
|
451
|
+
self._torsion = None
|
|
452
|
+
self._riemann = None
|
|
453
|
+
self._ricci = None
|
|
454
|
+
self._connection_forms = {} # dict. of dict. of connection 1-forms
|
|
455
|
+
# (key: vector frame)
|
|
456
|
+
self._torsion_forms = {} # dict. of dict. of torsion 1-forms
|
|
457
|
+
# (key: vector frame)
|
|
458
|
+
self._curvature_forms = {} # dict. of dict. of curvature 2-forms
|
|
459
|
+
# (key: vector frame)
|
|
460
|
+
|
|
461
|
+
def _del_derived(self):
|
|
462
|
+
r"""
|
|
463
|
+
Delete the derived quantities.
|
|
464
|
+
|
|
465
|
+
TESTS::
|
|
466
|
+
|
|
467
|
+
sage: M = Manifold(4, 'M')
|
|
468
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
469
|
+
sage: nab._del_derived()
|
|
470
|
+
"""
|
|
471
|
+
self._restrictions.clear()
|
|
472
|
+
self._torsion = None
|
|
473
|
+
self._riemann = None
|
|
474
|
+
self._ricci = None
|
|
475
|
+
self._connection_forms.clear()
|
|
476
|
+
self._torsion_forms.clear()
|
|
477
|
+
self._curvature_forms.clear()
|
|
478
|
+
|
|
479
|
+
def __eq__(self, other):
|
|
480
|
+
r"""
|
|
481
|
+
Comparison (equality) operator.
|
|
482
|
+
|
|
483
|
+
INPUT:
|
|
484
|
+
|
|
485
|
+
- ``other`` -- an affine connection
|
|
486
|
+
|
|
487
|
+
OUTPUT: ``True`` if ``self`` is equal to ``other`` and ``False`` otherwise
|
|
488
|
+
|
|
489
|
+
TESTS::
|
|
490
|
+
|
|
491
|
+
sage: M = Manifold(2, 'M')
|
|
492
|
+
sage: X.<x,y> = M.chart()
|
|
493
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
494
|
+
sage: nab[0,1,0], nab[0,1,1] = 1+x, x*y
|
|
495
|
+
sage: nab.display()
|
|
496
|
+
Gam^x_yx = x + 1
|
|
497
|
+
Gam^x_yy = x*y
|
|
498
|
+
sage: nab1 = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
499
|
+
sage: (nab1 == nab) or (nab == nab1)
|
|
500
|
+
False
|
|
501
|
+
sage: nab1[0,1,0], nab1[0,1,1] = 2, 3-y
|
|
502
|
+
sage: (nab1 == nab) or (nab == nab1)
|
|
503
|
+
False
|
|
504
|
+
sage: nab1[0,1,0], nab1[0,1,1] = 1+x, x*y
|
|
505
|
+
sage: (nab1 == nab) and (nab == nab1)
|
|
506
|
+
True
|
|
507
|
+
sage: nab2 = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
508
|
+
sage: a = M.automorphism_field()
|
|
509
|
+
sage: a[:] = [[0,1], [1,0]]
|
|
510
|
+
sage: e = X.frame().new_frame(a, 'e')
|
|
511
|
+
sage: nab2.set_coef(e)[1,0,1] = 1+x
|
|
512
|
+
sage: nab2.set_coef(e)[1,0,0] = x*y
|
|
513
|
+
sage: (nab2 == nab) and (nab == nab2)
|
|
514
|
+
True
|
|
515
|
+
sage: f = M.vector_frame('f')
|
|
516
|
+
sage: nab2.set_coef(f)[1,0,1] = x-y
|
|
517
|
+
sage: (nab2 == nab) or (nab == nab2)
|
|
518
|
+
False
|
|
519
|
+
"""
|
|
520
|
+
if other is self:
|
|
521
|
+
return True
|
|
522
|
+
if not isinstance(other, AffineConnection):
|
|
523
|
+
return False
|
|
524
|
+
if other._domain != self._domain:
|
|
525
|
+
return False
|
|
526
|
+
if self._coefficients == {}:
|
|
527
|
+
return False
|
|
528
|
+
for frame, coef in self._coefficients.items():
|
|
529
|
+
try:
|
|
530
|
+
if other.coef(frame) != coef:
|
|
531
|
+
return False
|
|
532
|
+
except ValueError:
|
|
533
|
+
return False
|
|
534
|
+
return True
|
|
535
|
+
|
|
536
|
+
def __ne__(self, other):
|
|
537
|
+
r"""
|
|
538
|
+
Inequality operator.
|
|
539
|
+
|
|
540
|
+
INPUT:
|
|
541
|
+
|
|
542
|
+
- ``other`` -- an affine connection
|
|
543
|
+
|
|
544
|
+
OUTPUT:
|
|
545
|
+
|
|
546
|
+
- ``True`` if ``self`` is different from ``other`` and ``False``
|
|
547
|
+
otherwise
|
|
548
|
+
|
|
549
|
+
TESTS::
|
|
550
|
+
|
|
551
|
+
sage: M = Manifold(2, 'M')
|
|
552
|
+
sage: X.<x,y> = M.chart()
|
|
553
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
554
|
+
sage: nab[0,1,0], nab[0,1,1] = 1+x, x*y
|
|
555
|
+
sage: nab1 = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
556
|
+
sage: (nab1 != nab) and (nab != nab1)
|
|
557
|
+
True
|
|
558
|
+
sage: nab1[0,1,0], nab1[0,1,1] = 2, 3-y
|
|
559
|
+
sage: (nab1 != nab) and (nab != nab1)
|
|
560
|
+
True
|
|
561
|
+
sage: nab1[0,1,0], nab1[0,1,1] = 1+x, x*y
|
|
562
|
+
sage: (nab1 != nab) or (nab != nab1)
|
|
563
|
+
False
|
|
564
|
+
"""
|
|
565
|
+
return not (self == other)
|
|
566
|
+
|
|
567
|
+
def domain(self):
|
|
568
|
+
r"""
|
|
569
|
+
Return the manifold subset on which the affine connection is defined.
|
|
570
|
+
|
|
571
|
+
OUTPUT:
|
|
572
|
+
|
|
573
|
+
- instance of class
|
|
574
|
+
:class:`~sage.manifolds.differentiable.manifold.DifferentiableManifold`
|
|
575
|
+
representing the manifold on which ``self`` is defined.
|
|
576
|
+
|
|
577
|
+
EXAMPLES::
|
|
578
|
+
|
|
579
|
+
sage: M = Manifold(3, 'M', start_index=1)
|
|
580
|
+
sage: c_xyz.<x,y,z> = M.chart()
|
|
581
|
+
sage: nab = M.affine_connection('nabla', r'\nabla')
|
|
582
|
+
sage: nab.domain()
|
|
583
|
+
3-dimensional differentiable manifold M
|
|
584
|
+
sage: U = M.open_subset('U', coord_def={c_xyz: x>0})
|
|
585
|
+
sage: nabU = U.affine_connection('D')
|
|
586
|
+
sage: nabU.domain()
|
|
587
|
+
Open subset U of the 3-dimensional differentiable manifold M
|
|
588
|
+
"""
|
|
589
|
+
return self._domain
|
|
590
|
+
|
|
591
|
+
def _new_coef(self, frame):
|
|
592
|
+
r"""
|
|
593
|
+
Create the connection coefficients w.r.t. the given frame.
|
|
594
|
+
|
|
595
|
+
This method, to be called by :meth:`coef`, must be redefined by derived
|
|
596
|
+
classes to adapt the output to the relevant subclass of
|
|
597
|
+
:class:`~sage.tensor.modules.comp.Components`.
|
|
598
|
+
|
|
599
|
+
TESTS::
|
|
600
|
+
|
|
601
|
+
sage: M = Manifold(2, 'M')
|
|
602
|
+
sage: X.<x,y> = M.chart()
|
|
603
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
604
|
+
sage: nab._new_coef(X.frame())
|
|
605
|
+
3-indices components w.r.t. Coordinate frame (M, (∂/∂x,∂/∂y))
|
|
606
|
+
"""
|
|
607
|
+
from sage.manifolds.differentiable.scalarfield import DiffScalarField
|
|
608
|
+
from sage.tensor.modules.comp import Components
|
|
609
|
+
return Components(frame._domain.scalar_field_algebra(), frame, 3,
|
|
610
|
+
start_index=self._domain._sindex,
|
|
611
|
+
output_formatter=DiffScalarField.coord_function)
|
|
612
|
+
|
|
613
|
+
def coef(self, frame=None):
|
|
614
|
+
r"""
|
|
615
|
+
Return the connection coefficients relative to the given frame.
|
|
616
|
+
|
|
617
|
+
`n` being the manifold's dimension, the connection coefficients
|
|
618
|
+
relative to the vector frame `(e_i)` are the `n^3` scalar fields
|
|
619
|
+
`\Gamma^k_{\ \, ij}` defined by
|
|
620
|
+
|
|
621
|
+
.. MATH::
|
|
622
|
+
|
|
623
|
+
\nabla_{e_j} e_i = \Gamma^k_{\ \, ij} e_k
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
If the connection coefficients are not known already, they are computed
|
|
627
|
+
from the above formula.
|
|
628
|
+
|
|
629
|
+
INPUT:
|
|
630
|
+
|
|
631
|
+
- ``frame`` -- (default: ``None``) vector frame relative to which the
|
|
632
|
+
connection coefficients are required; if none is provided, the
|
|
633
|
+
domain's default frame is assumed
|
|
634
|
+
|
|
635
|
+
OUTPUT:
|
|
636
|
+
|
|
637
|
+
- connection coefficients relative to the frame ``frame``, as an
|
|
638
|
+
instance of the class :class:`~sage.tensor.modules.comp.Components`
|
|
639
|
+
with 3 indices ordered as `(k,i,j)`
|
|
640
|
+
|
|
641
|
+
EXAMPLES:
|
|
642
|
+
|
|
643
|
+
Connection coefficient of an affine connection on a 3-dimensional
|
|
644
|
+
manifold::
|
|
645
|
+
|
|
646
|
+
sage: M = Manifold(3, 'M', start_index=1)
|
|
647
|
+
sage: c_xyz.<x,y,z> = M.chart()
|
|
648
|
+
sage: nab = M.affine_connection('nabla', r'\nabla')
|
|
649
|
+
sage: nab[1,1,2], nab[3,2,3] = x^2, y*z # Gamma^1_{12} = x^2, Gamma^3_{23} = yz
|
|
650
|
+
sage: nab.coef()
|
|
651
|
+
3-indices components w.r.t. Coordinate frame (M, (∂/∂x,∂/∂y,∂/∂z))
|
|
652
|
+
sage: type(nab.coef())
|
|
653
|
+
<class 'sage.tensor.modules.comp.Components'>
|
|
654
|
+
sage: M.default_frame()
|
|
655
|
+
Coordinate frame (M, (∂/∂x,∂/∂y,∂/∂z))
|
|
656
|
+
sage: nab.coef() is nab.coef(c_xyz.frame())
|
|
657
|
+
True
|
|
658
|
+
sage: nab.coef()[:] # full list of coefficients:
|
|
659
|
+
[[[0, x^2, 0], [0, 0, 0], [0, 0, 0]],
|
|
660
|
+
[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
|
|
661
|
+
[[0, 0, 0], [0, 0, y*z], [0, 0, 0]]]
|
|
662
|
+
"""
|
|
663
|
+
if frame is None:
|
|
664
|
+
frame = self._domain.default_frame()
|
|
665
|
+
if frame not in self._coefficients:
|
|
666
|
+
# the coefficients must be computed
|
|
667
|
+
#
|
|
668
|
+
# Check whether frame is a subframe of a frame in which the
|
|
669
|
+
# coefficients are already known:
|
|
670
|
+
for oframe in self._coefficients:
|
|
671
|
+
if frame in oframe._subframes:
|
|
672
|
+
self._coefficients[frame] = self._new_coef(frame)
|
|
673
|
+
comp_store = self._coefficients[frame]._comp
|
|
674
|
+
ocomp_store = self._coefficients[oframe]._comp
|
|
675
|
+
for ind, value in ocomp_store.items():
|
|
676
|
+
comp_store[ind] = value.restrict(frame._domain)
|
|
677
|
+
break
|
|
678
|
+
else:
|
|
679
|
+
# If not, the coefficients must be computed from scratch:
|
|
680
|
+
manif = self._domain
|
|
681
|
+
ev = frame # the vector frame
|
|
682
|
+
ef = ev.coframe() # the dual frame
|
|
683
|
+
gam = self._new_coef(ev)
|
|
684
|
+
for i in manif.irange():
|
|
685
|
+
nab_evi = self(ev[i])
|
|
686
|
+
for k in manif.irange():
|
|
687
|
+
for j in manif.irange():
|
|
688
|
+
gam[[k,i,j]] = nab_evi(ef[k],ev[j])
|
|
689
|
+
self._coefficients[frame] = gam
|
|
690
|
+
return self._coefficients[frame]
|
|
691
|
+
|
|
692
|
+
def set_coef(self, frame=None):
|
|
693
|
+
r"""
|
|
694
|
+
Return the connection coefficients in a given frame for assignment.
|
|
695
|
+
|
|
696
|
+
See method :meth:`coef` for details about the definition of the
|
|
697
|
+
connection coefficients.
|
|
698
|
+
|
|
699
|
+
The connection coefficients with respect to other frames are deleted,
|
|
700
|
+
in order to avoid any inconsistency. To keep them, use the method
|
|
701
|
+
:meth:`add_coef` instead.
|
|
702
|
+
|
|
703
|
+
INPUT:
|
|
704
|
+
|
|
705
|
+
- ``frame`` -- (default: ``None``) vector frame in which the connection
|
|
706
|
+
coefficients are defined; if ``None``, the default frame of the
|
|
707
|
+
connection's domain is assumed.
|
|
708
|
+
|
|
709
|
+
OUTPUT:
|
|
710
|
+
|
|
711
|
+
- connection coefficients in the given frame, as an instance of the
|
|
712
|
+
class :class:`~sage.tensor.modules.comp.Components`; if such
|
|
713
|
+
connection coefficients did not exist previously, they are created.
|
|
714
|
+
See method :meth:`coef` for the storage convention of the connection
|
|
715
|
+
coefficients.
|
|
716
|
+
|
|
717
|
+
EXAMPLES:
|
|
718
|
+
|
|
719
|
+
Setting the coefficients of an affine connection w.r.t. some coordinate
|
|
720
|
+
frame::
|
|
721
|
+
|
|
722
|
+
sage: M = Manifold(2, 'M', start_index=1)
|
|
723
|
+
sage: X.<x,y> = M.chart()
|
|
724
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
725
|
+
sage: eX = X.frame(); eX
|
|
726
|
+
Coordinate frame (M, (∂/∂x,∂/∂y))
|
|
727
|
+
sage: nab.set_coef(eX)
|
|
728
|
+
3-indices components w.r.t. Coordinate frame (M, (∂/∂x,∂/∂y))
|
|
729
|
+
sage: nab.set_coef(eX)[1,2,1] = x*y
|
|
730
|
+
sage: nab.display(eX)
|
|
731
|
+
Gam^x_yx = x*y
|
|
732
|
+
|
|
733
|
+
Since ``eX`` is the manifold's default vector frame, its mention may
|
|
734
|
+
be omitted::
|
|
735
|
+
|
|
736
|
+
sage: nab.set_coef()[1,2,1] = x*y
|
|
737
|
+
sage: nab.set_coef()
|
|
738
|
+
3-indices components w.r.t. Coordinate frame (M, (∂/∂x,∂/∂y))
|
|
739
|
+
sage: nab.set_coef()[1,2,1] = x*y
|
|
740
|
+
sage: nab.display()
|
|
741
|
+
Gam^x_yx = x*y
|
|
742
|
+
|
|
743
|
+
To set the coefficients in the default frame, one can even bypass the
|
|
744
|
+
method ``set_coef()`` and call directly the operator ``[]`` on the
|
|
745
|
+
connection object::
|
|
746
|
+
|
|
747
|
+
sage: nab[1,2,1] = x*y
|
|
748
|
+
sage: nab.display()
|
|
749
|
+
Gam^x_yx = x*y
|
|
750
|
+
|
|
751
|
+
Setting the connection coefficients w.r.t. to another vector frame::
|
|
752
|
+
|
|
753
|
+
sage: e = M.vector_frame('e')
|
|
754
|
+
sage: nab.set_coef(e)
|
|
755
|
+
3-indices components w.r.t. Vector frame (M, (e_1,e_2))
|
|
756
|
+
sage: nab.set_coef(e)[2,1,1] = x+y
|
|
757
|
+
sage: nab.set_coef(e)[2,1,2] = x-y
|
|
758
|
+
sage: nab.display(e)
|
|
759
|
+
Gam^2_11 = x + y
|
|
760
|
+
Gam^2_12 = x - y
|
|
761
|
+
|
|
762
|
+
The coefficients w.r.t. the frame ``eX`` have been deleted::
|
|
763
|
+
|
|
764
|
+
sage: nab.display(eX)
|
|
765
|
+
Traceback (most recent call last):
|
|
766
|
+
...
|
|
767
|
+
ValueError: no common frame found for the computation
|
|
768
|
+
|
|
769
|
+
To keep them, use the method :meth:`add_coef` instead.
|
|
770
|
+
"""
|
|
771
|
+
if self.is_immutable():
|
|
772
|
+
raise ValueError("the coefficients of an immutable element "
|
|
773
|
+
"cannot be changed")
|
|
774
|
+
if frame is None:
|
|
775
|
+
frame = self._domain._def_frame
|
|
776
|
+
if frame not in self._coefficients:
|
|
777
|
+
if frame not in self._domain._frames:
|
|
778
|
+
raise ValueError("the {} is not".format(frame) +
|
|
779
|
+
" a frame on the {}".format(self._domain))
|
|
780
|
+
self._coefficients[frame] = self._new_coef(frame)
|
|
781
|
+
self._del_derived() # deletes the derived quantities
|
|
782
|
+
self.del_other_coef(frame)
|
|
783
|
+
return self._coefficients[frame]
|
|
784
|
+
|
|
785
|
+
def add_coef(self, frame=None):
|
|
786
|
+
r"""
|
|
787
|
+
Return the connection coefficients in a given frame for assignment,
|
|
788
|
+
keeping the coefficients in other frames.
|
|
789
|
+
|
|
790
|
+
See method :meth:`coef` for details about the definition of the
|
|
791
|
+
connection coefficients.
|
|
792
|
+
|
|
793
|
+
To delete the connection coefficients in other frames, use the method
|
|
794
|
+
:meth:`set_coef` instead.
|
|
795
|
+
|
|
796
|
+
INPUT:
|
|
797
|
+
|
|
798
|
+
- ``frame`` -- (default: ``None``) vector frame in which the connection
|
|
799
|
+
coefficients are defined; if ``None``, the default frame of the
|
|
800
|
+
connection's domain is assumed.
|
|
801
|
+
|
|
802
|
+
.. WARNING::
|
|
803
|
+
|
|
804
|
+
If the connection has already coefficients in other frames, it
|
|
805
|
+
is the user's responsibility to make sure that the coefficients
|
|
806
|
+
to be added are consistent with them.
|
|
807
|
+
|
|
808
|
+
OUTPUT:
|
|
809
|
+
|
|
810
|
+
- connection coefficients in the given frame, as an instance of the
|
|
811
|
+
class :class:`~sage.tensor.modules.comp.Components`; if such
|
|
812
|
+
connection coefficients did not exist previously, they are created.
|
|
813
|
+
See method :meth:`coef` for the storage convention of the connection
|
|
814
|
+
coefficients.
|
|
815
|
+
|
|
816
|
+
EXAMPLES:
|
|
817
|
+
|
|
818
|
+
Setting the coefficients of an affine connection w.r.t. some coordinate
|
|
819
|
+
frame::
|
|
820
|
+
|
|
821
|
+
sage: M = Manifold(2, 'M', start_index=1)
|
|
822
|
+
sage: X.<x,y> = M.chart()
|
|
823
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
824
|
+
sage: eX = X.frame(); eX
|
|
825
|
+
Coordinate frame (M, (∂/∂x,∂/∂y))
|
|
826
|
+
sage: nab.add_coef(eX)
|
|
827
|
+
3-indices components w.r.t. Coordinate frame (M, (∂/∂x,∂/∂y))
|
|
828
|
+
sage: nab.add_coef(eX)[1,2,1] = x*y
|
|
829
|
+
sage: nab.display(eX)
|
|
830
|
+
Gam^x_yx = x*y
|
|
831
|
+
|
|
832
|
+
Since ``eX`` is the manifold's default vector frame, its mention may
|
|
833
|
+
be omitted::
|
|
834
|
+
|
|
835
|
+
sage: nab.add_coef()[1,2,1] = x*y
|
|
836
|
+
sage: nab.add_coef()
|
|
837
|
+
3-indices components w.r.t. Coordinate frame (M, (∂/∂x,∂/∂y))
|
|
838
|
+
sage: nab.add_coef()[1,2,1] = x*y
|
|
839
|
+
sage: nab.display()
|
|
840
|
+
Gam^x_yx = x*y
|
|
841
|
+
|
|
842
|
+
Adding connection coefficients w.r.t. to another vector frame::
|
|
843
|
+
|
|
844
|
+
sage: e = M.vector_frame('e')
|
|
845
|
+
sage: nab.add_coef(e)
|
|
846
|
+
3-indices components w.r.t. Vector frame (M, (e_1,e_2))
|
|
847
|
+
sage: nab.add_coef(e)[2,1,1] = x+y
|
|
848
|
+
sage: nab.add_coef(e)[2,1,2] = x-y
|
|
849
|
+
sage: nab.display(e)
|
|
850
|
+
Gam^2_11 = x + y
|
|
851
|
+
Gam^2_12 = x - y
|
|
852
|
+
|
|
853
|
+
The coefficients w.r.t. the frame ``eX`` have been kept::
|
|
854
|
+
|
|
855
|
+
sage: nab.display(eX)
|
|
856
|
+
Gam^x_yx = x*y
|
|
857
|
+
|
|
858
|
+
To delete them, use the method :meth:`set_coef` instead.
|
|
859
|
+
"""
|
|
860
|
+
if self.is_immutable():
|
|
861
|
+
raise ValueError("the coefficients of an immutable element "
|
|
862
|
+
"cannot be changed")
|
|
863
|
+
if frame is None:
|
|
864
|
+
frame = self._domain._def_frame
|
|
865
|
+
if frame not in self._coefficients:
|
|
866
|
+
if frame not in self._domain._frames:
|
|
867
|
+
raise ValueError("the {} is not".format(frame) +
|
|
868
|
+
" a frame on the {}".format(self._domain))
|
|
869
|
+
self._coefficients[frame] = self._new_coef(frame)
|
|
870
|
+
self._del_derived() # deletes the derived quantities
|
|
871
|
+
return self._coefficients[frame]
|
|
872
|
+
|
|
873
|
+
def del_other_coef(self, frame=None):
|
|
874
|
+
r"""
|
|
875
|
+
Delete all the coefficients but those corresponding to ``frame``.
|
|
876
|
+
|
|
877
|
+
INPUT:
|
|
878
|
+
|
|
879
|
+
- ``frame`` -- (default: ``None``) vector frame, the connection
|
|
880
|
+
coefficients w.r.t. which are to be kept; if ``None``, the default
|
|
881
|
+
frame of the connection's domain is assumed.
|
|
882
|
+
|
|
883
|
+
EXAMPLES:
|
|
884
|
+
|
|
885
|
+
We first create two sets of connection coefficients::
|
|
886
|
+
|
|
887
|
+
sage: M = Manifold(2, 'M', start_index=1)
|
|
888
|
+
sage: X.<x,y> = M.chart()
|
|
889
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
890
|
+
sage: eX = X.frame()
|
|
891
|
+
sage: nab.set_coef(eX)[1,2,1] = x*y
|
|
892
|
+
sage: e = M.vector_frame('e')
|
|
893
|
+
sage: nab.add_coef(e)[2,1,1] = x+y
|
|
894
|
+
sage: nab.display(eX)
|
|
895
|
+
Gam^x_yx = x*y
|
|
896
|
+
sage: nab.display(e)
|
|
897
|
+
Gam^2_11 = x + y
|
|
898
|
+
|
|
899
|
+
Let us delete the connection coefficients w.r.t. all frames except for
|
|
900
|
+
frame ``eX``::
|
|
901
|
+
|
|
902
|
+
sage: nab.del_other_coef(eX)
|
|
903
|
+
sage: nab.display(eX)
|
|
904
|
+
Gam^x_yx = x*y
|
|
905
|
+
|
|
906
|
+
The connection coefficients w.r.t. frame ``e`` have indeed been
|
|
907
|
+
deleted::
|
|
908
|
+
|
|
909
|
+
sage: nab.display(e)
|
|
910
|
+
Traceback (most recent call last):
|
|
911
|
+
...
|
|
912
|
+
ValueError: no common frame found for the computation
|
|
913
|
+
"""
|
|
914
|
+
if frame is None:
|
|
915
|
+
frame = self._domain._def_frame
|
|
916
|
+
if frame not in self._coefficients:
|
|
917
|
+
raise ValueError("the coefficients w.r.t. {}".format(frame) +
|
|
918
|
+
" have not been defined")
|
|
919
|
+
to_be_deleted = []
|
|
920
|
+
for other_frame in self._coefficients:
|
|
921
|
+
if other_frame != frame:
|
|
922
|
+
to_be_deleted.append(other_frame)
|
|
923
|
+
for other_frame in to_be_deleted:
|
|
924
|
+
del self._coefficients[other_frame]
|
|
925
|
+
|
|
926
|
+
def set_immutable(self):
|
|
927
|
+
r"""
|
|
928
|
+
Set ``self`` and all restrictions of ``self`` immutable.
|
|
929
|
+
|
|
930
|
+
EXAMPLES:
|
|
931
|
+
|
|
932
|
+
An affine connection can be set immutable::
|
|
933
|
+
|
|
934
|
+
sage: M = Manifold(2, 'M', start_index=1)
|
|
935
|
+
sage: X.<x,y> = M.chart()
|
|
936
|
+
sage: U = M.open_subset('U', coord_def={X: x^2+y^2<1})
|
|
937
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
938
|
+
sage: eX = X.frame()
|
|
939
|
+
sage: nab.set_coef(eX)[1,2,1] = x*y
|
|
940
|
+
sage: nab.is_immutable()
|
|
941
|
+
False
|
|
942
|
+
sage: nab.set_immutable()
|
|
943
|
+
sage: nab.is_immutable()
|
|
944
|
+
True
|
|
945
|
+
|
|
946
|
+
The coefficients of immutable elements cannot be changed::
|
|
947
|
+
|
|
948
|
+
sage: nab.add_coef(eX)[2,1,1] = x+y
|
|
949
|
+
Traceback (most recent call last):
|
|
950
|
+
...
|
|
951
|
+
ValueError: the coefficients of an immutable element cannot
|
|
952
|
+
be changed
|
|
953
|
+
|
|
954
|
+
The restriction are set immutable as well::
|
|
955
|
+
|
|
956
|
+
sage: nabU = nab.restrict(U)
|
|
957
|
+
sage: nabU.is_immutable()
|
|
958
|
+
True
|
|
959
|
+
"""
|
|
960
|
+
for rst in self._restrictions.values():
|
|
961
|
+
rst.set_immutable()
|
|
962
|
+
self._is_immutable = True
|
|
963
|
+
|
|
964
|
+
def is_immutable(self):
|
|
965
|
+
r"""
|
|
966
|
+
Return ``True`` if this object is immutable, i.e. its coefficients
|
|
967
|
+
cannot be chanced, and ``False`` if it is not.
|
|
968
|
+
|
|
969
|
+
To set an affine connection immutable, use :meth:`set_immutable`.
|
|
970
|
+
|
|
971
|
+
EXAMPLES::
|
|
972
|
+
|
|
973
|
+
sage: M = Manifold(2, 'M', start_index=1)
|
|
974
|
+
sage: X.<x,y> = M.chart()
|
|
975
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
976
|
+
sage: nab.is_immutable()
|
|
977
|
+
False
|
|
978
|
+
sage: nab.set_immutable()
|
|
979
|
+
sage: nab.is_immutable()
|
|
980
|
+
True
|
|
981
|
+
"""
|
|
982
|
+
return self._is_immutable
|
|
983
|
+
|
|
984
|
+
def is_mutable(self):
|
|
985
|
+
r"""
|
|
986
|
+
Return ``True`` if this object is mutable, i.e. its coefficients can
|
|
987
|
+
be changed, and ``False`` if it is not.
|
|
988
|
+
|
|
989
|
+
EXAMPLES::
|
|
990
|
+
|
|
991
|
+
sage: M = Manifold(2, 'M', start_index=1)
|
|
992
|
+
sage: X.<x,y> = M.chart()
|
|
993
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
994
|
+
sage: nab.is_mutable()
|
|
995
|
+
True
|
|
996
|
+
sage: nab.set_immutable()
|
|
997
|
+
sage: nab.is_mutable()
|
|
998
|
+
False
|
|
999
|
+
"""
|
|
1000
|
+
return not self._is_immutable
|
|
1001
|
+
|
|
1002
|
+
def copy(self, name, latex_name=None):
|
|
1003
|
+
r"""
|
|
1004
|
+
Return an exact copy of ``self``.
|
|
1005
|
+
|
|
1006
|
+
INPUT:
|
|
1007
|
+
|
|
1008
|
+
- ``name`` -- name given to the copy
|
|
1009
|
+
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
|
|
1010
|
+
copy; if none is provided, the LaTeX symbol is set to ``name``
|
|
1011
|
+
|
|
1012
|
+
.. NOTE::
|
|
1013
|
+
|
|
1014
|
+
The name and the derived quantities are not copied.
|
|
1015
|
+
|
|
1016
|
+
EXAMPLES::
|
|
1017
|
+
|
|
1018
|
+
sage: M = Manifold(2, 'M', start_index=1)
|
|
1019
|
+
sage: X.<x,y> = M.chart()
|
|
1020
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
1021
|
+
sage: eX = X.frame()
|
|
1022
|
+
sage: nab.set_coef(eX)[1,2,1] = x*y
|
|
1023
|
+
sage: nab.set_coef(eX)[1,2,2] = x+y
|
|
1024
|
+
sage: nab.display()
|
|
1025
|
+
Gam^x_yx = x*y
|
|
1026
|
+
Gam^x_yy = x + y
|
|
1027
|
+
sage: nab_copy = nab.copy(name='nabla_1', latex_name=r'\nabla_1')
|
|
1028
|
+
sage: nab is nab_copy
|
|
1029
|
+
False
|
|
1030
|
+
sage: nab == nab_copy
|
|
1031
|
+
True
|
|
1032
|
+
sage: nab_copy.display()
|
|
1033
|
+
Gam^x_yx = x*y
|
|
1034
|
+
Gam^x_yy = x + y
|
|
1035
|
+
"""
|
|
1036
|
+
copy = type(self)(self._domain, name, latex_name=latex_name)
|
|
1037
|
+
for dom, rst in self._restrictions.items():
|
|
1038
|
+
copy._restrictions[dom] = rst.copy(name, latex_name=latex_name)
|
|
1039
|
+
for frame, coef in self._coefficients.items():
|
|
1040
|
+
copy._coefficients[frame] = coef.copy()
|
|
1041
|
+
return copy
|
|
1042
|
+
|
|
1043
|
+
def __getitem__(self, args):
|
|
1044
|
+
r"""
|
|
1045
|
+
Return the connection coefficient w.r.t. some frame corresponding to
|
|
1046
|
+
the given indices.
|
|
1047
|
+
|
|
1048
|
+
INPUT:
|
|
1049
|
+
|
|
1050
|
+
- ``args`` -- list of indices defining the coefficient; if ``[:]`` is
|
|
1051
|
+
provided, all the coefficients are returned. The frame can be passed
|
|
1052
|
+
as the first item of ``args``; if not, the default frame of the
|
|
1053
|
+
connection's domain is assumed
|
|
1054
|
+
|
|
1055
|
+
OUTPUT:
|
|
1056
|
+
|
|
1057
|
+
- the connection coefficient corresponding to the specified frame and
|
|
1058
|
+
indices, as an instance of
|
|
1059
|
+
:class:`~sage.manifolds.chart_func.ChartFunction`
|
|
1060
|
+
(or the list of all connection coefficients if ``args==[:]`` or
|
|
1061
|
+
``args=[frame,:]``).
|
|
1062
|
+
|
|
1063
|
+
TESTS::
|
|
1064
|
+
|
|
1065
|
+
sage: M = Manifold(2, 'M', start_index=1)
|
|
1066
|
+
sage: X.<x,y> = M.chart()
|
|
1067
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
1068
|
+
sage: nab.set_coef(X.frame())[1,2,1] = x*y
|
|
1069
|
+
sage: nab.__getitem__((1,2,1))
|
|
1070
|
+
x*y
|
|
1071
|
+
sage: nab[1,2,1] # equivalent to above
|
|
1072
|
+
x*y
|
|
1073
|
+
sage: type(nab.__getitem__((1,2,1)))
|
|
1074
|
+
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
|
|
1075
|
+
sage: nab.__getitem__((X.frame(),1,2,1))
|
|
1076
|
+
x*y
|
|
1077
|
+
sage: nab[X.frame(),1,2,1] # equivalent to above
|
|
1078
|
+
x*y
|
|
1079
|
+
|
|
1080
|
+
Returning the full set of coefficients::
|
|
1081
|
+
|
|
1082
|
+
sage: nab.__getitem__(slice(None))
|
|
1083
|
+
[[[0, 0], [x*y, 0]], [[0, 0], [0, 0]]]
|
|
1084
|
+
sage: nab[:] # equivalent to above
|
|
1085
|
+
[[[0, 0], [x*y, 0]], [[0, 0], [0, 0]]]
|
|
1086
|
+
sage: nab.__getitem__((X.frame(), slice(None)))
|
|
1087
|
+
[[[0, 0], [x*y, 0]], [[0, 0], [0, 0]]]
|
|
1088
|
+
sage: nab[X.frame(), :] # equivalent to above
|
|
1089
|
+
[[[0, 0], [x*y, 0]], [[0, 0], [0, 0]]]
|
|
1090
|
+
|
|
1091
|
+
Returning a scalar field::
|
|
1092
|
+
|
|
1093
|
+
sage: nab.__getitem__(([1,2,1]))
|
|
1094
|
+
Scalar field on the 2-dimensional differentiable manifold M
|
|
1095
|
+
sage: nab[[1,2,1]] # equivalent to above
|
|
1096
|
+
Scalar field on the 2-dimensional differentiable manifold M
|
|
1097
|
+
sage: nab.__getitem__(([X.frame(),1,2,1])).coord_function() is nab[1,2,1]
|
|
1098
|
+
True
|
|
1099
|
+
"""
|
|
1100
|
+
if isinstance(args, list): # case of [[...]] syntax
|
|
1101
|
+
if isinstance(args[0], (int, Integer, slice)):
|
|
1102
|
+
frame = self._domain._def_frame
|
|
1103
|
+
else:
|
|
1104
|
+
frame = args[0]
|
|
1105
|
+
args = args[1:]
|
|
1106
|
+
else:
|
|
1107
|
+
if isinstance(args, (int, Integer, slice)):
|
|
1108
|
+
frame = self._domain._def_frame
|
|
1109
|
+
elif not isinstance(args[0], (int, Integer, slice)):
|
|
1110
|
+
frame = args[0]
|
|
1111
|
+
args = args[1:]
|
|
1112
|
+
if len(args) == 1:
|
|
1113
|
+
args = args[0] # to accommodate for [e,:] syntax
|
|
1114
|
+
else:
|
|
1115
|
+
frame = self._domain._def_frame
|
|
1116
|
+
return self.coef(frame)[args]
|
|
1117
|
+
|
|
1118
|
+
def __setitem__(self, args, value):
|
|
1119
|
+
r"""
|
|
1120
|
+
Set the connection coefficient w.r.t. some frame corresponding to the
|
|
1121
|
+
given indices.
|
|
1122
|
+
|
|
1123
|
+
INPUT:
|
|
1124
|
+
|
|
1125
|
+
- ``args`` -- list of indices defining the coefficient; if ``[:]`` is
|
|
1126
|
+
provided, all the coefficients are set. The frame can be passed
|
|
1127
|
+
as the first item of ``args``; if not, the default frame of the
|
|
1128
|
+
connection's domain is assumed
|
|
1129
|
+
- ``value`` -- the value to be set or a list of values if
|
|
1130
|
+
``args = [:]``
|
|
1131
|
+
|
|
1132
|
+
TESTS::
|
|
1133
|
+
|
|
1134
|
+
sage: M = Manifold(2, 'M', start_index=1)
|
|
1135
|
+
sage: X.<x,y> = M.chart()
|
|
1136
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
1137
|
+
sage: nab.__setitem__((1,2,1), x*y)
|
|
1138
|
+
sage: nab[:]
|
|
1139
|
+
[[[0, 0], [x*y, 0]], [[0, 0], [0, 0]]]
|
|
1140
|
+
sage: nab[1,2,1] = x*y # equivalent to __setitem__ above
|
|
1141
|
+
sage: nab[:]
|
|
1142
|
+
[[[0, 0], [x*y, 0]], [[0, 0], [0, 0]]]
|
|
1143
|
+
sage: nab.__setitem__((X.frame(),1,2,1), -x^2)
|
|
1144
|
+
sage: nab[1,2,1]
|
|
1145
|
+
-x^2
|
|
1146
|
+
sage: nab[X.frame(), 1,2,1] = -x^2 # equivalent to __setitem__ above
|
|
1147
|
+
sage: nab[1,2,1]
|
|
1148
|
+
-x^2
|
|
1149
|
+
|
|
1150
|
+
Setting all the coefficients at once::
|
|
1151
|
+
|
|
1152
|
+
sage: nab.__setitem__(slice(None),
|
|
1153
|
+
....: [[[-x^2, 0], [x*y, 0]], [[0, 1+y], [0, 0]]])
|
|
1154
|
+
sage: nab[:]
|
|
1155
|
+
[[[-x^2, 0], [x*y, 0]], [[0, y + 1], [0, 0]]]
|
|
1156
|
+
sage: nab[:] = [[[-x^2, 0], [x*y, 0]], [[0, 1+y], [0, 0]]] # equivalent to above
|
|
1157
|
+
sage: nab[:]
|
|
1158
|
+
[[[-x^2, 0], [x*y, 0]], [[0, y + 1], [0, 0]]]
|
|
1159
|
+
|
|
1160
|
+
Providing a scalar field as value::
|
|
1161
|
+
|
|
1162
|
+
sage: f = M.scalar_field({X: x*y})
|
|
1163
|
+
sage: nab.__setitem__((1,2,1), f)
|
|
1164
|
+
sage: nab[1,2,1]
|
|
1165
|
+
x*y
|
|
1166
|
+
"""
|
|
1167
|
+
if isinstance(args, list): # case of [[...]] syntax
|
|
1168
|
+
if isinstance(args[0], (int, Integer, slice)):
|
|
1169
|
+
frame = self._domain._def_frame
|
|
1170
|
+
else:
|
|
1171
|
+
frame = args[0]
|
|
1172
|
+
args = args[1:]
|
|
1173
|
+
else:
|
|
1174
|
+
if isinstance(args, (int, Integer, slice)):
|
|
1175
|
+
frame = self._domain._def_frame
|
|
1176
|
+
elif not isinstance(args[0], (int, Integer, slice)):
|
|
1177
|
+
frame = args[0]
|
|
1178
|
+
args = args[1:]
|
|
1179
|
+
if len(args) == 1:
|
|
1180
|
+
args = args[0] # to accommodate for [e,:] syntax
|
|
1181
|
+
else:
|
|
1182
|
+
frame = self._domain._def_frame
|
|
1183
|
+
self.set_coef(frame)[args] = value
|
|
1184
|
+
|
|
1185
|
+
def display(self, frame=None, chart=None, symbol=None, latex_symbol=None,
|
|
1186
|
+
index_labels=None, index_latex_labels=None,
|
|
1187
|
+
coordinate_labels=True, only_nonzero=True,
|
|
1188
|
+
only_nonredundant=False):
|
|
1189
|
+
r"""
|
|
1190
|
+
Display all the connection coefficients w.r.t. to a given frame, one
|
|
1191
|
+
per line.
|
|
1192
|
+
|
|
1193
|
+
The output is either text-formatted (console mode) or LaTeX-formatted
|
|
1194
|
+
(notebook mode).
|
|
1195
|
+
|
|
1196
|
+
INPUT:
|
|
1197
|
+
|
|
1198
|
+
- ``frame`` -- (default: ``None``) vector frame relative to which the
|
|
1199
|
+
connection coefficients are defined; if ``None``, the
|
|
1200
|
+
default frame of the connection's domain is used
|
|
1201
|
+
- ``chart`` -- (default: ``None``) chart specifying the coordinate
|
|
1202
|
+
expression of the connection coefficients; if ``None``,
|
|
1203
|
+
the default chart of the domain of ``frame`` is used
|
|
1204
|
+
- ``symbol`` -- (default: ``None``) string specifying the
|
|
1205
|
+
symbol of the connection coefficients; if ``None``, 'Gam' is used
|
|
1206
|
+
- ``latex_symbol`` -- (default: ``None``) string specifying the LaTeX
|
|
1207
|
+
symbol for the components; if ``None``, '\\Gamma' is used
|
|
1208
|
+
- ``index_labels`` -- (default: ``None``) list of strings representing
|
|
1209
|
+
the labels of each index; if ``None``, integer labels are used,
|
|
1210
|
+
except if ``frame`` is a coordinate frame and ``coordinate_symbols``
|
|
1211
|
+
is set to ``True``, in which case the coordinate symbols are used
|
|
1212
|
+
- ``index_latex_labels`` -- (default: ``None``) list of strings
|
|
1213
|
+
representing the LaTeX labels of each index; if ``None``, integer
|
|
1214
|
+
labels are used, except if ``frame`` is a coordinate frame and
|
|
1215
|
+
``coordinate_symbols`` is set to ``True``, in which case the
|
|
1216
|
+
coordinate LaTeX symbols are used
|
|
1217
|
+
- ``coordinate_labels`` -- boolean (default: ``True``); if ``True``,
|
|
1218
|
+
coordinate symbols are used by default (instead of integers) as
|
|
1219
|
+
index labels whenever ``frame`` is a coordinate frame
|
|
1220
|
+
- ``only_nonzero`` -- boolean (default: ``True``); if ``True``, only
|
|
1221
|
+
nonzero connection coefficients are displayed
|
|
1222
|
+
- ``only_nonredundant`` -- boolean (default: ``False``); if ``True``,
|
|
1223
|
+
only nonredundant connection coefficients are displayed in case of
|
|
1224
|
+
symmetries
|
|
1225
|
+
|
|
1226
|
+
EXAMPLES:
|
|
1227
|
+
|
|
1228
|
+
Coefficients of a connection on a 3-dimensional manifold::
|
|
1229
|
+
|
|
1230
|
+
sage: M = Manifold(3, 'M', start_index=1)
|
|
1231
|
+
sage: c_xyz.<x,y,z> = M.chart()
|
|
1232
|
+
sage: nab = M.affine_connection('nabla', r'\nabla')
|
|
1233
|
+
sage: nab[1,1,2], nab[3,2,3] = x^2, y*z
|
|
1234
|
+
|
|
1235
|
+
By default, only the nonzero connection coefficients are displayed::
|
|
1236
|
+
|
|
1237
|
+
sage: nab.display()
|
|
1238
|
+
Gam^x_xy = x^2
|
|
1239
|
+
Gam^z_yz = y*z
|
|
1240
|
+
sage: latex(nab.display())
|
|
1241
|
+
\begin{array}{lcl} \Gamma_{ \phantom{\, x} \, x \, y }^{ \, x \phantom{\, x} \phantom{\, y} }
|
|
1242
|
+
& = & x^{2} \\
|
|
1243
|
+
\Gamma_{ \phantom{\, z} \, y \, z }^{ \, z \phantom{\, y} \phantom{\, z} }
|
|
1244
|
+
& = & y z \end{array}
|
|
1245
|
+
|
|
1246
|
+
By default, the displayed connection coefficients are those w.r.t.
|
|
1247
|
+
to the default frame of the connection's domain, so the above is
|
|
1248
|
+
equivalent to::
|
|
1249
|
+
|
|
1250
|
+
sage: nab.display(frame=M.default_frame())
|
|
1251
|
+
Gam^x_xy = x^2
|
|
1252
|
+
Gam^z_yz = y*z
|
|
1253
|
+
|
|
1254
|
+
Since the default frame is a coordinate frame, coordinate symbols are
|
|
1255
|
+
used to label the indices, but one may ask for integers instead::
|
|
1256
|
+
|
|
1257
|
+
sage: M.default_frame() is c_xyz.frame()
|
|
1258
|
+
True
|
|
1259
|
+
sage: nab.display(coordinate_labels=False)
|
|
1260
|
+
Gam^1_12 = x^2
|
|
1261
|
+
Gam^3_23 = y*z
|
|
1262
|
+
|
|
1263
|
+
The index labels can also be customized::
|
|
1264
|
+
|
|
1265
|
+
sage: nab.display(index_labels=['(1)', '(2)', '(3)'])
|
|
1266
|
+
Gam^(1)_(1),(2) = x^2
|
|
1267
|
+
Gam^(3)_(2),(3) = y*z
|
|
1268
|
+
|
|
1269
|
+
The symbol 'Gam' can be changed::
|
|
1270
|
+
|
|
1271
|
+
sage: nab.display(symbol='C', latex_symbol='C')
|
|
1272
|
+
C^x_xy = x^2
|
|
1273
|
+
C^z_yz = y*z
|
|
1274
|
+
sage: latex(nab.display(symbol='C', latex_symbol='C'))
|
|
1275
|
+
\begin{array}{lcl} C_{ \phantom{\, x} \, x \, y }^{ \, x \phantom{\, x} \phantom{\, y} }
|
|
1276
|
+
& = & x^{2} \\
|
|
1277
|
+
C_{ \phantom{\, z} \, y \, z }^{ \, z \phantom{\, y} \phantom{\, z} }
|
|
1278
|
+
& = & y z \end{array}
|
|
1279
|
+
|
|
1280
|
+
Display of Christoffel symbols, skipping the redundancy associated
|
|
1281
|
+
with the symmetry of the last two indices::
|
|
1282
|
+
|
|
1283
|
+
sage: M = Manifold(3, 'R^3', start_index=1)
|
|
1284
|
+
sage: c_spher.<r,th,ph> = M.chart(r'r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi')
|
|
1285
|
+
sage: g = M.metric('g')
|
|
1286
|
+
sage: g[1,1], g[2,2], g[3,3] = 1, r^2 , (r*sin(th))^2
|
|
1287
|
+
sage: g.display()
|
|
1288
|
+
g = dr⊗dr + r^2 dth⊗dth + r^2*sin(th)^2 dph⊗dph
|
|
1289
|
+
sage: g.connection().display(only_nonredundant=True)
|
|
1290
|
+
Gam^r_th,th = -r
|
|
1291
|
+
Gam^r_ph,ph = -r*sin(th)^2
|
|
1292
|
+
Gam^th_r,th = 1/r
|
|
1293
|
+
Gam^th_ph,ph = -cos(th)*sin(th)
|
|
1294
|
+
Gam^ph_r,ph = 1/r
|
|
1295
|
+
Gam^ph_th,ph = cos(th)/sin(th)
|
|
1296
|
+
|
|
1297
|
+
By default, the parameter ``only_nonredundant`` is set to ``False``::
|
|
1298
|
+
|
|
1299
|
+
sage: g.connection().display()
|
|
1300
|
+
Gam^r_th,th = -r
|
|
1301
|
+
Gam^r_ph,ph = -r*sin(th)^2
|
|
1302
|
+
Gam^th_r,th = 1/r
|
|
1303
|
+
Gam^th_th,r = 1/r
|
|
1304
|
+
Gam^th_ph,ph = -cos(th)*sin(th)
|
|
1305
|
+
Gam^ph_r,ph = 1/r
|
|
1306
|
+
Gam^ph_th,ph = cos(th)/sin(th)
|
|
1307
|
+
Gam^ph_ph,r = 1/r
|
|
1308
|
+
Gam^ph_ph,th = cos(th)/sin(th)
|
|
1309
|
+
"""
|
|
1310
|
+
from sage.manifolds.differentiable.vectorframe import CoordFrame
|
|
1311
|
+
from sage.misc.latex import latex
|
|
1312
|
+
if frame is None:
|
|
1313
|
+
frame = self._domain.default_frame()
|
|
1314
|
+
if chart is None:
|
|
1315
|
+
chart = frame.domain().default_chart()
|
|
1316
|
+
if symbol is None:
|
|
1317
|
+
symbol = 'Gam'
|
|
1318
|
+
if latex_symbol is None:
|
|
1319
|
+
latex_symbol = r'\Gamma'
|
|
1320
|
+
if index_labels is None and isinstance(frame, CoordFrame) and \
|
|
1321
|
+
coordinate_labels:
|
|
1322
|
+
ch = frame.chart()
|
|
1323
|
+
index_labels = [str(z) for z in ch[:]]
|
|
1324
|
+
index_latex_labels = [latex(z) for z in ch[:]]
|
|
1325
|
+
return self.coef(frame=frame).display(symbol,
|
|
1326
|
+
latex_symbol=latex_symbol, index_positions='udd',
|
|
1327
|
+
index_labels=index_labels, index_latex_labels=index_latex_labels,
|
|
1328
|
+
format_spec=chart, only_nonzero=only_nonzero,
|
|
1329
|
+
only_nonredundant=only_nonredundant)
|
|
1330
|
+
|
|
1331
|
+
def restrict(self, subdomain):
|
|
1332
|
+
r"""
|
|
1333
|
+
Return the restriction of the connection to some subdomain.
|
|
1334
|
+
|
|
1335
|
+
If such restriction has not been defined yet, it is constructed here.
|
|
1336
|
+
|
|
1337
|
+
INPUT:
|
|
1338
|
+
|
|
1339
|
+
- ``subdomain`` -- open subset `U` of the connection's domain (must be
|
|
1340
|
+
an instance of
|
|
1341
|
+
:class:`~sage.manifolds.differentiable.manifold.DifferentiableManifold`)
|
|
1342
|
+
|
|
1343
|
+
OUTPUT: instance of :class:`AffineConnection` representing the restriction
|
|
1344
|
+
|
|
1345
|
+
EXAMPLES:
|
|
1346
|
+
|
|
1347
|
+
Restriction of a connection on a 2-dimensional manifold::
|
|
1348
|
+
|
|
1349
|
+
sage: M = Manifold(2, 'M', start_index=1)
|
|
1350
|
+
sage: c_xy.<x,y> = M.chart()
|
|
1351
|
+
sage: nab = M.affine_connection('nabla', r'\nabla')
|
|
1352
|
+
sage: nab[1,1,2], nab[2,1,1] = x^2, x+y
|
|
1353
|
+
sage: nab[:]
|
|
1354
|
+
[[[0, x^2], [0, 0]], [[x + y, 0], [0, 0]]]
|
|
1355
|
+
sage: U = M.open_subset('U', coord_def={c_xy: x>0})
|
|
1356
|
+
sage: nabU = nab.restrict(U) ; nabU
|
|
1357
|
+
Affine connection nabla on the Open subset U of the 2-dimensional
|
|
1358
|
+
differentiable manifold M
|
|
1359
|
+
sage: nabU.domain()
|
|
1360
|
+
Open subset U of the 2-dimensional differentiable manifold M
|
|
1361
|
+
sage: nabU[:]
|
|
1362
|
+
[[[0, x^2], [0, 0]], [[x + y, 0], [0, 0]]]
|
|
1363
|
+
|
|
1364
|
+
The result is cached::
|
|
1365
|
+
|
|
1366
|
+
sage: nab.restrict(U) is nabU
|
|
1367
|
+
True
|
|
1368
|
+
|
|
1369
|
+
until the connection is modified::
|
|
1370
|
+
|
|
1371
|
+
sage: nab[1,2,2] = -y
|
|
1372
|
+
sage: nab.restrict(U) is nabU
|
|
1373
|
+
False
|
|
1374
|
+
sage: nab.restrict(U)[:]
|
|
1375
|
+
[[[0, x^2], [0, -y]], [[x + y, 0], [0, 0]]]
|
|
1376
|
+
"""
|
|
1377
|
+
if subdomain == self._domain:
|
|
1378
|
+
return self
|
|
1379
|
+
if subdomain not in self._restrictions:
|
|
1380
|
+
if not subdomain.is_subset(self._domain):
|
|
1381
|
+
raise ValueError("The provided domains is not a subset of " +
|
|
1382
|
+
"the connection's domain.")
|
|
1383
|
+
resu = AffineConnection(subdomain, name=self._name,
|
|
1384
|
+
latex_name=self._latex_name)
|
|
1385
|
+
for frame in self._coefficients:
|
|
1386
|
+
for sframe in subdomain._top_frames:
|
|
1387
|
+
if sframe in frame._subframes:
|
|
1388
|
+
comp_store = self._coefficients[frame]._comp
|
|
1389
|
+
scoef = resu._new_coef(sframe)
|
|
1390
|
+
scomp_store = scoef._comp
|
|
1391
|
+
# the coefficients of the restriction are evaluated
|
|
1392
|
+
# index by index:
|
|
1393
|
+
for ind, value in comp_store.items():
|
|
1394
|
+
scomp_store[ind] = value.restrict(sframe._domain)
|
|
1395
|
+
resu._coefficients[sframe] = scoef
|
|
1396
|
+
if self._torsion is not None:
|
|
1397
|
+
resu._torsion = self._torsion.restrict(subdomain)
|
|
1398
|
+
if self._riemann is not None:
|
|
1399
|
+
resu._riemann = self._riemann.restrict(subdomain)
|
|
1400
|
+
if self._ricci is not None:
|
|
1401
|
+
resu._ricci = self._ricci.restrict(subdomain)
|
|
1402
|
+
resu.set_immutable() # restrictions must be immutable, too
|
|
1403
|
+
self._restrictions[subdomain] = resu
|
|
1404
|
+
return self._restrictions[subdomain]
|
|
1405
|
+
|
|
1406
|
+
def _common_frame(self, other):
|
|
1407
|
+
r"""
|
|
1408
|
+
Find a common vector frame for the coefficients of ``self`` and
|
|
1409
|
+
the components of ``other``.
|
|
1410
|
+
|
|
1411
|
+
In case of multiple common frames, the default frame of ``self``'s
|
|
1412
|
+
domain is privileged.
|
|
1413
|
+
|
|
1414
|
+
INPUT:
|
|
1415
|
+
|
|
1416
|
+
- ``other`` -- a tensor field on parallelizable domain, as an
|
|
1417
|
+
instance of
|
|
1418
|
+
:class:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal`
|
|
1419
|
+
|
|
1420
|
+
OUTPUT: common frame; if no common frame is found, ``None`` is returned
|
|
1421
|
+
|
|
1422
|
+
TESTS::
|
|
1423
|
+
|
|
1424
|
+
sage: M = Manifold(2, 'M', start_index=1)
|
|
1425
|
+
sage: X.<x,y> = M.chart()
|
|
1426
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
1427
|
+
sage: nab[1,2,1] = x*y
|
|
1428
|
+
sage: v = M.vector_field()
|
|
1429
|
+
sage: v[:] = [-y, x]
|
|
1430
|
+
sage: nab._common_frame(v)
|
|
1431
|
+
Coordinate frame (M, (∂/∂x,∂/∂y))
|
|
1432
|
+
sage: e = M.vector_frame('e')
|
|
1433
|
+
sage: u = M.vector_field()
|
|
1434
|
+
sage: u[e,:] = [-3, 2]
|
|
1435
|
+
sage: nab._common_frame(u) # no common frame is found
|
|
1436
|
+
"""
|
|
1437
|
+
# The domain of search is restricted to other._domain:
|
|
1438
|
+
dom = other._domain
|
|
1439
|
+
# 1/ Does each object have components on the domain's default frame ?
|
|
1440
|
+
def_frame = dom._def_frame
|
|
1441
|
+
if def_frame in self._coefficients and def_frame in other._components:
|
|
1442
|
+
return def_frame
|
|
1443
|
+
# 2/ Search for a common frame among the existing components, i.e.
|
|
1444
|
+
# without performing any component transformation.
|
|
1445
|
+
# -------------------------------------------------------------
|
|
1446
|
+
for frame in self._coefficients:
|
|
1447
|
+
if frame in other._components:
|
|
1448
|
+
return frame
|
|
1449
|
+
# 3/ Search for a common frame among the subframes of self's frames:
|
|
1450
|
+
# --------------------------------------------------------------
|
|
1451
|
+
for frame in self._coefficients:
|
|
1452
|
+
for oframe in other._components:
|
|
1453
|
+
if oframe in frame._subframes:
|
|
1454
|
+
self.coef(oframe) # update the coefficients of self in oframe
|
|
1455
|
+
return oframe
|
|
1456
|
+
#
|
|
1457
|
+
# 4/ Search for a common frame via one component transformation
|
|
1458
|
+
# ----------------------------------------------------------
|
|
1459
|
+
# If this point is reached, it is necessary to perform at least
|
|
1460
|
+
# one component transformation to get a common frame
|
|
1461
|
+
for frame in self._coefficients:
|
|
1462
|
+
for oframe in other._components:
|
|
1463
|
+
if (oframe, frame) in dom._frame_changes:
|
|
1464
|
+
other.comp(frame, from_basis=oframe)
|
|
1465
|
+
return frame
|
|
1466
|
+
# 5/ Search for a common frame via one component transformation to
|
|
1467
|
+
# a subframe of self's frames:
|
|
1468
|
+
# -------------------------------------------------------------
|
|
1469
|
+
for frame in self._coefficients:
|
|
1470
|
+
for oframe in other._components:
|
|
1471
|
+
for sframe in frame._subframes:
|
|
1472
|
+
if (oframe, sframe) in dom._frame_changes:
|
|
1473
|
+
self.coef(sframe)
|
|
1474
|
+
other.comp(sframe, from_basis=oframe)
|
|
1475
|
+
return sframe
|
|
1476
|
+
#
|
|
1477
|
+
# If this point is reached, no common frame could be found, even at
|
|
1478
|
+
# the price of a component transformation:
|
|
1479
|
+
return None
|
|
1480
|
+
|
|
1481
|
+
def __call__(self, tensor):
|
|
1482
|
+
r"""
|
|
1483
|
+
Action of the connection on a tensor field.
|
|
1484
|
+
|
|
1485
|
+
INPUT:
|
|
1486
|
+
|
|
1487
|
+
- ``tensor`` -- a tensor field `T`, of type `(k,\ell)`
|
|
1488
|
+
|
|
1489
|
+
OUTPUT: tensor field `\nabla T`
|
|
1490
|
+
|
|
1491
|
+
TESTS::
|
|
1492
|
+
|
|
1493
|
+
sage: M = Manifold(2, 'M', start_index=1)
|
|
1494
|
+
sage: X.<x,y> = M.chart()
|
|
1495
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
1496
|
+
sage: nab[1,2,1] = x*y
|
|
1497
|
+
sage: v = M.vector_field()
|
|
1498
|
+
sage: v[:] = [-y, x]
|
|
1499
|
+
sage: nab.__call__(v)
|
|
1500
|
+
Tensor field of type (1,1) on the 2-dimensional differentiable
|
|
1501
|
+
manifold M
|
|
1502
|
+
|
|
1503
|
+
See documentation of
|
|
1504
|
+
:class:`~sage.manifolds.differentiable.affine_connection.AffineConnection`
|
|
1505
|
+
for more examples.
|
|
1506
|
+
"""
|
|
1507
|
+
from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal
|
|
1508
|
+
from sage.tensor.modules.format_utilities import format_unop_latex
|
|
1509
|
+
dom_resu = self._domain.intersection(tensor._domain)
|
|
1510
|
+
tensor_r = tensor.restrict(dom_resu)
|
|
1511
|
+
if tensor_r._tensor_type == (0,0): # scalar field case
|
|
1512
|
+
return tensor_r.differential()
|
|
1513
|
+
if isinstance(tensor_r, TensorFieldParal):
|
|
1514
|
+
return self._derive_paral(tensor_r)
|
|
1515
|
+
resu_rst = []
|
|
1516
|
+
for dom, rst in tensor_r._restrictions.items():
|
|
1517
|
+
# the computation is performed only if dom is not a subdomain
|
|
1518
|
+
# of another restriction:
|
|
1519
|
+
for odom in tensor_r._restrictions:
|
|
1520
|
+
if dom in odom._subsets and dom is not odom:
|
|
1521
|
+
break
|
|
1522
|
+
else:
|
|
1523
|
+
# dom is a not a subdomain and the computation is performed:
|
|
1524
|
+
resu_rst.append(self.__call__(rst))
|
|
1525
|
+
tensor_type_resu = (tensor_r._tensor_type[0],
|
|
1526
|
+
tensor_r._tensor_type[1]+1)
|
|
1527
|
+
if tensor_r._name is None:
|
|
1528
|
+
name_resu = None
|
|
1529
|
+
else:
|
|
1530
|
+
name_resu = self._name + '(' + tensor_r._name + ')'
|
|
1531
|
+
if tensor_r._latex_name is None:
|
|
1532
|
+
latex_name_resu = None
|
|
1533
|
+
else:
|
|
1534
|
+
latex_name_resu = format_unop_latex(self._latex_name + ' ',
|
|
1535
|
+
tensor_r._latex_name)
|
|
1536
|
+
vmodule = dom_resu.vector_field_module()
|
|
1537
|
+
resu = vmodule.tensor(tensor_type_resu, name=name_resu,
|
|
1538
|
+
latex_name=latex_name_resu,
|
|
1539
|
+
sym=resu_rst[0]._sym,
|
|
1540
|
+
antisym=resu_rst[0]._antisym)
|
|
1541
|
+
for rst in resu_rst:
|
|
1542
|
+
resu._restrictions[rst._domain] = rst
|
|
1543
|
+
return resu
|
|
1544
|
+
|
|
1545
|
+
def _derive_paral(self, tensor):
|
|
1546
|
+
r"""
|
|
1547
|
+
Action of the connection on a tensor field on a parallelizable domain.
|
|
1548
|
+
|
|
1549
|
+
INPUT:
|
|
1550
|
+
|
|
1551
|
+
- ``tensor`` -- a tensor field `T`, of type `(k,\ell)`
|
|
1552
|
+
|
|
1553
|
+
OUTPUT: tensor field `\nabla T`
|
|
1554
|
+
|
|
1555
|
+
TESTS::
|
|
1556
|
+
|
|
1557
|
+
sage: M = Manifold(2, 'M', start_index=1)
|
|
1558
|
+
sage: X.<x,y> = M.chart()
|
|
1559
|
+
sage: nab = M.affine_connection('nabla', latex_name=r'\nabla')
|
|
1560
|
+
sage: nab[1,2,1] = x*y
|
|
1561
|
+
sage: v = M.vector_field()
|
|
1562
|
+
sage: v[:] = [-y, x]
|
|
1563
|
+
sage: nab._derive_paral(v)
|
|
1564
|
+
Tensor field of type (1,1) on the 2-dimensional differentiable
|
|
1565
|
+
manifold M
|
|
1566
|
+
"""
|
|
1567
|
+
from sage.manifolds.differentiable.scalarfield import DiffScalarField
|
|
1568
|
+
from sage.tensor.modules.comp import Components, CompWithSym
|
|
1569
|
+
from sage.tensor.modules.format_utilities import format_unop_latex
|
|
1570
|
+
manif = self._domain
|
|
1571
|
+
tdom = tensor._domain
|
|
1572
|
+
frame = self._common_frame(tensor)
|
|
1573
|
+
if frame is None:
|
|
1574
|
+
raise ValueError("no common frame found for the computation")
|
|
1575
|
+
# Component computation in the common frame:
|
|
1576
|
+
tc = tensor._components[frame]
|
|
1577
|
+
gam = self._coefficients[frame]
|
|
1578
|
+
if not tensor._sym and not tensor._antisym:
|
|
1579
|
+
resc = Components(tdom.scalar_field_algebra(), frame,
|
|
1580
|
+
tensor._tensor_rank+1,
|
|
1581
|
+
start_index=self._domain._sindex,
|
|
1582
|
+
output_formatter=DiffScalarField.coord_function)
|
|
1583
|
+
else:
|
|
1584
|
+
resc = CompWithSym(tdom.scalar_field_algebra(), frame,
|
|
1585
|
+
tensor._tensor_rank+1,
|
|
1586
|
+
start_index=self._domain._sindex,
|
|
1587
|
+
output_formatter=DiffScalarField.coord_function,
|
|
1588
|
+
sym=tensor._sym, antisym=tensor._antisym)
|
|
1589
|
+
n_con = tensor._tensor_type[0]
|
|
1590
|
+
n_cov = tensor._tensor_type[1]
|
|
1591
|
+
|
|
1592
|
+
if Parallelism().get('tensor') != 1:
|
|
1593
|
+
# parallel computation
|
|
1594
|
+
# !!!!! Seems to work only when a frame is chosen !!!!!!
|
|
1595
|
+
|
|
1596
|
+
nproc = Parallelism().get('tensor')
|
|
1597
|
+
lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)]
|
|
1598
|
+
|
|
1599
|
+
ind_list = list(resc.non_redundant_index_generator())
|
|
1600
|
+
ind_step = max(1,int(len(ind_list)/nproc/2))
|
|
1601
|
+
local_list = lol(ind_list,ind_step)
|
|
1602
|
+
|
|
1603
|
+
# definition of the list of input parameters
|
|
1604
|
+
listParalInput = []
|
|
1605
|
+
for ind_part in local_list:
|
|
1606
|
+
listParalInput.append((ind_part,tc,gam,frame,n_con,
|
|
1607
|
+
tensor._tensor_rank,manif))
|
|
1608
|
+
|
|
1609
|
+
# definition of the parallel function
|
|
1610
|
+
@parallel(p_iter='multiprocessing',ncpus=nproc)
|
|
1611
|
+
def make_CovDerivative(ind_part, tc, gam, frame, n_con, rank, manif):
|
|
1612
|
+
partial = []
|
|
1613
|
+
for ind in ind_part:
|
|
1614
|
+
p = ind[-1] # derivation index
|
|
1615
|
+
ind0 = ind[:-1]
|
|
1616
|
+
rsum = frame[p](tc[[ind0]])
|
|
1617
|
+
# loop on contravariant indices:
|
|
1618
|
+
for k in range(n_con):
|
|
1619
|
+
for i in manif.irange():
|
|
1620
|
+
indk = list(ind0)
|
|
1621
|
+
indk[k] = i
|
|
1622
|
+
rsum += gam[[ind0[k], i, p]] * tc[[indk]]
|
|
1623
|
+
# loop on covariant indices:
|
|
1624
|
+
for k in range(n_con, rank):
|
|
1625
|
+
for i in manif.irange():
|
|
1626
|
+
indk = list(ind0)
|
|
1627
|
+
indk[k] = i
|
|
1628
|
+
rsum -= gam[[i, ind0[k], p]] * tc[[indk]]
|
|
1629
|
+
partial.append([ind,rsum])
|
|
1630
|
+
return partial
|
|
1631
|
+
|
|
1632
|
+
# Computation and Assignation of values
|
|
1633
|
+
for ii,val in make_CovDerivative(listParalInput):
|
|
1634
|
+
for jj in val:
|
|
1635
|
+
resc[[jj[0]]] = jj[1]
|
|
1636
|
+
|
|
1637
|
+
else:
|
|
1638
|
+
# sequential
|
|
1639
|
+
for ind in resc.non_redundant_index_generator():
|
|
1640
|
+
p = ind[-1] # derivation index
|
|
1641
|
+
ind0 = ind[:-1]
|
|
1642
|
+
rsum = frame[p](tc[[ind0]])
|
|
1643
|
+
# loop on contravariant indices:
|
|
1644
|
+
for k in range(n_con):
|
|
1645
|
+
for i in manif.irange():
|
|
1646
|
+
indk = list(ind0)
|
|
1647
|
+
indk[k] = i
|
|
1648
|
+
rsum += gam[[ind0[k], i, p]] * tc[[indk]]
|
|
1649
|
+
# loop on covariant indices:
|
|
1650
|
+
for k in range(n_con, tensor._tensor_rank):
|
|
1651
|
+
for i in manif.irange():
|
|
1652
|
+
indk = list(ind0)
|
|
1653
|
+
indk[k] = i
|
|
1654
|
+
rsum -= gam[[i, ind0[k], p]] * tc[[indk]]
|
|
1655
|
+
resc[[ind]] = rsum
|
|
1656
|
+
|
|
1657
|
+
# Resulting tensor field
|
|
1658
|
+
if tensor._name is None:
|
|
1659
|
+
name_resu = None
|
|
1660
|
+
else:
|
|
1661
|
+
name_resu = self._name + '(' + tensor._name + ')'
|
|
1662
|
+
if tensor._latex_name is None:
|
|
1663
|
+
latex_name_resu = None
|
|
1664
|
+
else:
|
|
1665
|
+
latex_name_resu = format_unop_latex(self._latex_name + ' ',
|
|
1666
|
+
tensor._latex_name)
|
|
1667
|
+
return tdom.vector_field_module().tensor_from_comp((n_con, n_cov+1),
|
|
1668
|
+
resc, name=name_resu, latex_name=latex_name_resu)
|
|
1669
|
+
|
|
1670
|
+
def torsion(self):
|
|
1671
|
+
r"""
|
|
1672
|
+
Return the connection's torsion tensor.
|
|
1673
|
+
|
|
1674
|
+
The torsion tensor is the tensor field `T` of type (1,2) defined by
|
|
1675
|
+
|
|
1676
|
+
.. MATH::
|
|
1677
|
+
|
|
1678
|
+
T(\omega, u, v) = \left\langle \omega, \nabla_u v - \nabla_v u
|
|
1679
|
+
- [u, v] \right\rangle
|
|
1680
|
+
|
|
1681
|
+
for any 1-form `\omega` and any vector fields `u` and `v`.
|
|
1682
|
+
|
|
1683
|
+
OUTPUT:
|
|
1684
|
+
|
|
1685
|
+
- the torsion tensor `T`, as an instance of
|
|
1686
|
+
:class:`~sage.manifolds.differentiable.tensorfield.TensorField`
|
|
1687
|
+
|
|
1688
|
+
EXAMPLES:
|
|
1689
|
+
|
|
1690
|
+
Torsion of an affine connection on a 3-dimensional manifold::
|
|
1691
|
+
|
|
1692
|
+
sage: M = Manifold(3, 'M', start_index=1)
|
|
1693
|
+
sage: c_xyz.<x,y,z> = M.chart()
|
|
1694
|
+
sage: nab = M.affine_connection('nabla', r'\nabla')
|
|
1695
|
+
sage: nab[1,1,2], nab[3,2,3] = x^2, y*z # Gamma^1_{12} = x^2, Gamma^3_{23} = yz
|
|
1696
|
+
sage: t = nab.torsion() ; t
|
|
1697
|
+
Tensor field of type (1,2) on the 3-dimensional differentiable
|
|
1698
|
+
manifold M
|
|
1699
|
+
sage: t.symmetries()
|
|
1700
|
+
no symmetry; antisymmetry: (1, 2)
|
|
1701
|
+
sage: t[:]
|
|
1702
|
+
[[[0, -x^2, 0], [x^2, 0, 0], [0, 0, 0]],
|
|
1703
|
+
[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
|
|
1704
|
+
[[0, 0, 0], [0, 0, -y*z], [0, y*z, 0]]]
|
|
1705
|
+
|
|
1706
|
+
The torsion expresses the lack of commutativity of two successive
|
|
1707
|
+
derivatives of a scalar field::
|
|
1708
|
+
|
|
1709
|
+
sage: f = M.scalar_field(x*z^2 + y^2 - z^2, name='f')
|
|
1710
|
+
sage: DDf = nab(nab(f)) ; DDf
|
|
1711
|
+
Tensor field nabla(df) of type (0,2) on the 3-dimensional
|
|
1712
|
+
differentiable manifold M
|
|
1713
|
+
sage: DDf.antisymmetrize()[:] # two successive derivatives do not commute:
|
|
1714
|
+
[ 0 -1/2*x^2*z^2 0]
|
|
1715
|
+
[ 1/2*x^2*z^2 0 -(x - 1)*y*z^2]
|
|
1716
|
+
[ 0 (x - 1)*y*z^2 0]
|
|
1717
|
+
sage: 2*DDf.antisymmetrize() == nab.torsion().contract(0,nab(f))
|
|
1718
|
+
True
|
|
1719
|
+
|
|
1720
|
+
The above identity is the standard formula
|
|
1721
|
+
|
|
1722
|
+
.. MATH::
|
|
1723
|
+
|
|
1724
|
+
\nabla_j \nabla_i \, f - \nabla_i \nabla_j \, f = T^k_{\ \, ij} \nabla_k \, f ,
|
|
1725
|
+
|
|
1726
|
+
where the `T^k_{\ \, ij}`'s are the components of the torsion tensor.
|
|
1727
|
+
|
|
1728
|
+
The result is cached::
|
|
1729
|
+
|
|
1730
|
+
sage: nab.torsion() is t
|
|
1731
|
+
True
|
|
1732
|
+
|
|
1733
|
+
as long as the connection remains unchanged::
|
|
1734
|
+
|
|
1735
|
+
sage: nab[2,1,3] = 1+x # changing the connection
|
|
1736
|
+
sage: nab.torsion() is t # a new computation of the torsion has been made
|
|
1737
|
+
False
|
|
1738
|
+
sage: (nab.torsion() - t).display()
|
|
1739
|
+
(-x - 1) ∂/∂y⊗dx⊗dz + (x + 1) ∂/∂y⊗dz⊗dx
|
|
1740
|
+
|
|
1741
|
+
Another example: torsion of some connection on a non-parallelizable
|
|
1742
|
+
2-dimensional manifold::
|
|
1743
|
+
|
|
1744
|
+
sage: M = Manifold(2, 'M')
|
|
1745
|
+
sage: U = M.open_subset('U') ; V = M.open_subset('V')
|
|
1746
|
+
sage: M.declare_union(U,V) # M is the union of U and V
|
|
1747
|
+
sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
|
|
1748
|
+
sage: transf = c_xy.transition_map(c_uv, (x+y, x-y), intersection_name='W',
|
|
1749
|
+
....: restrictions1= x>0, restrictions2= u+v>0)
|
|
1750
|
+
sage: inv = transf.inverse()
|
|
1751
|
+
sage: W = U.intersection(V)
|
|
1752
|
+
sage: eU = c_xy.frame() ; eV = c_uv.frame()
|
|
1753
|
+
sage: c_xyW = c_xy.restrict(W) ; c_uvW = c_uv.restrict(W)
|
|
1754
|
+
sage: eUW = c_xyW.frame() ; eVW = c_uvW.frame()
|
|
1755
|
+
sage: nab = M.affine_connection('nabla', r'\nabla')
|
|
1756
|
+
sage: nab[0,0,0], nab[0,1,0], nab[1,0,1] = x, x-y, x*y
|
|
1757
|
+
sage: for i in M.irange():
|
|
1758
|
+
....: for j in M.irange():
|
|
1759
|
+
....: for k in M.irange():
|
|
1760
|
+
....: nab.add_coef(eV)[i,j,k] = nab.coef(eVW)[i,j,k,c_uvW].expr()
|
|
1761
|
+
sage: t = nab.torsion() ; t
|
|
1762
|
+
Tensor field of type (1,2) on the 2-dimensional differentiable
|
|
1763
|
+
manifold M
|
|
1764
|
+
sage: t.parent()
|
|
1765
|
+
Module T^(1,2)(M) of type-(1,2) tensors fields on the 2-dimensional
|
|
1766
|
+
differentiable manifold M
|
|
1767
|
+
sage: t[eU,:]
|
|
1768
|
+
[[[0, x - y], [-x + y, 0]], [[0, -x*y], [x*y, 0]]]
|
|
1769
|
+
sage: t[eV,:]
|
|
1770
|
+
[[[0, 1/8*u^2 - 1/8*v^2 - 1/2*v], [-1/8*u^2 + 1/8*v^2 + 1/2*v, 0]],
|
|
1771
|
+
[[0, -1/8*u^2 + 1/8*v^2 - 1/2*v], [1/8*u^2 - 1/8*v^2 + 1/2*v, 0]]]
|
|
1772
|
+
|
|
1773
|
+
Check of the torsion formula::
|
|
1774
|
+
|
|
1775
|
+
sage: f = M.scalar_field({c_xy: (x+y)^2, c_uv: u^2}, name='f')
|
|
1776
|
+
sage: DDf = nab(nab(f)) ; DDf
|
|
1777
|
+
Tensor field nabla(df) of type (0,2) on the 2-dimensional
|
|
1778
|
+
differentiable manifold M
|
|
1779
|
+
sage: DDf.antisymmetrize().display(eU)
|
|
1780
|
+
(-x^2*y - (x + 1)*y^2 + x^2) dx∧dy
|
|
1781
|
+
sage: DDf.antisymmetrize().display(eV)
|
|
1782
|
+
(1/8*u^3 - 1/8*u*v^2 - 1/2*u*v) du∧dv
|
|
1783
|
+
sage: 2*DDf.antisymmetrize() == nab(f).contract(nab.torsion())
|
|
1784
|
+
True
|
|
1785
|
+
"""
|
|
1786
|
+
if self._torsion is None:
|
|
1787
|
+
manif = self._domain
|
|
1788
|
+
resu = self._domain.tensor_field(1, 2, antisym=(1, 2))
|
|
1789
|
+
for frame, gam in self._coefficients.items():
|
|
1790
|
+
sc = frame.structure_coeff()
|
|
1791
|
+
res = resu.add_comp(frame)
|
|
1792
|
+
for k in manif.irange():
|
|
1793
|
+
for i in manif.irange():
|
|
1794
|
+
for j in manif.irange(start=i + 1):
|
|
1795
|
+
res[[k,i,j]] = gam[[k,j,i]] - gam[[k,i,j]] - \
|
|
1796
|
+
sc[[k,i,j]]
|
|
1797
|
+
self._torsion = resu
|
|
1798
|
+
return self._torsion
|
|
1799
|
+
|
|
1800
|
+
def riemann(self):
|
|
1801
|
+
r"""
|
|
1802
|
+
Return the connection's Riemann curvature tensor.
|
|
1803
|
+
|
|
1804
|
+
The *Riemann curvature tensor* is the tensor field `R` of type (1,3)
|
|
1805
|
+
defined by
|
|
1806
|
+
|
|
1807
|
+
.. MATH::
|
|
1808
|
+
|
|
1809
|
+
R(\omega, w, u, v) = \left\langle \omega, \nabla_u \nabla_v w
|
|
1810
|
+
- \nabla_v \nabla_u w - \nabla_{[u, v]} w \right\rangle
|
|
1811
|
+
|
|
1812
|
+
for any 1-form `\omega` and any vector fields `u`, `v` and `w`.
|
|
1813
|
+
|
|
1814
|
+
OUTPUT:
|
|
1815
|
+
|
|
1816
|
+
- the Riemann curvature tensor `R`, as an instance of
|
|
1817
|
+
:class:`~sage.manifolds.differentiable.tensorfield.TensorField`
|
|
1818
|
+
|
|
1819
|
+
EXAMPLES:
|
|
1820
|
+
|
|
1821
|
+
Curvature of an affine connection on a 3-dimensional manifold::
|
|
1822
|
+
|
|
1823
|
+
sage: M = Manifold(3, 'M', start_index=1)
|
|
1824
|
+
sage: c_xyz.<x,y,z> = M.chart()
|
|
1825
|
+
sage: nab = M.affine_connection('nabla', r'\nabla') ; nab
|
|
1826
|
+
Affine connection nabla on the 3-dimensional differentiable
|
|
1827
|
+
manifold M
|
|
1828
|
+
sage: nab[1,1,2], nab[3,2,3] = x^2, y*z # Gamma^1_{12} = x^2, Gamma^3_{23} = yz
|
|
1829
|
+
sage: r = nab.riemann() ; r
|
|
1830
|
+
Tensor field of type (1,3) on the 3-dimensional differentiable
|
|
1831
|
+
manifold M
|
|
1832
|
+
sage: r.parent()
|
|
1833
|
+
Free module T^(1,3)(M) of type-(1,3) tensors fields on the
|
|
1834
|
+
3-dimensional differentiable manifold M
|
|
1835
|
+
|
|
1836
|
+
By construction, the Riemann tensor is antisymmetric with respect to
|
|
1837
|
+
its last two arguments (denoted `u` and `v` in the definition above),
|
|
1838
|
+
which are at positions 2 and 3 (the first argument being at position
|
|
1839
|
+
0)::
|
|
1840
|
+
|
|
1841
|
+
sage: r.symmetries()
|
|
1842
|
+
no symmetry; antisymmetry: (2, 3)
|
|
1843
|
+
|
|
1844
|
+
The components::
|
|
1845
|
+
|
|
1846
|
+
sage: r[:]
|
|
1847
|
+
[[[[0, 2*x, 0], [-2*x, 0, 0], [0, 0, 0]],
|
|
1848
|
+
[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
|
|
1849
|
+
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]],
|
|
1850
|
+
[[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
|
|
1851
|
+
[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
|
|
1852
|
+
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]],
|
|
1853
|
+
[[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
|
|
1854
|
+
[[0, 0, 0], [0, 0, z], [0, -z, 0]],
|
|
1855
|
+
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]]]
|
|
1856
|
+
|
|
1857
|
+
The result is cached (until the connection is modified via
|
|
1858
|
+
:meth:`set_coef` or :meth:`add_coef`)::
|
|
1859
|
+
|
|
1860
|
+
sage: nab.riemann() is r
|
|
1861
|
+
True
|
|
1862
|
+
|
|
1863
|
+
Another example: Riemann curvature tensor of some connection on a
|
|
1864
|
+
non-parallelizable 2-dimensional manifold::
|
|
1865
|
+
|
|
1866
|
+
sage: M = Manifold(2, 'M')
|
|
1867
|
+
sage: U = M.open_subset('U') ; V = M.open_subset('V')
|
|
1868
|
+
sage: M.declare_union(U,V) # M is the union of U and V
|
|
1869
|
+
sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
|
|
1870
|
+
sage: transf = c_xy.transition_map(c_uv, (x+y, x-y), intersection_name='W',
|
|
1871
|
+
....: restrictions1= x>0, restrictions2= u+v>0)
|
|
1872
|
+
sage: inv = transf.inverse()
|
|
1873
|
+
sage: W = U.intersection(V)
|
|
1874
|
+
sage: eU = c_xy.frame() ; eV = c_uv.frame()
|
|
1875
|
+
sage: c_xyW = c_xy.restrict(W) ; c_uvW = c_uv.restrict(W)
|
|
1876
|
+
sage: eUW = c_xyW.frame() ; eVW = c_uvW.frame()
|
|
1877
|
+
sage: nab = M.affine_connection('nabla', r'\nabla')
|
|
1878
|
+
sage: nab[0,0,0], nab[0,1,0], nab[1,0,1] = x, x-y, x*y
|
|
1879
|
+
sage: for i in M.irange():
|
|
1880
|
+
....: for j in M.irange():
|
|
1881
|
+
....: for k in M.irange():
|
|
1882
|
+
....: nab.add_coef(eV)[i,j,k] = nab.coef(eVW)[i,j,k,c_uvW].expr()
|
|
1883
|
+
sage: r = nab.riemann() ; r # long time
|
|
1884
|
+
Tensor field of type (1,3) on the 2-dimensional differentiable
|
|
1885
|
+
manifold M
|
|
1886
|
+
sage: r.parent() # long time
|
|
1887
|
+
Module T^(1,3)(M) of type-(1,3) tensors fields on the 2-dimensional
|
|
1888
|
+
differentiable manifold M
|
|
1889
|
+
sage: r.display(eU) # long time
|
|
1890
|
+
(x^2*y - x*y^2) ∂/∂x⊗dx⊗dx⊗dy + (-x^2*y + x*y^2) ∂/∂x⊗dx⊗dy⊗dx + ∂/∂x⊗dy⊗dx⊗dy
|
|
1891
|
+
- ∂/∂x⊗dy⊗dy⊗dx - (x^2 - 1)*y ∂/∂y⊗dx⊗dx⊗dy + (x^2 - 1)*y ∂/∂y⊗dx⊗dy⊗dx
|
|
1892
|
+
+ (-x^2*y + x*y^2) ∂/∂y⊗dy⊗dx⊗dy + (x^2*y - x*y^2) ∂/∂y⊗dy⊗dy⊗dx
|
|
1893
|
+
sage: r.display(eV) # long time
|
|
1894
|
+
(1/32*u^3 - 1/32*u*v^2 - 1/32*v^3 + 1/32*(u^2 + 4)*v - 1/8*u - 1/4) ∂/∂u⊗du⊗du⊗dv
|
|
1895
|
+
+ (-1/32*u^3 + 1/32*u*v^2 + 1/32*v^3 - 1/32*(u^2 + 4)*v + 1/8*u + 1/4) ∂/∂u⊗du⊗dv⊗du
|
|
1896
|
+
+ (1/32*u^3 - 1/32*u*v^2 + 3/32*v^3 - 1/32*(3*u^2 - 4)*v - 1/8*u + 1/4) ∂/∂u⊗dv⊗du⊗dv
|
|
1897
|
+
+ (-1/32*u^3 + 1/32*u*v^2 - 3/32*v^3 + 1/32*(3*u^2 - 4)*v + 1/8*u - 1/4) ∂/∂u⊗dv⊗dv⊗du
|
|
1898
|
+
+ (-1/32*u^3 + 1/32*u*v^2 + 5/32*v^3 - 1/32*(5*u^2 + 4)*v + 1/8*u - 1/4) ∂/∂v⊗du⊗du⊗dv
|
|
1899
|
+
+ (1/32*u^3 - 1/32*u*v^2 - 5/32*v^3 + 1/32*(5*u^2 + 4)*v - 1/8*u + 1/4) ∂/∂v⊗du⊗dv⊗du
|
|
1900
|
+
+ (-1/32*u^3 + 1/32*u*v^2 + 1/32*v^3 - 1/32*(u^2 + 4)*v + 1/8*u + 1/4) ∂/∂v⊗dv⊗du⊗dv
|
|
1901
|
+
+ (1/32*u^3 - 1/32*u*v^2 - 1/32*v^3 + 1/32*(u^2 + 4)*v - 1/8*u - 1/4) ∂/∂v⊗dv⊗dv⊗du
|
|
1902
|
+
|
|
1903
|
+
The same computation parallelized on 2 cores::
|
|
1904
|
+
|
|
1905
|
+
sage: Parallelism().set(nproc=2)
|
|
1906
|
+
sage: r_backup = r # long time
|
|
1907
|
+
sage: nab = M.affine_connection('nabla', r'\nabla')
|
|
1908
|
+
sage: nab[0,0,0], nab[0,1,0], nab[1,0,1] = x, x-y, x*y
|
|
1909
|
+
sage: for i in M.irange():
|
|
1910
|
+
....: for j in M.irange():
|
|
1911
|
+
....: for k in M.irange():
|
|
1912
|
+
....: nab.add_coef(eV)[i,j,k] = nab.coef(eVW)[i,j,k,c_uvW].expr()
|
|
1913
|
+
sage: r = nab.riemann() ; r # long time
|
|
1914
|
+
Tensor field of type (1,3) on the 2-dimensional differentiable
|
|
1915
|
+
manifold M
|
|
1916
|
+
sage: r.parent() # long time
|
|
1917
|
+
Module T^(1,3)(M) of type-(1,3) tensors fields on the 2-dimensional
|
|
1918
|
+
differentiable manifold M
|
|
1919
|
+
sage: r == r_backup # long time
|
|
1920
|
+
True
|
|
1921
|
+
sage: Parallelism().set(nproc=1) # switch off parallelization
|
|
1922
|
+
"""
|
|
1923
|
+
if self._riemann is None:
|
|
1924
|
+
manif = self._domain
|
|
1925
|
+
resu = manif.tensor_field(1, 3, antisym=(2,3))
|
|
1926
|
+
for frame, gam in self._coefficients.items():
|
|
1927
|
+
# The computation is performed only on the top frames:
|
|
1928
|
+
for oframe in self._coefficients:
|
|
1929
|
+
if frame in oframe._subframes and frame is not oframe:
|
|
1930
|
+
break
|
|
1931
|
+
else:
|
|
1932
|
+
# frame in not a subframe and the computation is performed:
|
|
1933
|
+
sc = frame.structure_coeff()
|
|
1934
|
+
gam_gam = gam.contract(1, gam, 0)
|
|
1935
|
+
gam_sc = gam.contract(2, sc, 0)
|
|
1936
|
+
res = resu.add_comp(frame)
|
|
1937
|
+
if Parallelism().get('tensor') != 1:
|
|
1938
|
+
# parallel computation
|
|
1939
|
+
nproc = Parallelism().get('tensor')
|
|
1940
|
+
lol = lambda lst, sz: [lst[i:i+sz] for i in range(0,
|
|
1941
|
+
len(lst), sz)]
|
|
1942
|
+
ind_list = []
|
|
1943
|
+
for i in manif.irange():
|
|
1944
|
+
for j in manif.irange():
|
|
1945
|
+
for k in manif.irange():
|
|
1946
|
+
for l in manif.irange(start=k+1):
|
|
1947
|
+
ind_list.append((i,j,k,l))
|
|
1948
|
+
ind_step = max(1, int(len(ind_list)/nproc/2))
|
|
1949
|
+
local_list = lol(ind_list, ind_step)
|
|
1950
|
+
# definition of the list of input parameters
|
|
1951
|
+
listParalInput = []
|
|
1952
|
+
for ind_part in local_list:
|
|
1953
|
+
listParalInput.append((frame, gam, gam_gam, gam_sc,
|
|
1954
|
+
ind_part))
|
|
1955
|
+
|
|
1956
|
+
# definition of the parallel function
|
|
1957
|
+
@parallel(p_iter='multiprocessing', ncpus=nproc)
|
|
1958
|
+
def make_Riem(frame, gam, gam_gam, gam_sc, local_list_ijkl):
|
|
1959
|
+
partial = []
|
|
1960
|
+
for i, j, k, l in local_list_ijkl:
|
|
1961
|
+
partial.append([i, j, k, l,
|
|
1962
|
+
frame[k](gam[[i, j, l]]) -
|
|
1963
|
+
frame[l](gam[[i, j, k]]) +
|
|
1964
|
+
gam_gam[[i, k, j, l]] -
|
|
1965
|
+
gam_gam[[i, l, j, k]] -
|
|
1966
|
+
gam_sc[[i, j, k, l]]])
|
|
1967
|
+
return partial
|
|
1968
|
+
# Computation and assignation of values
|
|
1969
|
+
for ii, val in make_Riem(listParalInput):
|
|
1970
|
+
for jj in val:
|
|
1971
|
+
res[jj[0], jj[1], jj[2], jj[3]] = jj[4]
|
|
1972
|
+
|
|
1973
|
+
else:
|
|
1974
|
+
# sequential
|
|
1975
|
+
for i in manif.irange():
|
|
1976
|
+
for j in manif.irange():
|
|
1977
|
+
for k in manif.irange():
|
|
1978
|
+
# antisymmetry of the Riemann tensor taken
|
|
1979
|
+
# into account by l>k:
|
|
1980
|
+
for l in manif.irange(start=k+1):
|
|
1981
|
+
res[i,j,k,l] = frame[k](gam[[i,j,l]]) - \
|
|
1982
|
+
frame[l](gam[[i,j,k]]) + \
|
|
1983
|
+
gam_gam[[i,k,j,l]] - \
|
|
1984
|
+
gam_gam[[i,l,j,k]] - \
|
|
1985
|
+
gam_sc[[i,j,k,l]]
|
|
1986
|
+
self._riemann = resu
|
|
1987
|
+
return self._riemann
|
|
1988
|
+
|
|
1989
|
+
def ricci(self):
|
|
1990
|
+
r"""
|
|
1991
|
+
Return the connection's Ricci tensor.
|
|
1992
|
+
|
|
1993
|
+
The *Ricci tensor* is the tensor field `Ric` of type (0,2)
|
|
1994
|
+
defined from the Riemann curvature tensor `R` by
|
|
1995
|
+
|
|
1996
|
+
.. MATH::
|
|
1997
|
+
|
|
1998
|
+
Ric(u, v) = R(e^i, u, e_i, v)
|
|
1999
|
+
|
|
2000
|
+
for any vector fields `u` and `v`, `(e_i)` being any vector frame and
|
|
2001
|
+
`(e^i)` the dual coframe.
|
|
2002
|
+
|
|
2003
|
+
OUTPUT:
|
|
2004
|
+
|
|
2005
|
+
- the Ricci tensor `Ric`, as an instance of
|
|
2006
|
+
:class:`~sage.manifolds.differentiable.tensorfield.TensorField`
|
|
2007
|
+
|
|
2008
|
+
EXAMPLES:
|
|
2009
|
+
|
|
2010
|
+
Ricci tensor of an affine connection on a 3-dimensional manifold::
|
|
2011
|
+
|
|
2012
|
+
sage: M = Manifold(3, 'M', start_index=1)
|
|
2013
|
+
sage: c_xyz.<x,y,z> = M.chart()
|
|
2014
|
+
sage: nab = M.affine_connection('nabla', r'\nabla') ; nab
|
|
2015
|
+
Affine connection nabla on the 3-dimensional differentiable
|
|
2016
|
+
manifold M
|
|
2017
|
+
sage: nab[1,1,2], nab[3,2,3] = x^2, y*z # Gamma^1_{12} = x^2, Gamma^3_{23} = yz
|
|
2018
|
+
sage: r = nab.ricci() ; r
|
|
2019
|
+
Tensor field of type (0,2) on the 3-dimensional differentiable
|
|
2020
|
+
manifold M
|
|
2021
|
+
sage: r[:]
|
|
2022
|
+
[ 0 2*x 0]
|
|
2023
|
+
[ 0 -z 0]
|
|
2024
|
+
[ 0 0 0]
|
|
2025
|
+
|
|
2026
|
+
The result is cached (until the connection is modified via
|
|
2027
|
+
:meth:`set_coef` or :meth:`add_coef`)::
|
|
2028
|
+
|
|
2029
|
+
sage: nab.ricci() is r
|
|
2030
|
+
True
|
|
2031
|
+
"""
|
|
2032
|
+
if self._ricci is None:
|
|
2033
|
+
self._ricci = self.riemann().trace(0,2)
|
|
2034
|
+
return self._ricci
|
|
2035
|
+
|
|
2036
|
+
def connection_form(self, i, j, frame=None):
|
|
2037
|
+
r"""
|
|
2038
|
+
Return the connection 1-form corresponding to the given index and
|
|
2039
|
+
vector frame.
|
|
2040
|
+
|
|
2041
|
+
The *connection 1-forms* with respect to the frame `(e_i)` are the
|
|
2042
|
+
`n^2` 1-forms `\omega^i_{\ \, j}` defined by
|
|
2043
|
+
|
|
2044
|
+
.. MATH::
|
|
2045
|
+
|
|
2046
|
+
\nabla_v e_j = \langle \omega^i_{\ \, j}, v \rangle
|
|
2047
|
+
\, e_i
|
|
2048
|
+
|
|
2049
|
+
for any vector `v`.
|
|
2050
|
+
|
|
2051
|
+
The components of `\omega^i_{\ \, j}` in the coframe `(e^i)` dual to
|
|
2052
|
+
`(e_i)` are nothing but the connection coefficients `\Gamma^i_{\ \, jk}`
|
|
2053
|
+
relative to the frame `(e_i)`:
|
|
2054
|
+
|
|
2055
|
+
.. MATH::
|
|
2056
|
+
|
|
2057
|
+
\omega^i_{\ \, j} = \Gamma^i_{\ \, jk} e^k
|
|
2058
|
+
|
|
2059
|
+
|
|
2060
|
+
INPUT:
|
|
2061
|
+
|
|
2062
|
+
- ``i``, ``j`` -- indices identifying the 1-form `\omega^i_{\ \, j}`
|
|
2063
|
+
- ``frame`` -- (default: ``None``) vector frame relative to which the
|
|
2064
|
+
connection 1-forms are defined; if ``None``, the default frame of the
|
|
2065
|
+
connection's domain is assumed.
|
|
2066
|
+
|
|
2067
|
+
OUTPUT:
|
|
2068
|
+
|
|
2069
|
+
- the 1-form `\omega^i_{\ \, j}`, as an instance of
|
|
2070
|
+
:class:`~sage.manifolds.differentiable.diff_form.DiffForm`
|
|
2071
|
+
|
|
2072
|
+
EXAMPLES:
|
|
2073
|
+
|
|
2074
|
+
Connection 1-forms on a 3-dimensional manifold::
|
|
2075
|
+
|
|
2076
|
+
sage: M = Manifold(3, 'M', start_index=1)
|
|
2077
|
+
sage: c_xyz.<x,y,z> = M.chart()
|
|
2078
|
+
sage: nab = M.affine_connection('nabla', r'\nabla')
|
|
2079
|
+
sage: nab[1,1,1], nab[1,1,2], nab[1,1,3] = x*y*z, x^2, -y*z
|
|
2080
|
+
sage: nab[1,2,3], nab[1,3,1], nab[1,3,2] = -x^3, y^2*z, y^2-x^2
|
|
2081
|
+
sage: nab[2,1,1], nab[2,1,2], nab[2,2,1] = z^2, x*y*z^2, -x^2
|
|
2082
|
+
sage: nab[2,3,1], nab[2,3,3], nab[3,1,2] = x^2+y^2+z^2, y^2-z^2, x*y+z^2
|
|
2083
|
+
sage: nab[3,2,1], nab[3,2,2], nab[3,3,3] = x*y+z, z^3 -y^2, x*z^2 - z*y^2
|
|
2084
|
+
sage: nab.connection_form(1,1) # connection 1-form (i,j)=(1,1) w.r.t. M's default frame
|
|
2085
|
+
1-form nabla connection 1-form (1,1) on the 3-dimensional
|
|
2086
|
+
differentiable manifold M
|
|
2087
|
+
sage: nab.connection_form(1,1)[:]
|
|
2088
|
+
[x*y*z, x^2, -y*z]
|
|
2089
|
+
|
|
2090
|
+
The result is cached (until the connection is modified via
|
|
2091
|
+
:meth:`set_coef` or :meth:`add_coef`)::
|
|
2092
|
+
|
|
2093
|
+
sage: nab.connection_form(1,1) is nab.connection_form(1,1)
|
|
2094
|
+
True
|
|
2095
|
+
|
|
2096
|
+
Connection 1-forms w.r.t. a non-holonomic frame::
|
|
2097
|
+
|
|
2098
|
+
sage: ch_basis = M.automorphism_field()
|
|
2099
|
+
sage: ch_basis[1,1], ch_basis[2,2], ch_basis[3,3] = y, z, x
|
|
2100
|
+
sage: e = M.default_frame().new_frame(ch_basis, 'e')
|
|
2101
|
+
sage: e[1][:], e[2][:], e[3][:]
|
|
2102
|
+
([y, 0, 0], [0, z, 0], [0, 0, x])
|
|
2103
|
+
sage: nab.connection_form(1,1,e)
|
|
2104
|
+
1-form nabla connection 1-form (1,1) on the 3-dimensional
|
|
2105
|
+
differentiable manifold M
|
|
2106
|
+
sage: nab.connection_form(1,1,e).comp(e)[:]
|
|
2107
|
+
[x*y^2*z, (x^2*y + 1)*z/y, -x*y*z]
|
|
2108
|
+
|
|
2109
|
+
Check of the formula `\omega^i_{\ \, j} = \Gamma^i_{\ \, jk} e^k`:
|
|
2110
|
+
|
|
2111
|
+
First on the manifold's default frame (∂/∂x, ∂/∂y, d:dz)::
|
|
2112
|
+
|
|
2113
|
+
sage: dx = M.default_frame().coframe() ; dx
|
|
2114
|
+
Coordinate coframe (M, (dx,dy,dz))
|
|
2115
|
+
sage: check = []
|
|
2116
|
+
sage: for i in M.irange():
|
|
2117
|
+
....: for j in M.irange():
|
|
2118
|
+
....: check.append( nab.connection_form(i,j) == \
|
|
2119
|
+
....: sum( nab[[i,j,k]]*dx[k] for k in M.irange() ) )
|
|
2120
|
+
sage: check
|
|
2121
|
+
[True, True, True, True, True, True, True, True, True]
|
|
2122
|
+
|
|
2123
|
+
Then on the frame e::
|
|
2124
|
+
|
|
2125
|
+
sage: ef = e.coframe() ; ef
|
|
2126
|
+
Coframe (M, (e^1,e^2,e^3))
|
|
2127
|
+
sage: check = []
|
|
2128
|
+
sage: for i in M.irange():
|
|
2129
|
+
....: for j in M.irange():
|
|
2130
|
+
....: s = nab.connection_form(i,j,e).comp(c_xyz.frame(), from_basis=e)
|
|
2131
|
+
....: check.append( nab.connection_form(i,j,e) == sum( nab.coef(e)[[i,j,k]]*ef[k] for k in M.irange() ) )
|
|
2132
|
+
sage: check
|
|
2133
|
+
[True, True, True, True, True, True, True, True, True]
|
|
2134
|
+
|
|
2135
|
+
Check of the formula
|
|
2136
|
+
`\nabla_v e_j = \langle \omega^i_{\ \, j}, v \rangle e_i`::
|
|
2137
|
+
|
|
2138
|
+
sage: v = M.vector_field()
|
|
2139
|
+
sage: v[:] = (x*y, z^2-3*x, z+2*y)
|
|
2140
|
+
sage: b = M.default_frame()
|
|
2141
|
+
sage: for j in M.irange(): # check on M's default frame # long time
|
|
2142
|
+
....: nab(b[j]).contract(v) == \
|
|
2143
|
+
....: sum( nab.connection_form(i,j)(v)*b[i] for i in M.irange())
|
|
2144
|
+
True
|
|
2145
|
+
True
|
|
2146
|
+
True
|
|
2147
|
+
sage: for j in M.irange(): # check on frame e # long time
|
|
2148
|
+
....: nab(e[j]).contract(v) == \
|
|
2149
|
+
....: sum( nab.connection_form(i,j,e)(v)*e[i] for i in M.irange())
|
|
2150
|
+
True
|
|
2151
|
+
True
|
|
2152
|
+
True
|
|
2153
|
+
"""
|
|
2154
|
+
if frame is None:
|
|
2155
|
+
frame = self._domain._def_frame
|
|
2156
|
+
if frame not in self._connection_forms:
|
|
2157
|
+
forms = {}
|
|
2158
|
+
frame_dom = frame.domain()
|
|
2159
|
+
coef_frame = self.coef(frame)
|
|
2160
|
+
for i1 in self._domain.irange():
|
|
2161
|
+
for j1 in self._domain.irange():
|
|
2162
|
+
name = self._name + " connection 1-form (" + str(i1) + \
|
|
2163
|
+
"," + str(j1) + ")"
|
|
2164
|
+
latex_name = r"\omega^" + str(i1) + r"_{\ \, " + \
|
|
2165
|
+
str(j1) + "}"
|
|
2166
|
+
omega = frame_dom.one_form(name=name,
|
|
2167
|
+
latex_name=latex_name)
|
|
2168
|
+
comega = omega.set_comp(frame)
|
|
2169
|
+
for k in self._domain.irange():
|
|
2170
|
+
comega[k] = coef_frame[[i1,j1,k]]
|
|
2171
|
+
forms[(i1,j1)] = omega
|
|
2172
|
+
self._connection_forms[frame] = forms
|
|
2173
|
+
return self._connection_forms[frame][(i,j)]
|
|
2174
|
+
|
|
2175
|
+
def torsion_form(self, i, frame=None):
|
|
2176
|
+
r"""
|
|
2177
|
+
Return the torsion 2-form corresponding to the given index and
|
|
2178
|
+
vector frame.
|
|
2179
|
+
|
|
2180
|
+
The *torsion 2-forms* with respect to the frame `(e_i)` are the
|
|
2181
|
+
`n` 2-forms `\theta^i` defined by
|
|
2182
|
+
|
|
2183
|
+
.. MATH::
|
|
2184
|
+
|
|
2185
|
+
\theta^i(u,v) = T(e^i, u, v)
|
|
2186
|
+
|
|
2187
|
+
where `T` is the connection's torsion tensor (cf. :meth:`torsion`),
|
|
2188
|
+
`(e^i)` is the coframe dual to `(e_i)` and `(u,v)` is a generic pair of
|
|
2189
|
+
vectors.
|
|
2190
|
+
|
|
2191
|
+
INPUT:
|
|
2192
|
+
|
|
2193
|
+
- ``i`` -- index identifying the 2-form `\theta^i`
|
|
2194
|
+
- ``frame`` -- (default: ``None``) vector frame relative to which the
|
|
2195
|
+
torsion 2-forms are defined; if ``None``, the default frame of the
|
|
2196
|
+
connection's domain is assumed.
|
|
2197
|
+
|
|
2198
|
+
OUTPUT:
|
|
2199
|
+
|
|
2200
|
+
- the 2-form `\theta^i`, as an instance of
|
|
2201
|
+
:class:`~sage.manifolds.differentiable.diff_form.DiffForm`
|
|
2202
|
+
|
|
2203
|
+
EXAMPLES:
|
|
2204
|
+
|
|
2205
|
+
Torsion 2-forms on a 3-dimensional manifold::
|
|
2206
|
+
|
|
2207
|
+
sage: M = Manifold(3, 'M', start_index=1)
|
|
2208
|
+
sage: c_xyz.<x,y,z> = M.chart()
|
|
2209
|
+
sage: nab = M.affine_connection('nabla', r'\nabla')
|
|
2210
|
+
sage: nab[1,1,1], nab[1,1,2], nab[1,1,3] = x*y*z, x^2, -y*z
|
|
2211
|
+
sage: nab[1,2,3], nab[1,3,1], nab[1,3,2] = -x^3, y^2*z, y^2-x^2
|
|
2212
|
+
sage: nab[2,1,1], nab[2,1,2], nab[2,2,1] = z^2, x*y*z^2, -x^2
|
|
2213
|
+
sage: nab[2,3,1], nab[2,3,3], nab[3,1,2] = x^2+y^2+z^2, y^2-z^2, x*y+z^2
|
|
2214
|
+
sage: nab[3,2,1], nab[3,2,2], nab[3,3,3] = x*y+z, z^3 -y^2, x*z^2 - z*y^2
|
|
2215
|
+
sage: nab.torsion_form(1)
|
|
2216
|
+
2-form torsion (1) of connection nabla w.r.t. Coordinate frame
|
|
2217
|
+
(M, (∂/∂x,∂/∂y,∂/∂z)) on the 3-dimensional differentiable manifold M
|
|
2218
|
+
sage: nab.torsion_form(1)[:]
|
|
2219
|
+
[ 0 -x^2 (y^2 + y)*z]
|
|
2220
|
+
[ x^2 0 x^3 - x^2 + y^2]
|
|
2221
|
+
[ -(y^2 + y)*z -x^3 + x^2 - y^2 0]
|
|
2222
|
+
|
|
2223
|
+
Torsion 2-forms w.r.t. a non-holonomic frame::
|
|
2224
|
+
|
|
2225
|
+
sage: ch_basis = M.automorphism_field()
|
|
2226
|
+
sage: ch_basis[1,1], ch_basis[2,2], ch_basis[3,3] = y, z, x
|
|
2227
|
+
sage: e = M.default_frame().new_frame(ch_basis, 'e')
|
|
2228
|
+
sage: e[1][:], e[2][:], e[3][:]
|
|
2229
|
+
([y, 0, 0], [0, z, 0], [0, 0, x])
|
|
2230
|
+
sage: ef = e.coframe()
|
|
2231
|
+
sage: ef[1][:], ef[2][:], ef[3][:]
|
|
2232
|
+
([1/y, 0, 0], [0, 1/z, 0], [0, 0, 1/x])
|
|
2233
|
+
sage: nab.torsion_form(1, e) # long time
|
|
2234
|
+
2-form torsion (1) of connection nabla w.r.t. Vector frame
|
|
2235
|
+
(M, (e_1,e_2,e_3)) on the 3-dimensional differentiable manifold M
|
|
2236
|
+
sage: nab.torsion_form(1, e).comp(e)[:] # long time
|
|
2237
|
+
[ 0 -x^2*z (x*y^2 + x*y)*z]
|
|
2238
|
+
[ x^2*z 0 (x^4 - x^3 + x*y^2)*z/y]
|
|
2239
|
+
[ -(x*y^2 + x*y)*z -(x^4 - x^3 + x*y^2)*z/y 0]
|
|
2240
|
+
|
|
2241
|
+
Cartan's first structure equation is
|
|
2242
|
+
|
|
2243
|
+
.. MATH::
|
|
2244
|
+
|
|
2245
|
+
\theta^i = \mathrm{d} e^i + \omega^i_{\ \, j} \wedge e^j
|
|
2246
|
+
|
|
2247
|
+
where the `\omega^i_{\ \, j}`'s are the connection 1-forms (cf.
|
|
2248
|
+
:meth:`connection_form`). Let us check it on the frame e::
|
|
2249
|
+
|
|
2250
|
+
sage: for i in M.irange(): # long time
|
|
2251
|
+
....: nab.torsion_form(i, e) == ef[i].exterior_derivative() + \
|
|
2252
|
+
....: sum(nab.connection_form(i,j,e).wedge(ef[j]) for j in M.irange())
|
|
2253
|
+
True
|
|
2254
|
+
True
|
|
2255
|
+
True
|
|
2256
|
+
"""
|
|
2257
|
+
if frame is None:
|
|
2258
|
+
frame = self._domain._def_frame
|
|
2259
|
+
if frame not in self._torsion_forms:
|
|
2260
|
+
forms = {}
|
|
2261
|
+
frame_dom = frame.domain()
|
|
2262
|
+
torsion_comp = self.torsion().comp(frame)
|
|
2263
|
+
for i1 in self._domain.irange():
|
|
2264
|
+
name = "torsion ({}) of connection ".format(i1) + \
|
|
2265
|
+
self._name + " w.r.t. {}".format(frame)
|
|
2266
|
+
latex_name = r"\theta^" + str(i1)
|
|
2267
|
+
theta = frame_dom.diff_form(2, name=name,
|
|
2268
|
+
latex_name=latex_name)
|
|
2269
|
+
ctheta = theta.set_comp(frame)
|
|
2270
|
+
for k in self._domain.irange():
|
|
2271
|
+
for l in self._domain.irange(start=k+1):
|
|
2272
|
+
ctheta[k,l] = torsion_comp[[i1,k,l]]
|
|
2273
|
+
forms[i1] = theta
|
|
2274
|
+
self._torsion_forms[frame] = forms
|
|
2275
|
+
return self._torsion_forms[frame][i]
|
|
2276
|
+
|
|
2277
|
+
def curvature_form(self, i, j, frame=None):
|
|
2278
|
+
r"""
|
|
2279
|
+
Return the curvature 2-form corresponding to the given index and
|
|
2280
|
+
vector frame.
|
|
2281
|
+
|
|
2282
|
+
The *curvature 2-forms* with respect to the frame `(e_i)` are the
|
|
2283
|
+
`n^2` 2-forms `\Omega^i_{\ \, j}` defined by
|
|
2284
|
+
|
|
2285
|
+
.. MATH::
|
|
2286
|
+
|
|
2287
|
+
\Omega^i_{\ \, j}(u,v) = R(e^i, e_j, u, v)
|
|
2288
|
+
|
|
2289
|
+
where `R` is the connection's Riemann curvature tensor (cf.
|
|
2290
|
+
:meth:`riemann`), `(e^i)` is the coframe dual to `(e_i)` and `(u,v)` is
|
|
2291
|
+
a generic pair of vectors.
|
|
2292
|
+
|
|
2293
|
+
INPUT:
|
|
2294
|
+
|
|
2295
|
+
- ``i``, ``j`` -- indices identifying the 2-form `\Omega^i_{\ \, j}`
|
|
2296
|
+
- ``frame`` -- (default: ``None``) vector frame relative to which the
|
|
2297
|
+
curvature 2-forms are defined; if ``None``, the default frame
|
|
2298
|
+
of the connection's domain is assumed.
|
|
2299
|
+
|
|
2300
|
+
OUTPUT:
|
|
2301
|
+
|
|
2302
|
+
- the 2-form `\Omega^i_{\ \, j}`, as an instance of
|
|
2303
|
+
:class:`~sage.manifolds.differentiable.diff_form.DiffForm`
|
|
2304
|
+
|
|
2305
|
+
EXAMPLES:
|
|
2306
|
+
|
|
2307
|
+
Curvature 2-forms on a 3-dimensional manifold::
|
|
2308
|
+
|
|
2309
|
+
sage: M = Manifold(3, 'M', start_index=1)
|
|
2310
|
+
sage: c_xyz.<x,y,z> = M.chart()
|
|
2311
|
+
sage: nab = M.affine_connection('nabla', r'\nabla')
|
|
2312
|
+
sage: nab[1,1,1], nab[1,1,2], nab[1,1,3] = x*y*z, x^2, -y*z
|
|
2313
|
+
sage: nab[1,2,3], nab[1,3,1], nab[1,3,2] = -x^3, y^2*z, y^2-x^2
|
|
2314
|
+
sage: nab[2,1,1], nab[2,1,2], nab[2,2,1] = z^2, x*y*z^2, -x^2
|
|
2315
|
+
sage: nab[2,3,1], nab[2,3,3], nab[3,1,2] = x^2+y^2+z^2, y^2-z^2, x*y+z^2
|
|
2316
|
+
sage: nab[3,2,1], nab[3,2,2], nab[3,3,3] = x*y+z, z^3 -y^2, x*z^2 - z*y^2
|
|
2317
|
+
sage: nab.curvature_form(1,1) # long time
|
|
2318
|
+
2-form curvature (1,1) of connection nabla w.r.t. Coordinate frame
|
|
2319
|
+
(M, (∂/∂x,∂/∂y,∂/∂z)) on the 3-dimensional differentiable manifold M
|
|
2320
|
+
sage: nab.curvature_form(1,1).display() # long time (if above is skipped)
|
|
2321
|
+
curvature (1,1) of connection nabla w.r.t. Coordinate frame
|
|
2322
|
+
(M, (∂/∂x,∂/∂y,∂/∂z)) = (y^2*z^3 + (x*y^3 - x)*z + 2*x) dx∧dy
|
|
2323
|
+
+ (x^3*z^2 - x*y) dx∧dz + (x^4*y*z^2 - z) dy∧dz
|
|
2324
|
+
|
|
2325
|
+
Curvature 2-forms w.r.t. a non-holonomic frame::
|
|
2326
|
+
|
|
2327
|
+
sage: ch_basis = M.automorphism_field()
|
|
2328
|
+
sage: ch_basis[1,1], ch_basis[2,2], ch_basis[3,3] = y, z, x
|
|
2329
|
+
sage: e = M.default_frame().new_frame(ch_basis, 'e')
|
|
2330
|
+
sage: e[1].display(), e[2].display(), e[3].display()
|
|
2331
|
+
(e_1 = y ∂/∂x, e_2 = z ∂/∂y, e_3 = x ∂/∂z)
|
|
2332
|
+
sage: ef = e.coframe()
|
|
2333
|
+
sage: ef[1].display(), ef[2].display(), ef[3].display()
|
|
2334
|
+
(e^1 = 1/y dx, e^2 = 1/z dy, e^3 = 1/x dz)
|
|
2335
|
+
sage: nab.curvature_form(1,1,e) # long time
|
|
2336
|
+
2-form curvature (1,1) of connection nabla w.r.t. Vector frame
|
|
2337
|
+
(M, (e_1,e_2,e_3)) on the 3-dimensional differentiable manifold M
|
|
2338
|
+
sage: nab.curvature_form(1,1,e).display(e) # long time (if above is skipped)
|
|
2339
|
+
curvature (1,1) of connection nabla w.r.t. Vector frame
|
|
2340
|
+
(M, (e_1,e_2,e_3)) =
|
|
2341
|
+
(y^3*z^4 + 2*x*y*z + (x*y^4 - x*y)*z^2) e^1∧e^2
|
|
2342
|
+
+ (x^4*y*z^2 - x^2*y^2) e^1∧e^3 + (x^5*y*z^3 - x*z^2) e^2∧e^3
|
|
2343
|
+
|
|
2344
|
+
Cartan's second structure equation is
|
|
2345
|
+
|
|
2346
|
+
.. MATH::
|
|
2347
|
+
|
|
2348
|
+
\Omega^i_{\ \, j} = \mathrm{d} \omega^i_{\ \, j}
|
|
2349
|
+
+ \omega^i_{\ \, k} \wedge \omega^k_{\ \, j}
|
|
2350
|
+
|
|
2351
|
+
where the `\omega^i_{\ \, j}`'s are the connection 1-forms (cf.
|
|
2352
|
+
:meth:`connection_form`). Let us check it on the frame e::
|
|
2353
|
+
|
|
2354
|
+
sage: omega = nab.connection_form
|
|
2355
|
+
sage: check = []
|
|
2356
|
+
sage: for i in M.irange(): # long time
|
|
2357
|
+
....: for j in M.irange():
|
|
2358
|
+
....: check.append( nab.curvature_form(i,j,e) == \
|
|
2359
|
+
....: omega(i,j,e).exterior_derivative() + \
|
|
2360
|
+
....: sum( omega(i,k,e).wedge(omega(k,j,e)) for k in M.irange()) )
|
|
2361
|
+
sage: check # long time
|
|
2362
|
+
[True, True, True, True, True, True, True, True, True]
|
|
2363
|
+
"""
|
|
2364
|
+
if frame is None:
|
|
2365
|
+
frame = self._domain._def_frame
|
|
2366
|
+
if frame not in self._curvature_forms:
|
|
2367
|
+
forms = {}
|
|
2368
|
+
frame_dom = frame.domain()
|
|
2369
|
+
riemann_comp = self.riemann().comp(frame)
|
|
2370
|
+
for i1 in self._domain.irange():
|
|
2371
|
+
for j1 in self._domain.irange():
|
|
2372
|
+
name = "curvature ({},{}) of connection ".format(i1,j1) + \
|
|
2373
|
+
self._name + " w.r.t. {}".format(frame)
|
|
2374
|
+
latex_name = r"\Omega^" + str(i1) + r"_{\ \, " + \
|
|
2375
|
+
str(j1) + "}"
|
|
2376
|
+
omega = frame_dom.diff_form(2, name=name,
|
|
2377
|
+
latex_name=latex_name)
|
|
2378
|
+
comega = omega.set_comp(frame)
|
|
2379
|
+
for k in self._domain.irange():
|
|
2380
|
+
for l in self._domain.irange(start=k+1):
|
|
2381
|
+
comega[k,l] = riemann_comp[[i1,j1,k,l]]
|
|
2382
|
+
forms[(i1,j1)] = omega
|
|
2383
|
+
self._curvature_forms[frame] = forms
|
|
2384
|
+
return self._curvature_forms[frame][(i, j)]
|
|
2385
|
+
|
|
2386
|
+
def set_calc_order(self, symbol, order, truncate=False):
|
|
2387
|
+
r"""
|
|
2388
|
+
Trigger a series expansion with respect to a small parameter in
|
|
2389
|
+
computations involving ``self``.
|
|
2390
|
+
|
|
2391
|
+
This property is propagated by usual operations. The internal
|
|
2392
|
+
representation must be ``SR`` for this to take effect.
|
|
2393
|
+
|
|
2394
|
+
INPUT:
|
|
2395
|
+
|
|
2396
|
+
- ``symbol`` -- symbolic variable (the "small parameter" `\epsilon`)
|
|
2397
|
+
with respect to which the connection coefficients are expanded in
|
|
2398
|
+
power series
|
|
2399
|
+
- ``order`` -- integer; the order `n` of the expansion, defined as the
|
|
2400
|
+
degree of the polynomial representing the truncated power series in
|
|
2401
|
+
``symbol``
|
|
2402
|
+
- ``truncate`` -- boolean (default: ``False``); determines whether the
|
|
2403
|
+
connection coefficients are replaced by their expansions to the
|
|
2404
|
+
given order
|
|
2405
|
+
|
|
2406
|
+
EXAMPLES::
|
|
2407
|
+
|
|
2408
|
+
sage: M = Manifold(4, 'M', structure='Lorentzian')
|
|
2409
|
+
sage: C.<t,x,y,z> = M.chart()
|
|
2410
|
+
sage: e = var('e')
|
|
2411
|
+
sage: g = M.metric()
|
|
2412
|
+
sage: h = M.tensor_field(0, 2, sym=(0,1))
|
|
2413
|
+
sage: g[0, 0], g[1, 1], g[2, 2], g[3, 3] = -1, 1, 1, 1
|
|
2414
|
+
sage: h[0, 1] = x
|
|
2415
|
+
sage: g.set(g + e*h)
|
|
2416
|
+
sage: g[:]
|
|
2417
|
+
[ -1 e*x 0 0]
|
|
2418
|
+
[e*x 1 0 0]
|
|
2419
|
+
[ 0 0 1 0]
|
|
2420
|
+
[ 0 0 0 1]
|
|
2421
|
+
sage: nab = g.connection()
|
|
2422
|
+
sage: nab[0, 1, 1]
|
|
2423
|
+
-e/(e^2*x^2 + 1)
|
|
2424
|
+
sage: nab.set_calc_order(e, 1, truncate=True)
|
|
2425
|
+
sage: nab[0, 1, 1]
|
|
2426
|
+
-e
|
|
2427
|
+
"""
|
|
2428
|
+
for coef in self._coefficients.values():
|
|
2429
|
+
for ind in coef.non_redundant_index_generator():
|
|
2430
|
+
coef[ind]._expansion_symbol = symbol
|
|
2431
|
+
coef[ind]._order = order
|
|
2432
|
+
if truncate:
|
|
2433
|
+
coef[ind].simplify()
|
|
2434
|
+
self._del_derived()
|
|
2435
|
+
|
|
2436
|
+
@cached_method
|
|
2437
|
+
def __hash__(self):
|
|
2438
|
+
r"""
|
|
2439
|
+
Hash function.
|
|
2440
|
+
|
|
2441
|
+
TESTS::
|
|
2442
|
+
|
|
2443
|
+
sage: M = Manifold(2, 'M', start_index=1)
|
|
2444
|
+
sage: X.<x,y> = M.chart()
|
|
2445
|
+
sage: eX = X.frame()
|
|
2446
|
+
sage: nab1 = M.affine_connection('nabla1', latex_name=r'\nabla_1')
|
|
2447
|
+
sage: nab1.set_coef(eX)[1,2,1] = x*y
|
|
2448
|
+
sage: nab2 = M.affine_connection('nabla2', latex_name=r'\nabla_2')
|
|
2449
|
+
sage: nab2.set_coef(eX)[1,2,1] = x*y
|
|
2450
|
+
sage: nab1.set_immutable(); nab2.set_immutable()
|
|
2451
|
+
sage: nab1 == nab2
|
|
2452
|
+
True
|
|
2453
|
+
sage: hash(nab1) == hash(nab2)
|
|
2454
|
+
True
|
|
2455
|
+
|
|
2456
|
+
Let us check that affine connections can be used as dictionary keys::
|
|
2457
|
+
|
|
2458
|
+
sage: M = Manifold(2, 'M', start_index=1)
|
|
2459
|
+
sage: X.<x,y> = M.chart()
|
|
2460
|
+
sage: eX = X.frame()
|
|
2461
|
+
sage: nab1 = M.affine_connection('nabla1', latex_name=r'\nabla_1')
|
|
2462
|
+
sage: nab1.set_coef(eX)[1,2,1] = x*y
|
|
2463
|
+
sage: nab2 = M.affine_connection('nabla2', latex_name=r'\nabla_2')
|
|
2464
|
+
sage: nab2.set_coef(eX)[1,2,1] = x^2
|
|
2465
|
+
sage: nab1.set_immutable(); nab2.set_immutable()
|
|
2466
|
+
sage: d = {nab1: 1, nab2: 2}
|
|
2467
|
+
sage: d[nab1]
|
|
2468
|
+
1
|
|
2469
|
+
sage: d[nab2]
|
|
2470
|
+
2
|
|
2471
|
+
"""
|
|
2472
|
+
if self.is_mutable():
|
|
2473
|
+
raise ValueError('element must be immutable in order to be '
|
|
2474
|
+
'hashable')
|
|
2475
|
+
return hash((type(self).__name__, self._domain))
|