passagemath-symbolics 10.8.1a1__cp314-cp314t-musllinux_1_2_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_symbolics/__init__.py +3 -0
- passagemath_symbolics-10.8.1a1.dist-info/METADATA +186 -0
- passagemath_symbolics-10.8.1a1.dist-info/RECORD +181 -0
- passagemath_symbolics-10.8.1a1.dist-info/WHEEL +5 -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-314t-aarch64-linux-musl.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-314t-aarch64-linux-musl.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-314t-aarch64-linux-musl.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-314t-aarch64-linux-musl.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-314t-aarch64-linux-musl.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,1186 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-symbolics
|
|
2
|
+
r"""
|
|
3
|
+
Spheres smoothly embedded in Euclidean Space
|
|
4
|
+
|
|
5
|
+
Let `E^{n+1}` be a Euclidean space of dimension `n+1` and `c \in E^{n+1}`. An
|
|
6
|
+
`n`-sphere with radius `r` and centered at `c`, usually denoted by
|
|
7
|
+
`\mathbb{S}^n_r(c)`, smoothly embedded in the Euclidean space `E^{n+1}` is an
|
|
8
|
+
`n`-dimensional smooth manifold together with a smooth embedding
|
|
9
|
+
|
|
10
|
+
.. MATH::
|
|
11
|
+
|
|
12
|
+
\iota \colon \mathbb{S}^n_r \to E^{n+1}
|
|
13
|
+
|
|
14
|
+
whose image consists of all points having the same Euclidean distance to the
|
|
15
|
+
fixed point `c`. If we choose Cartesian coordinates `(x_1, \ldots, x_{n+1})` on
|
|
16
|
+
`E^{n+1}` with `x(c)=0` then the above translates to
|
|
17
|
+
|
|
18
|
+
.. MATH::
|
|
19
|
+
|
|
20
|
+
\iota(\mathbb{S}^n_r(c)) = \left\{ p \in E^{n+1} : \lVert x(p) \rVert = r \right\}.
|
|
21
|
+
|
|
22
|
+
This corresponds to the standard `n`-sphere of radius `r` centered at `c`.
|
|
23
|
+
|
|
24
|
+
AUTHORS:
|
|
25
|
+
|
|
26
|
+
- Michael Jung (2020): initial version
|
|
27
|
+
|
|
28
|
+
REFERENCES:
|
|
29
|
+
|
|
30
|
+
- \M. Berger: *Geometry I&II* [Ber1987]_, [Ber1987a]_
|
|
31
|
+
- \J. Lee: *Introduction to Smooth Manifolds* [Lee2013]_
|
|
32
|
+
|
|
33
|
+
EXAMPLES:
|
|
34
|
+
|
|
35
|
+
We start by defining a 2-sphere of unspecified radius `r`::
|
|
36
|
+
|
|
37
|
+
sage: r = var('r')
|
|
38
|
+
sage: S2_r = manifolds.Sphere(2, radius=r); S2_r
|
|
39
|
+
2-sphere S^2_r of radius r smoothly embedded in the Euclidean space E^3
|
|
40
|
+
|
|
41
|
+
The embedding `\iota` is constructed from scratch and can be returned by the
|
|
42
|
+
following command::
|
|
43
|
+
|
|
44
|
+
sage: i = S2_r.embedding(); i
|
|
45
|
+
Differentiable map iota from the 2-sphere S^2_r of radius r smoothly
|
|
46
|
+
embedded in the Euclidean space E^3 to the Euclidean space E^3
|
|
47
|
+
sage: i.display()
|
|
48
|
+
iota: S^2_r → E^3
|
|
49
|
+
on A: (theta, phi) ↦ (x, y, z) = (r*cos(phi)*sin(theta),
|
|
50
|
+
r*sin(phi)*sin(theta),
|
|
51
|
+
r*cos(theta))
|
|
52
|
+
|
|
53
|
+
As a submanifold of a Riemannian manifold, namely the Euclidean space,
|
|
54
|
+
the 2-sphere admits an induced metric::
|
|
55
|
+
|
|
56
|
+
sage: g = S2_r.induced_metric()
|
|
57
|
+
sage: g.display()
|
|
58
|
+
g = r^2 dtheta⊗dtheta + r^2*sin(theta)^2 dphi⊗dphi
|
|
59
|
+
|
|
60
|
+
The induced metric is also known as the *first fundamental form* (see
|
|
61
|
+
:meth:`~sage.manifolds.differentiable.pseudo_riemannian_submanifold.PseudoRiemannianSubmanifold.first_fundamental_form`)::
|
|
62
|
+
|
|
63
|
+
sage: g is S2_r.first_fundamental_form()
|
|
64
|
+
True
|
|
65
|
+
|
|
66
|
+
The *second fundamental form* encodes the extrinsic curvature of the
|
|
67
|
+
2-sphere as hypersurface of Euclidean space (see
|
|
68
|
+
:meth:`~sage.manifolds.differentiable.pseudo_riemannian_submanifold.PseudoRiemannianSubmanifold.second_fundamental_form`)::
|
|
69
|
+
|
|
70
|
+
sage: K = S2_r.second_fundamental_form(); K
|
|
71
|
+
Field of symmetric bilinear forms K on the 2-sphere S^2_r of radius r
|
|
72
|
+
smoothly embedded in the Euclidean space E^3
|
|
73
|
+
sage: K.display()
|
|
74
|
+
K = r dtheta⊗dtheta + r*sin(theta)^2 dphi⊗dphi
|
|
75
|
+
|
|
76
|
+
One quantity that can be derived from the second fundamental form is the
|
|
77
|
+
Gaussian curvature::
|
|
78
|
+
|
|
79
|
+
sage: K = S2_r.gauss_curvature()
|
|
80
|
+
sage: K.display()
|
|
81
|
+
S^2_r → ℝ
|
|
82
|
+
on A: (theta, phi) ↦ r^(-2)
|
|
83
|
+
|
|
84
|
+
As we have seen, spherical coordinates are initialized by default. To
|
|
85
|
+
initialize stereographic coordinates retrospectively, we can use the following
|
|
86
|
+
command::
|
|
87
|
+
|
|
88
|
+
sage: S2_r.stereographic_coordinates()
|
|
89
|
+
Chart (S^2_r-{NP}, (y1, y2))
|
|
90
|
+
|
|
91
|
+
To get all charts corresponding to stereographic coordinates, we can use the
|
|
92
|
+
:meth:`~sage.manifolds.differentiable.examples.sphere.Sphere.coordinate_charts`::
|
|
93
|
+
|
|
94
|
+
sage: stereoN, stereoS = S2_r.coordinate_charts('stereographic')
|
|
95
|
+
sage: stereoN, stereoS
|
|
96
|
+
(Chart (S^2_r-{NP}, (y1, y2)), Chart (S^2_r-{SP}, (yp1, yp2)))
|
|
97
|
+
|
|
98
|
+
.. SEEALSO::
|
|
99
|
+
|
|
100
|
+
See :meth:`~sage.manifolds.differentiable.examples.sphere.Sphere.stereographic_coordinates`
|
|
101
|
+
and :meth:`~sage.manifolds.differentiable.examples.sphere.Sphere.spherical_coordinates`
|
|
102
|
+
for details.
|
|
103
|
+
|
|
104
|
+
.. NOTE::
|
|
105
|
+
|
|
106
|
+
Notice that the derived quantities such as the embedding as well as the
|
|
107
|
+
first and second fundamental forms must be computed from scratch again
|
|
108
|
+
when new coordinates have been initialized. That makes the usage of
|
|
109
|
+
previously declared objects obsolete.
|
|
110
|
+
|
|
111
|
+
Consider now a 1-sphere with barycenter `(1,0)` in Cartesian coordinates::
|
|
112
|
+
|
|
113
|
+
sage: E2 = EuclideanSpace(2)
|
|
114
|
+
sage: c = E2.point((1,0), name='c')
|
|
115
|
+
sage: S1c.<chi> = E2.sphere(center=c); S1c
|
|
116
|
+
1-sphere S^1(c) of radius 1 smoothly embedded in the Euclidean plane
|
|
117
|
+
E^2 centered at the Point c
|
|
118
|
+
sage: S1c.spherical_coordinates()
|
|
119
|
+
Chart (A, (chi,))
|
|
120
|
+
|
|
121
|
+
Get stereographic coordinates::
|
|
122
|
+
|
|
123
|
+
sage: stereoN, stereoS = S1c.coordinate_charts('stereographic')
|
|
124
|
+
sage: stereoN, stereoS
|
|
125
|
+
(Chart (S^1(c)-{NP}, (y1,)), Chart (S^1(c)-{SP}, (yp1,)))
|
|
126
|
+
|
|
127
|
+
The embedding takes now the following form in all coordinates::
|
|
128
|
+
|
|
129
|
+
sage: S1c.embedding().display()
|
|
130
|
+
iota: S^1(c) → E^2
|
|
131
|
+
on A: chi ↦ (x, y) = (cos(chi) + 1, sin(chi))
|
|
132
|
+
on S^1(c)-{NP}: y1 ↦ (x, y) = (2*y1/(y1^2 + 1) + 1, (y1^2 - 1)/(y1^2 + 1))
|
|
133
|
+
on S^1(c)-{SP}: yp1 ↦ (x, y) = (2*yp1/(yp1^2 + 1) + 1, -(yp1^2 - 1)/(yp1^2 + 1))
|
|
134
|
+
|
|
135
|
+
Since the sphere is a hypersurface, we can get a normal vector field by using
|
|
136
|
+
``normal``::
|
|
137
|
+
|
|
138
|
+
sage: n = S1c.normal(); n
|
|
139
|
+
Vector field n along the 1-sphere S^1(c) of radius 1 smoothly embedded in
|
|
140
|
+
the Euclidean plane E^2 centered at the Point c with values on the
|
|
141
|
+
Euclidean plane E^2
|
|
142
|
+
sage: n.display()
|
|
143
|
+
n = -cos(chi) e_x - sin(chi) e_y
|
|
144
|
+
|
|
145
|
+
Notice that this is just *one* normal field with arbitrary direction,
|
|
146
|
+
in this particular case `n` points inwards whereas `-n` points outwards.
|
|
147
|
+
However, the vector field `n` is indeed non-vanishing and hence the sphere
|
|
148
|
+
admits an orientation (as all spheres do)::
|
|
149
|
+
|
|
150
|
+
sage: orient = S1c.orientation(); orient
|
|
151
|
+
[Coordinate frame (S^1(c)-{SP}, (∂/∂yp1)), Vector frame (S^1(c)-{NP}, (f_1))]
|
|
152
|
+
sage: f = orient[1]
|
|
153
|
+
sage: f[1].display()
|
|
154
|
+
f_1 = -∂/∂y1
|
|
155
|
+
|
|
156
|
+
Notice that the orientation is chosen is such a way that `(\iota_*(f_1), -n)`
|
|
157
|
+
is oriented in the ambient Euclidean space, i.e. the last entry is the normal
|
|
158
|
+
vector field pointing outwards. Henceforth, the manifold admits
|
|
159
|
+
a volume form::
|
|
160
|
+
|
|
161
|
+
sage: g = S1c.induced_metric()
|
|
162
|
+
sage: g.display()
|
|
163
|
+
g = dchi⊗dchi
|
|
164
|
+
sage: eps = g.volume_form()
|
|
165
|
+
sage: eps.display()
|
|
166
|
+
eps_g = -dchi
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
from sage.categories.manifolds import Manifolds
|
|
170
|
+
from sage.categories.metric_spaces import MetricSpaces
|
|
171
|
+
from sage.categories.topological_spaces import TopologicalSpaces
|
|
172
|
+
from sage.manifolds.differentiable.examples.euclidean import EuclideanSpace
|
|
173
|
+
from sage.manifolds.differentiable.pseudo_riemannian_submanifold import (
|
|
174
|
+
PseudoRiemannianSubmanifold,
|
|
175
|
+
)
|
|
176
|
+
from sage.rings.real_mpfr import RR
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class Sphere(PseudoRiemannianSubmanifold):
|
|
180
|
+
r"""
|
|
181
|
+
Sphere smoothly embedded in Euclidean Space.
|
|
182
|
+
|
|
183
|
+
An `n`-sphere of radius `r`smoothly embedded in a Euclidean space `E^{n+1}`
|
|
184
|
+
is a smooth `n`-dimensional manifold smoothly embedded into `E^{n+1}`,
|
|
185
|
+
such that the embedding constitutes a standard `n`-sphere of radius `r`
|
|
186
|
+
in that Euclidean space (possibly shifted by a point).
|
|
187
|
+
|
|
188
|
+
- ``n`` -- positive integer representing dimension of the sphere
|
|
189
|
+
- ``radius`` -- (default: ``1``) positive number that states the radius
|
|
190
|
+
of the sphere
|
|
191
|
+
- ``name`` -- (default: ``None``) string; name (symbol) given to the
|
|
192
|
+
sphere; if ``None``, the name will be set according to the input
|
|
193
|
+
(see convention above)
|
|
194
|
+
- ``ambient_space`` -- (default: ``None``) Euclidean space in which the
|
|
195
|
+
sphere should be embedded; if ``None``, a new instance of Euclidean
|
|
196
|
+
space is created
|
|
197
|
+
- ``center`` -- (default: ``None``) the barycenter of the sphere as point of
|
|
198
|
+
the ambient Euclidean space; if ``None`` the barycenter is set to the
|
|
199
|
+
origin of the ambient space's standard Cartesian coordinates
|
|
200
|
+
- ``latex_name`` -- (default: ``None``) string; LaTeX symbol to
|
|
201
|
+
denote the space; if ``None``, it will be set according to the input
|
|
202
|
+
(see convention above)
|
|
203
|
+
- ``coordinates`` -- (default: ``'spherical'``) string describing the
|
|
204
|
+
type of coordinates to be initialized at the sphere's creation; allowed
|
|
205
|
+
values are
|
|
206
|
+
|
|
207
|
+
- ``'spherical'`` spherical coordinates (see
|
|
208
|
+
:meth:`~sage.manifolds.differentiable.examples.sphere.Sphere.spherical_coordinates`))
|
|
209
|
+
- ``'stereographic'`` stereographic coordinates given by the
|
|
210
|
+
stereographic projection (see
|
|
211
|
+
:meth:`~sage.manifolds.differentiable.examples.sphere.Sphere.stereographic_coordinates`)
|
|
212
|
+
|
|
213
|
+
- ``names`` -- (default: ``None``) must be a tuple containing
|
|
214
|
+
the coordinate symbols (this guarantees the shortcut operator
|
|
215
|
+
``<,>`` to function); if ``None``, the usual conventions are used (see
|
|
216
|
+
examples below for details)
|
|
217
|
+
- ``unique_tag`` -- (default: ``None``) tag used to force the construction
|
|
218
|
+
of a new object when all the other arguments have been used previously
|
|
219
|
+
(without ``unique_tag``, the
|
|
220
|
+
:class:`~sage.structure.unique_representation.UniqueRepresentation`
|
|
221
|
+
behavior inherited from
|
|
222
|
+
:class:`~sage.manifolds.differentiable.pseudo_riemannian.PseudoRiemannianManifold`
|
|
223
|
+
would return the previously constructed object corresponding to these
|
|
224
|
+
arguments)
|
|
225
|
+
|
|
226
|
+
EXAMPLES:
|
|
227
|
+
|
|
228
|
+
A 2-sphere embedded in Euclidean space::
|
|
229
|
+
|
|
230
|
+
sage: S2 = manifolds.Sphere(2); S2
|
|
231
|
+
2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3
|
|
232
|
+
sage: latex(S2)
|
|
233
|
+
\mathbb{S}^{2}
|
|
234
|
+
|
|
235
|
+
The ambient Euclidean space is constructed incidentally::
|
|
236
|
+
|
|
237
|
+
sage: S2.ambient()
|
|
238
|
+
Euclidean space E^3
|
|
239
|
+
|
|
240
|
+
Another call creates another sphere and hence another Euclidean space::
|
|
241
|
+
|
|
242
|
+
sage: S2 is manifolds.Sphere(2)
|
|
243
|
+
False
|
|
244
|
+
sage: S2.ambient() is manifolds.Sphere(2).ambient()
|
|
245
|
+
False
|
|
246
|
+
|
|
247
|
+
By default, the barycenter is set to the coordinate origin of the
|
|
248
|
+
standard Cartesian coordinates in the ambient Euclidean space::
|
|
249
|
+
|
|
250
|
+
sage: c = S2.center(); c
|
|
251
|
+
Point on the Euclidean space E^3
|
|
252
|
+
sage: c.coord()
|
|
253
|
+
(0, 0, 0)
|
|
254
|
+
|
|
255
|
+
Each `n`-sphere is a compact manifold and a complete metric space::
|
|
256
|
+
|
|
257
|
+
sage: S2.category()
|
|
258
|
+
Join of Category of compact topological spaces and Category of smooth
|
|
259
|
+
manifolds over Real Field with 53 bits of precision and Category of
|
|
260
|
+
connected manifolds over Real Field with 53 bits of precision and
|
|
261
|
+
Category of complete metric spaces
|
|
262
|
+
|
|
263
|
+
If not stated otherwise, each `n`-sphere is automatically endowed with
|
|
264
|
+
spherical coordinates::
|
|
265
|
+
|
|
266
|
+
sage: S2.atlas()
|
|
267
|
+
[Chart (A, (theta, phi))]
|
|
268
|
+
sage: S2.default_chart()
|
|
269
|
+
Chart (A, (theta, phi))
|
|
270
|
+
sage: spher = S2.spherical_coordinates()
|
|
271
|
+
sage: spher is S2.default_chart()
|
|
272
|
+
True
|
|
273
|
+
|
|
274
|
+
Notice that the spherical coordinates do not cover the whole sphere. To
|
|
275
|
+
cover the entire sphere with charts, use stereographic coordinates instead::
|
|
276
|
+
|
|
277
|
+
sage: stereoN, stereoS = S2.coordinate_charts('stereographic')
|
|
278
|
+
sage: stereoN, stereoS
|
|
279
|
+
(Chart (S^2-{NP}, (y1, y2)), Chart (S^2-{SP}, (yp1, yp2)))
|
|
280
|
+
sage: list(S2.open_covers())
|
|
281
|
+
[Set {S^2} of open subsets of the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3,
|
|
282
|
+
Set {S^2-{NP}, S^2-{SP}} of open subsets of the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3]
|
|
283
|
+
|
|
284
|
+
.. NOTE::
|
|
285
|
+
|
|
286
|
+
Keep in mind that the initialization process of stereographic
|
|
287
|
+
coordinates and their transition maps is computational complex in
|
|
288
|
+
higher dimensions. Henceforth, high computation times are expected with
|
|
289
|
+
increasing dimension.
|
|
290
|
+
"""
|
|
291
|
+
@staticmethod
|
|
292
|
+
def __classcall_private__(cls, n=None, radius=1, ambient_space=None,
|
|
293
|
+
center=None, name=None, latex_name=None,
|
|
294
|
+
coordinates='spherical', names=None,
|
|
295
|
+
unique_tag=None):
|
|
296
|
+
r"""
|
|
297
|
+
Determine the correct class to return based upon the input.
|
|
298
|
+
|
|
299
|
+
TESTS:
|
|
300
|
+
|
|
301
|
+
Each call gives a new instance::
|
|
302
|
+
|
|
303
|
+
sage: S2 = manifolds.Sphere(2)
|
|
304
|
+
sage: S2 is manifolds.Sphere(2)
|
|
305
|
+
False
|
|
306
|
+
|
|
307
|
+
The dimension can be determined using the ``<...>`` operator::
|
|
308
|
+
|
|
309
|
+
sage: S.<x,y> = manifolds.Sphere(coordinates='stereographic'); S
|
|
310
|
+
2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3
|
|
311
|
+
sage: S._first_ngens(2)
|
|
312
|
+
(x, y)
|
|
313
|
+
"""
|
|
314
|
+
if n is None:
|
|
315
|
+
if names is None:
|
|
316
|
+
raise ValueError("either n or names must be specified")
|
|
317
|
+
n = len(names)
|
|
318
|
+
|
|
319
|
+
# Technical bit for UniqueRepresentation
|
|
320
|
+
from time import time
|
|
321
|
+
|
|
322
|
+
from sage.misc.prandom import getrandbits
|
|
323
|
+
if unique_tag is None:
|
|
324
|
+
unique_tag = getrandbits(128) * time()
|
|
325
|
+
|
|
326
|
+
return super().__classcall__(cls, n, radius=radius,
|
|
327
|
+
ambient_space=ambient_space,
|
|
328
|
+
center=center,
|
|
329
|
+
name=name, latex_name=latex_name,
|
|
330
|
+
coordinates=coordinates, names=names,
|
|
331
|
+
unique_tag=unique_tag)
|
|
332
|
+
|
|
333
|
+
def __init__(self, n, radius=1, ambient_space=None, center=None, name=None,
|
|
334
|
+
latex_name=None, coordinates='spherical', names=None,
|
|
335
|
+
category=None, init_coord_methods=None, unique_tag=None):
|
|
336
|
+
r"""
|
|
337
|
+
Construct sphere smoothly embedded in Euclidean space.
|
|
338
|
+
|
|
339
|
+
TESTS::
|
|
340
|
+
|
|
341
|
+
sage: S2 = manifolds.Sphere(2); S2
|
|
342
|
+
2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3
|
|
343
|
+
sage: S2.metric()
|
|
344
|
+
Riemannian metric g on the 2-sphere S^2 of radius 1 smoothly
|
|
345
|
+
embedded in the Euclidean space E^3
|
|
346
|
+
sage: TestSuite(S2).run()
|
|
347
|
+
"""
|
|
348
|
+
# radius
|
|
349
|
+
if radius <= 0:
|
|
350
|
+
raise ValueError('radius must be greater than zero')
|
|
351
|
+
# ambient space
|
|
352
|
+
if ambient_space is None:
|
|
353
|
+
ambient_space = EuclideanSpace(n+1)
|
|
354
|
+
elif not isinstance(ambient_space, EuclideanSpace):
|
|
355
|
+
raise TypeError("the argument 'ambient_space' must be a Euclidean space")
|
|
356
|
+
elif ambient_space._dim != n+1:
|
|
357
|
+
raise ValueError("Euclidean space must have dimension {}".format(n+1))
|
|
358
|
+
if center is None:
|
|
359
|
+
cart = ambient_space.cartesian_coordinates()
|
|
360
|
+
c_coords = [0]*(n+1)
|
|
361
|
+
center = ambient_space.point(c_coords, chart=cart)
|
|
362
|
+
elif center not in ambient_space:
|
|
363
|
+
raise ValueError('{} must be an element of {}'.format(center, ambient_space))
|
|
364
|
+
if name is None:
|
|
365
|
+
name = 'S^{}'.format(n)
|
|
366
|
+
if radius != 1:
|
|
367
|
+
name += r'_{}'.format(radius)
|
|
368
|
+
if center._name:
|
|
369
|
+
name += r'({})'.format(center._name)
|
|
370
|
+
if latex_name is None:
|
|
371
|
+
latex_name = r'\mathbb{S}^{' + str(n) + r'}'
|
|
372
|
+
if radius != 1:
|
|
373
|
+
latex_name += r'_{{{}}}'.format(radius)
|
|
374
|
+
if center._latex_name:
|
|
375
|
+
latex_name += r'({})'.format(center._latex_name)
|
|
376
|
+
if category is None:
|
|
377
|
+
category = Manifolds(RR).Smooth() & MetricSpaces().Complete() & \
|
|
378
|
+
TopologicalSpaces().Compact().Connected()
|
|
379
|
+
# initialize
|
|
380
|
+
PseudoRiemannianSubmanifold.__init__(self, n, name,
|
|
381
|
+
ambient=ambient_space,
|
|
382
|
+
signature=n, latex_name=latex_name,
|
|
383
|
+
metric_name='g', start_index=1,
|
|
384
|
+
category=category)
|
|
385
|
+
# set attributes
|
|
386
|
+
self._radius = radius
|
|
387
|
+
self._center = center
|
|
388
|
+
self._coordinates = {} # established coordinates; values are lists
|
|
389
|
+
self._init_coordinates = {'spherical': self._init_spherical,
|
|
390
|
+
'stereographic': self._init_stereographic}
|
|
391
|
+
# predefined coordinates
|
|
392
|
+
if init_coord_methods:
|
|
393
|
+
self._init_coordinates.update(init_coord_methods)
|
|
394
|
+
if coordinates not in self._init_coordinates:
|
|
395
|
+
raise ValueError('{} coordinates not available'.format(coordinates))
|
|
396
|
+
# up here, the actual initialization begins:
|
|
397
|
+
self._init_chart_domains()
|
|
398
|
+
self._init_embedding()
|
|
399
|
+
self._init_coordinates[coordinates](names)
|
|
400
|
+
|
|
401
|
+
def _init_embedding(self):
|
|
402
|
+
r"""
|
|
403
|
+
Initialize the embedding into Euclidean space.
|
|
404
|
+
|
|
405
|
+
TESTS::
|
|
406
|
+
|
|
407
|
+
sage: S2 = manifolds.Sphere(2)
|
|
408
|
+
sage: i = S2.embedding(); i
|
|
409
|
+
Differentiable map iota from the 2-sphere S^2 of radius 1 smoothly
|
|
410
|
+
embedded in the Euclidean space E^3 to the Euclidean space E^3
|
|
411
|
+
sage: i.display()
|
|
412
|
+
iota: S^2 → E^3
|
|
413
|
+
on A: (theta, phi) ↦ (x, y, z) = (cos(phi)*sin(theta),
|
|
414
|
+
sin(phi)*sin(theta), cos(theta))
|
|
415
|
+
"""
|
|
416
|
+
name = 'iota'
|
|
417
|
+
latex_name = r'\iota'
|
|
418
|
+
iota = self.diff_map(self._ambient, name=name, latex_name=latex_name)
|
|
419
|
+
self.set_embedding(iota)
|
|
420
|
+
|
|
421
|
+
def _repr_(self):
|
|
422
|
+
r"""
|
|
423
|
+
Return a string representation of ``self``.
|
|
424
|
+
|
|
425
|
+
TESTS::
|
|
426
|
+
|
|
427
|
+
sage: S2_3 = manifolds.Sphere(2, radius=3)
|
|
428
|
+
sage: S2_3._repr_()
|
|
429
|
+
'2-sphere S^2_3 of radius 3 smoothly embedded in the Euclidean space E^3'
|
|
430
|
+
sage: S2_3 # indirect doctest
|
|
431
|
+
2-sphere S^2_3 of radius 3 smoothly embedded in the Euclidean space E^3
|
|
432
|
+
"""
|
|
433
|
+
s = "{}-sphere {} of radius {} smoothly embedded in " \
|
|
434
|
+
"the {}".format(self._dim, self._name, self._radius, self._ambient)
|
|
435
|
+
if self._center._name:
|
|
436
|
+
s += ' centered at the Point {}'.format(self._center._name)
|
|
437
|
+
return s
|
|
438
|
+
|
|
439
|
+
def coordinate_charts(self, coord_name, names=None):
|
|
440
|
+
r"""
|
|
441
|
+
Return a list of all charts belonging to the coordinates ``coord_name``.
|
|
442
|
+
|
|
443
|
+
INPUT:
|
|
444
|
+
|
|
445
|
+
- ``coord_name`` -- string describing the type of coordinates
|
|
446
|
+
- ``names`` -- (default: ``None``) must be a tuple containing
|
|
447
|
+
the coordinate symbols for the first chart in the list; if
|
|
448
|
+
``None``, the standard convention is used
|
|
449
|
+
|
|
450
|
+
EXAMPLES:
|
|
451
|
+
|
|
452
|
+
Spherical coordinates on `S^1`::
|
|
453
|
+
|
|
454
|
+
sage: S1 = manifolds.Sphere(1)
|
|
455
|
+
sage: S1.coordinate_charts('spherical')
|
|
456
|
+
[Chart (A, (phi,))]
|
|
457
|
+
|
|
458
|
+
Stereographic coordinates on `S^1`::
|
|
459
|
+
|
|
460
|
+
sage: stereo_charts = S1.coordinate_charts('stereographic', names=['a'])
|
|
461
|
+
sage: stereo_charts
|
|
462
|
+
[Chart (S^1-{NP}, (a,)), Chart (S^1-{SP}, (ap,))]
|
|
463
|
+
"""
|
|
464
|
+
if coord_name not in self._coordinates:
|
|
465
|
+
if coord_name not in self._init_coordinates:
|
|
466
|
+
raise ValueError('{} coordinates not available'.format(coord_name))
|
|
467
|
+
self._init_coordinates[coord_name](names)
|
|
468
|
+
return list(self._coordinates[coord_name])
|
|
469
|
+
|
|
470
|
+
def _first_ngens(self, n):
|
|
471
|
+
r"""
|
|
472
|
+
Return the list of coordinates of the default chart.
|
|
473
|
+
|
|
474
|
+
This is useful only for the use of Sage preparser::
|
|
475
|
+
|
|
476
|
+
sage: preparse("S3.<x,y,z> = manifolds.Sphere(coordinates='stereographic')")
|
|
477
|
+
"S3 = manifolds.Sphere(coordinates='stereographic', names=('x', 'y', 'z',));
|
|
478
|
+
(x, y, z,) = S3._first_ngens(3)"
|
|
479
|
+
|
|
480
|
+
TESTS::
|
|
481
|
+
|
|
482
|
+
sage: S2 = manifolds.Sphere(2)
|
|
483
|
+
sage: S2._first_ngens(2)
|
|
484
|
+
(theta, phi)
|
|
485
|
+
sage: S2.<u,v> = manifolds.Sphere(2)
|
|
486
|
+
sage: S2._first_ngens(2)
|
|
487
|
+
(u, v)
|
|
488
|
+
"""
|
|
489
|
+
return self._def_chart[:]
|
|
490
|
+
|
|
491
|
+
def _init_chart_domains(self):
|
|
492
|
+
r"""
|
|
493
|
+
Construct the chart domains on ``self``.
|
|
494
|
+
|
|
495
|
+
TESTS::
|
|
496
|
+
|
|
497
|
+
sage: S2 = manifolds.Sphere(2)
|
|
498
|
+
sage: list(S2.open_covers())
|
|
499
|
+
[Set {S^2} of open subsets of the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3,
|
|
500
|
+
Set {S^2-{NP}, S^2-{SP}} of open subsets of the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3]
|
|
501
|
+
sage: frozenset(S2.subsets()) # random
|
|
502
|
+
frozenset({Euclidean 2-sphere S^2 of radius 1,
|
|
503
|
+
Open subset A of the Euclidean 2-sphere S^2 of radius 1,
|
|
504
|
+
Open subset S^2-{NP,SP} of the Euclidean 2-sphere S^2 of radius 1,
|
|
505
|
+
Open subset S^2-{NP} of the Euclidean 2-sphere S^2 of radius 1,
|
|
506
|
+
Open subset S^2-{SP} of the Euclidean 2-sphere S^2 of radius 1})
|
|
507
|
+
"""
|
|
508
|
+
# without north pole:
|
|
509
|
+
name = self._name + '-{NP}'
|
|
510
|
+
latex_name = self._latex_name + r'\setminus\{\mathrm{NP}\}'
|
|
511
|
+
self._stereoN_dom = self.open_subset(name, latex_name)
|
|
512
|
+
# without south pole:
|
|
513
|
+
name = self._name + '-{SP}'
|
|
514
|
+
latex_name = self._latex_name + r'\setminus\{\mathrm{SP}\}'
|
|
515
|
+
self._stereoS_dom = self.open_subset(name, latex_name)
|
|
516
|
+
# intersection:
|
|
517
|
+
int = self._stereoN_dom.intersection(self._stereoS_dom)
|
|
518
|
+
int._name = self._name + '-{NP,SP}'
|
|
519
|
+
int._latex_name = self._latex_name + \
|
|
520
|
+
r'\setminus\{\mathrm{NP}, \mathrm{SP}\}'
|
|
521
|
+
# without half circle:
|
|
522
|
+
self._spher_dom = int.open_subset('A')
|
|
523
|
+
# declare union:
|
|
524
|
+
self.declare_union(self._stereoN_dom, self._stereoS_dom)
|
|
525
|
+
|
|
526
|
+
def _shift_coords(self, coordfunc, s='+'):
|
|
527
|
+
r"""
|
|
528
|
+
Shift the coordinates ``coordfunc`` given in Cartesian coordinates to
|
|
529
|
+
the barycenter.
|
|
530
|
+
|
|
531
|
+
INPUT:
|
|
532
|
+
|
|
533
|
+
- ``coordfunc`` -- coordinate expression given in the standard
|
|
534
|
+
Cartesian coordinates of the ambient Euclidean space
|
|
535
|
+
- ``s`` -- either ``'+'`` or ``'-'`` depending on whether ``coordfunc``
|
|
536
|
+
should be shifted from the coordinate origin to the center or from
|
|
537
|
+
the center to the coordinate origin
|
|
538
|
+
|
|
539
|
+
TESTS::
|
|
540
|
+
|
|
541
|
+
sage: E3 = EuclideanSpace(3)
|
|
542
|
+
sage: c = E3.point((1,2,3), name='c')
|
|
543
|
+
sage: S2c = manifolds.Sphere(2, ambient_space=E3, center=c)
|
|
544
|
+
sage: spher = S2c.spherical_coordinates()
|
|
545
|
+
sage: cart = E3.cartesian_coordinates()
|
|
546
|
+
sage: coordfunc = S2c.embedding().expr(spher, cart); coordfunc
|
|
547
|
+
(cos(phi)*sin(theta) + 1, sin(phi)*sin(theta) + 2, cos(theta) + 3)
|
|
548
|
+
sage: S2c._shift_coords(coordfunc, s='-')
|
|
549
|
+
(cos(phi)*sin(theta), sin(phi)*sin(theta), cos(theta))
|
|
550
|
+
"""
|
|
551
|
+
cart = self._ambient.cartesian_coordinates()
|
|
552
|
+
c_coords = cart(self._center)
|
|
553
|
+
if s == '+':
|
|
554
|
+
res = [x + c for x, c in zip(coordfunc, c_coords)]
|
|
555
|
+
elif s == '-':
|
|
556
|
+
res = [x - c for x, c in zip(coordfunc, c_coords)]
|
|
557
|
+
return tuple(res)
|
|
558
|
+
|
|
559
|
+
def _init_spherical(self, names=None):
|
|
560
|
+
r"""
|
|
561
|
+
Construct the chart of spherical coordinates.
|
|
562
|
+
|
|
563
|
+
TESTS:
|
|
564
|
+
|
|
565
|
+
Spherical coordinates on a 2-sphere::
|
|
566
|
+
|
|
567
|
+
sage: S2 = manifolds.Sphere(2)
|
|
568
|
+
sage: S2.spherical_coordinates()
|
|
569
|
+
Chart (A, (theta, phi))
|
|
570
|
+
|
|
571
|
+
Spherical coordinates on a 1-sphere::
|
|
572
|
+
|
|
573
|
+
sage: S1 = manifolds.Sphere(1, coordinates='stereographic')
|
|
574
|
+
sage: spher = S1.spherical_coordinates(); spher # create coords
|
|
575
|
+
Chart (A, (phi,))
|
|
576
|
+
sage: S1.atlas()
|
|
577
|
+
[Chart (S^1-{NP}, (y1,)),
|
|
578
|
+
Chart (S^1-{SP}, (yp1,)),
|
|
579
|
+
Chart (S^1-{NP,SP}, (y1,)),
|
|
580
|
+
Chart (S^1-{NP,SP}, (yp1,)),
|
|
581
|
+
Chart (A, (phi,)),
|
|
582
|
+
Chart (A, (y1,)),
|
|
583
|
+
Chart (A, (yp1,))]
|
|
584
|
+
"""
|
|
585
|
+
# speed-up via simplification method...
|
|
586
|
+
self.set_simplify_function(lambda expr: expr.simplify_trig())
|
|
587
|
+
|
|
588
|
+
# get domain...
|
|
589
|
+
A = self._spher_dom
|
|
590
|
+
|
|
591
|
+
# initialize coordinates...
|
|
592
|
+
n = self._dim
|
|
593
|
+
if names:
|
|
594
|
+
# add interval:
|
|
595
|
+
names = tuple([x + ':(0,pi)' for x in names[:-1]] +
|
|
596
|
+
[names[-1] + ':(-pi,pi):periodic'])
|
|
597
|
+
else:
|
|
598
|
+
if n == 1:
|
|
599
|
+
names = ('phi:(-pi,pi):periodic',)
|
|
600
|
+
elif n == 2:
|
|
601
|
+
names = ('theta:(0,pi)', 'phi:(-pi,pi):periodic')
|
|
602
|
+
elif n == 3:
|
|
603
|
+
names = ('chi:(0,pi)', 'theta:(0,pi)', 'phi:(-pi,pi):periodic')
|
|
604
|
+
else:
|
|
605
|
+
names = tuple(["phi_{}:(0,pi)".format(i) for i in range(1,n)] +
|
|
606
|
+
["phi_{}:(-pi,pi):periodic".format(n)])
|
|
607
|
+
spher = A.chart(names=names)
|
|
608
|
+
coord = spher[:]
|
|
609
|
+
|
|
610
|
+
# make spherical chart and frame the default ones on their domain:
|
|
611
|
+
A.set_default_chart(spher)
|
|
612
|
+
A.set_default_frame(spher.frame())
|
|
613
|
+
|
|
614
|
+
# manage embedding...
|
|
615
|
+
from sage.functions.trig import cos, sin
|
|
616
|
+
from sage.misc.misc_c import prod
|
|
617
|
+
|
|
618
|
+
R = self._radius
|
|
619
|
+
|
|
620
|
+
coordfunc = [R*cos(coord[n-1])*prod(sin(coord[i]) for i in range(n-1))]
|
|
621
|
+
coordfunc += [R*prod(sin(coord[i]) for i in range(n))]
|
|
622
|
+
for k in reversed(range(n-1)):
|
|
623
|
+
c = R*cos(coord[k])*prod(sin(coord[i]) for i in range(k))
|
|
624
|
+
coordfunc.append(c)
|
|
625
|
+
cart = self._ambient.cartesian_coordinates()
|
|
626
|
+
# shift coordinates to barycenter:
|
|
627
|
+
coordfunc = self._shift_coords(coordfunc, s='+')
|
|
628
|
+
# add expression to embedding:
|
|
629
|
+
self._immersion.add_expr(spher, cart, coordfunc)
|
|
630
|
+
self.clear_cache() # clear cache of extrinsic information
|
|
631
|
+
|
|
632
|
+
# finish process...
|
|
633
|
+
self._coordinates['spherical'] = [spher]
|
|
634
|
+
|
|
635
|
+
# adapt other coordinates...
|
|
636
|
+
if 'stereographic' in self._coordinates:
|
|
637
|
+
self._transition_spher_stereo()
|
|
638
|
+
|
|
639
|
+
# reset simplification method...
|
|
640
|
+
self.set_simplify_function('default')
|
|
641
|
+
|
|
642
|
+
def stereographic_coordinates(self, pole='north', names=None):
|
|
643
|
+
r"""
|
|
644
|
+
Return stereographic coordinates given by the stereographic
|
|
645
|
+
projection of ``self`` w.r.t. to a given pole.
|
|
646
|
+
|
|
647
|
+
INPUT:
|
|
648
|
+
|
|
649
|
+
- ``pole`` -- (default: ``'north'``) the pole determining the
|
|
650
|
+
stereographic projection; possible options are ``'north'`` and
|
|
651
|
+
``'south'``
|
|
652
|
+
- ``names`` -- (default: ``None``) must be a tuple containing
|
|
653
|
+
the coordinate symbols (this guarantees the usage of the shortcut
|
|
654
|
+
operator ``<,>``)
|
|
655
|
+
|
|
656
|
+
OUTPUT:
|
|
657
|
+
|
|
658
|
+
- the chart of stereographic coordinates w.r.t. to the given pole,
|
|
659
|
+
as an instance of
|
|
660
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`
|
|
661
|
+
|
|
662
|
+
Let `\mathbb{S}^n_r(c)` be an `n`-sphere of radius `r` smoothly
|
|
663
|
+
embedded in the Euclidean space `E^{n+1}` centered at `c \in E^{n+1}`.
|
|
664
|
+
We denote the north pole of `\mathbb{S}^n_r(c)` by `\mathrm{NP}` and the
|
|
665
|
+
south pole by `\mathrm{SP}`. These poles are uniquely determined by
|
|
666
|
+
the requirement
|
|
667
|
+
|
|
668
|
+
.. MATH::
|
|
669
|
+
|
|
670
|
+
x(\iota(\mathrm{NP})) &= (0, \ldots, 0, r) + x(c), \\
|
|
671
|
+
x(\iota(\mathrm{SP})) &= (0, \ldots, 0, -r) + x(c).
|
|
672
|
+
|
|
673
|
+
The coordinates `(y_1, \ldots, y_n)` (`(y'_1, \ldots, y'_n)`
|
|
674
|
+
respectively) define *stereographic coordinates* on `\mathbb{S}^n_r(c)`
|
|
675
|
+
for the Cartesian coordinates `(x_1, \ldots, x_{n+1})` on `E^{n+1}`
|
|
676
|
+
if they arise from the stereographic projection from
|
|
677
|
+
`\iota(\mathrm{NP})` (`\iota(\mathrm{SP})`) to the hypersurface
|
|
678
|
+
`x_n = x_n(c)`. In concrete formulas, this means:
|
|
679
|
+
|
|
680
|
+
.. MATH::
|
|
681
|
+
|
|
682
|
+
\left. x \circ \iota \right|_{\mathbb{S}^n_r(c) \setminus \{
|
|
683
|
+
\mathrm{NP}\}}
|
|
684
|
+
&= \left( \frac{2y_1r^2}{r^2+\sum^n_{i=1} y^2_i},
|
|
685
|
+
\ldots, \frac{2y_nr^2}{r^2+\sum^n_{i=1} y^2_i},
|
|
686
|
+
\frac{r\sum^n_{i=1} y^2_i-r^3}{r^2+\sum^n_{i=1} y^2_i} \right) +
|
|
687
|
+
x(c), \\
|
|
688
|
+
\left. x \circ \iota \right|_{\mathbb{S}^n_r(c) \setminus \{
|
|
689
|
+
\mathrm{SP}\}} &= \left( \frac{2y'_1r^2}{r^2+\sum^n_{i=1} y'^2_i},
|
|
690
|
+
\ldots, \frac{2y'_nr^2}{r^2+\sum^n_{i=1} y'^2_i},
|
|
691
|
+
\frac{r^3 - r\sum^n_{i=1} y'^2_i}{r^2+\sum^n_{i=1} y'^2_i} \right) +
|
|
692
|
+
x(c).
|
|
693
|
+
|
|
694
|
+
EXAMPLES:
|
|
695
|
+
|
|
696
|
+
Initialize a 1-sphere centered at `(1,0)` in the Euclidean plane
|
|
697
|
+
using the shortcut operator::
|
|
698
|
+
|
|
699
|
+
sage: E2 = EuclideanSpace(2)
|
|
700
|
+
sage: c = E2.point((1,0), name='c')
|
|
701
|
+
sage: S1.<a> = E2.sphere(center=c, coordinates='stereographic'); S1
|
|
702
|
+
1-sphere S^1(c) of radius 1 smoothly embedded in the Euclidean plane
|
|
703
|
+
E^2 centered at the Point c
|
|
704
|
+
|
|
705
|
+
By default, the shortcut variables belong to the stereographic
|
|
706
|
+
projection from the north pole::
|
|
707
|
+
|
|
708
|
+
sage: S1.coordinate_charts('stereographic')
|
|
709
|
+
[Chart (S^1(c)-{NP}, (a,)), Chart (S^1(c)-{SP}, (ap,))]
|
|
710
|
+
sage: S1.embedding().display()
|
|
711
|
+
iota: S^1(c) → E^2
|
|
712
|
+
on S^1(c)-{NP}: a ↦ (x, y) = (2*a/(a^2 + 1) + 1, (a^2 - 1)/(a^2 + 1))
|
|
713
|
+
on S^1(c)-{SP}: ap ↦ (x, y) = (2*ap/(ap^2 + 1) + 1, -(ap^2 - 1)/(ap^2 + 1))
|
|
714
|
+
|
|
715
|
+
Initialize a 2-sphere from scratch::
|
|
716
|
+
|
|
717
|
+
sage: S2 = manifolds.Sphere(2)
|
|
718
|
+
sage: S2.atlas()
|
|
719
|
+
[Chart (A, (theta, phi))]
|
|
720
|
+
|
|
721
|
+
In the previous block, the stereographic coordinates have not been
|
|
722
|
+
initialized. This happens subsequently with the invocation of
|
|
723
|
+
``stereographic_coordinates``::
|
|
724
|
+
|
|
725
|
+
sage: stereoS.<u,v> = S2.stereographic_coordinates(pole='south')
|
|
726
|
+
sage: S2.coordinate_charts('stereographic')
|
|
727
|
+
[Chart (S^2-{NP}, (up, vp)), Chart (S^2-{SP}, (u, v))]
|
|
728
|
+
|
|
729
|
+
If not specified by the user, the default coordinate names are given by
|
|
730
|
+
`(y_1, \ldots, y_n)` and `(y'_1, \ldots, y'_n)` respectively::
|
|
731
|
+
|
|
732
|
+
sage: S3 = manifolds.Sphere(3, coordinates='stereographic')
|
|
733
|
+
sage: S3.stereographic_coordinates(pole='north')
|
|
734
|
+
Chart (S^3-{NP}, (y1, y2, y3))
|
|
735
|
+
sage: S3.stereographic_coordinates(pole='south')
|
|
736
|
+
Chart (S^3-{SP}, (yp1, yp2, yp3))
|
|
737
|
+
"""
|
|
738
|
+
coordinates = 'stereographic'
|
|
739
|
+
if coordinates not in self._coordinates:
|
|
740
|
+
self._init_coordinates[coordinates](names, default_pole=pole)
|
|
741
|
+
if pole == 'north':
|
|
742
|
+
return self._coordinates[coordinates][0]
|
|
743
|
+
elif pole == 'south':
|
|
744
|
+
return self._coordinates[coordinates][1]
|
|
745
|
+
else:
|
|
746
|
+
raise ValueError("pole must be 'north' or 'south'")
|
|
747
|
+
|
|
748
|
+
def spherical_coordinates(self, names=None):
|
|
749
|
+
r"""
|
|
750
|
+
Return the spherical coordinates of ``self``.
|
|
751
|
+
|
|
752
|
+
INPUT:
|
|
753
|
+
|
|
754
|
+
- ``names`` -- (default: ``None``) must be a tuple containing
|
|
755
|
+
the coordinate symbols (this guarantees the usage of the shortcut
|
|
756
|
+
operator ``<,>``)
|
|
757
|
+
|
|
758
|
+
OUTPUT:
|
|
759
|
+
|
|
760
|
+
- the chart of spherical coordinates, as an instance of
|
|
761
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`
|
|
762
|
+
|
|
763
|
+
Let `\mathbb{S}^n_r(c)` be an `n`-sphere of radius `r` smoothly
|
|
764
|
+
embedded in the Euclidean space `E^{n+1}` centered at `c \in E^{n+1}`.
|
|
765
|
+
We say that `(\varphi_1, \ldots, \varphi_n)` define *spherical
|
|
766
|
+
coordinates* on the open subset `A \subset \mathbb{S}^n_r(c)` for the
|
|
767
|
+
Cartesian coordinates `(x_1, \ldots, x_{n+1})` on `E^{n+1}` (not
|
|
768
|
+
necessarily centered at `c`) if
|
|
769
|
+
|
|
770
|
+
.. MATH::
|
|
771
|
+
|
|
772
|
+
\begin{aligned}
|
|
773
|
+
\left. x_1 \circ \iota \right|_{A} &= r \cos(\varphi_n)\sin(
|
|
774
|
+
\varphi_{n-1}) \cdots
|
|
775
|
+
\sin(\varphi_1)
|
|
776
|
+
+ x_1(c), \\
|
|
777
|
+
\left. x_1 \circ \iota \right|_{A} &= r \sin(\varphi_n)\sin(
|
|
778
|
+
\varphi_{n-1}) \cdots
|
|
779
|
+
\sin(\varphi_1)
|
|
780
|
+
+ x_1(c), \\
|
|
781
|
+
\left. x_2 \circ \iota \right|_{A} &= r \cos(\varphi_{
|
|
782
|
+
n-1})\sin(\varphi_{n-2}) \cdots
|
|
783
|
+
\sin(\varphi_1)
|
|
784
|
+
+ x_2(c), \\
|
|
785
|
+
\left. x_3 \circ \iota \right|_{A} &= r \cos(\varphi_{
|
|
786
|
+
n-2})\sin(\varphi_{n-3}) \cdots
|
|
787
|
+
\sin(\varphi_1)
|
|
788
|
+
+ x_3(c), \\
|
|
789
|
+
\vdots & \\
|
|
790
|
+
\left. x_{n+1} \circ \iota \right|_{A} &= r \cos(\varphi_1) +
|
|
791
|
+
x_{n+1}(c),
|
|
792
|
+
\end{aligned}
|
|
793
|
+
|
|
794
|
+
where `\varphi_i` has range `(0, \pi)` for `i=1, \ldots, n-1` and
|
|
795
|
+
`\varphi_n` lies in `(-\pi, \pi)`. Notice that the above expressions
|
|
796
|
+
together with the ranges of the `\varphi_i` fully determine the open
|
|
797
|
+
set `A`.
|
|
798
|
+
|
|
799
|
+
.. NOTE::
|
|
800
|
+
|
|
801
|
+
Notice that our convention slightly differs from the one given on
|
|
802
|
+
the :wikipedia:`N-sphere#Spherical_coordinates`. The definition
|
|
803
|
+
above ensures that the conventions for the most common cases
|
|
804
|
+
`n=1` and `n=2` are maintained.
|
|
805
|
+
|
|
806
|
+
EXAMPLES:
|
|
807
|
+
|
|
808
|
+
The spherical coordinates on a 2-sphere follow the common conventions::
|
|
809
|
+
|
|
810
|
+
sage: S2 = manifolds.Sphere(2)
|
|
811
|
+
sage: spher = S2.spherical_coordinates(); spher
|
|
812
|
+
Chart (A, (theta, phi))
|
|
813
|
+
|
|
814
|
+
The coordinate range of spherical coordinates::
|
|
815
|
+
|
|
816
|
+
sage: spher.coord_range()
|
|
817
|
+
theta: (0, pi); phi: [-pi, pi] (periodic)
|
|
818
|
+
|
|
819
|
+
Spherical coordinates do not cover the 2-sphere entirely::
|
|
820
|
+
|
|
821
|
+
sage: A = spher.domain(); A
|
|
822
|
+
Open subset A of the 2-sphere S^2 of radius 1 smoothly embedded in
|
|
823
|
+
the Euclidean space E^3
|
|
824
|
+
|
|
825
|
+
The embedding of a 2-sphere in Euclidean space via spherical
|
|
826
|
+
coordinates::
|
|
827
|
+
|
|
828
|
+
sage: S2.embedding().display()
|
|
829
|
+
iota: S^2 → E^3
|
|
830
|
+
on A: (theta, phi) ↦ (x, y, z) =
|
|
831
|
+
(cos(phi)*sin(theta),
|
|
832
|
+
sin(phi)*sin(theta),
|
|
833
|
+
cos(theta))
|
|
834
|
+
|
|
835
|
+
Now, consider spherical coordinates on a 3-sphere::
|
|
836
|
+
|
|
837
|
+
sage: S3 = manifolds.Sphere(3)
|
|
838
|
+
sage: spher = S3.spherical_coordinates(); spher
|
|
839
|
+
Chart (A, (chi, theta, phi))
|
|
840
|
+
sage: S3.embedding().display()
|
|
841
|
+
iota: S^3 → E^4
|
|
842
|
+
on A: (chi, theta, phi) ↦ (x1, x2, x3, x4) =
|
|
843
|
+
(cos(phi)*sin(chi)*sin(theta),
|
|
844
|
+
sin(chi)*sin(phi)*sin(theta),
|
|
845
|
+
cos(theta)*sin(chi),
|
|
846
|
+
cos(chi))
|
|
847
|
+
|
|
848
|
+
By convention, the last coordinate is periodic::
|
|
849
|
+
|
|
850
|
+
sage: spher.coord_range()
|
|
851
|
+
chi: (0, pi); theta: (0, pi); phi: [-pi, pi] (periodic)
|
|
852
|
+
"""
|
|
853
|
+
coordinates = 'spherical'
|
|
854
|
+
if coordinates not in self._coordinates:
|
|
855
|
+
self._init_coordinates[coordinates](names)
|
|
856
|
+
return self._coordinates[coordinates][0]
|
|
857
|
+
|
|
858
|
+
def _init_stereographic(self, names, default_pole='north'):
|
|
859
|
+
r"""
|
|
860
|
+
Construct the charts of stereographic coordinates.
|
|
861
|
+
|
|
862
|
+
TESTS:
|
|
863
|
+
|
|
864
|
+
Stereographic coordinates on the 2-sphere::
|
|
865
|
+
|
|
866
|
+
sage: S2.<x,y> = manifolds.Sphere(2, coordinates='stereographic')
|
|
867
|
+
sage: S2.atlas()
|
|
868
|
+
[Chart (S^2-{NP}, (x, y)),
|
|
869
|
+
Chart (S^2-{SP}, (xp, yp)),
|
|
870
|
+
Chart (S^2-{NP,SP}, (x, y)),
|
|
871
|
+
Chart (S^2-{NP,SP}, (xp, yp))]
|
|
872
|
+
|
|
873
|
+
Stereographic coordinates on the 1-sphere::
|
|
874
|
+
|
|
875
|
+
sage: S1 = manifolds.Sphere(1)
|
|
876
|
+
sage: stereoS.<x> = S1.stereographic_coordinates(pole='south')
|
|
877
|
+
sage: S1.atlas()
|
|
878
|
+
[Chart (A, (phi,)),
|
|
879
|
+
Chart (S^1-{NP}, (xp,)),
|
|
880
|
+
Chart (S^1-{SP}, (x,)),
|
|
881
|
+
Chart (S^1-{NP,SP}, (xp,)),
|
|
882
|
+
Chart (S^1-{NP,SP}, (x,)),
|
|
883
|
+
Chart (A, (xp,)),
|
|
884
|
+
Chart (A, (x,))]
|
|
885
|
+
|
|
886
|
+
The stereographic chart is the default one on its domain::
|
|
887
|
+
|
|
888
|
+
sage: V = stereoS.domain()
|
|
889
|
+
sage: V.default_chart()
|
|
890
|
+
Chart (S^1-{SP}, (x,))
|
|
891
|
+
|
|
892
|
+
Accordingly, we have::
|
|
893
|
+
|
|
894
|
+
sage: S1.metric().restrict(V).display()
|
|
895
|
+
g = 4/(x^4 + 2*x^2 + 1) dx⊗dx
|
|
896
|
+
|
|
897
|
+
while the spherical chart is still the default one on ``S1``::
|
|
898
|
+
|
|
899
|
+
sage: S1.metric().display()
|
|
900
|
+
g = dphi⊗dphi
|
|
901
|
+
"""
|
|
902
|
+
# speed-up via simplification method...
|
|
903
|
+
self.set_simplify_function(lambda expr: expr.simplify_rational())
|
|
904
|
+
# TODO: More speed-up?
|
|
905
|
+
|
|
906
|
+
# get domains...
|
|
907
|
+
U = self._stereoN_dom
|
|
908
|
+
V = self._stereoS_dom
|
|
909
|
+
|
|
910
|
+
# initialize coordinates...
|
|
911
|
+
symbols_N = ''
|
|
912
|
+
symbols_S = ''
|
|
913
|
+
if names:
|
|
914
|
+
for x in names:
|
|
915
|
+
if default_pole == 'north':
|
|
916
|
+
symbols_N += x + ' '
|
|
917
|
+
symbols_S += "{}p".format(x) + ":{}' ".format(x)
|
|
918
|
+
elif default_pole == 'south':
|
|
919
|
+
symbols_S += x + ' '
|
|
920
|
+
symbols_N += "{}p".format(x) + ":{}' ".format(x)
|
|
921
|
+
else:
|
|
922
|
+
for i in self.irange():
|
|
923
|
+
symbols_N += "y{}".format(i) + r":y_{" + str(i) + r"} "
|
|
924
|
+
symbols_S += "yp{}".format(i) + r":y'_{" + str(i) + r"} "
|
|
925
|
+
symbols_N = symbols_N[:-1]
|
|
926
|
+
symbols_S = symbols_S[:-1]
|
|
927
|
+
stereoN = U.chart(coordinates=symbols_N)
|
|
928
|
+
stereoS = V.chart(coordinates=symbols_S)
|
|
929
|
+
coordN = stereoN[:]
|
|
930
|
+
coordS = stereoS[:]
|
|
931
|
+
|
|
932
|
+
# make stereographic charts and frames the default ones on their
|
|
933
|
+
# respective domains:
|
|
934
|
+
U.set_default_chart(stereoN)
|
|
935
|
+
V.set_default_chart(stereoS)
|
|
936
|
+
U.set_default_frame(stereoN.frame())
|
|
937
|
+
V.set_default_frame(stereoS.frame())
|
|
938
|
+
|
|
939
|
+
# predefine variables...
|
|
940
|
+
r2_N = sum(y ** 2 for y in coordN)
|
|
941
|
+
r2_S = sum(yp ** 2 for yp in coordS)
|
|
942
|
+
R = self._radius
|
|
943
|
+
R2 = R**2
|
|
944
|
+
|
|
945
|
+
# define transition map...
|
|
946
|
+
coordN_to_S = tuple(R*y/r2_N for y in coordN)
|
|
947
|
+
coordS_to_N = tuple(R*yp/r2_S for yp in coordS)
|
|
948
|
+
stereoN_to_S = stereoN.transition_map(stereoS, coordN_to_S,
|
|
949
|
+
restrictions1=r2_N != 0,
|
|
950
|
+
restrictions2=r2_S != 0)
|
|
951
|
+
stereoN_to_S.set_inverse(*coordS_to_N, check=False)
|
|
952
|
+
|
|
953
|
+
# manage embedding...
|
|
954
|
+
coordfuncN = [2*y*R2 / (R2+r2_N) for y in coordN]
|
|
955
|
+
coordfuncN += [(R*r2_N-R*R2)/(R2+r2_N)]
|
|
956
|
+
coordfuncS = [2*yp*R2 / (R2+r2_S) for yp in coordS]
|
|
957
|
+
coordfuncS += [(R*R2-R*r2_S)/(R2+r2_S)]
|
|
958
|
+
cart = self._ambient.cartesian_coordinates()
|
|
959
|
+
# shift coordinates to barycenter:
|
|
960
|
+
coordfuncN = self._shift_coords(coordfuncN, s='+')
|
|
961
|
+
coordfuncS = self._shift_coords(coordfuncS, s='+')
|
|
962
|
+
# add expressions to embedding:
|
|
963
|
+
self._immersion.add_expr(stereoN, cart, coordfuncN)
|
|
964
|
+
self._immersion.add_expr(stereoS, cart, coordfuncS)
|
|
965
|
+
self.clear_cache() # clear cache of extrinsic information
|
|
966
|
+
|
|
967
|
+
# define orientation...
|
|
968
|
+
eN = stereoN.frame()
|
|
969
|
+
eS = stereoS.frame() # oriented w.r.t. embedding
|
|
970
|
+
frame_comp = list(eN[:])
|
|
971
|
+
frame_comp[0] = -frame_comp[0] # reverse orientation
|
|
972
|
+
f = U.vector_frame('f', frame_comp)
|
|
973
|
+
self.set_orientation([eS, f])
|
|
974
|
+
|
|
975
|
+
# finish process...
|
|
976
|
+
self._coordinates['stereographic'] = [stereoN, stereoS]
|
|
977
|
+
|
|
978
|
+
# adapt other coordinates...
|
|
979
|
+
if 'spherical' in self._coordinates:
|
|
980
|
+
self._transition_spher_stereo()
|
|
981
|
+
|
|
982
|
+
# reset simplification method...
|
|
983
|
+
self.set_simplify_function('default')
|
|
984
|
+
|
|
985
|
+
def _transition_spher_stereo(self):
|
|
986
|
+
r"""
|
|
987
|
+
Initialize the transition map between spherical and stereographic
|
|
988
|
+
coordinates.
|
|
989
|
+
|
|
990
|
+
TESTS::
|
|
991
|
+
|
|
992
|
+
sage: S1 = manifolds.Sphere(1)
|
|
993
|
+
sage: spher = S1.spherical_coordinates(); spher
|
|
994
|
+
Chart (A, (phi,))
|
|
995
|
+
sage: A = spher.domain()
|
|
996
|
+
sage: stereoN = S1.stereographic_coordinates(pole='north'); stereoN
|
|
997
|
+
Chart (S^1-{NP}, (y1,))
|
|
998
|
+
sage: S1.coord_change(spher, stereoN.restrict(A))
|
|
999
|
+
Change of coordinates from Chart (A, (phi,)) to Chart (A, (y1,))
|
|
1000
|
+
"""
|
|
1001
|
+
# speed-up via simplification method...
|
|
1002
|
+
self.set_simplify_function(lambda expr: expr.simplify())
|
|
1003
|
+
|
|
1004
|
+
# configure preexisting charts...
|
|
1005
|
+
W = self._stereoN_dom.intersection(self._stereoS_dom)
|
|
1006
|
+
A = self._spher_dom
|
|
1007
|
+
stereoN, stereoS = self._coordinates['stereographic'][:]
|
|
1008
|
+
coordN = stereoN[:]
|
|
1009
|
+
coordS = stereoS[:]
|
|
1010
|
+
rstN = (coordN[0] != 0,)
|
|
1011
|
+
rstS = (coordS[0] != 0,)
|
|
1012
|
+
if self._dim > 1:
|
|
1013
|
+
rstN += (coordN[0] > 0,)
|
|
1014
|
+
rstS += (coordS[0] > 0,)
|
|
1015
|
+
stereoN_A = stereoN.restrict(A, rstN)
|
|
1016
|
+
stereoS_A = stereoS.restrict(A, rstS)
|
|
1017
|
+
self._coord_changes[(stereoN.restrict(W),
|
|
1018
|
+
stereoS.restrict(W))].restrict(A)
|
|
1019
|
+
self._coord_changes[(stereoS.restrict(W),
|
|
1020
|
+
stereoN.restrict(W))].restrict(A)
|
|
1021
|
+
spher = self._coordinates['spherical'][0]
|
|
1022
|
+
|
|
1023
|
+
R = self._radius
|
|
1024
|
+
n = self._dim
|
|
1025
|
+
|
|
1026
|
+
# transition: spher to stereoN...
|
|
1027
|
+
imm = self.embedding()
|
|
1028
|
+
cart = self._ambient.cartesian_coordinates()
|
|
1029
|
+
# get ambient coordinates and shift to coordinate origin:
|
|
1030
|
+
x = self._shift_coords(imm.expr(spher, cart), s='-')
|
|
1031
|
+
coordfunc = [(R*x[i])/(R-x[-1]) for i in range(n)]
|
|
1032
|
+
# define transition map:
|
|
1033
|
+
spher_to_stereoN = spher.transition_map(stereoN_A, coordfunc)
|
|
1034
|
+
|
|
1035
|
+
# transition: stereoN to spher...
|
|
1036
|
+
from sage.functions.trig import acos, atan2
|
|
1037
|
+
from sage.misc.functional import sqrt
|
|
1038
|
+
# get ambient coordinates and shift to coordinate origin:
|
|
1039
|
+
x = self._shift_coords(imm.expr(stereoN, cart), s='-')
|
|
1040
|
+
coordfunc = [atan2(x[1],x[0])]
|
|
1041
|
+
for k in range(2, n+1):
|
|
1042
|
+
c = acos(x[k]/sqrt(sum(x[i]**2 for i in range(k+1))))
|
|
1043
|
+
coordfunc.append(c)
|
|
1044
|
+
coordfunc = reversed(coordfunc)
|
|
1045
|
+
spher_to_stereoN.set_inverse(*coordfunc, check=False)
|
|
1046
|
+
|
|
1047
|
+
# transition spher <-> stereoS...
|
|
1048
|
+
stereoN_to_S_A = self.coord_change(stereoN_A, stereoS_A)
|
|
1049
|
+
stereoN_to_S_A * spher_to_stereoN # generates spher_to_stereoS
|
|
1050
|
+
stereoS_to_N_A = self.coord_change(stereoS_A, stereoN_A)
|
|
1051
|
+
spher_to_stereoN.inverse() * stereoS_to_N_A # generates stereoS_to_spher
|
|
1052
|
+
|
|
1053
|
+
def dist(self, p, q):
|
|
1054
|
+
r"""
|
|
1055
|
+
Return the great circle distance between the points ``p`` and ``q`` on
|
|
1056
|
+
``self``.
|
|
1057
|
+
|
|
1058
|
+
INPUT:
|
|
1059
|
+
|
|
1060
|
+
- ``p`` -- an element of ``self``
|
|
1061
|
+
- ``q`` -- an element of ``self``
|
|
1062
|
+
|
|
1063
|
+
OUTPUT:
|
|
1064
|
+
|
|
1065
|
+
- the great circle distance `d(p, q)` on ``self``
|
|
1066
|
+
|
|
1067
|
+
The great circle distance `d(p, q)` of the points
|
|
1068
|
+
`p, q \in \mathbb{S}^n_r(c)` is the length of the shortest great circle
|
|
1069
|
+
segment on `\mathbb{S}^n_r(c)` that joins `p` and `q`. If we choose
|
|
1070
|
+
Cartesian coordinates `(x_1, \ldots, x_{n+1})` of the ambient Euclidean
|
|
1071
|
+
space such that the center lies in the coordinate origin, i.e.
|
|
1072
|
+
`x(c)=0`, the great circle distance can be expressed in terms of the
|
|
1073
|
+
following formula:
|
|
1074
|
+
|
|
1075
|
+
.. MATH::
|
|
1076
|
+
|
|
1077
|
+
d(p,q) = r \, \arccos\left(\frac{x(\iota(p)) \cdot
|
|
1078
|
+
x(\iota(q))}{r^2}\right).
|
|
1079
|
+
|
|
1080
|
+
EXAMPLES:
|
|
1081
|
+
|
|
1082
|
+
Define a 2-sphere with unspecified radius::
|
|
1083
|
+
|
|
1084
|
+
sage: r = var('r')
|
|
1085
|
+
sage: S2_r = manifolds.Sphere(2, radius=r); S2_r
|
|
1086
|
+
2-sphere S^2_r of radius r smoothly embedded in the Euclidean space E^3
|
|
1087
|
+
|
|
1088
|
+
Given two antipodal points in spherical coordinates::
|
|
1089
|
+
|
|
1090
|
+
sage: p = S2_r.point((pi/2, pi/2), name='p'); p
|
|
1091
|
+
Point p on the 2-sphere S^2_r of radius r smoothly embedded in the
|
|
1092
|
+
Euclidean space E^3
|
|
1093
|
+
sage: q = S2_r.point((pi/2, -pi/2), name='q'); q
|
|
1094
|
+
Point q on the 2-sphere S^2_r of radius r smoothly embedded in the
|
|
1095
|
+
Euclidean space E^3
|
|
1096
|
+
|
|
1097
|
+
The distance is determined as the length of the half great circle::
|
|
1098
|
+
|
|
1099
|
+
sage: S2_r.dist(p, q)
|
|
1100
|
+
pi*r
|
|
1101
|
+
"""
|
|
1102
|
+
from sage.functions.trig import acos
|
|
1103
|
+
# get Euclidean points:
|
|
1104
|
+
x = self._immersion(p)
|
|
1105
|
+
y = self._immersion(q)
|
|
1106
|
+
cart = self._ambient.cartesian_coordinates()
|
|
1107
|
+
# get ambient coordinates and shift to coordinate origin:
|
|
1108
|
+
x_coord = self._shift_coords(x.coord(chart=cart), s='-')
|
|
1109
|
+
y_coord = self._shift_coords(y.coord(chart=cart), s='-')
|
|
1110
|
+
|
|
1111
|
+
n = self._dim + 1
|
|
1112
|
+
r = self._radius
|
|
1113
|
+
inv_angle = sum(x_coord[i]*y_coord[i] for i in range(n)) / r**2
|
|
1114
|
+
return (r * acos(inv_angle)).simplify()
|
|
1115
|
+
|
|
1116
|
+
def radius(self):
|
|
1117
|
+
r"""
|
|
1118
|
+
Return the radius of ``self``.
|
|
1119
|
+
|
|
1120
|
+
EXAMPLES:
|
|
1121
|
+
|
|
1122
|
+
3-sphere with radius 3::
|
|
1123
|
+
|
|
1124
|
+
sage: S3_2 = manifolds.Sphere(3, radius=2); S3_2
|
|
1125
|
+
3-sphere S^3_2 of radius 2 smoothly embedded in the 4-dimensional
|
|
1126
|
+
Euclidean space E^4
|
|
1127
|
+
sage: S3_2.radius()
|
|
1128
|
+
2
|
|
1129
|
+
|
|
1130
|
+
2-sphere with unspecified radius::
|
|
1131
|
+
|
|
1132
|
+
sage: r = var('r')
|
|
1133
|
+
sage: S2_r = manifolds.Sphere(3, radius=r); S2_r
|
|
1134
|
+
3-sphere S^3_r of radius r smoothly embedded in the 4-dimensional
|
|
1135
|
+
Euclidean space E^4
|
|
1136
|
+
sage: S2_r.radius()
|
|
1137
|
+
r
|
|
1138
|
+
"""
|
|
1139
|
+
return self._radius
|
|
1140
|
+
|
|
1141
|
+
def minimal_triangulation(self):
|
|
1142
|
+
r"""
|
|
1143
|
+
Return the minimal triangulation of ``self`` as a simplicial complex.
|
|
1144
|
+
|
|
1145
|
+
EXAMPLES:
|
|
1146
|
+
|
|
1147
|
+
Minimal triangulation of the 2-sphere::
|
|
1148
|
+
|
|
1149
|
+
sage: S2 = manifolds.Sphere(2)
|
|
1150
|
+
sage: S = S2.minimal_triangulation(); S # needs sage.graphs
|
|
1151
|
+
Minimal triangulation of the 2-sphere
|
|
1152
|
+
|
|
1153
|
+
The Euler characteristic of a 2-sphere::
|
|
1154
|
+
|
|
1155
|
+
sage: S.euler_characteristic() # needs sage.graphs
|
|
1156
|
+
2
|
|
1157
|
+
"""
|
|
1158
|
+
from sage.topology.simplicial_complex_examples import Sphere as SymplicialSphere
|
|
1159
|
+
return SymplicialSphere(self._dim)
|
|
1160
|
+
|
|
1161
|
+
def center(self):
|
|
1162
|
+
r"""
|
|
1163
|
+
Return the barycenter of ``self`` in the ambient Euclidean space.
|
|
1164
|
+
|
|
1165
|
+
EXAMPLES:
|
|
1166
|
+
|
|
1167
|
+
2-sphere embedded in Euclidean space centered at `(1,2,3)` in
|
|
1168
|
+
Cartesian coordinates::
|
|
1169
|
+
|
|
1170
|
+
sage: E3 = EuclideanSpace(3)
|
|
1171
|
+
sage: c = E3.point((1,2,3), name='c')
|
|
1172
|
+
sage: S2c = manifolds.Sphere(2, ambient_space=E3, center=c); S2c
|
|
1173
|
+
2-sphere S^2(c) of radius 1 smoothly embedded in the Euclidean space
|
|
1174
|
+
E^3 centered at the Point c
|
|
1175
|
+
sage: S2c.center()
|
|
1176
|
+
Point c on the Euclidean space E^3
|
|
1177
|
+
|
|
1178
|
+
We can see that the embedding is shifted accordingly::
|
|
1179
|
+
|
|
1180
|
+
sage: S2c.embedding().display()
|
|
1181
|
+
iota: S^2(c) → E^3
|
|
1182
|
+
on A: (theta, phi) ↦ (x, y, z) = (cos(phi)*sin(theta) + 1,
|
|
1183
|
+
sin(phi)*sin(theta) + 2,
|
|
1184
|
+
cos(theta) + 3)
|
|
1185
|
+
"""
|
|
1186
|
+
return self._center
|