passagemath-symbolics 10.8.1a1__cp311-cp311-macosx_13_0_arm64.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/.dylibs/libgmp.10.dylib +0 -0
- passagemath_symbolics/__init__.py +3 -0
- passagemath_symbolics-10.8.1a1.dist-info/METADATA +186 -0
- passagemath_symbolics-10.8.1a1.dist-info/RECORD +182 -0
- passagemath_symbolics-10.8.1a1.dist-info/WHEEL +6 -0
- passagemath_symbolics-10.8.1a1.dist-info/top_level.txt +3 -0
- sage/all__sagemath_symbolics.py +17 -0
- sage/calculus/all.py +14 -0
- sage/calculus/calculus.py +2838 -0
- sage/calculus/desolvers.py +1864 -0
- sage/calculus/predefined.py +51 -0
- sage/calculus/tests.py +225 -0
- sage/calculus/var.cpython-311-darwin.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-311-darwin.so +0 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1034 -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 +755 -0
- sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2419 -0
- sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
- sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1083 -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 +2991 -0
- sage/interfaces/magma_free.py +90 -0
- sage/interfaces/maple.py +1402 -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 +553 -0
- sage/manifolds/catalog.py +437 -0
- sage/manifolds/chart.py +4010 -0
- sage/manifolds/chart_func.py +3416 -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 +1668 -0
- sage/manifolds/differentiable/diff_form.py +1660 -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 +1522 -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 +912 -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 +1725 -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 +2721 -0
- sage/manifolds/subsets/all.py +1 -0
- sage/manifolds/subsets/closure.py +131 -0
- sage/manifolds/subsets/pullback.py +883 -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 +1347 -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-311-darwin.so +0 -0
- sage/matrix/matrix_symbolic_dense.pxd +6 -0
- sage/matrix/matrix_symbolic_dense.pyx +1030 -0
- sage/matrix/matrix_symbolic_sparse.cpython-311-darwin.so +0 -0
- sage/matrix/matrix_symbolic_sparse.pxd +6 -0
- sage/matrix/matrix_symbolic_sparse.pyx +1038 -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 +4106 -0
- sage/rings/asymptotic/growth_group.py +5373 -0
- sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
- sage/rings/asymptotic/term_monoid.py +5205 -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 +987 -0
- sage/symbolic/benchmark.py +93 -0
- sage/symbolic/callable.py +456 -0
- sage/symbolic/callable.pyi +66 -0
- sage/symbolic/comparison_impl.pyi +38 -0
- sage/symbolic/complexity_measures.py +35 -0
- sage/symbolic/constants.py +1286 -0
- sage/symbolic/constants_c_impl.pyi +10 -0
- sage/symbolic/expression_conversion_algebraic.py +310 -0
- sage/symbolic/expression_conversion_sympy.py +317 -0
- sage/symbolic/expression_conversions.py +1727 -0
- sage/symbolic/function_factory.py +355 -0
- sage/symbolic/function_factory.pyi +41 -0
- sage/symbolic/getitem_impl.pyi +24 -0
- sage/symbolic/integration/all.py +1 -0
- sage/symbolic/integration/external.py +271 -0
- sage/symbolic/integration/integral.py +1075 -0
- sage/symbolic/maxima_wrapper.py +162 -0
- sage/symbolic/operators.py +267 -0
- sage/symbolic/operators.pyi +61 -0
- sage/symbolic/pynac_constant_impl.pyi +13 -0
- sage/symbolic/pynac_function_impl.pyi +8 -0
- sage/symbolic/random_tests.py +461 -0
- sage/symbolic/relation.py +2062 -0
- sage/symbolic/ring.cpython-311-darwin.so +0 -0
- sage/symbolic/ring.pxd +5 -0
- sage/symbolic/ring.pyi +110 -0
- sage/symbolic/ring.pyx +1393 -0
- sage/symbolic/series_impl.pyi +10 -0
- sage/symbolic/subring.py +1025 -0
- sage/symbolic/symengine.py +19 -0
- sage/symbolic/tests.py +40 -0
- sage/symbolic/units.py +1468 -0
|
@@ -0,0 +1,1839 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-symbolics
|
|
2
|
+
r"""
|
|
3
|
+
Pseudo-Riemannian submanifolds
|
|
4
|
+
|
|
5
|
+
An *embedded (resp. immersed) submanifold of a pseudo-Riemannian manifold*
|
|
6
|
+
`(M,g)` is an embedded (resp. immersed) submanifold `N` of `M` as a
|
|
7
|
+
differentiable manifold (see
|
|
8
|
+
:mod:`~sage.manifolds.differentiable.differentiable_submanifold`) such that
|
|
9
|
+
pull back of the metric tensor `g` via the embedding (resp. immersion) endows
|
|
10
|
+
`N` with the structure of a pseudo-Riemannian manifold.
|
|
11
|
+
|
|
12
|
+
The following example shows how to compute the various quantities related
|
|
13
|
+
to the intrinsic and extrinsic geometries of a hyperbolic slicing of the
|
|
14
|
+
3-dimensional Minkowski space.
|
|
15
|
+
|
|
16
|
+
We start by declaring the ambient manifold `M` and the submanifold `N`::
|
|
17
|
+
|
|
18
|
+
sage: M = Manifold(3, 'M', structure='Lorentzian')
|
|
19
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian', start_index=1)
|
|
20
|
+
|
|
21
|
+
The considered slices being spacelike hypersurfaces, they are Riemannian
|
|
22
|
+
manifolds.
|
|
23
|
+
|
|
24
|
+
Let us introduce the Minkowskian coordinates `(w,x,y)` on `M` and the polar
|
|
25
|
+
coordinates `(\rho, \theta)` on the submanifold `N`::
|
|
26
|
+
|
|
27
|
+
sage: E.<w,x,y> = M.chart()
|
|
28
|
+
sage: C.<rh,th> = N.chart(r'rh:(0,+oo):\rho th:(0,2*pi):\theta')
|
|
29
|
+
|
|
30
|
+
Let `b` be the hyperbola semi-major axis and `t` the parameter of the
|
|
31
|
+
foliation::
|
|
32
|
+
|
|
33
|
+
sage: b = var('b', domain='real')
|
|
34
|
+
sage: assume(b>0)
|
|
35
|
+
sage: t = var('t', domain='real')
|
|
36
|
+
|
|
37
|
+
One can then define the embedding `\phi_t`::
|
|
38
|
+
|
|
39
|
+
sage: phi = N.diff_map(M, {(C,E): [b*cosh(rh)+t,
|
|
40
|
+
....: b*sinh(rh)*cos(th),
|
|
41
|
+
....: b*sinh(rh)*sin(th)]})
|
|
42
|
+
sage: phi.display()
|
|
43
|
+
N → M
|
|
44
|
+
(rh, th) ↦ (w, x, y) = (b*cosh(rh) + t, b*cos(th)*sinh(rh),
|
|
45
|
+
b*sin(th)*sinh(rh))
|
|
46
|
+
|
|
47
|
+
as well as its inverse (when considered as a diffeomorphism onto its image)::
|
|
48
|
+
|
|
49
|
+
sage: phi_inv = M.diff_map(N, {(E,C): [log(sqrt(x^2+y^2+b^2)/b+
|
|
50
|
+
....: sqrt((x^2+y^2+b^2)/b^2-1)),
|
|
51
|
+
....: atan2(y,x)]})
|
|
52
|
+
sage: phi_inv.display()
|
|
53
|
+
M → N
|
|
54
|
+
(w, x, y) ↦ (rh, th) = (log(sqrt((b^2 + x^2 + y^2)/b^2 - 1)
|
|
55
|
+
+ sqrt(b^2 + x^2 + y^2)/b), arctan2(y, x))
|
|
56
|
+
|
|
57
|
+
and the partial inverse expressing the foliation parameter `t` as a scalar
|
|
58
|
+
field on `M`::
|
|
59
|
+
|
|
60
|
+
sage: phi_inv_t = M.scalar_field({E: w-sqrt(x^2+y^2+b^2)})
|
|
61
|
+
sage: phi_inv_t.display()
|
|
62
|
+
M → ℝ
|
|
63
|
+
(w, x, y) ↦ w - sqrt(b^2 + x^2 + y^2)
|
|
64
|
+
|
|
65
|
+
One can check that the inverse is correct with::
|
|
66
|
+
|
|
67
|
+
sage: (phi*phi_inv).display()
|
|
68
|
+
M → M
|
|
69
|
+
(w, x, y) ↦ ((b^2 + x^2 + y^2 + sqrt(b^2 + x^2 + y^2)*(t + sqrt(x^2 +
|
|
70
|
+
y^2)) + sqrt(x^2 + y^2)*t)/(sqrt(b^2 + x^2 + y^2) + sqrt(x^2 + y^2)), x, y)
|
|
71
|
+
|
|
72
|
+
The first item of the 3-uple in the right-hand does not appear as `w` because
|
|
73
|
+
`t` has not been replaced by its value provided by ``phi_inv_t``. Once this is
|
|
74
|
+
done, we do get `w`::
|
|
75
|
+
|
|
76
|
+
sage: (phi*phi_inv).expr()[0].subs({t: phi_inv_t.expr()}).simplify_full()
|
|
77
|
+
w
|
|
78
|
+
|
|
79
|
+
The embedding can then be declared::
|
|
80
|
+
|
|
81
|
+
sage: N.set_embedding(phi, inverse=phi_inv, var=t,
|
|
82
|
+
....: t_inverse = {t: phi_inv_t})
|
|
83
|
+
|
|
84
|
+
This line does not perform any calculation yet. It just check the coherence of
|
|
85
|
+
the arguments, but not the inverse, the user is trusted on this point.
|
|
86
|
+
|
|
87
|
+
Finally, we initialize the metric of `M` to be that of Minkowski space::
|
|
88
|
+
|
|
89
|
+
sage: g = M.metric()
|
|
90
|
+
sage: g[0,0], g[1,1], g[2,2] = -1, 1, 1
|
|
91
|
+
sage: g.display()
|
|
92
|
+
g = -dw⊗dw + dx⊗dx + dy⊗dy
|
|
93
|
+
|
|
94
|
+
With this, the declaration the ambient manifold and its foliation parametrized
|
|
95
|
+
by `t` is finished, and calculations can be performed.
|
|
96
|
+
|
|
97
|
+
The first step is always to find a chart adapted to the foliation. This is done
|
|
98
|
+
by the method "adapted_chart"::
|
|
99
|
+
|
|
100
|
+
sage: T = N.adapted_chart(); T
|
|
101
|
+
[Chart (M, (rh_M, th_M, t_M))]
|
|
102
|
+
|
|
103
|
+
``T`` contains a new chart defined on `M`. By default, the coordinate names
|
|
104
|
+
are constructed from the names of the submanifold coordinates and the foliation
|
|
105
|
+
parameter indexed by the name of the ambient manifold. By this can be
|
|
106
|
+
customized, see
|
|
107
|
+
:meth:`~sage.manifolds.topological_submanifold.TopologicalSubmanifold.adapted_chart`.
|
|
108
|
+
|
|
109
|
+
One can check that the adapted chart has been added to `M`'s atlas, along with
|
|
110
|
+
some coordinates changes::
|
|
111
|
+
|
|
112
|
+
sage: M.atlas()
|
|
113
|
+
[Chart (M, (w, x, y)), Chart (M, (rh_M, th_M, t_M))]
|
|
114
|
+
sage: len(M.coord_changes())
|
|
115
|
+
2
|
|
116
|
+
|
|
117
|
+
Let us compute the induced metric (or first fundamental form)::
|
|
118
|
+
|
|
119
|
+
sage: # long time
|
|
120
|
+
sage: gamma = N.induced_metric()
|
|
121
|
+
sage: gamma.display()
|
|
122
|
+
gamma = b^2 drh⊗drh + b^2*sinh(rh)^2 dth⊗dth
|
|
123
|
+
sage: gamma[:]
|
|
124
|
+
[ b^2 0]
|
|
125
|
+
[ 0 b^2*sinh(rh)^2]
|
|
126
|
+
sage: gamma[1,1]
|
|
127
|
+
b^2
|
|
128
|
+
|
|
129
|
+
the normal vector::
|
|
130
|
+
|
|
131
|
+
sage: N.normal().display() # long time
|
|
132
|
+
n = sqrt(b^2 + x^2 + y^2)/b ∂/∂w + x/b ∂/∂x + y/b ∂/∂y
|
|
133
|
+
|
|
134
|
+
Check that the hypersurface is indeed spacelike, i.e. that its normal is
|
|
135
|
+
timelike::
|
|
136
|
+
|
|
137
|
+
sage: N.ambient_metric()(N.normal(), N.normal()).display() # long time
|
|
138
|
+
g(n,n): M → ℝ
|
|
139
|
+
(w, x, y) ↦ -1
|
|
140
|
+
(rh_M, th_M, t_M) ↦ -1
|
|
141
|
+
|
|
142
|
+
The lapse function is::
|
|
143
|
+
|
|
144
|
+
sage: N.lapse().display() # long time
|
|
145
|
+
N: M → ℝ
|
|
146
|
+
(w, x, y) ↦ sqrt(b^2 + x^2 + y^2)/b
|
|
147
|
+
(rh_M, th_M, t_M) ↦ cosh(rh_M)
|
|
148
|
+
|
|
149
|
+
while the shift vector is::
|
|
150
|
+
|
|
151
|
+
sage: N.shift().display() # long time
|
|
152
|
+
beta = -(x^2 + y^2)/b^2 ∂/∂w - sqrt(b^2 + x^2 + y^2)*x/b^2 ∂/∂x
|
|
153
|
+
- sqrt(b^2 + x^2 + y^2)*y/b^2 ∂/∂y
|
|
154
|
+
|
|
155
|
+
The extrinsic curvature (or second fundamental form) as a tensor field on the
|
|
156
|
+
ambient manifold::
|
|
157
|
+
|
|
158
|
+
sage: N.ambient_extrinsic_curvature()[:] # long time
|
|
159
|
+
[ -(x^2 + y^2)/b^3 (b^2*x + x^3 + x*y^2)/(sqrt(b^2 + x^2 + y^2)*b^3) (y^3 + (b^2 + x^2)*y)/(sqrt(b^2 + x^2 + y^2)*b^3)]
|
|
160
|
+
[ sqrt(b^2 + x^2 + y^2)*x/b^3 -(b^2 + x^2)/b^3 -x*y/b^3]
|
|
161
|
+
[ sqrt(b^2 + x^2 + y^2)*y/b^3 -x*y/b^3 -(b^2 + y^2)/b^3]
|
|
162
|
+
|
|
163
|
+
The extrinsic curvature as a tensor field on the submanifold::
|
|
164
|
+
|
|
165
|
+
sage: N.extrinsic_curvature()[:] # long time
|
|
166
|
+
[ -b 0]
|
|
167
|
+
[ 0 -b*sinh(rh)^2]
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
AUTHORS:
|
|
171
|
+
|
|
172
|
+
- Florentin Jaffredo (2018): initial version
|
|
173
|
+
- Eric Gourgoulhon (2018-2019): add documentation
|
|
174
|
+
- Matthias Koeppe (2021): open subsets of submanifolds
|
|
175
|
+
|
|
176
|
+
REFERENCES:
|
|
177
|
+
|
|
178
|
+
- \B. O'Neill : *Semi-Riemannian Geometry* [ONe1983]_
|
|
179
|
+
- \J. M. Lee : *Riemannian Manifolds* [Lee1997]_
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
# *****************************************************************************
|
|
183
|
+
# Copyright (C) 2018 Florentin Jaffredo <florentin.jaffredo@polytechnique.edu>
|
|
184
|
+
# Copyright (C) 2018-2019 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
|
|
185
|
+
# Copyright (C) 2021 Matthias Koeppe <mkoeppe@math.ucdavis.edu>
|
|
186
|
+
#
|
|
187
|
+
# This program is free software: you can redistribute it and/or modify
|
|
188
|
+
# it under the terms of the GNU General Public License as published by
|
|
189
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
190
|
+
# (at your option) any later version.
|
|
191
|
+
# http://www.gnu.org/licenses/
|
|
192
|
+
# *****************************************************************************
|
|
193
|
+
|
|
194
|
+
from queue import Queue
|
|
195
|
+
|
|
196
|
+
from sage.functions.other import factorial
|
|
197
|
+
from sage.manifolds.differentiable.degenerate import DegenerateManifold
|
|
198
|
+
from sage.manifolds.differentiable.differentiable_submanifold import (
|
|
199
|
+
DifferentiableSubmanifold,
|
|
200
|
+
)
|
|
201
|
+
from sage.manifolds.differentiable.pseudo_riemannian import PseudoRiemannianManifold
|
|
202
|
+
from sage.matrix.constructor import matrix
|
|
203
|
+
from sage.misc.cachefunc import cached_method
|
|
204
|
+
from sage.rings.infinity import infinity
|
|
205
|
+
from sage.rings.integer import Integer
|
|
206
|
+
from sage.symbolic.ring import SR
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class PseudoRiemannianSubmanifold(PseudoRiemannianManifold,
|
|
210
|
+
DifferentiableSubmanifold):
|
|
211
|
+
r"""
|
|
212
|
+
Pseudo-Riemannian submanifold.
|
|
213
|
+
|
|
214
|
+
An *embedded (resp. immersed) submanifold of a pseudo-Riemannian manifold*
|
|
215
|
+
`(M,g)` is an embedded (resp. immersed) submanifold `N` of `M` as a
|
|
216
|
+
differentiable manifold such that pull back of the metric tensor `g` via
|
|
217
|
+
the embedding (resp. immersion) endows `N` with the structure of a
|
|
218
|
+
pseudo-Riemannian manifold.
|
|
219
|
+
|
|
220
|
+
INPUT:
|
|
221
|
+
|
|
222
|
+
- ``n`` -- positive integer; dimension of the submanifold
|
|
223
|
+
- ``name`` -- string; name (symbol) given to the submanifold
|
|
224
|
+
- ``ambient`` -- (default: ``None``) pseudo-Riemannian manifold `M` in
|
|
225
|
+
which the submanifold is embedded (or immersed). If ``None``, it is set
|
|
226
|
+
to ``self``
|
|
227
|
+
- ``metric_name`` -- (default: ``None``) string; name (symbol) given to the
|
|
228
|
+
metric; if ``None``, ``'gamma'`` is used
|
|
229
|
+
- ``signature`` -- (default: ``None``) signature `S` of the metric as a
|
|
230
|
+
single integer: `S = n_+ - n_-`, where `n_+` (resp. `n_-`) is the
|
|
231
|
+
number of positive terms (resp. number of negative terms) in any
|
|
232
|
+
diagonal writing of the metric components; if ``signature`` is not
|
|
233
|
+
provided, `S` is set to the submanifold's dimension (Riemannian
|
|
234
|
+
signature)
|
|
235
|
+
- ``base_manifold`` -- (default: ``None``) if not ``None``, must be a
|
|
236
|
+
differentiable manifold; the created object is then an open subset of
|
|
237
|
+
``base_manifold``
|
|
238
|
+
- ``diff_degree`` -- (default: ``infinity``) degree of differentiability
|
|
239
|
+
- ``latex_name`` -- (default: ``None``) string; LaTeX symbol to
|
|
240
|
+
denote the submanifold; if none is provided, it is set to ``name``
|
|
241
|
+
- ``metric_latex_name`` -- (default: ``None``) string; LaTeX symbol to
|
|
242
|
+
denote the metric; if none is provided, it is set to ``metric_name`` if
|
|
243
|
+
the latter is not ``None`` and to ``r'\gamma'`` otherwise
|
|
244
|
+
- ``start_index`` -- (default: 0) integer; lower value of the range of
|
|
245
|
+
indices used for "indexed objects" on the submanifold, e.g. coordinates
|
|
246
|
+
in a chart
|
|
247
|
+
- ``category`` -- (default: ``None``) to specify the category; if ``None``,
|
|
248
|
+
``Manifolds(RR).Differentiable()`` (or ``Manifolds(RR).Smooth()``
|
|
249
|
+
if ``diff_degree`` = ``infinity``) is assumed (see the category
|
|
250
|
+
:class:`~sage.categories.manifolds.Manifolds`)
|
|
251
|
+
- ``unique_tag`` -- (default: ``None``) tag used to force the construction
|
|
252
|
+
of a new object when all the other arguments have been used previously
|
|
253
|
+
(without ``unique_tag``, the
|
|
254
|
+
:class:`~sage.structure.unique_representation.UniqueRepresentation`
|
|
255
|
+
behavior inherited from
|
|
256
|
+
:class:`~sage.manifolds.subset.ManifoldSubset`, via
|
|
257
|
+
:class:`~sage.manifolds.differentiable.manifold.DifferentiableManifold`
|
|
258
|
+
and :class:`~sage.manifolds.manifold.TopologicalManifold`,
|
|
259
|
+
would return the previously constructed object corresponding to these
|
|
260
|
+
arguments).
|
|
261
|
+
|
|
262
|
+
EXAMPLES:
|
|
263
|
+
|
|
264
|
+
Let `N` be a 2-dimensional submanifold of a 3-dimensional Riemannian
|
|
265
|
+
manifold `M`::
|
|
266
|
+
|
|
267
|
+
sage: M = Manifold(3, 'M', structure ='Riemannian')
|
|
268
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian')
|
|
269
|
+
sage: N
|
|
270
|
+
2-dimensional Riemannian submanifold N immersed in the 3-dimensional
|
|
271
|
+
Riemannian manifold M
|
|
272
|
+
sage: CM.<x,y,z> = M.chart()
|
|
273
|
+
sage: CN.<u,v> = N.chart()
|
|
274
|
+
|
|
275
|
+
Let us define a 1-dimension foliation indexed by `t`. The inverse map is
|
|
276
|
+
needed in order to compute the adapted chart in the ambient manifold::
|
|
277
|
+
|
|
278
|
+
sage: t = var('t')
|
|
279
|
+
sage: phi = N.diff_map(M, {(CN,CM):[u, v, t+u^2+v^2]}); phi
|
|
280
|
+
Differentiable map from the 2-dimensional Riemannian submanifold N
|
|
281
|
+
immersed in the 3-dimensional Riemannian manifold M to the
|
|
282
|
+
3-dimensional Riemannian manifold M
|
|
283
|
+
sage: phi_inv = M.diff_map(N,{(CM, CN): [x,y]})
|
|
284
|
+
sage: phi_inv_t = M.scalar_field({CM: z-x^2-y^2})
|
|
285
|
+
|
|
286
|
+
`\phi` can then be declared as an embedding `N\to M`::
|
|
287
|
+
|
|
288
|
+
sage: N.set_embedding(phi, inverse=phi_inv, var=t,
|
|
289
|
+
....: t_inverse={t: phi_inv_t})
|
|
290
|
+
|
|
291
|
+
The foliation can also be used to find new charts on the ambient manifold
|
|
292
|
+
that are adapted to the foliation, ie in which the expression of the
|
|
293
|
+
immersion is trivial. At the same time, the appropriate coordinate changes
|
|
294
|
+
are computed::
|
|
295
|
+
|
|
296
|
+
sage: N.adapted_chart()
|
|
297
|
+
[Chart (M, (u_M, v_M, t_M))]
|
|
298
|
+
sage: len(M.coord_changes())
|
|
299
|
+
2
|
|
300
|
+
|
|
301
|
+
.. SEEALSO::
|
|
302
|
+
|
|
303
|
+
:mod:`~sage.manifolds.manifold` and
|
|
304
|
+
:mod:`~sage.manifolds.differentiable.differentiable_submanifold`
|
|
305
|
+
"""
|
|
306
|
+
def __init__(self, n, name, ambient=None, metric_name=None,
|
|
307
|
+
signature=None, base_manifold=None, diff_degree=infinity,
|
|
308
|
+
latex_name=None, metric_latex_name=None, start_index=0,
|
|
309
|
+
category=None, unique_tag=None):
|
|
310
|
+
r"""
|
|
311
|
+
Construct a pseudo-Riemannian submanifold.
|
|
312
|
+
|
|
313
|
+
TESTS::
|
|
314
|
+
|
|
315
|
+
sage: M = Manifold(3, 'M', structure='Lorentzian')
|
|
316
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian')
|
|
317
|
+
sage: N
|
|
318
|
+
2-dimensional Riemannian submanifold N immersed in the
|
|
319
|
+
3-dimensional Lorentzian manifold M
|
|
320
|
+
sage: phi = N.diff_map(M)
|
|
321
|
+
sage: N.set_embedding(phi)
|
|
322
|
+
sage: N
|
|
323
|
+
2-dimensional Riemannian submanifold N embedded in the
|
|
324
|
+
3-dimensional Lorentzian manifold M
|
|
325
|
+
sage: S = Manifold(2, 'S', latex_name=r"\Sigma", ambient=M,
|
|
326
|
+
....: structure='Riemannian', start_index=1)
|
|
327
|
+
sage: latex(S)
|
|
328
|
+
\Sigma
|
|
329
|
+
sage: S.start_index()
|
|
330
|
+
1
|
|
331
|
+
|
|
332
|
+
::
|
|
333
|
+
|
|
334
|
+
sage: M = Manifold(5, 'M', structure='pseudo-Riemannian',
|
|
335
|
+
....: signature=1)
|
|
336
|
+
sage: N = Manifold(4, 'N', ambient=M,
|
|
337
|
+
....: structure='pseudo-Riemannian', signature=0)
|
|
338
|
+
sage: N
|
|
339
|
+
4-dimensional pseudo-Riemannian submanifold N immersed in the
|
|
340
|
+
5-dimensional pseudo-Riemannian manifold M
|
|
341
|
+
"""
|
|
342
|
+
if metric_name is None:
|
|
343
|
+
metric_name = 'gamma'
|
|
344
|
+
metric_latex_name = r'\gamma'
|
|
345
|
+
PseudoRiemannianManifold.__init__(self, n, name=name,
|
|
346
|
+
metric_name=metric_name,
|
|
347
|
+
signature=signature,
|
|
348
|
+
base_manifold=base_manifold,
|
|
349
|
+
diff_degree=diff_degree,
|
|
350
|
+
latex_name=latex_name,
|
|
351
|
+
metric_latex_name=metric_latex_name,
|
|
352
|
+
start_index=start_index,
|
|
353
|
+
category=category)
|
|
354
|
+
if not (ambient is None
|
|
355
|
+
or isinstance(ambient, (PseudoRiemannianManifold, DegenerateManifold))):
|
|
356
|
+
raise TypeError("ambient must be a pseudo-Riemannian manifold")
|
|
357
|
+
self._init_immersion(ambient=ambient)
|
|
358
|
+
self._difft = None
|
|
359
|
+
self._gradt = None
|
|
360
|
+
self._normal = None
|
|
361
|
+
self._lapse = None
|
|
362
|
+
self._shift = None
|
|
363
|
+
self._first_fundamental_form = None
|
|
364
|
+
self._ambient_first_fundamental_form = None
|
|
365
|
+
self._second_fundamental_form = None
|
|
366
|
+
self._ambient_second_fundamental_form = None
|
|
367
|
+
self._ambient_metric = None
|
|
368
|
+
self._projector = None
|
|
369
|
+
self._gauss_curvature = None
|
|
370
|
+
self._principal_directions = {}
|
|
371
|
+
self._principal_curvatures = {}
|
|
372
|
+
self._mean_curvature = None
|
|
373
|
+
self._shape_operator = None
|
|
374
|
+
self._sgn = 1 if ambient._structure.name == "Riemannian" else -1
|
|
375
|
+
|
|
376
|
+
def _repr_(self):
|
|
377
|
+
r"""
|
|
378
|
+
Return a string representation of the submanifold.
|
|
379
|
+
|
|
380
|
+
If no ambient manifold is specified, the submanifold is considered
|
|
381
|
+
as a manifold.
|
|
382
|
+
|
|
383
|
+
TESTS::
|
|
384
|
+
|
|
385
|
+
sage: M = Manifold(3, 'M', structure='Lorentzian')
|
|
386
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian')
|
|
387
|
+
sage: N
|
|
388
|
+
2-dimensional Riemannian submanifold N immersed in the
|
|
389
|
+
3-dimensional Lorentzian manifold M
|
|
390
|
+
sage: phi = N.diff_map(M)
|
|
391
|
+
sage: N.set_embedding(phi)
|
|
392
|
+
sage: N
|
|
393
|
+
2-dimensional Riemannian submanifold N embedded in the
|
|
394
|
+
3-dimensional Lorentzian manifold M
|
|
395
|
+
"""
|
|
396
|
+
if self is not self._manifold:
|
|
397
|
+
return "Open subset {} of the {}".format(self._name, self._manifold)
|
|
398
|
+
if self._ambient is None:
|
|
399
|
+
return super(PseudoRiemannianManifold, self).__repr__()
|
|
400
|
+
if self._embedded:
|
|
401
|
+
return "{}-dimensional {} submanifold {} embedded in the {}".format(
|
|
402
|
+
self._dim, self._structure.name, self._name, self._ambient)
|
|
403
|
+
return "{}-dimensional {} submanifold {} immersed in the {}".format(
|
|
404
|
+
self._dim, self._structure.name, self._name, self._ambient)
|
|
405
|
+
|
|
406
|
+
def open_subset(self, name, latex_name=None, coord_def={}, supersets=None):
|
|
407
|
+
r"""
|
|
408
|
+
Create an open subset of ``self``.
|
|
409
|
+
|
|
410
|
+
An open subset is a set that is (i) included in the manifold and (ii)
|
|
411
|
+
open with respect to the manifold's topology. It is a differentiable
|
|
412
|
+
manifold by itself. Moreover, equipped with the restriction of the
|
|
413
|
+
manifold metric to itself, it is a pseudo-Riemannian manifold.
|
|
414
|
+
|
|
415
|
+
As ``self`` is a submanifold of its ambient manifold,
|
|
416
|
+
the new open subset is also considered a submanifold of that.
|
|
417
|
+
Hence the returned object is an instance of
|
|
418
|
+
:class:`PseudoRiemannianSubmanifold`.
|
|
419
|
+
|
|
420
|
+
INPUT:
|
|
421
|
+
|
|
422
|
+
- ``name`` -- name given to the open subset
|
|
423
|
+
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
|
|
424
|
+
subset; if none is provided, it is set to ``name``
|
|
425
|
+
- ``coord_def`` -- (default: {}) definition of the subset in
|
|
426
|
+
terms of coordinates; ``coord_def`` must a be dictionary with keys
|
|
427
|
+
charts in the manifold's atlas and values the symbolic expressions
|
|
428
|
+
formed by the coordinates to define the subset.
|
|
429
|
+
- ``supersets`` -- (default: only ``self``) list of sets that the
|
|
430
|
+
new open subset is a subset of
|
|
431
|
+
|
|
432
|
+
OUTPUT:
|
|
433
|
+
|
|
434
|
+
- instance of :class:`PseudoRiemannianSubmanifold` representing the
|
|
435
|
+
created open subset
|
|
436
|
+
|
|
437
|
+
EXAMPLES::
|
|
438
|
+
|
|
439
|
+
sage: M = Manifold(3, 'M', structure='Riemannian')
|
|
440
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian'); N
|
|
441
|
+
2-dimensional Riemannian submanifold N immersed in the
|
|
442
|
+
3-dimensional Riemannian manifold M
|
|
443
|
+
sage: S = N.subset('S'); S
|
|
444
|
+
Subset S of the
|
|
445
|
+
2-dimensional Riemannian submanifold N immersed in the
|
|
446
|
+
3-dimensional Riemannian manifold M
|
|
447
|
+
sage: O = N.subset('O', is_open=True); O # indirect doctest
|
|
448
|
+
Open subset O of the
|
|
449
|
+
2-dimensional Riemannian submanifold N immersed in the
|
|
450
|
+
3-dimensional Riemannian manifold M
|
|
451
|
+
|
|
452
|
+
sage: phi = N.diff_map(M)
|
|
453
|
+
sage: N.set_embedding(phi)
|
|
454
|
+
sage: N
|
|
455
|
+
2-dimensional Riemannian submanifold N embedded in the
|
|
456
|
+
3-dimensional Riemannian manifold M
|
|
457
|
+
sage: S = N.subset('S'); S
|
|
458
|
+
Subset S of the
|
|
459
|
+
2-dimensional Riemannian submanifold N embedded in the
|
|
460
|
+
3-dimensional Riemannian manifold M
|
|
461
|
+
sage: O = N.subset('O', is_open=True); O # indirect doctest
|
|
462
|
+
Open subset O of the
|
|
463
|
+
2-dimensional Riemannian submanifold N embedded in the
|
|
464
|
+
3-dimensional Riemannian manifold M
|
|
465
|
+
"""
|
|
466
|
+
resu = PseudoRiemannianSubmanifold(self._dim, name,
|
|
467
|
+
ambient=self._ambient,
|
|
468
|
+
metric_name=self._metric_name,
|
|
469
|
+
signature=self._metric_signature,
|
|
470
|
+
base_manifold=self._manifold,
|
|
471
|
+
diff_degree=self._diff_degree,
|
|
472
|
+
latex_name=latex_name,
|
|
473
|
+
metric_latex_name=self._metric_latex_name,
|
|
474
|
+
start_index=self._sindex)
|
|
475
|
+
if supersets is None:
|
|
476
|
+
supersets = [self]
|
|
477
|
+
for superset in supersets:
|
|
478
|
+
superset._init_open_subset(resu, coord_def=coord_def)
|
|
479
|
+
return resu
|
|
480
|
+
|
|
481
|
+
def ambient_metric(self):
|
|
482
|
+
r"""
|
|
483
|
+
Return the metric of the ambient manifold.
|
|
484
|
+
|
|
485
|
+
OUTPUT: the metric of the ambient manifold
|
|
486
|
+
|
|
487
|
+
EXAMPLES::
|
|
488
|
+
|
|
489
|
+
sage: M.<x,y,z> = EuclideanSpace()
|
|
490
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian')
|
|
491
|
+
sage: N.ambient_metric()
|
|
492
|
+
Riemannian metric g on the Euclidean space E^3
|
|
493
|
+
sage: N.ambient_metric().display()
|
|
494
|
+
g = dx⊗dx + dy⊗dy + dz⊗dz
|
|
495
|
+
sage: N.ambient_metric() is M.metric()
|
|
496
|
+
True
|
|
497
|
+
"""
|
|
498
|
+
if self._ambient_metric is None:
|
|
499
|
+
self._ambient_metric = self._ambient.metric()
|
|
500
|
+
return self._ambient_metric
|
|
501
|
+
|
|
502
|
+
def first_fundamental_form(self):
|
|
503
|
+
r"""
|
|
504
|
+
Return the first fundamental form of the submanifold.
|
|
505
|
+
|
|
506
|
+
The result is cached, so calling this method multiple times always
|
|
507
|
+
returns the same result at no additional cost.
|
|
508
|
+
|
|
509
|
+
OUTPUT:
|
|
510
|
+
|
|
511
|
+
- the first fundamental form, as an instance of
|
|
512
|
+
:class:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric`
|
|
513
|
+
|
|
514
|
+
EXAMPLES:
|
|
515
|
+
|
|
516
|
+
A sphere embedded in Euclidean space::
|
|
517
|
+
|
|
518
|
+
sage: M.<x,y,z> = EuclideanSpace()
|
|
519
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian')
|
|
520
|
+
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
|
|
521
|
+
sage: r = var('r', domain='real')
|
|
522
|
+
sage: assume(r>0)
|
|
523
|
+
sage: E = M.cartesian_coordinates()
|
|
524
|
+
sage: phi = N.diff_map(M, {(C,E): [r*sin(th)*cos(ph),
|
|
525
|
+
....: r*sin(th)*sin(ph),
|
|
526
|
+
....: r*cos(th)]})
|
|
527
|
+
sage: N.set_embedding(phi)
|
|
528
|
+
sage: N.first_fundamental_form() # long time
|
|
529
|
+
Riemannian metric gamma on the 2-dimensional Riemannian
|
|
530
|
+
submanifold N embedded in the Euclidean space E^3
|
|
531
|
+
sage: N.first_fundamental_form()[:] # long time
|
|
532
|
+
[ r^2 0]
|
|
533
|
+
[ 0 r^2*sin(th)^2]
|
|
534
|
+
|
|
535
|
+
An alias is ``induced_metric``::
|
|
536
|
+
|
|
537
|
+
sage: N.induced_metric()[:] # long time
|
|
538
|
+
[ r^2 0]
|
|
539
|
+
[ 0 r^2*sin(th)^2]
|
|
540
|
+
|
|
541
|
+
By default, the first fundamental form is named ``gamma``, but this
|
|
542
|
+
can be customized by means of the argument ``metric_name`` when
|
|
543
|
+
declaring the submanifold::
|
|
544
|
+
|
|
545
|
+
sage: P = Manifold(1, 'P', ambient=M, structure='Riemannian',
|
|
546
|
+
....: metric_name='g')
|
|
547
|
+
sage: CP.<t> = P.chart()
|
|
548
|
+
sage: F = P.diff_map(M, [t, 2*t, 3*t])
|
|
549
|
+
sage: P.set_embedding(F)
|
|
550
|
+
sage: P.induced_metric()
|
|
551
|
+
Riemannian metric g on the 1-dimensional Riemannian submanifold P
|
|
552
|
+
embedded in the Euclidean space E^3
|
|
553
|
+
sage: P.induced_metric().display()
|
|
554
|
+
g = 14 dt⊗dt
|
|
555
|
+
"""
|
|
556
|
+
if self._first_fundamental_form is None:
|
|
557
|
+
self._first_fundamental_form = super().metric()
|
|
558
|
+
self._first_fundamental_form.set(
|
|
559
|
+
self._immersion.pullback(self.ambient_metric()))
|
|
560
|
+
return self._first_fundamental_form
|
|
561
|
+
|
|
562
|
+
induced_metric = first_fundamental_form
|
|
563
|
+
|
|
564
|
+
def metric(self, name=None, signature=None, latex_name=None,
|
|
565
|
+
dest_map=None):
|
|
566
|
+
r"""
|
|
567
|
+
Return the induced metric (first fundamental form) or define a new
|
|
568
|
+
metric tensor on the submanifold.
|
|
569
|
+
|
|
570
|
+
A new (uninitialized) metric is returned only if the argument ``name``
|
|
571
|
+
is provided and differs from the metric name declared at the
|
|
572
|
+
construction of the submanifold; otherwise, the first fundamental
|
|
573
|
+
form is returned.
|
|
574
|
+
|
|
575
|
+
INPUT:
|
|
576
|
+
|
|
577
|
+
- ``name`` -- (default: ``None``) name given to the metric; if ``name``
|
|
578
|
+
is ``None`` or equals the metric name declared when constructing
|
|
579
|
+
the submanifold, the first fundamental form is returned (see
|
|
580
|
+
:meth:`first_fundamental_form`)
|
|
581
|
+
- ``signature`` -- (default: ``None``; ignored if ``name`` is ``None``)
|
|
582
|
+
signature `S` of the metric as a single integer: `S = n_+ - n_-`,
|
|
583
|
+
where `n_+` (resp. `n_-`) is the number of positive terms (resp.
|
|
584
|
+
number of negative terms) in any diagonal writing of the metric
|
|
585
|
+
components; if ``signature`` is not provided, `S` is set to the
|
|
586
|
+
submanifold's dimension (Riemannian signature)
|
|
587
|
+
- ``latex_name`` -- (default: ``None``; ignored if ``name`` is ``None``)
|
|
588
|
+
LaTeX symbol to denote the metric; if ``None``, it is formed from
|
|
589
|
+
``name``
|
|
590
|
+
- ``dest_map`` -- (default: ``None``; ignored if ``name`` is ``None``)
|
|
591
|
+
instance of
|
|
592
|
+
class :class:`~sage.manifolds.differentiable.diff_map.DiffMap`
|
|
593
|
+
representing the destination map `\Phi:\ U \rightarrow M`, where `U`
|
|
594
|
+
is the current submanifold; if ``None``, the identity map is assumed
|
|
595
|
+
(case of a metric tensor field *on* `U`)
|
|
596
|
+
|
|
597
|
+
OUTPUT:
|
|
598
|
+
|
|
599
|
+
- instance of
|
|
600
|
+
:class:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric`
|
|
601
|
+
|
|
602
|
+
EXAMPLES:
|
|
603
|
+
|
|
604
|
+
Induced metric on a straight line of the Euclidean plane::
|
|
605
|
+
|
|
606
|
+
sage: M.<x,y> = EuclideanSpace()
|
|
607
|
+
sage: N = Manifold(1, 'N', ambient=M, structure='Riemannian')
|
|
608
|
+
sage: CN.<t> = N.chart()
|
|
609
|
+
sage: F = N.diff_map(M, [t, 2*t])
|
|
610
|
+
sage: N.set_embedding(F)
|
|
611
|
+
sage: N.metric()
|
|
612
|
+
Riemannian metric gamma on the 1-dimensional Riemannian
|
|
613
|
+
submanifold N embedded in the Euclidean plane E^2
|
|
614
|
+
sage: N.metric().display()
|
|
615
|
+
gamma = 5 dt⊗dt
|
|
616
|
+
|
|
617
|
+
Setting the argument ``name`` to that declared while constructing
|
|
618
|
+
the submanifold (default: ``'gamma'``) yields the same result::
|
|
619
|
+
|
|
620
|
+
sage: N.metric(name='gamma') is N.metric()
|
|
621
|
+
True
|
|
622
|
+
|
|
623
|
+
while using a different name allows one to define a new metric on the
|
|
624
|
+
submanifold::
|
|
625
|
+
|
|
626
|
+
sage: h = N.metric(name='h'); h
|
|
627
|
+
Riemannian metric h on the 1-dimensional Riemannian submanifold N
|
|
628
|
+
embedded in the Euclidean plane E^2
|
|
629
|
+
sage: h[0, 0] = 1 # initialization
|
|
630
|
+
sage: h.display()
|
|
631
|
+
h = dt⊗dt
|
|
632
|
+
"""
|
|
633
|
+
if name is None or name == self._metric_name:
|
|
634
|
+
return self.first_fundamental_form()
|
|
635
|
+
return super().metric(name=name, signature=signature,
|
|
636
|
+
latex_name=latex_name, dest_map=dest_map)
|
|
637
|
+
|
|
638
|
+
@cached_method
|
|
639
|
+
def difft(self):
|
|
640
|
+
r"""
|
|
641
|
+
Return the differential of the scalar field on the ambient manifold
|
|
642
|
+
representing the first parameter of the foliation associated to
|
|
643
|
+
``self``.
|
|
644
|
+
|
|
645
|
+
The result is cached, so calling this method multiple times always
|
|
646
|
+
returns the same result at no additional cost.
|
|
647
|
+
|
|
648
|
+
OUTPUT: 1-form field on the ambient manifold
|
|
649
|
+
|
|
650
|
+
EXAMPLES:
|
|
651
|
+
|
|
652
|
+
Foliation of the Euclidean 3-space by 2-spheres parametrized by their
|
|
653
|
+
radii::
|
|
654
|
+
|
|
655
|
+
sage: M.<x,y,z> = EuclideanSpace()
|
|
656
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian')
|
|
657
|
+
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
|
|
658
|
+
sage: r = var('r', domain='real')
|
|
659
|
+
sage: assume(r>0)
|
|
660
|
+
sage: E = M.cartesian_coordinates()
|
|
661
|
+
sage: phi = N.diff_map(M, {(C,E): [r*sin(th)*cos(ph),
|
|
662
|
+
....: r*sin(th)*sin(ph),
|
|
663
|
+
....: r*cos(th)]})
|
|
664
|
+
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
|
|
665
|
+
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
|
|
666
|
+
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
|
|
667
|
+
....: t_inverse={r: phi_inv_r})
|
|
668
|
+
sage: N.difft()
|
|
669
|
+
1-form dr on the Euclidean space E^3
|
|
670
|
+
sage: N.difft().display()
|
|
671
|
+
dr = x/sqrt(x^2 + y^2 + z^2) dx + y/sqrt(x^2 + y^2 + z^2) dy +
|
|
672
|
+
z/sqrt(x^2 + y^2 + z^2) dz
|
|
673
|
+
"""
|
|
674
|
+
if self._dim_foliation == 0:
|
|
675
|
+
raise ValueError("A foliation is needed to "
|
|
676
|
+
"perform this calculation")
|
|
677
|
+
self._difft = self._t_inverse[self._var[0]].differential()
|
|
678
|
+
self._difft.set_name("d" + self._var[0]._repr_(),
|
|
679
|
+
r"\mathrm{d}" + self._var[0]._latex_())
|
|
680
|
+
return self._difft
|
|
681
|
+
|
|
682
|
+
@cached_method
|
|
683
|
+
def gradt(self):
|
|
684
|
+
r"""
|
|
685
|
+
Return the gradient of the scalar field on the ambient manifold
|
|
686
|
+
representing the first parameter of the foliation associated to
|
|
687
|
+
``self``.
|
|
688
|
+
|
|
689
|
+
The result is cached, so calling this method multiple times always
|
|
690
|
+
returns the same result at no additional cost.
|
|
691
|
+
|
|
692
|
+
OUTPUT: vector field on the ambient manifold
|
|
693
|
+
|
|
694
|
+
EXAMPLES:
|
|
695
|
+
|
|
696
|
+
Foliation of the Euclidean 3-space by 2-spheres parametrized by their
|
|
697
|
+
radii::
|
|
698
|
+
|
|
699
|
+
sage: M.<x,y,z> = EuclideanSpace()
|
|
700
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian')
|
|
701
|
+
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
|
|
702
|
+
sage: r = var('r', domain='real')
|
|
703
|
+
sage: assume(r>0)
|
|
704
|
+
sage: E = M.cartesian_coordinates()
|
|
705
|
+
sage: phi = N.diff_map(M, {(C,E): [r*sin(th)*cos(ph),
|
|
706
|
+
....: r*sin(th)*sin(ph),
|
|
707
|
+
....: r*cos(th)]})
|
|
708
|
+
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
|
|
709
|
+
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
|
|
710
|
+
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
|
|
711
|
+
....: t_inverse={r: phi_inv_r})
|
|
712
|
+
sage: N.gradt()
|
|
713
|
+
Vector field grad(r) on the Euclidean space E^3
|
|
714
|
+
sage: N.gradt().display()
|
|
715
|
+
grad(r) = x/sqrt(x^2 + y^2 + z^2) e_x + y/sqrt(x^2 + y^2 + z^2) e_y
|
|
716
|
+
+ z/sqrt(x^2 + y^2 + z^2) e_z
|
|
717
|
+
"""
|
|
718
|
+
if self._dim_foliation == 0:
|
|
719
|
+
raise ValueError("A foliation is needed to perform "
|
|
720
|
+
"this calculation")
|
|
721
|
+
param = self._var[0]
|
|
722
|
+
self._gradt = self._t_inverse[param].gradient()
|
|
723
|
+
self._gradt.set_name("grad({})".format(param),
|
|
724
|
+
r"\mathrm{grad}\left(" + param._latex_()
|
|
725
|
+
+ r"\right)")
|
|
726
|
+
return self._gradt
|
|
727
|
+
|
|
728
|
+
@cached_method
|
|
729
|
+
def normal(self):
|
|
730
|
+
r"""
|
|
731
|
+
Return a normal unit vector to the submanifold.
|
|
732
|
+
|
|
733
|
+
If a foliation is defined, it is used to compute the gradient of the
|
|
734
|
+
foliation parameter and then the normal vector. If not, the normal
|
|
735
|
+
vector is computed using the following formula:
|
|
736
|
+
|
|
737
|
+
.. MATH::
|
|
738
|
+
|
|
739
|
+
n = \vec{*}(\mathrm{d}x_0\wedge\mathrm{d}x_1\wedge\cdots
|
|
740
|
+
\wedge\mathrm{d}x_{n-1})
|
|
741
|
+
|
|
742
|
+
where the star stands for the Hodge dual operator and the wedge for the
|
|
743
|
+
exterior product.
|
|
744
|
+
|
|
745
|
+
This formula does not always define a proper vector field when
|
|
746
|
+
multiple charts overlap, because of the arbitrariness of the direction
|
|
747
|
+
of the normal vector. To avoid this problem, the method ``normal()``
|
|
748
|
+
considers the graph defined by the atlas of the submanifold and the
|
|
749
|
+
changes of coordinates, and only calculate the normal vector once by
|
|
750
|
+
connected component. The expression is then propagate by restriction,
|
|
751
|
+
continuation, or change of coordinates using a breadth-first
|
|
752
|
+
exploration of the graph.
|
|
753
|
+
|
|
754
|
+
The result is cached, so calling this method multiple times always
|
|
755
|
+
returns the same result at no additional cost.
|
|
756
|
+
|
|
757
|
+
OUTPUT:
|
|
758
|
+
|
|
759
|
+
- vector field on the ambient manifold (case of a foliation) or along
|
|
760
|
+
the submanifold with values in the ambient manifold (case of a
|
|
761
|
+
single submanifold)
|
|
762
|
+
|
|
763
|
+
EXAMPLES:
|
|
764
|
+
|
|
765
|
+
Foliation of the Euclidean 3-space by 2-spheres parametrized by their
|
|
766
|
+
radii::
|
|
767
|
+
|
|
768
|
+
sage: M.<x,y,z> = EuclideanSpace()
|
|
769
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian')
|
|
770
|
+
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
|
|
771
|
+
sage: r = var('r', domain='real') # foliation parameter
|
|
772
|
+
sage: assume(r>0)
|
|
773
|
+
sage: E = M.cartesian_coordinates()
|
|
774
|
+
sage: phi = N.diff_map(M, {(C,E): [r*sin(th)*cos(ph),
|
|
775
|
+
....: r*sin(th)*sin(ph),
|
|
776
|
+
....: r*cos(th)]})
|
|
777
|
+
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
|
|
778
|
+
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
|
|
779
|
+
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
|
|
780
|
+
....: t_inverse={r: phi_inv_r})
|
|
781
|
+
sage: T = N.adapted_chart()
|
|
782
|
+
sage: N.normal() # long time
|
|
783
|
+
Vector field n on the Euclidean space E^3
|
|
784
|
+
sage: N.normal().display() # long time
|
|
785
|
+
n = x/sqrt(x^2 + y^2 + z^2) e_x + y/sqrt(x^2 + y^2 + z^2) e_y
|
|
786
|
+
+ z/sqrt(x^2 + y^2 + z^2) e_z
|
|
787
|
+
|
|
788
|
+
Or in spherical coordinates::
|
|
789
|
+
|
|
790
|
+
sage: N.normal().display(T[0].frame(),T[0]) # long time
|
|
791
|
+
n = ∂/∂r_E3
|
|
792
|
+
|
|
793
|
+
Let us now consider a sphere of constant radius, i.e. not assumed to be
|
|
794
|
+
part of a foliation, in stereographic coordinates::
|
|
795
|
+
|
|
796
|
+
sage: M.<X,Y,Z> = EuclideanSpace()
|
|
797
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian')
|
|
798
|
+
sage: U = N.open_subset('U')
|
|
799
|
+
sage: V = N.open_subset('V')
|
|
800
|
+
sage: N.declare_union(U, V)
|
|
801
|
+
sage: stereoN.<x,y> = U.chart()
|
|
802
|
+
sage: stereoS.<xp,yp> = V.chart("xp:x' yp:y'")
|
|
803
|
+
sage: stereoN_to_S = stereoN.transition_map(stereoS,
|
|
804
|
+
....: (x/(x^2+y^2), y/(x^2+y^2)),
|
|
805
|
+
....: intersection_name='W',
|
|
806
|
+
....: restrictions1= x^2+y^2!=0,
|
|
807
|
+
....: restrictions2= xp^2+yp^2!=0)
|
|
808
|
+
sage: stereoS_to_N = stereoN_to_S.inverse()
|
|
809
|
+
sage: W = U.intersection(V)
|
|
810
|
+
sage: stereoN_W = stereoN.restrict(W)
|
|
811
|
+
sage: stereoS_W = stereoS.restrict(W)
|
|
812
|
+
sage: A = W.open_subset('A', coord_def={stereoN_W: (y!=0, x<0),
|
|
813
|
+
....: stereoS_W: (yp!=0, xp<0)})
|
|
814
|
+
sage: spher.<the,phi> = A.chart(r'the:(0,pi):\theta phi:(0,2*pi):\phi')
|
|
815
|
+
sage: stereoN_A = stereoN_W.restrict(A)
|
|
816
|
+
sage: spher_to_stereoN = spher.transition_map(stereoN_A,
|
|
817
|
+
....: (sin(the)*cos(phi)/(1-cos(the)),
|
|
818
|
+
....: sin(the)*sin(phi)/(1-cos(the))))
|
|
819
|
+
sage: spher_to_stereoN.set_inverse(2*atan(1/sqrt(x^2+y^2)),
|
|
820
|
+
....: atan2(-y,-x)+pi)
|
|
821
|
+
Check of the inverse coordinate transformation:
|
|
822
|
+
the == 2*arctan(sqrt(-cos(the) + 1)/sqrt(cos(the) + 1)) **failed**
|
|
823
|
+
phi == pi + arctan2(sin(phi)*sin(the)/(cos(the) - 1),
|
|
824
|
+
cos(phi)*sin(the)/(cos(the) - 1)) **failed**
|
|
825
|
+
x == x *passed*
|
|
826
|
+
y == y *passed*
|
|
827
|
+
NB: a failed report can reflect a mere lack of simplification.
|
|
828
|
+
sage: stereoN_to_S_A = stereoN_to_S.restrict(A)
|
|
829
|
+
sage: spher_to_stereoS = stereoN_to_S_A * spher_to_stereoN
|
|
830
|
+
sage: stereoS_to_N_A = stereoN_to_S.inverse().restrict(A)
|
|
831
|
+
sage: stereoS_to_spher = spher_to_stereoN.inverse() * stereoS_to_N_A
|
|
832
|
+
sage: E = M.cartesian_coordinates()
|
|
833
|
+
sage: phi = N.diff_map(M, {(stereoN, E): [2*x/(1+x^2+y^2),
|
|
834
|
+
....: 2*y/(1+x^2+y^2),
|
|
835
|
+
....: (x^2+y^2-1)/(1+x^2+y^2)],
|
|
836
|
+
....: (stereoS, E): [2*xp/(1+xp^2+yp^2),
|
|
837
|
+
....: 2*yp/(1+xp^2+yp^2),
|
|
838
|
+
....: (1-xp^2-yp^2)/(1+xp^2+yp^2)]},
|
|
839
|
+
....: name='Phi', latex_name=r'\Phi')
|
|
840
|
+
sage: N.set_embedding(phi)
|
|
841
|
+
|
|
842
|
+
The method ``normal()`` now returns a tensor field along ``N``::
|
|
843
|
+
|
|
844
|
+
sage: n = N.normal() # long time
|
|
845
|
+
sage: n # long time
|
|
846
|
+
Vector field n along the 2-dimensional Riemannian submanifold N
|
|
847
|
+
embedded in the Euclidean space E^3 with values on the Euclidean
|
|
848
|
+
space E^3
|
|
849
|
+
|
|
850
|
+
Let us check that the choice of orientation is coherent on the two top
|
|
851
|
+
frames::
|
|
852
|
+
|
|
853
|
+
sage: n.restrict(V).display(format_spec=spher) # long time
|
|
854
|
+
n = -cos(phi)*sin(the) e_X - sin(phi)*sin(the) e_Y - cos(the) e_Z
|
|
855
|
+
sage: n.restrict(U).display(format_spec=spher) # long time
|
|
856
|
+
n = -cos(phi)*sin(the) e_X - sin(phi)*sin(the) e_Y - cos(the) e_Z
|
|
857
|
+
"""
|
|
858
|
+
if self._dim_foliation != 0: # case of a foliation
|
|
859
|
+
self._normal = self._sgn * self.lapse() * self.gradt()
|
|
860
|
+
self._normal.set_name("n")
|
|
861
|
+
return self._normal
|
|
862
|
+
# case of no foliation:
|
|
863
|
+
max_frame = self._ambient.default_frame().along(self._immersion)
|
|
864
|
+
self._normal = self.multivector_field(self._ambient._dim - self._dim,
|
|
865
|
+
name='n',
|
|
866
|
+
dest_map=self._immersion)
|
|
867
|
+
|
|
868
|
+
# an auxiliary function:
|
|
869
|
+
def calc_normal(chart):
|
|
870
|
+
"""
|
|
871
|
+
Calculate the normal vector field according to the formula in the
|
|
872
|
+
documentation in a given chart.
|
|
873
|
+
"""
|
|
874
|
+
eps = self.ambient_metric().volume_form(self._dim).along(
|
|
875
|
+
self._immersion).restrict(chart.domain())
|
|
876
|
+
args = list(range(self._dim)) + [eps] + list(range(self._dim))
|
|
877
|
+
r = self.irange()
|
|
878
|
+
n_form = self._immersion.restrict(chart.domain()).pushforward(
|
|
879
|
+
chart.frame()[next(r)]).down(
|
|
880
|
+
self.ambient_metric().along(self._immersion).restrict(
|
|
881
|
+
chart.domain()))
|
|
882
|
+
for i in r:
|
|
883
|
+
n_form = n_form.wedge(
|
|
884
|
+
self._immersion.restrict(chart.domain()).pushforward(
|
|
885
|
+
chart.frame()[i]).down(
|
|
886
|
+
self.ambient_metric().along(
|
|
887
|
+
self._immersion).restrict(
|
|
888
|
+
chart.domain())))
|
|
889
|
+
n_comp = (n_form.contract(*args) / factorial(self._dim)).contract(
|
|
890
|
+
self.ambient_metric().inverse().along(self._immersion))
|
|
891
|
+
if self._ambient._dim - self._dim == 1:
|
|
892
|
+
n_comp = n_comp / n_comp.norm(self.ambient_metric())
|
|
893
|
+
|
|
894
|
+
norm_rst = self._normal.restrict(chart.domain())
|
|
895
|
+
norm_rst.add_comp(max_frame.restrict(chart.domain()))[:] = n_comp[:]
|
|
896
|
+
self._normal.add_comp_by_continuation(max_frame, chart.domain(),
|
|
897
|
+
chart)
|
|
898
|
+
|
|
899
|
+
# start breadth-first graph exploration
|
|
900
|
+
marked = set()
|
|
901
|
+
f = Queue()
|
|
902
|
+
|
|
903
|
+
for v in self.top_charts():
|
|
904
|
+
if v not in marked:
|
|
905
|
+
f.put(v)
|
|
906
|
+
calc_normal(v) # initial calculus
|
|
907
|
+
marked.add(v)
|
|
908
|
+
while not f.empty():
|
|
909
|
+
v = f.get()
|
|
910
|
+
# for each neighbor:
|
|
911
|
+
for vp in self.atlas():
|
|
912
|
+
# case restriction
|
|
913
|
+
if vp in v._subcharts and vp not in marked:
|
|
914
|
+
f.put(vp)
|
|
915
|
+
self._normal.restrict(vp.domain())
|
|
916
|
+
marked.add(vp)
|
|
917
|
+
|
|
918
|
+
# case continuation
|
|
919
|
+
if vp in v._supercharts and vp not in marked:
|
|
920
|
+
f.put(vp)
|
|
921
|
+
self._normal.add_comp_by_continuation(
|
|
922
|
+
max_frame.restrict(vp.domain()), v.domain(), vp)
|
|
923
|
+
marked.add(vp)
|
|
924
|
+
|
|
925
|
+
# case coordinates change
|
|
926
|
+
if (v, vp) in self.coord_changes() and vp not in marked:
|
|
927
|
+
f.put(vp)
|
|
928
|
+
self._normal.comp(max_frame, vp)
|
|
929
|
+
marked.add(vp)
|
|
930
|
+
|
|
931
|
+
# Going up from each top_chart to the full manifold :
|
|
932
|
+
for v in self.top_charts():
|
|
933
|
+
self._normal.add_expr_from_subdomain(max_frame, v.domain())
|
|
934
|
+
|
|
935
|
+
return self._normal
|
|
936
|
+
|
|
937
|
+
def ambient_first_fundamental_form(self):
|
|
938
|
+
r"""
|
|
939
|
+
Return the first fundamental form of the submanifold as a tensor of the
|
|
940
|
+
ambient manifold.
|
|
941
|
+
|
|
942
|
+
The result is cached, so calling this method multiple times always
|
|
943
|
+
returns the same result at no additional cost.
|
|
944
|
+
|
|
945
|
+
OUTPUT:
|
|
946
|
+
|
|
947
|
+
- (0,2) tensor field on the ambient manifold describing the induced
|
|
948
|
+
metric before projection on the submanifold
|
|
949
|
+
|
|
950
|
+
EXAMPLES:
|
|
951
|
+
|
|
952
|
+
A unit circle embedded in the Euclidean plane::
|
|
953
|
+
|
|
954
|
+
sage: M.<X,Y> = EuclideanSpace()
|
|
955
|
+
sage: N = Manifold(1, 'N', ambient=M, structure='Riemannian')
|
|
956
|
+
sage: U = N.open_subset('U')
|
|
957
|
+
sage: V = N.open_subset('V')
|
|
958
|
+
sage: N.declare_union(U,V)
|
|
959
|
+
sage: stereoN.<x> = U.chart()
|
|
960
|
+
sage: stereoS.<y> = V.chart()
|
|
961
|
+
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
|
|
962
|
+
....: intersection_name='W',
|
|
963
|
+
....: restrictions1=x!=0, restrictions2=y!=0)
|
|
964
|
+
sage: stereoS_to_N = stereoN_to_S.inverse()
|
|
965
|
+
sage: E = M.cartesian_coordinates()
|
|
966
|
+
sage: phi = N.diff_map(M,
|
|
967
|
+
....: {(stereoN, E): [1/sqrt(1+x^2/4), x/2/sqrt(1+x^2/4)],
|
|
968
|
+
....: (stereoS, E): [1/sqrt(1+4/y^2), 2/y/sqrt(1+4/y^2)]})
|
|
969
|
+
sage: N.set_embedding(phi)
|
|
970
|
+
sage: N.ambient_first_fundamental_form()
|
|
971
|
+
Tensor field gamma of type (0,2) along the 1-dimensional Riemannian
|
|
972
|
+
submanifold N embedded in the Euclidean plane E^2 with values on
|
|
973
|
+
the Euclidean plane E^2
|
|
974
|
+
sage: N.ambient_first_fundamental_form()[:]
|
|
975
|
+
[ x^2/(x^2 + 4) -2*x/(x^2 + 4)]
|
|
976
|
+
[-2*x/(x^2 + 4) 4/(x^2 + 4)]
|
|
977
|
+
|
|
978
|
+
An alias is ``ambient_induced_metric``::
|
|
979
|
+
|
|
980
|
+
sage: N.ambient_induced_metric()[:]
|
|
981
|
+
[ x^2/(x^2 + 4) -2*x/(x^2 + 4)]
|
|
982
|
+
[-2*x/(x^2 + 4) 4/(x^2 + 4)]
|
|
983
|
+
"""
|
|
984
|
+
if self._ambient._dim - self._dim != 1:
|
|
985
|
+
raise NotImplementedError("ambient_first_fundamental_form() is "
|
|
986
|
+
"implemented only for hypersurfaces")
|
|
987
|
+
if self._ambient_first_fundamental_form is None:
|
|
988
|
+
g = self.ambient_metric()
|
|
989
|
+
if self._dim_foliation == 0: # case no foliation
|
|
990
|
+
g = g.along(self._immersion)
|
|
991
|
+
self._ambient_first_fundamental_form = g - self._sgn * g.contract(
|
|
992
|
+
self.normal()) * g.contract(self.normal())
|
|
993
|
+
self._ambient_first_fundamental_form.set_name("gamma", r"\gamma")
|
|
994
|
+
return self._ambient_first_fundamental_form
|
|
995
|
+
|
|
996
|
+
ambient_induced_metric = ambient_first_fundamental_form
|
|
997
|
+
|
|
998
|
+
@cached_method
|
|
999
|
+
def lapse(self):
|
|
1000
|
+
r"""
|
|
1001
|
+
Return the lapse function of the foliation.
|
|
1002
|
+
|
|
1003
|
+
The result is cached, so calling this method multiple times always
|
|
1004
|
+
returns the same result at no additional cost.
|
|
1005
|
+
|
|
1006
|
+
OUTPUT: the lapse function, as a scalar field on the ambient manifold
|
|
1007
|
+
|
|
1008
|
+
EXAMPLES:
|
|
1009
|
+
|
|
1010
|
+
Foliation of the Euclidean 3-space by 2-spheres parametrized by their
|
|
1011
|
+
radii::
|
|
1012
|
+
|
|
1013
|
+
sage: M.<x,y,z> = EuclideanSpace()
|
|
1014
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian')
|
|
1015
|
+
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
|
|
1016
|
+
sage: r = var('r', domain='real') # foliation parameter
|
|
1017
|
+
sage: assume(r>0)
|
|
1018
|
+
sage: E = M.cartesian_coordinates()
|
|
1019
|
+
sage: phi = N.diff_map(M, {(C,E): [r*sin(th)*cos(ph),
|
|
1020
|
+
....: r*sin(th)*sin(ph),
|
|
1021
|
+
....: r*cos(th)]})
|
|
1022
|
+
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
|
|
1023
|
+
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
|
|
1024
|
+
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
|
|
1025
|
+
....: t_inverse={r: phi_inv_r})
|
|
1026
|
+
sage: T = N.adapted_chart()
|
|
1027
|
+
sage: N.lapse()
|
|
1028
|
+
Scalar field N on the Euclidean space E^3
|
|
1029
|
+
sage: N.lapse().display()
|
|
1030
|
+
N: E^3 → ℝ
|
|
1031
|
+
(x, y, z) ↦ 1
|
|
1032
|
+
(th_E3, ph_E3, r_E3) ↦ 1
|
|
1033
|
+
"""
|
|
1034
|
+
if self._dim_foliation == 0:
|
|
1035
|
+
raise ValueError("A foliation is needed "
|
|
1036
|
+
"to perform this calculation")
|
|
1037
|
+
self._lapse = 1 / (self._sgn * self.ambient_metric()(
|
|
1038
|
+
self.gradt(), self.gradt())).sqrt()
|
|
1039
|
+
self._lapse.set_name("N")
|
|
1040
|
+
return self._lapse
|
|
1041
|
+
|
|
1042
|
+
@cached_method
|
|
1043
|
+
def shift(self):
|
|
1044
|
+
r"""
|
|
1045
|
+
Return the shift vector associated with the first adapted chart of the
|
|
1046
|
+
foliation.
|
|
1047
|
+
|
|
1048
|
+
The result is cached, so calling this method multiple times always
|
|
1049
|
+
returns the same result at no additional cost.
|
|
1050
|
+
|
|
1051
|
+
OUTPUT: shift vector field on the ambient manifold
|
|
1052
|
+
|
|
1053
|
+
EXAMPLES:
|
|
1054
|
+
|
|
1055
|
+
Foliation of the Euclidean 3-space by 2-spheres parametrized by their
|
|
1056
|
+
radii::
|
|
1057
|
+
|
|
1058
|
+
sage: M.<x,y,z> = EuclideanSpace()
|
|
1059
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian')
|
|
1060
|
+
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
|
|
1061
|
+
sage: r = var('r', domain='real') # foliation parameter
|
|
1062
|
+
sage: assume(r>0)
|
|
1063
|
+
sage: E = M.cartesian_coordinates()
|
|
1064
|
+
sage: phi = N.diff_map(M, {(C,E): [r*sin(th)*cos(ph),
|
|
1065
|
+
....: r*sin(th)*sin(ph),
|
|
1066
|
+
....: r*cos(th)]})
|
|
1067
|
+
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
|
|
1068
|
+
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
|
|
1069
|
+
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
|
|
1070
|
+
....: t_inverse={r: phi_inv_r})
|
|
1071
|
+
sage: T = N.adapted_chart()
|
|
1072
|
+
sage: N.shift() # long time
|
|
1073
|
+
Vector field beta on the Euclidean space E^3
|
|
1074
|
+
sage: N.shift().display() # long time
|
|
1075
|
+
beta = 0
|
|
1076
|
+
"""
|
|
1077
|
+
if self._dim_foliation == 0:
|
|
1078
|
+
raise ValueError("A foliation is needed "
|
|
1079
|
+
"to perform this calculation")
|
|
1080
|
+
sia = self._ambient._sindex
|
|
1081
|
+
self._shift = self._adapted_charts[0].frame()[self._dim + sia]\
|
|
1082
|
+
- self.lapse() * self.normal()
|
|
1083
|
+
self._shift.set_name("beta", r"\beta")
|
|
1084
|
+
return self._shift
|
|
1085
|
+
|
|
1086
|
+
def ambient_second_fundamental_form(self):
|
|
1087
|
+
r"""
|
|
1088
|
+
Return the second fundamental form of the submanifold as a tensor field
|
|
1089
|
+
on the ambient manifold.
|
|
1090
|
+
|
|
1091
|
+
The result is cached, so calling this method multiple times always
|
|
1092
|
+
returns the same result at no additional cost.
|
|
1093
|
+
|
|
1094
|
+
OUTPUT:
|
|
1095
|
+
|
|
1096
|
+
- (0,2) tensor field on the ambient manifold equal to the second
|
|
1097
|
+
fundamental form once orthogonally projected onto the submanifold
|
|
1098
|
+
|
|
1099
|
+
EXAMPLES:
|
|
1100
|
+
|
|
1101
|
+
A unit circle embedded in the Euclidean plane::
|
|
1102
|
+
|
|
1103
|
+
sage: M.<X,Y> = EuclideanSpace()
|
|
1104
|
+
sage: N = Manifold(1, 'N', ambient=M, structure='Riemannian')
|
|
1105
|
+
sage: U = N.open_subset('U')
|
|
1106
|
+
sage: V = N.open_subset('V')
|
|
1107
|
+
sage: N.declare_union(U,V)
|
|
1108
|
+
sage: stereoN.<x> = U.chart()
|
|
1109
|
+
sage: stereoS.<y> = V.chart()
|
|
1110
|
+
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
|
|
1111
|
+
....: intersection_name='W',
|
|
1112
|
+
....: restrictions1=x!=0, restrictions2=y!=0)
|
|
1113
|
+
sage: stereoS_to_N = stereoN_to_S.inverse()
|
|
1114
|
+
sage: E = M.cartesian_coordinates()
|
|
1115
|
+
sage: phi = N.diff_map(M,
|
|
1116
|
+
....: {(stereoN, E): [1/sqrt(1+x^2/4), x/2/sqrt(1+x^2/4)],
|
|
1117
|
+
....: (stereoS, E): [1/sqrt(1+4/y^2), 2/y/sqrt(1+4/y^2)]})
|
|
1118
|
+
sage: N.set_embedding(phi)
|
|
1119
|
+
sage: N.ambient_second_fundamental_form() # long time
|
|
1120
|
+
Field of symmetric bilinear forms K along the 1-dimensional
|
|
1121
|
+
Riemannian submanifold N embedded in the Euclidean plane E^2 with
|
|
1122
|
+
values on the Euclidean plane E^2
|
|
1123
|
+
sage: N.ambient_second_fundamental_form()[:] # long time
|
|
1124
|
+
[-x^2/(x^2 + 4) 2*x/(x^2 + 4)]
|
|
1125
|
+
[ 2*x/(x^2 + 4) -4/(x^2 + 4)]
|
|
1126
|
+
|
|
1127
|
+
An alias is ``ambient_extrinsic_curvature``::
|
|
1128
|
+
|
|
1129
|
+
sage: N.ambient_extrinsic_curvature()[:] # long time
|
|
1130
|
+
[-x^2/(x^2 + 4) 2*x/(x^2 + 4)]
|
|
1131
|
+
[ 2*x/(x^2 + 4) -4/(x^2 + 4)]
|
|
1132
|
+
"""
|
|
1133
|
+
if self._ambient._dim - self._dim != 1:
|
|
1134
|
+
raise ValueError("ambient_second_fundamental_form is defined only "
|
|
1135
|
+
"for hypersurfaces")
|
|
1136
|
+
if self._ambient_second_fundamental_form is None:
|
|
1137
|
+
if self._dim_foliation == 0:
|
|
1138
|
+
self._ambient_second_fundamental_form = self.tensor_field(0, 2,
|
|
1139
|
+
sym=[(0, 1)], dest_map=self._immersion)
|
|
1140
|
+
k = self.second_fundamental_form()
|
|
1141
|
+
g = self.ambient_metric().along(self._immersion)
|
|
1142
|
+
max_frame = self._ambient.default_frame().along(self._immersion)
|
|
1143
|
+
for chart in self.top_charts():
|
|
1144
|
+
pf = [self._immersion.restrict(chart.domain()).pushforward(
|
|
1145
|
+
chart.frame()[i]) for i in self.irange()]
|
|
1146
|
+
for i in range(self._dim):
|
|
1147
|
+
pf[i] = pf[i] / g(pf[i], pf[i])
|
|
1148
|
+
gam_rst = sum(
|
|
1149
|
+
g.restrict(chart.domain()).contract(pf[i]) *
|
|
1150
|
+
g.restrict(chart.domain()).contract(pf[j]) *
|
|
1151
|
+
self.scalar_field({chart: k.comp(chart.frame())[:][i, j]})
|
|
1152
|
+
for i in range(self._dim) for j in range(self._dim))
|
|
1153
|
+
gam_rst._sym = ((0, 1),)
|
|
1154
|
+
self._ambient_second_fundamental_form.set_restriction(gam_rst)
|
|
1155
|
+
|
|
1156
|
+
charts = iter(self.top_charts())
|
|
1157
|
+
self._ambient_second_fundamental_form.add_comp_by_continuation(
|
|
1158
|
+
max_frame, next(charts).domain())
|
|
1159
|
+
for chart in charts:
|
|
1160
|
+
self._ambient_second_fundamental_form.add_expr_from_subdomain(
|
|
1161
|
+
max_frame, chart.domain())
|
|
1162
|
+
else:
|
|
1163
|
+
nab = self.ambient_metric().connection('nabla', r'\nabla')
|
|
1164
|
+
self._ambient_second_fundamental_form = \
|
|
1165
|
+
-self.ambient_metric().contract(nab(self.normal())) \
|
|
1166
|
+
- nab(self.normal()).contract(self.normal())\
|
|
1167
|
+
.contract(self.ambient_metric())\
|
|
1168
|
+
* self.normal().contract(self.ambient_metric())
|
|
1169
|
+
self._ambient_second_fundamental_form.set_name("K")
|
|
1170
|
+
return self._ambient_second_fundamental_form
|
|
1171
|
+
|
|
1172
|
+
ambient_extrinsic_curvature = ambient_second_fundamental_form
|
|
1173
|
+
|
|
1174
|
+
def second_fundamental_form(self):
|
|
1175
|
+
r"""
|
|
1176
|
+
Return the second fundamental form of the submanifold.
|
|
1177
|
+
|
|
1178
|
+
The result is cached, so calling this method multiple times always
|
|
1179
|
+
returns the same result at no additional cost.
|
|
1180
|
+
|
|
1181
|
+
OUTPUT:
|
|
1182
|
+
|
|
1183
|
+
- the second fundamental form, as a symmetric tensor field of type
|
|
1184
|
+
(0,2) on the submanifold
|
|
1185
|
+
|
|
1186
|
+
EXAMPLES:
|
|
1187
|
+
|
|
1188
|
+
A unit circle embedded in the Euclidean plane::
|
|
1189
|
+
|
|
1190
|
+
sage: M.<X,Y> = EuclideanSpace()
|
|
1191
|
+
sage: N = Manifold(1, 'N', ambient=M, structure='Riemannian')
|
|
1192
|
+
sage: U = N.open_subset('U')
|
|
1193
|
+
sage: V = N.open_subset('V')
|
|
1194
|
+
sage: N.declare_union(U,V)
|
|
1195
|
+
sage: stereoN.<x> = U.chart()
|
|
1196
|
+
sage: stereoS.<y> = V.chart()
|
|
1197
|
+
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
|
|
1198
|
+
....: intersection_name='W',
|
|
1199
|
+
....: restrictions1=x!=0, restrictions2=y!=0)
|
|
1200
|
+
sage: stereoS_to_N = stereoN_to_S.inverse()
|
|
1201
|
+
sage: E = M.cartesian_coordinates()
|
|
1202
|
+
sage: phi = N.diff_map(M,
|
|
1203
|
+
....: {(stereoN, E): [1/sqrt(1+x^2/4), x/2/sqrt(1+x^2/4)],
|
|
1204
|
+
....: (stereoS, E): [1/sqrt(1+4/y^2), 2/y/sqrt(1+4/y^2)]})
|
|
1205
|
+
sage: N.set_embedding(phi)
|
|
1206
|
+
sage: N.second_fundamental_form() # long time
|
|
1207
|
+
Field of symmetric bilinear forms K on the 1-dimensional Riemannian
|
|
1208
|
+
submanifold N embedded in the Euclidean plane E^2
|
|
1209
|
+
sage: N.second_fundamental_form().display() # long time
|
|
1210
|
+
K = -4/(x^4 + 8*x^2 + 16) dx⊗dx
|
|
1211
|
+
|
|
1212
|
+
An alias is ``extrinsic_curvature``::
|
|
1213
|
+
|
|
1214
|
+
sage: N.extrinsic_curvature().display() # long time
|
|
1215
|
+
K = -4/(x^4 + 8*x^2 + 16) dx⊗dx
|
|
1216
|
+
|
|
1217
|
+
An example with a non-Euclidean ambient metric::
|
|
1218
|
+
|
|
1219
|
+
sage: M = Manifold(2, 'M', structure='Riemannian')
|
|
1220
|
+
sage: N = Manifold(1, 'N', ambient=M, structure='Riemannian',
|
|
1221
|
+
....: start_index=1)
|
|
1222
|
+
sage: CM.<x,y> = M.chart()
|
|
1223
|
+
sage: CN.<u> = N.chart()
|
|
1224
|
+
sage: g = M.metric()
|
|
1225
|
+
sage: g[0, 0], g[1, 1] = 1, 1/(1 + y^2)^2
|
|
1226
|
+
sage: phi = N.diff_map(M, (u, u))
|
|
1227
|
+
sage: N.set_embedding(phi)
|
|
1228
|
+
sage: N.second_fundamental_form()
|
|
1229
|
+
Field of symmetric bilinear forms K on the 1-dimensional Riemannian
|
|
1230
|
+
submanifold N embedded in the 2-dimensional Riemannian manifold M
|
|
1231
|
+
sage: N.second_fundamental_form().display()
|
|
1232
|
+
K = 2*sqrt(u^4 + 2*u^2 + 2)*u/(u^6 + 3*u^4 + 4*u^2 + 2) du⊗du
|
|
1233
|
+
"""
|
|
1234
|
+
if self._ambient._dim - self._dim != 1:
|
|
1235
|
+
raise ValueError("second_fundamental_form is defined only for"
|
|
1236
|
+
+ " hypersurfaces")
|
|
1237
|
+
if self._second_fundamental_form is None:
|
|
1238
|
+
resu = self.vector_field_module().tensor((0, 2), name='K',
|
|
1239
|
+
sym=[(0, 1)])
|
|
1240
|
+
if self._dim_foliation != 0:
|
|
1241
|
+
inverse_subs = {v: k for k, v in self._subs[0].items()}
|
|
1242
|
+
asff = self.ambient_second_fundamental_form()
|
|
1243
|
+
adapted_chart = self._adapted_charts[0]
|
|
1244
|
+
dsi = self._ambient._sindex - self._sindex
|
|
1245
|
+
for i in self.irange():
|
|
1246
|
+
for j in self.irange(start=i):
|
|
1247
|
+
resu[i, j] = asff[adapted_chart.frame(),
|
|
1248
|
+
i + dsi, j + dsi,
|
|
1249
|
+
adapted_chart].expr().subs(inverse_subs)
|
|
1250
|
+
else:
|
|
1251
|
+
nab = self.ambient_metric().connection('nabla', r'\nabla')
|
|
1252
|
+
n = self.normal()
|
|
1253
|
+
|
|
1254
|
+
for chart in self.atlas():
|
|
1255
|
+
gamma_n = matrix(SR, self._dim + 1, self._dim + 1)
|
|
1256
|
+
subs = dict(zip(self._ambient.default_chart()[:],
|
|
1257
|
+
self._immersion.expression(chart)))
|
|
1258
|
+
for i in range(self._dim + 1):
|
|
1259
|
+
for j in range(self._dim + 1):
|
|
1260
|
+
Gam_ij = [nab[self._ambient.frames()[0],
|
|
1261
|
+
:][i][j][k].expr().subs(subs)
|
|
1262
|
+
for k in range(self._dim + 1)]
|
|
1263
|
+
gamma_n[i, j] = chart.simplify(sum(
|
|
1264
|
+
Gam_ij[k] *
|
|
1265
|
+
n.restrict(chart.domain()).comp(
|
|
1266
|
+
n.restrict(chart.domain())._fmodule.bases()[0])
|
|
1267
|
+
[:][k].expr() for k in range(self._dim + 1)))
|
|
1268
|
+
dXdu = self._immersion.differential_functions(chart)
|
|
1269
|
+
dNdu = matrix(SR, self._dim + 1, self._dim)
|
|
1270
|
+
for i in range(self._dim + 1):
|
|
1271
|
+
for j in range(self._dim):
|
|
1272
|
+
dNdu[i, j] = n.restrict(chart.domain()).comp(
|
|
1273
|
+
n.restrict(chart.domain())._fmodule.bases()[0])[:,
|
|
1274
|
+
chart][i].diff(chart[:][j]).expr()
|
|
1275
|
+
g = self.ambient_metric().along(
|
|
1276
|
+
self._immersion.restrict(chart.domain())).restrict(
|
|
1277
|
+
chart.domain())[:, chart]
|
|
1278
|
+
K = dXdu.transpose() * g * (dNdu + gamma_n * dXdu)
|
|
1279
|
+
si = self._sindex
|
|
1280
|
+
for i in self.irange():
|
|
1281
|
+
for j in self.irange(i): # since K is symmetric
|
|
1282
|
+
resu[chart.frame(), i, j, chart] = chart.simplify(
|
|
1283
|
+
K[i - si, j - si].expr())
|
|
1284
|
+
|
|
1285
|
+
self._second_fundamental_form = resu
|
|
1286
|
+
return self._second_fundamental_form
|
|
1287
|
+
|
|
1288
|
+
extrinsic_curvature = second_fundamental_form
|
|
1289
|
+
|
|
1290
|
+
@cached_method
|
|
1291
|
+
def projector(self):
|
|
1292
|
+
r"""
|
|
1293
|
+
Return the orthogonal projector onto the submanifold.
|
|
1294
|
+
|
|
1295
|
+
The result is cached, so calling this method multiple times always
|
|
1296
|
+
returns the same result at no additional cost.
|
|
1297
|
+
|
|
1298
|
+
OUTPUT:
|
|
1299
|
+
|
|
1300
|
+
- the orthogonal projector onto the submanifold, as tensor field of
|
|
1301
|
+
type (1,1) on the ambient manifold
|
|
1302
|
+
|
|
1303
|
+
EXAMPLES:
|
|
1304
|
+
|
|
1305
|
+
Foliation of the Euclidean 3-space by 2-spheres parametrized by their
|
|
1306
|
+
radii::
|
|
1307
|
+
|
|
1308
|
+
sage: M.<x,y,z> = EuclideanSpace()
|
|
1309
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian')
|
|
1310
|
+
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
|
|
1311
|
+
sage: r = var('r', domain='real') # foliation parameter
|
|
1312
|
+
sage: assume(r>0)
|
|
1313
|
+
sage: E = M.cartesian_coordinates()
|
|
1314
|
+
sage: phi = N.diff_map(M, {(C,E): [r*sin(th)*cos(ph),
|
|
1315
|
+
....: r*sin(th)*sin(ph),
|
|
1316
|
+
....: r*cos(th)]})
|
|
1317
|
+
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
|
|
1318
|
+
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
|
|
1319
|
+
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
|
|
1320
|
+
....: t_inverse={r: phi_inv_r})
|
|
1321
|
+
sage: T = N.adapted_chart()
|
|
1322
|
+
|
|
1323
|
+
The orthogonal projector onto ``N`` is a type-(1,1) tensor field on
|
|
1324
|
+
``M``::
|
|
1325
|
+
|
|
1326
|
+
sage: N.projector() # long time
|
|
1327
|
+
Tensor field gamma of type (1,1) on the Euclidean space E^3
|
|
1328
|
+
|
|
1329
|
+
Check that the orthogonal projector applied to the normal vector is
|
|
1330
|
+
zero::
|
|
1331
|
+
|
|
1332
|
+
sage: N.projector().contract(N.normal()).display() # long time
|
|
1333
|
+
0
|
|
1334
|
+
"""
|
|
1335
|
+
if self._ambient._dim - self._dim != 1:
|
|
1336
|
+
raise NotImplementedError("projector() is implemented only for "
|
|
1337
|
+
"hypersurfaces")
|
|
1338
|
+
g = self.ambient_metric().inverse()
|
|
1339
|
+
if self._dim_foliation == 0:
|
|
1340
|
+
g = g.along(self._immersion)
|
|
1341
|
+
|
|
1342
|
+
self._projector = self.ambient_first_fundamental_form().contract(0, g)
|
|
1343
|
+
self._projector.set_name("gamma", r"\vec{\gamma}")
|
|
1344
|
+
return self._projector
|
|
1345
|
+
|
|
1346
|
+
def project(self, tensor):
|
|
1347
|
+
r"""
|
|
1348
|
+
Return the orthogonal projection of a tensor field onto the submanifold.
|
|
1349
|
+
|
|
1350
|
+
INPUT:
|
|
1351
|
+
|
|
1352
|
+
- ``tensor`` -- any tensor field to be projected onto the submanifold.
|
|
1353
|
+
If no foliation is provided, must be a tensor field along the
|
|
1354
|
+
submanifold.
|
|
1355
|
+
|
|
1356
|
+
OUTPUT:
|
|
1357
|
+
|
|
1358
|
+
- orthogonal projection of ``tensor`` onto the submanifold, as a
|
|
1359
|
+
tensor field of the *ambient* manifold
|
|
1360
|
+
|
|
1361
|
+
EXAMPLES:
|
|
1362
|
+
|
|
1363
|
+
Foliation of the Euclidean 3-space by 2-spheres parametrized by their
|
|
1364
|
+
radii::
|
|
1365
|
+
|
|
1366
|
+
sage: M.<x,y,z> = EuclideanSpace()
|
|
1367
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian')
|
|
1368
|
+
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
|
|
1369
|
+
sage: r = var('r', domain='real') # foliation parameter
|
|
1370
|
+
sage: assume(r>0)
|
|
1371
|
+
sage: E = M.cartesian_coordinates()
|
|
1372
|
+
sage: phi = N.diff_map(M, {(C,E): [r*sin(th)*cos(ph),
|
|
1373
|
+
....: r*sin(th)*sin(ph),
|
|
1374
|
+
....: r*cos(th)]})
|
|
1375
|
+
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
|
|
1376
|
+
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
|
|
1377
|
+
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
|
|
1378
|
+
....: t_inverse={r: phi_inv_r})
|
|
1379
|
+
sage: T = N.adapted_chart()
|
|
1380
|
+
|
|
1381
|
+
Let us perform the projection of the ambient metric and check that it
|
|
1382
|
+
is equal to the first fundamental form::
|
|
1383
|
+
|
|
1384
|
+
sage: pg = N.project(M.metric()); pg # long time
|
|
1385
|
+
Tensor field of type (0,2) on the Euclidean space E^3
|
|
1386
|
+
sage: pg == N.ambient_first_fundamental_form() # long time
|
|
1387
|
+
True
|
|
1388
|
+
|
|
1389
|
+
Note that the output of ``project()`` is not cached.
|
|
1390
|
+
"""
|
|
1391
|
+
if self._ambient._dim - self._dim != 1:
|
|
1392
|
+
raise NotImplementedError("project() is implemented only for "
|
|
1393
|
+
"hypersurfaces")
|
|
1394
|
+
resu = tensor.copy()
|
|
1395
|
+
resu.set_name(tensor._name + "_" + self._name,
|
|
1396
|
+
r"{" + tensor._latex_() + r"}_{" + self._latex_() + r"}")
|
|
1397
|
+
for i in range(tensor.tensor_type()[0]):
|
|
1398
|
+
resu = self.projector().contract(1, resu, i)
|
|
1399
|
+
for i in range(tensor.tensor_type()[1]):
|
|
1400
|
+
resu = self.projector().contract(0, resu, i)
|
|
1401
|
+
return resu
|
|
1402
|
+
|
|
1403
|
+
def mixed_projection(self, tensor, indices=0):
|
|
1404
|
+
r"""
|
|
1405
|
+
Return de n+1 decomposition of a tensor on the submanifold and the
|
|
1406
|
+
normal vector.
|
|
1407
|
+
|
|
1408
|
+
The n+1 decomposition of a tensor of rank `k` can be obtained by
|
|
1409
|
+
contracting each index either with the normal vector or the projection
|
|
1410
|
+
operator of the submanifold (see
|
|
1411
|
+
:meth:`~sage.manifolds.differentiable.pseudo_riemannian_submanifold.PseudoRiemannianSubmanifold.projector`).
|
|
1412
|
+
|
|
1413
|
+
INPUT:
|
|
1414
|
+
|
|
1415
|
+
- ``tensor`` -- any tensor field, eventually along the submanifold if
|
|
1416
|
+
no foliation is provided
|
|
1417
|
+
- ``indices`` -- (default: ``0``) list of integers containing the
|
|
1418
|
+
indices on which the projection is made on the normal vector.
|
|
1419
|
+
By default, all projections are made on the submanifold. If
|
|
1420
|
+
an integer `n` is provided, the `n` first contractions are made with
|
|
1421
|
+
the normal vector, all the other ones with the orthogonal projection
|
|
1422
|
+
operator.
|
|
1423
|
+
|
|
1424
|
+
OUTPUT: tensor field of rank `k`-``len(indices)``
|
|
1425
|
+
|
|
1426
|
+
EXAMPLES:
|
|
1427
|
+
|
|
1428
|
+
Foliation of the Euclidean 3-space by 2-spheres parametrized by their
|
|
1429
|
+
radii::
|
|
1430
|
+
|
|
1431
|
+
sage: M.<x,y,z> = EuclideanSpace()
|
|
1432
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian')
|
|
1433
|
+
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
|
|
1434
|
+
sage: r = var('r', domain='real') # foliation parameter
|
|
1435
|
+
sage: assume(r>0)
|
|
1436
|
+
sage: E = M.cartesian_coordinates()
|
|
1437
|
+
sage: phi = N.diff_map(M, {(C,E): [r*sin(th)*cos(ph),
|
|
1438
|
+
....: r*sin(th)*sin(ph),
|
|
1439
|
+
....: r*cos(th)]})
|
|
1440
|
+
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
|
|
1441
|
+
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
|
|
1442
|
+
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
|
|
1443
|
+
....: t_inverse={r: phi_inv_r})
|
|
1444
|
+
sage: T = N.adapted_chart()
|
|
1445
|
+
|
|
1446
|
+
If ``indices`` is not specified, the mixed projection of the ambient
|
|
1447
|
+
metric coincides with the first fundamental form::
|
|
1448
|
+
|
|
1449
|
+
sage: g = M.metric()
|
|
1450
|
+
sage: gpp = N.mixed_projection(g); gpp # long time
|
|
1451
|
+
Tensor field of type (0,2) on the Euclidean space E^3
|
|
1452
|
+
sage: gpp == N.ambient_first_fundamental_form() # long time
|
|
1453
|
+
True
|
|
1454
|
+
|
|
1455
|
+
The other non-redundant projections are::
|
|
1456
|
+
|
|
1457
|
+
sage: gnp = N.mixed_projection(g, [0]); gnp # long time
|
|
1458
|
+
1-form on the Euclidean space E^3
|
|
1459
|
+
|
|
1460
|
+
and::
|
|
1461
|
+
|
|
1462
|
+
sage: gnn = N.mixed_projection(g, [0,1]); gnn
|
|
1463
|
+
Scalar field on the Euclidean space E^3
|
|
1464
|
+
|
|
1465
|
+
which is constant and equal to 1 (the norm of the unit normal vector)::
|
|
1466
|
+
|
|
1467
|
+
sage: gnn.display()
|
|
1468
|
+
E^3 → ℝ
|
|
1469
|
+
(x, y, z) ↦ 1
|
|
1470
|
+
(th_E3, ph_E3, r_E3) ↦ 1
|
|
1471
|
+
"""
|
|
1472
|
+
if self._ambient._dim - self._dim != 1:
|
|
1473
|
+
raise NotImplementedError("mixed_projection() is implemented only "
|
|
1474
|
+
"for hypersurfaces")
|
|
1475
|
+
if isinstance(indices, (Integer, int)):
|
|
1476
|
+
indices = list(range(indices))
|
|
1477
|
+
|
|
1478
|
+
if len(indices) > tensor.tensor_rank():
|
|
1479
|
+
raise ValueError("Too much contractions")
|
|
1480
|
+
|
|
1481
|
+
g = self.ambient_metric()
|
|
1482
|
+
if self._dim_foliation == 0:
|
|
1483
|
+
g = g.along(self._immersion)
|
|
1484
|
+
|
|
1485
|
+
multiprojector = 1
|
|
1486
|
+
k = tensor.tensor_rank() # order of the tensor
|
|
1487
|
+
kp = 2 * k - len(indices) # order of the multiprojector
|
|
1488
|
+
for i in range(tensor.tensor_type()[1]):
|
|
1489
|
+
if i in indices:
|
|
1490
|
+
multiprojector = multiprojector * self.normal()
|
|
1491
|
+
else:
|
|
1492
|
+
multiprojector = multiprojector * self.projector()
|
|
1493
|
+
for i in range(tensor.tensor_type()[0]):
|
|
1494
|
+
if i in indices:
|
|
1495
|
+
multiprojector = multiprojector * self.normal().contract(g)
|
|
1496
|
+
else:
|
|
1497
|
+
multiprojector = multiprojector * self.projector()
|
|
1498
|
+
args = list(range(kp - tensor.tensor_type()[0], kp)) + list(range(
|
|
1499
|
+
tensor.tensor_type()[1])) + [tensor] + list(range(k))
|
|
1500
|
+
return multiprojector.contract(*args)
|
|
1501
|
+
|
|
1502
|
+
@cached_method
|
|
1503
|
+
def gauss_curvature(self):
|
|
1504
|
+
r"""
|
|
1505
|
+
Return the Gauss curvature of the submanifold.
|
|
1506
|
+
|
|
1507
|
+
The *Gauss curvature* is the product or the principal curvatures, or
|
|
1508
|
+
equivalently the determinant of the projection operator.
|
|
1509
|
+
|
|
1510
|
+
The result is cached, so calling this method multiple times always
|
|
1511
|
+
returns the same result at no additional cost.
|
|
1512
|
+
|
|
1513
|
+
OUTPUT: the Gauss curvature as a scalar field on the submanifold
|
|
1514
|
+
|
|
1515
|
+
EXAMPLES:
|
|
1516
|
+
|
|
1517
|
+
A unit circle embedded in the Euclidean plane::
|
|
1518
|
+
|
|
1519
|
+
sage: M.<X,Y> = EuclideanSpace()
|
|
1520
|
+
sage: N = Manifold(1, 'N', ambient=M, structure='Riemannian')
|
|
1521
|
+
sage: U = N.open_subset('U')
|
|
1522
|
+
sage: V = N.open_subset('V')
|
|
1523
|
+
sage: N.declare_union(U,V)
|
|
1524
|
+
sage: stereoN.<x> = U.chart()
|
|
1525
|
+
sage: stereoS.<y> = V.chart()
|
|
1526
|
+
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
|
|
1527
|
+
....: intersection_name='W',
|
|
1528
|
+
....: restrictions1=x!=0, restrictions2=y!=0)
|
|
1529
|
+
sage: stereoS_to_N = stereoN_to_S.inverse()
|
|
1530
|
+
sage: E = M.cartesian_coordinates()
|
|
1531
|
+
sage: phi = N.diff_map(M,
|
|
1532
|
+
....: {(stereoN, E): [1/sqrt(1+x^2/4), x/2/sqrt(1+x^2/4)],
|
|
1533
|
+
....: (stereoS, E): [1/sqrt(1+4/y^2), 2/y/sqrt(1+4/y^2)]})
|
|
1534
|
+
sage: N.set_embedding(phi)
|
|
1535
|
+
sage: N.gauss_curvature() # long time
|
|
1536
|
+
Scalar field on the 1-dimensional Riemannian submanifold N embedded
|
|
1537
|
+
in the Euclidean plane E^2
|
|
1538
|
+
sage: N.gauss_curvature().display() # long time
|
|
1539
|
+
N → ℝ
|
|
1540
|
+
on U: x ↦ -1
|
|
1541
|
+
on V: y ↦ -1
|
|
1542
|
+
"""
|
|
1543
|
+
if self._ambient._dim - self._dim != 1:
|
|
1544
|
+
raise ValueError("gauss_curvature is defined only for "
|
|
1545
|
+
"hypersurfaces")
|
|
1546
|
+
a = self.shape_operator()
|
|
1547
|
+
self._gauss_curvature = self.scalar_field(
|
|
1548
|
+
{chart: a[chart.frame(), :, chart].determinant()
|
|
1549
|
+
for chart in self.top_charts()})
|
|
1550
|
+
return self._gauss_curvature
|
|
1551
|
+
|
|
1552
|
+
@cached_method
|
|
1553
|
+
def principal_directions(self, chart):
|
|
1554
|
+
r"""
|
|
1555
|
+
Return the principal directions of the submanifold.
|
|
1556
|
+
|
|
1557
|
+
The *principal directions* are the eigenvectors of the projection
|
|
1558
|
+
operator. The result is formatted as a list of pairs
|
|
1559
|
+
(eigenvector, eigenvalue).
|
|
1560
|
+
|
|
1561
|
+
The result is cached, so calling this method multiple times always
|
|
1562
|
+
returns the same result at no additional cost.
|
|
1563
|
+
|
|
1564
|
+
INPUT:
|
|
1565
|
+
|
|
1566
|
+
- ``chart`` -- chart in which the principal directions are to be
|
|
1567
|
+
computed
|
|
1568
|
+
|
|
1569
|
+
OUTPUT:
|
|
1570
|
+
|
|
1571
|
+
- list of pairs (vector field, scalar field) representing the
|
|
1572
|
+
principal directions and the associated principal curvatures
|
|
1573
|
+
|
|
1574
|
+
EXAMPLES:
|
|
1575
|
+
|
|
1576
|
+
A unit circle embedded in the Euclidean plane::
|
|
1577
|
+
|
|
1578
|
+
sage: M.<X,Y> = EuclideanSpace()
|
|
1579
|
+
sage: N = Manifold(1, 'N', ambient=M, structure='Riemannian')
|
|
1580
|
+
sage: U = N.open_subset('U')
|
|
1581
|
+
sage: V = N.open_subset('V')
|
|
1582
|
+
sage: N.declare_union(U,V)
|
|
1583
|
+
sage: stereoN.<x> = U.chart()
|
|
1584
|
+
sage: stereoS.<y> = V.chart()
|
|
1585
|
+
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
|
|
1586
|
+
....: intersection_name='W',
|
|
1587
|
+
....: restrictions1=x!=0, restrictions2=y!=0)
|
|
1588
|
+
sage: stereoS_to_N = stereoN_to_S.inverse()
|
|
1589
|
+
sage: E = M.cartesian_coordinates()
|
|
1590
|
+
sage: phi = N.diff_map(M,
|
|
1591
|
+
....: {(stereoN, E): [1/sqrt(1+x^2/4), x/2/sqrt(1+x^2/4)],
|
|
1592
|
+
....: (stereoS, E): [1/sqrt(1+4/y^2), 2/y/sqrt(1+4/y^2)]})
|
|
1593
|
+
sage: N.set_embedding(phi)
|
|
1594
|
+
sage: N.principal_directions(stereoN) # long time
|
|
1595
|
+
[(Vector field e_0 on the 1-dimensional Riemannian submanifold N
|
|
1596
|
+
embedded in the Euclidean plane E^2, -1)]
|
|
1597
|
+
sage: N.principal_directions(stereoN)[0][0].display() # long time
|
|
1598
|
+
e_0 = ∂/∂x
|
|
1599
|
+
"""
|
|
1600
|
+
if self._ambient._dim - self._dim != 1:
|
|
1601
|
+
raise ValueError("principal directions is defined only for "
|
|
1602
|
+
"hypersurfaces")
|
|
1603
|
+
a = self.shape_operator()
|
|
1604
|
+
pr_d = matrix(
|
|
1605
|
+
[[a[chart.frame(), :, chart][i, j].expr() for i in self.irange()]
|
|
1606
|
+
for j in self.irange()]).eigenvectors_right()
|
|
1607
|
+
res = []
|
|
1608
|
+
v = self.vector_field()
|
|
1609
|
+
counter = self.irange()
|
|
1610
|
+
for eigen_space in pr_d:
|
|
1611
|
+
for eigen_vector in eigen_space[1]:
|
|
1612
|
+
v[chart.frame(), :] = eigen_vector
|
|
1613
|
+
res.append((v.copy(), eigen_space[0]))
|
|
1614
|
+
res[-1][0].set_name("e_{}".format(next(counter)))
|
|
1615
|
+
self._principal_directions[chart] = res
|
|
1616
|
+
return res
|
|
1617
|
+
|
|
1618
|
+
@cached_method
|
|
1619
|
+
def principal_curvatures(self, chart):
|
|
1620
|
+
r"""
|
|
1621
|
+
Return the principal curvatures of the submanifold.
|
|
1622
|
+
|
|
1623
|
+
The *principal curvatures* are the eigenvalues of the projection
|
|
1624
|
+
operator. The resulting scalar fields are named ``k_i`` with the
|
|
1625
|
+
index ``i`` ranging from 0 to the submanifold dimension minus one.
|
|
1626
|
+
|
|
1627
|
+
The result is cached, so calling this method multiple times always
|
|
1628
|
+
returns the same result at no additional cost.
|
|
1629
|
+
|
|
1630
|
+
INPUT:
|
|
1631
|
+
|
|
1632
|
+
- ``chart`` -- chart in which the principal curvatures are to be
|
|
1633
|
+
computed
|
|
1634
|
+
|
|
1635
|
+
OUTPUT:
|
|
1636
|
+
|
|
1637
|
+
- the principal curvatures, as a list of scalar fields on the
|
|
1638
|
+
submanifold
|
|
1639
|
+
|
|
1640
|
+
EXAMPLES:
|
|
1641
|
+
|
|
1642
|
+
A unit circle embedded in the Euclidean plane::
|
|
1643
|
+
|
|
1644
|
+
sage: M.<X,Y> = EuclideanSpace()
|
|
1645
|
+
sage: N = Manifold(1, 'N', ambient=M, structure='Riemannian')
|
|
1646
|
+
sage: U = N.open_subset('U')
|
|
1647
|
+
sage: V = N.open_subset('V')
|
|
1648
|
+
sage: N.declare_union(U,V)
|
|
1649
|
+
sage: stereoN.<x> = U.chart()
|
|
1650
|
+
sage: stereoS.<y> = V.chart()
|
|
1651
|
+
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
|
|
1652
|
+
....: intersection_name='W',
|
|
1653
|
+
....: restrictions1=x!=0, restrictions2=y!=0)
|
|
1654
|
+
sage: stereoS_to_N = stereoN_to_S.inverse()
|
|
1655
|
+
sage: E = M.cartesian_coordinates()
|
|
1656
|
+
sage: phi = N.diff_map(M,
|
|
1657
|
+
....: {(stereoN, E): [1/sqrt(1+x^2/4), x/2/sqrt(1+x^2/4)],
|
|
1658
|
+
....: (stereoS, E): [1/sqrt(1+4/y^2), 2/y/sqrt(1+4/y^2)]})
|
|
1659
|
+
sage: N.set_embedding(phi)
|
|
1660
|
+
sage: N.principal_curvatures(stereoN) # long time
|
|
1661
|
+
[Scalar field k_0 on the 1-dimensional Riemannian submanifold N
|
|
1662
|
+
embedded in the Euclidean plane E^2]
|
|
1663
|
+
sage: N.principal_curvatures(stereoN)[0].display() # long time
|
|
1664
|
+
k_0: N → ℝ
|
|
1665
|
+
on U: x ↦ -1
|
|
1666
|
+
on W: y ↦ -1
|
|
1667
|
+
"""
|
|
1668
|
+
if self._ambient._dim - self._dim != 1:
|
|
1669
|
+
raise ValueError("principal_curvatures is defined only for "
|
|
1670
|
+
"hypersurfaces")
|
|
1671
|
+
a = self.shape_operator()
|
|
1672
|
+
res = matrix(
|
|
1673
|
+
[[a[chart.frame(), :, chart][i, j].expr() for i in self.irange()]
|
|
1674
|
+
for j in self.irange()]).eigenvalues()
|
|
1675
|
+
counter = self.irange()
|
|
1676
|
+
for i in range(self._dim):
|
|
1677
|
+
res[i] = self.scalar_field({chart: res[i]},
|
|
1678
|
+
name="k_{}".format(next(counter)))
|
|
1679
|
+
self._principal_curvatures[chart] = res
|
|
1680
|
+
return res
|
|
1681
|
+
|
|
1682
|
+
@cached_method
|
|
1683
|
+
def mean_curvature(self):
|
|
1684
|
+
r"""
|
|
1685
|
+
Return the mean curvature of the submanifold.
|
|
1686
|
+
|
|
1687
|
+
The *mean curvature* is the arithmetic mean of the principal curvatures,
|
|
1688
|
+
or equivalently the trace of the projection operator.
|
|
1689
|
+
|
|
1690
|
+
The result is cached, so calling this method multiple times always
|
|
1691
|
+
returns the same result at no additional cost.
|
|
1692
|
+
|
|
1693
|
+
OUTPUT: the mean curvature, as a scalar field on the submanifold
|
|
1694
|
+
|
|
1695
|
+
EXAMPLES:
|
|
1696
|
+
|
|
1697
|
+
A unit circle embedded in the Euclidean plane::
|
|
1698
|
+
|
|
1699
|
+
sage: M.<X,Y> = EuclideanSpace()
|
|
1700
|
+
sage: N = Manifold(1, 'N', ambient=M, structure='Riemannian')
|
|
1701
|
+
sage: U = N.open_subset('U')
|
|
1702
|
+
sage: V = N.open_subset('V')
|
|
1703
|
+
sage: N.declare_union(U,V)
|
|
1704
|
+
sage: stereoN.<x> = U.chart()
|
|
1705
|
+
sage: stereoS.<y> = V.chart()
|
|
1706
|
+
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
|
|
1707
|
+
....: intersection_name='W',
|
|
1708
|
+
....: restrictions1=x!=0, restrictions2=y!=0)
|
|
1709
|
+
sage: stereoS_to_N = stereoN_to_S.inverse()
|
|
1710
|
+
sage: E = M.cartesian_coordinates()
|
|
1711
|
+
sage: phi = N.diff_map(M,
|
|
1712
|
+
....: {(stereoN, E): [1/sqrt(1+x^2/4), x/2/sqrt(1+x^2/4)],
|
|
1713
|
+
....: (stereoS, E): [1/sqrt(1+4/y^2), 2/y/sqrt(1+4/y^2)]})
|
|
1714
|
+
sage: N.set_embedding(phi)
|
|
1715
|
+
sage: N.mean_curvature() # long time
|
|
1716
|
+
Scalar field on the 1-dimensional Riemannian submanifold N
|
|
1717
|
+
embedded in the Euclidean plane E^2
|
|
1718
|
+
sage: N.mean_curvature().display() # long time
|
|
1719
|
+
N → ℝ
|
|
1720
|
+
on U: x ↦ -1
|
|
1721
|
+
on V: y ↦ -1
|
|
1722
|
+
"""
|
|
1723
|
+
if self._ambient._dim - self._dim != 1:
|
|
1724
|
+
raise ValueError("mean_curvature is defined only for "
|
|
1725
|
+
"hypersurfaces")
|
|
1726
|
+
self._shape_operator = self.scalar_field({chart: self._sgn * sum(
|
|
1727
|
+
self.principal_curvatures(chart)).expr(chart) / self._dim
|
|
1728
|
+
for chart in
|
|
1729
|
+
self.top_charts()})
|
|
1730
|
+
return self._shape_operator
|
|
1731
|
+
|
|
1732
|
+
@cached_method
|
|
1733
|
+
def shape_operator(self):
|
|
1734
|
+
r"""
|
|
1735
|
+
Return the shape operator of the submanifold.
|
|
1736
|
+
|
|
1737
|
+
The shape operator is equal to the second fundamental form with one of
|
|
1738
|
+
the indices upped.
|
|
1739
|
+
|
|
1740
|
+
The result is cached, so calling this method multiple times always
|
|
1741
|
+
returns the same result at no additional cost.
|
|
1742
|
+
|
|
1743
|
+
OUTPUT:
|
|
1744
|
+
|
|
1745
|
+
- the shape operator, as a tensor field of type (1,1) on the
|
|
1746
|
+
submanifold
|
|
1747
|
+
|
|
1748
|
+
EXAMPLES:
|
|
1749
|
+
|
|
1750
|
+
A unit circle embedded in the Euclidean plane::
|
|
1751
|
+
|
|
1752
|
+
sage: M.<X,Y> = EuclideanSpace()
|
|
1753
|
+
sage: N = Manifold(1, 'N', ambient=M, structure='Riemannian')
|
|
1754
|
+
sage: U = N.open_subset('U')
|
|
1755
|
+
sage: V = N.open_subset('V')
|
|
1756
|
+
sage: N.declare_union(U,V)
|
|
1757
|
+
sage: stereoN.<x> = U.chart()
|
|
1758
|
+
sage: stereoS.<y> = V.chart()
|
|
1759
|
+
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
|
|
1760
|
+
....: intersection_name='W',
|
|
1761
|
+
....: restrictions1=x!=0, restrictions2=y!=0)
|
|
1762
|
+
sage: stereoS_to_N = stereoN_to_S.inverse()
|
|
1763
|
+
sage: E = M.cartesian_coordinates()
|
|
1764
|
+
sage: phi = N.diff_map(M,
|
|
1765
|
+
....: {(stereoN, E): [1/sqrt(1+x^2/4), x/2/sqrt(1+x^2/4)],
|
|
1766
|
+
....: (stereoS, E): [1/sqrt(1+4/y^2), 2/y/sqrt(1+4/y^2)]})
|
|
1767
|
+
sage: N.set_embedding(phi)
|
|
1768
|
+
sage: N.shape_operator() # long time
|
|
1769
|
+
Tensor field of type (1,1) on the 1-dimensional Riemannian
|
|
1770
|
+
submanifold N embedded in the Euclidean plane E^2
|
|
1771
|
+
sage: N.shape_operator().display() # long time
|
|
1772
|
+
-∂/∂x⊗dx
|
|
1773
|
+
"""
|
|
1774
|
+
if self._ambient._dim - self._dim != 1:
|
|
1775
|
+
raise ValueError("shape_operator is defined only for "
|
|
1776
|
+
"hypersurfaces")
|
|
1777
|
+
self._shape_operator = self.second_fundamental_form().contract(
|
|
1778
|
+
self.induced_metric().inverse())
|
|
1779
|
+
return self._shape_operator
|
|
1780
|
+
|
|
1781
|
+
def clear_cache(self):
|
|
1782
|
+
r"""
|
|
1783
|
+
Reset all the cached functions and the derived quantities.
|
|
1784
|
+
|
|
1785
|
+
Use this function if you modified the immersion (or embedding) of the
|
|
1786
|
+
submanifold. Note that when calling a calculus function after clearing,
|
|
1787
|
+
new Python objects will be created.
|
|
1788
|
+
|
|
1789
|
+
EXAMPLES::
|
|
1790
|
+
|
|
1791
|
+
sage: M.<x,y,z> = EuclideanSpace()
|
|
1792
|
+
sage: N = Manifold(2, 'N', ambient=M, structure='Riemannian')
|
|
1793
|
+
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
|
|
1794
|
+
sage: r = var('r', domain='real') # foliation parameter
|
|
1795
|
+
sage: assume(r>0)
|
|
1796
|
+
sage: E = M.cartesian_coordinates()
|
|
1797
|
+
sage: phi = N.diff_map(M, {(C,E): [r*sin(th)*cos(ph),
|
|
1798
|
+
....: r*sin(th)*sin(ph),
|
|
1799
|
+
....: r*cos(th)]})
|
|
1800
|
+
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
|
|
1801
|
+
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
|
|
1802
|
+
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
|
|
1803
|
+
....: t_inverse={r: phi_inv_r})
|
|
1804
|
+
sage: T = N.adapted_chart()
|
|
1805
|
+
sage: n = N.normal()
|
|
1806
|
+
sage: n is N.normal()
|
|
1807
|
+
True
|
|
1808
|
+
sage: N.clear_cache()
|
|
1809
|
+
sage: n is N.normal()
|
|
1810
|
+
False
|
|
1811
|
+
sage: n == N.normal()
|
|
1812
|
+
True
|
|
1813
|
+
"""
|
|
1814
|
+
self.difft.clear_cache()
|
|
1815
|
+
self.gradt.clear_cache()
|
|
1816
|
+
self.normal.clear_cache()
|
|
1817
|
+
self.lapse.clear_cache()
|
|
1818
|
+
self.shift.clear_cache()
|
|
1819
|
+
self.projector.clear_cache()
|
|
1820
|
+
self.gauss_curvature.clear_cache()
|
|
1821
|
+
self.principal_directions.clear_cache()
|
|
1822
|
+
self.principal_curvatures.clear_cache()
|
|
1823
|
+
self.shape_operator.clear_cache()
|
|
1824
|
+
self._difft = None
|
|
1825
|
+
self._gradt = None
|
|
1826
|
+
self._normal = None
|
|
1827
|
+
self._lapse = None
|
|
1828
|
+
self._shift = None
|
|
1829
|
+
self._first_fundamental_form = None
|
|
1830
|
+
self._ambient_first_fundamental_form = None
|
|
1831
|
+
self._second_fundamental_form = None
|
|
1832
|
+
self._ambient_second_fundamental_form = None
|
|
1833
|
+
self._ambient_metric = None
|
|
1834
|
+
self._projector = None
|
|
1835
|
+
self._gauss_curvature = None
|
|
1836
|
+
self._principal_directions = {}
|
|
1837
|
+
self._principal_curvatures = {}
|
|
1838
|
+
self._mean_curvature = None
|
|
1839
|
+
self._shape_operator = None
|