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