passagemath-symbolics 10.6.37__cp314-cp314t-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.6.37.dist-info/METADATA +187 -0
- passagemath_symbolics-10.6.37.dist-info/RECORD +172 -0
- passagemath_symbolics-10.6.37.dist-info/WHEEL +6 -0
- passagemath_symbolics-10.6.37.dist-info/top_level.txt +3 -0
- sage/all__sagemath_symbolics.py +17 -0
- sage/calculus/all.py +14 -0
- sage/calculus/calculus.py +2826 -0
- sage/calculus/desolvers.py +1866 -0
- sage/calculus/predefined.py +51 -0
- sage/calculus/tests.py +225 -0
- sage/calculus/var.cpython-314t-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-314t-darwin.so +0 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1035 -0
- sage/ext/all__sagemath_symbolics.py +1 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/ext_data/magma/latex/latex.m +1021 -0
- sage/ext_data/magma/latex/latex.spec +1 -0
- sage/ext_data/magma/sage/basic.m +356 -0
- sage/ext_data/magma/sage/sage.spec +1 -0
- sage/ext_data/magma/spec +9 -0
- sage/geometry/all__sagemath_symbolics.py +8 -0
- sage/geometry/hyperbolic_space/all.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_coercion.py +743 -0
- sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2409 -0
- sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
- sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1082 -0
- sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
- sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
- sage/geometry/riemannian_manifolds/all.py +7 -0
- sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
- sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
- sage/interfaces/all__sagemath_symbolics.py +1 -0
- sage/interfaces/magma.py +3017 -0
- sage/interfaces/magma_free.py +92 -0
- sage/interfaces/maple.py +1397 -0
- sage/interfaces/mathematica.py +1345 -0
- sage/interfaces/mathics.py +1312 -0
- sage/interfaces/sympy.py +1398 -0
- sage/interfaces/sympy_wrapper.py +197 -0
- sage/interfaces/tides.py +938 -0
- sage/libs/all__sagemath_symbolics.py +6 -0
- sage/manifolds/all.py +7 -0
- sage/manifolds/calculus_method.py +555 -0
- sage/manifolds/catalog.py +437 -0
- sage/manifolds/chart.py +4019 -0
- sage/manifolds/chart_func.py +3419 -0
- sage/manifolds/continuous_map.py +2183 -0
- sage/manifolds/continuous_map_image.py +155 -0
- sage/manifolds/differentiable/affine_connection.py +2475 -0
- sage/manifolds/differentiable/all.py +1 -0
- sage/manifolds/differentiable/automorphismfield.py +1383 -0
- sage/manifolds/differentiable/automorphismfield_group.py +604 -0
- sage/manifolds/differentiable/bundle_connection.py +1445 -0
- sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
- sage/manifolds/differentiable/chart.py +1241 -0
- sage/manifolds/differentiable/curve.py +1028 -0
- sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
- sage/manifolds/differentiable/degenerate.py +559 -0
- sage/manifolds/differentiable/degenerate_submanifold.py +1671 -0
- sage/manifolds/differentiable/diff_form.py +1658 -0
- sage/manifolds/differentiable/diff_form_module.py +1062 -0
- sage/manifolds/differentiable/diff_map.py +1315 -0
- sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
- sage/manifolds/differentiable/examples/all.py +1 -0
- sage/manifolds/differentiable/examples/euclidean.py +2517 -0
- sage/manifolds/differentiable/examples/real_line.py +897 -0
- sage/manifolds/differentiable/examples/sphere.py +1186 -0
- sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
- sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
- sage/manifolds/differentiable/integrated_curve.py +4035 -0
- sage/manifolds/differentiable/levi_civita_connection.py +841 -0
- sage/manifolds/differentiable/manifold.py +4254 -0
- sage/manifolds/differentiable/manifold_homset.py +1826 -0
- sage/manifolds/differentiable/metric.py +3032 -0
- sage/manifolds/differentiable/mixed_form.py +1507 -0
- sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
- sage/manifolds/differentiable/multivector_module.py +800 -0
- sage/manifolds/differentiable/multivectorfield.py +1520 -0
- sage/manifolds/differentiable/poisson_tensor.py +268 -0
- sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
- sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
- sage/manifolds/differentiable/scalarfield.py +1343 -0
- sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
- sage/manifolds/differentiable/symplectic_form.py +910 -0
- sage/manifolds/differentiable/symplectic_form_test.py +220 -0
- sage/manifolds/differentiable/tangent_space.py +412 -0
- sage/manifolds/differentiable/tangent_vector.py +616 -0
- sage/manifolds/differentiable/tensorfield.py +4665 -0
- sage/manifolds/differentiable/tensorfield_module.py +963 -0
- sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
- sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
- sage/manifolds/differentiable/vector_bundle.py +1728 -0
- sage/manifolds/differentiable/vectorfield.py +1717 -0
- sage/manifolds/differentiable/vectorfield_module.py +2445 -0
- sage/manifolds/differentiable/vectorframe.py +1832 -0
- sage/manifolds/family.py +270 -0
- sage/manifolds/local_frame.py +1490 -0
- sage/manifolds/manifold.py +3090 -0
- sage/manifolds/manifold_homset.py +452 -0
- sage/manifolds/operators.py +359 -0
- sage/manifolds/point.py +994 -0
- sage/manifolds/scalarfield.py +3718 -0
- sage/manifolds/scalarfield_algebra.py +629 -0
- sage/manifolds/section.py +3111 -0
- sage/manifolds/section_module.py +831 -0
- sage/manifolds/structure.py +229 -0
- sage/manifolds/subset.py +2764 -0
- sage/manifolds/subsets/all.py +1 -0
- sage/manifolds/subsets/closure.py +131 -0
- sage/manifolds/subsets/pullback.py +885 -0
- sage/manifolds/topological_submanifold.py +891 -0
- sage/manifolds/trivialization.py +733 -0
- sage/manifolds/utilities.py +1348 -0
- sage/manifolds/vector_bundle.py +1342 -0
- sage/manifolds/vector_bundle_fiber.py +332 -0
- sage/manifolds/vector_bundle_fiber_element.py +111 -0
- sage/matrix/all__sagemath_symbolics.py +1 -0
- sage/matrix/matrix_symbolic_dense.cpython-314t-darwin.so +0 -0
- sage/matrix/matrix_symbolic_dense.pxd +6 -0
- sage/matrix/matrix_symbolic_dense.pyx +1022 -0
- sage/matrix/matrix_symbolic_sparse.cpython-314t-darwin.so +0 -0
- sage/matrix/matrix_symbolic_sparse.pxd +6 -0
- sage/matrix/matrix_symbolic_sparse.pyx +1029 -0
- sage/modules/all__sagemath_symbolics.py +1 -0
- sage/modules/vector_callable_symbolic_dense.py +105 -0
- sage/modules/vector_symbolic_dense.py +116 -0
- sage/modules/vector_symbolic_sparse.py +118 -0
- sage/rings/all__sagemath_symbolics.py +4 -0
- sage/rings/asymptotic/all.py +6 -0
- sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
- sage/rings/asymptotic/asymptotic_ring.py +4858 -0
- sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4153 -0
- sage/rings/asymptotic/growth_group.py +5373 -0
- sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
- sage/rings/asymptotic/term_monoid.py +5237 -0
- sage/rings/function_field/all__sagemath_symbolics.py +2 -0
- sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
- sage/symbolic/all.py +15 -0
- sage/symbolic/assumptions.py +985 -0
- sage/symbolic/benchmark.py +93 -0
- sage/symbolic/callable.py +459 -0
- sage/symbolic/complexity_measures.py +35 -0
- sage/symbolic/constants.py +1287 -0
- sage/symbolic/expression_conversion_algebraic.py +310 -0
- sage/symbolic/expression_conversion_sympy.py +317 -0
- sage/symbolic/expression_conversions.py +1713 -0
- sage/symbolic/function_factory.py +355 -0
- sage/symbolic/integration/all.py +1 -0
- sage/symbolic/integration/external.py +270 -0
- sage/symbolic/integration/integral.py +1115 -0
- sage/symbolic/maxima_wrapper.py +162 -0
- sage/symbolic/operators.py +267 -0
- sage/symbolic/random_tests.py +462 -0
- sage/symbolic/relation.py +1907 -0
- sage/symbolic/ring.cpython-314t-darwin.so +0 -0
- sage/symbolic/ring.pxd +5 -0
- sage/symbolic/ring.pyx +1396 -0
- sage/symbolic/subring.py +1025 -0
- sage/symbolic/symengine.py +19 -0
- sage/symbolic/tests.py +40 -0
- sage/symbolic/units.py +1470 -0
|
@@ -0,0 +1,1315 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-symbolics
|
|
2
|
+
r"""
|
|
3
|
+
Differentiable Maps between Differentiable Manifolds
|
|
4
|
+
|
|
5
|
+
The class :class:`DiffMap` implements differentiable maps from a differentiable
|
|
6
|
+
manifold `M` to a differentiable manifold `N` over the same topological field
|
|
7
|
+
`K` as `M` (in most applications, `K = \RR` or `K = \CC`):
|
|
8
|
+
|
|
9
|
+
.. MATH::
|
|
10
|
+
|
|
11
|
+
\Phi: M \longrightarrow N
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
AUTHORS:
|
|
15
|
+
|
|
16
|
+
- Eric Gourgoulhon, Michal Bejger (2013-2015): initial version
|
|
17
|
+
- Marco Mancini (2018): pullback parallelization
|
|
18
|
+
|
|
19
|
+
REFERENCES:
|
|
20
|
+
|
|
21
|
+
- Chap. 1 of [KN1963]_
|
|
22
|
+
- Chaps. 2 and 3 of [Lee2013]_
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
# ****************************************************************************
|
|
26
|
+
# Copyright (C) 2015-2021 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
|
|
27
|
+
# Copyright (C) 2015 Michal Bejger <bejger@camk.edu.pl>
|
|
28
|
+
# Copyright (C) 2018 Marco Mancini <marco.mancini@obspm.fr>
|
|
29
|
+
#
|
|
30
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
31
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
32
|
+
# the License, or (at your option) any later version.
|
|
33
|
+
# https://www.gnu.org/licenses/
|
|
34
|
+
# ****************************************************************************
|
|
35
|
+
from __future__ import annotations
|
|
36
|
+
|
|
37
|
+
from typing import TYPE_CHECKING
|
|
38
|
+
|
|
39
|
+
from sage.manifolds.continuous_map import ContinuousMap
|
|
40
|
+
from sage.parallel.decorate import parallel
|
|
41
|
+
from sage.parallel.parallelism import Parallelism
|
|
42
|
+
|
|
43
|
+
if TYPE_CHECKING:
|
|
44
|
+
from sage.manifolds.point import ManifoldPoint
|
|
45
|
+
from sage.tensor.modules.free_module_morphism import FiniteRankFreeModuleMorphism
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class DiffMap(ContinuousMap):
|
|
49
|
+
r"""
|
|
50
|
+
Differentiable map between two differentiable manifolds.
|
|
51
|
+
|
|
52
|
+
This class implements differentiable maps of the type
|
|
53
|
+
|
|
54
|
+
.. MATH::
|
|
55
|
+
|
|
56
|
+
\Phi: M \longrightarrow N
|
|
57
|
+
|
|
58
|
+
where `M` and `N` are differentiable manifolds over the same topological
|
|
59
|
+
field `K` (in most applications, `K = \RR` or `K = \CC`).
|
|
60
|
+
|
|
61
|
+
Differentiable maps are the *morphisms* of the *category* of
|
|
62
|
+
differentiable manifolds. The set of all differentiable maps from `M` to
|
|
63
|
+
`N` is therefore the homset between `M` and `N`, which is denoted by
|
|
64
|
+
`\mathrm{Hom}(M,N)`.
|
|
65
|
+
|
|
66
|
+
The class :class:`DiffMap` is a Sage *element* class, whose *parent*
|
|
67
|
+
class is
|
|
68
|
+
:class:`~sage.manifolds.differentiable.manifold_homset.DifferentiableManifoldHomset`.
|
|
69
|
+
It inherits from the class
|
|
70
|
+
:class:`~sage.manifolds.continuous_map.ContinuousMap` since a
|
|
71
|
+
differentiable map is obviously a continuous one.
|
|
72
|
+
|
|
73
|
+
INPUT:
|
|
74
|
+
|
|
75
|
+
- ``parent`` -- homset `\mathrm{Hom}(M,N)` to which the differentiable
|
|
76
|
+
map belongs
|
|
77
|
+
- ``coord_functions`` -- (default: ``None``) if not ``None``, must be
|
|
78
|
+
a dictionary of the coordinate expressions (as lists (or tuples) of the
|
|
79
|
+
coordinates of the image expressed in terms of the coordinates of
|
|
80
|
+
the considered point) with the pairs of charts (chart1, chart2)
|
|
81
|
+
as keys (chart1 being a chart on `M` and chart2 a chart on `N`).
|
|
82
|
+
If the dimension of the map's codomain is 1, a single coordinate
|
|
83
|
+
expression can be passed instead of a tuple with a single element
|
|
84
|
+
- ``name`` -- (default: ``None``) name given to the differentiable map
|
|
85
|
+
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
|
|
86
|
+
differentiable map; if ``None``, the LaTeX symbol is set to ``name``
|
|
87
|
+
- ``is_isomorphism`` -- boolean (default: ``False``); determines whether the
|
|
88
|
+
constructed object is a isomorphism (i.e. a diffeomorphism). If set to
|
|
89
|
+
``True``, then the manifolds `M` and `N` must have the same dimension.
|
|
90
|
+
- ``is_identity`` -- boolean (default: ``False``); determines whether the
|
|
91
|
+
constructed object is the identity map. If set to ``True``,
|
|
92
|
+
then `N` must be `M` and the entry ``coord_functions`` is not used.
|
|
93
|
+
|
|
94
|
+
.. NOTE::
|
|
95
|
+
|
|
96
|
+
If the information passed by means of the argument ``coord_functions``
|
|
97
|
+
is not sufficient to fully specify the differentiable map,
|
|
98
|
+
further coordinate expressions, in other charts, can be subsequently
|
|
99
|
+
added by means of the method
|
|
100
|
+
:meth:`~sage.manifolds.continuous_map.ContinuousMap.add_expr`
|
|
101
|
+
|
|
102
|
+
EXAMPLES:
|
|
103
|
+
|
|
104
|
+
The standard embedding of the sphere `S^2` into `\RR^3`::
|
|
105
|
+
|
|
106
|
+
sage: M = Manifold(2, 'S^2') # the 2-dimensional sphere S^2
|
|
107
|
+
sage: U = M.open_subset('U') # complement of the North pole
|
|
108
|
+
sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
|
|
109
|
+
sage: V = M.open_subset('V') # complement of the South pole
|
|
110
|
+
sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
|
|
111
|
+
sage: M.declare_union(U,V) # S^2 is the union of U and V
|
|
112
|
+
sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)),
|
|
113
|
+
....: intersection_name='W', restrictions1= x^2+y^2!=0,
|
|
114
|
+
....: restrictions2= u^2+v^2!=0)
|
|
115
|
+
sage: uv_to_xy = xy_to_uv.inverse()
|
|
116
|
+
sage: N = Manifold(3, 'R^3', r'\RR^3') # R^3
|
|
117
|
+
sage: c_cart.<X,Y,Z> = N.chart() # Cartesian coordinates on R^3
|
|
118
|
+
sage: Phi = M.diff_map(N,
|
|
119
|
+
....: {(c_xy, c_cart): [2*x/(1+x^2+y^2), 2*y/(1+x^2+y^2), (x^2+y^2-1)/(1+x^2+y^2)],
|
|
120
|
+
....: (c_uv, c_cart): [2*u/(1+u^2+v^2), 2*v/(1+u^2+v^2), (1-u^2-v^2)/(1+u^2+v^2)]},
|
|
121
|
+
....: name='Phi', latex_name=r'\Phi')
|
|
122
|
+
sage: Phi
|
|
123
|
+
Differentiable map Phi from the 2-dimensional differentiable manifold
|
|
124
|
+
S^2 to the 3-dimensional differentiable manifold R^3
|
|
125
|
+
sage: Phi.parent()
|
|
126
|
+
Set of Morphisms from 2-dimensional differentiable manifold S^2 to
|
|
127
|
+
3-dimensional differentiable manifold R^3 in Category of smooth
|
|
128
|
+
manifolds over Real Field with 53 bits of precision
|
|
129
|
+
sage: Phi.parent() is Hom(M, N)
|
|
130
|
+
True
|
|
131
|
+
sage: type(Phi)
|
|
132
|
+
<class 'sage.manifolds.differentiable.manifold_homset.DifferentiableManifoldHomset_with_category.element_class'>
|
|
133
|
+
sage: Phi.display()
|
|
134
|
+
Phi: S^2 → R^3
|
|
135
|
+
on U: (x, y) ↦ (X, Y, Z) = (2*x/(x^2 + y^2 + 1), 2*y/(x^2 + y^2 + 1),
|
|
136
|
+
(x^2 + y^2 - 1)/(x^2 + y^2 + 1))
|
|
137
|
+
on V: (u, v) ↦ (X, Y, Z) = (2*u/(u^2 + v^2 + 1), 2*v/(u^2 + v^2 + 1),
|
|
138
|
+
-(u^2 + v^2 - 1)/(u^2 + v^2 + 1))
|
|
139
|
+
|
|
140
|
+
It is possible to create the map via the method
|
|
141
|
+
:meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.diff_map`
|
|
142
|
+
only in a single pair of charts: the argument ``coord_functions`` is then
|
|
143
|
+
a mere list of coordinate expressions (and not a dictionary) and the
|
|
144
|
+
arguments ``chart1`` and ``chart2`` have to be provided if the charts
|
|
145
|
+
differ from the default ones on the domain and/or the codomain::
|
|
146
|
+
|
|
147
|
+
sage: Phi1 = M.diff_map(N, [2*x/(1+x^2+y^2), 2*y/(1+x^2+y^2),
|
|
148
|
+
....: (x^2+y^2-1)/(1+x^2+y^2)],
|
|
149
|
+
....: chart1=c_xy, chart2=c_cart, name='Phi',
|
|
150
|
+
....: latex_name=r'\Phi')
|
|
151
|
+
|
|
152
|
+
Since ``c_xy`` and ``c_cart`` are the default charts on respectively ``M``
|
|
153
|
+
and ``N``, they can be omitted, so that the above declaration is equivalent
|
|
154
|
+
to::
|
|
155
|
+
|
|
156
|
+
sage: Phi1 = M.diff_map(N, [2*x/(1+x^2+y^2), 2*y/(1+x^2+y^2),
|
|
157
|
+
....: (x^2+y^2-1)/(1+x^2+y^2)],
|
|
158
|
+
....: name='Phi', latex_name=r'\Phi')
|
|
159
|
+
|
|
160
|
+
With such a declaration, the differentiable map is only partially defined
|
|
161
|
+
on the manifold `S^2`, being known in only one chart::
|
|
162
|
+
|
|
163
|
+
sage: Phi1.display()
|
|
164
|
+
Phi: S^2 → R^3
|
|
165
|
+
on U: (x, y) ↦ (X, Y, Z) = (2*x/(x^2 + y^2 + 1), 2*y/(x^2 + y^2 + 1),
|
|
166
|
+
(x^2 + y^2 - 1)/(x^2 + y^2 + 1))
|
|
167
|
+
|
|
168
|
+
The definition can be completed by means of the method
|
|
169
|
+
:meth:`~sage.manifolds.continuous_map.ContinuousMap.add_expr`::
|
|
170
|
+
|
|
171
|
+
sage: Phi1.add_expr(c_uv, c_cart, [2*u/(1+u^2+v^2), 2*v/(1+u^2+v^2),
|
|
172
|
+
....: (1-u^2-v^2)/(1+u^2+v^2)])
|
|
173
|
+
sage: Phi1.display()
|
|
174
|
+
Phi: S^2 → R^3
|
|
175
|
+
on U: (x, y) ↦ (X, Y, Z) = (2*x/(x^2 + y^2 + 1), 2*y/(x^2 + y^2 + 1),
|
|
176
|
+
(x^2 + y^2 - 1)/(x^2 + y^2 + 1))
|
|
177
|
+
on V: (u, v) ↦ (X, Y, Z) = (2*u/(u^2 + v^2 + 1), 2*v/(u^2 + v^2 + 1),
|
|
178
|
+
-(u^2 + v^2 - 1)/(u^2 + v^2 + 1))
|
|
179
|
+
|
|
180
|
+
At this stage, ``Phi1`` and ``Phi`` are fully equivalent::
|
|
181
|
+
|
|
182
|
+
sage: Phi1 == Phi
|
|
183
|
+
True
|
|
184
|
+
|
|
185
|
+
The test suite is passed::
|
|
186
|
+
|
|
187
|
+
sage: TestSuite(Phi).run()
|
|
188
|
+
sage: TestSuite(Phi1).run()
|
|
189
|
+
|
|
190
|
+
The map acts on points::
|
|
191
|
+
|
|
192
|
+
sage: np = M.point((0,0), chart=c_uv, name='N') # the North pole
|
|
193
|
+
sage: Phi(np)
|
|
194
|
+
Point Phi(N) on the 3-dimensional differentiable manifold R^3
|
|
195
|
+
sage: Phi(np).coord() # Cartesian coordinates
|
|
196
|
+
(0, 0, 1)
|
|
197
|
+
sage: sp = M.point((0,0), chart=c_xy, name='S') # the South pole
|
|
198
|
+
sage: Phi(sp).coord() # Cartesian coordinates
|
|
199
|
+
(0, 0, -1)
|
|
200
|
+
|
|
201
|
+
The differential `\mathrm{d}\Phi` of the map `\Phi` at the North pole and
|
|
202
|
+
at the South pole::
|
|
203
|
+
|
|
204
|
+
sage: Phi.differential(np)
|
|
205
|
+
Generic morphism:
|
|
206
|
+
From: Tangent space at Point N on the 2-dimensional differentiable manifold S^2
|
|
207
|
+
To: Tangent space at Point Phi(N) on the 3-dimensional differentiable manifold R^3
|
|
208
|
+
sage: Phi.differential(sp)
|
|
209
|
+
Generic morphism:
|
|
210
|
+
From: Tangent space at Point S on the 2-dimensional differentiable manifold S^2
|
|
211
|
+
To: Tangent space at Point Phi(S) on the 3-dimensional differentiable manifold R^3
|
|
212
|
+
|
|
213
|
+
The matrix of the linear map `\mathrm{d}\Phi_N` with respect to the default
|
|
214
|
+
bases of `T_N S^2` and `T_{\Phi(N)} \RR^3`::
|
|
215
|
+
|
|
216
|
+
sage: Phi.differential(np).matrix()
|
|
217
|
+
[2 0]
|
|
218
|
+
[0 2]
|
|
219
|
+
[0 0]
|
|
220
|
+
|
|
221
|
+
the default bases being::
|
|
222
|
+
|
|
223
|
+
sage: Phi.differential(np).domain().default_basis()
|
|
224
|
+
Basis (∂/∂u,∂/∂v) on the Tangent space at Point N on the 2-dimensional
|
|
225
|
+
differentiable manifold S^2
|
|
226
|
+
sage: Phi.differential(np).codomain().default_basis()
|
|
227
|
+
Basis (∂/∂X,∂/∂Y,∂/∂Z) on the Tangent space at Point Phi(N) on the
|
|
228
|
+
3-dimensional differentiable manifold R^3
|
|
229
|
+
|
|
230
|
+
A convenient way to display the matrix of the differential::
|
|
231
|
+
|
|
232
|
+
sage: Phi.differential(np).display()
|
|
233
|
+
∂/∂u ∂/∂v
|
|
234
|
+
∂/∂X⎛ 2 0⎞
|
|
235
|
+
∂/∂Y⎜ 0 2⎟
|
|
236
|
+
∂/∂Z⎝ 0 0⎠
|
|
237
|
+
|
|
238
|
+
Differentiable maps can be composed by means of the operator ``*``: let
|
|
239
|
+
us introduce the map `\RR^3\rightarrow \RR^2` corresponding to
|
|
240
|
+
the projection from the point `(X,Y,Z)=(0,0,1)` onto the equatorial plane
|
|
241
|
+
`Z=0`::
|
|
242
|
+
|
|
243
|
+
sage: P = Manifold(2, 'R^2', r'\RR^2') # R^2 (equatorial plane)
|
|
244
|
+
sage: cP.<xP, yP> = P.chart()
|
|
245
|
+
sage: Psi = N.diff_map(P, (X/(1-Z), Y/(1-Z)), name='Psi',
|
|
246
|
+
....: latex_name=r'\Psi')
|
|
247
|
+
sage: Psi
|
|
248
|
+
Differentiable map Psi from the 3-dimensional differentiable manifold
|
|
249
|
+
R^3 to the 2-dimensional differentiable manifold R^2
|
|
250
|
+
sage: Psi.display()
|
|
251
|
+
Psi: R^3 → R^2
|
|
252
|
+
(X, Y, Z) ↦ (xP, yP) = (-X/(Z - 1), -Y/(Z - 1))
|
|
253
|
+
|
|
254
|
+
Then we compose ``Psi`` with ``Phi``, thereby getting a map
|
|
255
|
+
`S^2\rightarrow \RR^2`::
|
|
256
|
+
|
|
257
|
+
sage: ster = Psi*Phi ; ster
|
|
258
|
+
Differentiable map from the 2-dimensional differentiable manifold S^2
|
|
259
|
+
to the 2-dimensional differentiable manifold R^2
|
|
260
|
+
|
|
261
|
+
Let us test on the South pole (``sp``) that ``ster`` is indeed the
|
|
262
|
+
composite of ``Psi`` and ``Phi``::
|
|
263
|
+
|
|
264
|
+
sage: ster(sp) == Psi(Phi(sp))
|
|
265
|
+
True
|
|
266
|
+
|
|
267
|
+
Actually ``ster`` is the stereographic projection from the North pole, as
|
|
268
|
+
its coordinate expression reveals::
|
|
269
|
+
|
|
270
|
+
sage: ster.display()
|
|
271
|
+
S^2 → R^2
|
|
272
|
+
on U: (x, y) ↦ (xP, yP) = (x, y)
|
|
273
|
+
on V: (u, v) ↦ (xP, yP) = (u/(u^2 + v^2), v/(u^2 + v^2))
|
|
274
|
+
|
|
275
|
+
If its codomain is 1-dimensional, a differentiable map must be
|
|
276
|
+
defined by a single symbolic expression for each pair of charts, and not
|
|
277
|
+
by a list/tuple with a single element::
|
|
278
|
+
|
|
279
|
+
sage: N = Manifold(1, 'N')
|
|
280
|
+
sage: c_N = N.chart('X')
|
|
281
|
+
sage: Phi = M.diff_map(N, {(c_xy, c_N): x^2+y^2,
|
|
282
|
+
....: (c_uv, c_N): 1/(u^2+v^2)}) # not ...[1/(u^2+v^2)] or (1/(u^2+v^2),)
|
|
283
|
+
|
|
284
|
+
An example of differentiable map `\RR \rightarrow \RR^2`::
|
|
285
|
+
|
|
286
|
+
sage: R = Manifold(1, 'R') # field R
|
|
287
|
+
sage: T.<t> = R.chart() # canonical chart on R
|
|
288
|
+
sage: R2 = Manifold(2, 'R^2') # R^2
|
|
289
|
+
sage: c_xy.<x,y> = R2.chart() # Cartesian coordinates on R^2
|
|
290
|
+
sage: Phi = R.diff_map(R2, [cos(t), sin(t)], name='Phi') ; Phi
|
|
291
|
+
Differentiable map Phi from the 1-dimensional differentiable manifold R
|
|
292
|
+
to the 2-dimensional differentiable manifold R^2
|
|
293
|
+
sage: Phi.parent()
|
|
294
|
+
Set of Morphisms from 1-dimensional differentiable manifold R to
|
|
295
|
+
2-dimensional differentiable manifold R^2 in Category of smooth
|
|
296
|
+
manifolds over Real Field with 53 bits of precision
|
|
297
|
+
sage: Phi.parent() is Hom(R, R2)
|
|
298
|
+
True
|
|
299
|
+
sage: Phi.display()
|
|
300
|
+
Phi: R → R^2
|
|
301
|
+
t ↦ (x, y) = (cos(t), sin(t))
|
|
302
|
+
|
|
303
|
+
An example of diffeomorphism between the unit open disk and the Euclidean
|
|
304
|
+
plane `\RR^2`::
|
|
305
|
+
|
|
306
|
+
sage: D = R2.open_subset('D', coord_def={c_xy: x^2+y^2<1}) # the open unit disk
|
|
307
|
+
sage: Phi = D.diffeomorphism(R2, [x/sqrt(1-x^2-y^2), y/sqrt(1-x^2-y^2)],
|
|
308
|
+
....: name='Phi', latex_name=r'\Phi')
|
|
309
|
+
sage: Phi
|
|
310
|
+
Diffeomorphism Phi from the Open subset D of the 2-dimensional
|
|
311
|
+
differentiable manifold R^2 to the 2-dimensional differentiable
|
|
312
|
+
manifold R^2
|
|
313
|
+
sage: Phi.parent()
|
|
314
|
+
Set of Morphisms from Open subset D of the 2-dimensional differentiable
|
|
315
|
+
manifold R^2 to 2-dimensional differentiable manifold R^2 in Category
|
|
316
|
+
of smooth manifolds over Real Field with 53 bits of precision
|
|
317
|
+
sage: Phi.parent() is Hom(D, R2)
|
|
318
|
+
True
|
|
319
|
+
sage: Phi.display()
|
|
320
|
+
Phi: D → R^2
|
|
321
|
+
(x, y) ↦ (x, y) = (x/sqrt(-x^2 - y^2 + 1), y/sqrt(-x^2 - y^2 + 1))
|
|
322
|
+
|
|
323
|
+
The image of a point::
|
|
324
|
+
|
|
325
|
+
sage: p = D.point((1/2,0))
|
|
326
|
+
sage: q = Phi(p) ; q
|
|
327
|
+
Point on the 2-dimensional differentiable manifold R^2
|
|
328
|
+
sage: q.coord()
|
|
329
|
+
(1/3*sqrt(3), 0)
|
|
330
|
+
|
|
331
|
+
The inverse diffeomorphism is computed by means of the method
|
|
332
|
+
:meth:`~sage.manifolds.continuous_map.ContinuousMap.inverse`::
|
|
333
|
+
|
|
334
|
+
sage: Phi.inverse()
|
|
335
|
+
Diffeomorphism Phi^(-1) from the 2-dimensional differentiable manifold R^2
|
|
336
|
+
to the Open subset D of the 2-dimensional differentiable manifold R^2
|
|
337
|
+
sage: Phi.inverse().display()
|
|
338
|
+
Phi^(-1): R^2 → D
|
|
339
|
+
(x, y) ↦ (x, y) = (x/sqrt(x^2 + y^2 + 1), y/sqrt(x^2 + y^2 + 1))
|
|
340
|
+
|
|
341
|
+
Equivalently, one may use the notations ``^(-1)`` or ``~`` to get the
|
|
342
|
+
inverse::
|
|
343
|
+
|
|
344
|
+
sage: Phi^(-1) is Phi.inverse()
|
|
345
|
+
True
|
|
346
|
+
sage: ~Phi is Phi.inverse()
|
|
347
|
+
True
|
|
348
|
+
|
|
349
|
+
Check that ``~Phi`` is indeed the inverse of ``Phi``::
|
|
350
|
+
|
|
351
|
+
sage: (~Phi)(q) == p
|
|
352
|
+
True
|
|
353
|
+
sage: Phi * ~Phi == R2.identity_map()
|
|
354
|
+
True
|
|
355
|
+
sage: ~Phi * Phi == D.identity_map()
|
|
356
|
+
True
|
|
357
|
+
|
|
358
|
+
The coordinate expression of the inverse diffeomorphism::
|
|
359
|
+
|
|
360
|
+
sage: (~Phi).display()
|
|
361
|
+
Phi^(-1): R^2 → D
|
|
362
|
+
(x, y) ↦ (x, y) = (x/sqrt(x^2 + y^2 + 1), y/sqrt(x^2 + y^2 + 1))
|
|
363
|
+
|
|
364
|
+
A special case of diffeomorphism: the identity map of the open unit disk::
|
|
365
|
+
|
|
366
|
+
sage: id = D.identity_map() ; id
|
|
367
|
+
Identity map Id_D of the Open subset D of the 2-dimensional
|
|
368
|
+
differentiable manifold R^2
|
|
369
|
+
sage: latex(id)
|
|
370
|
+
\mathrm{Id}_{D}
|
|
371
|
+
sage: id.parent()
|
|
372
|
+
Set of Morphisms from Open subset D of the 2-dimensional differentiable
|
|
373
|
+
manifold R^2 to Open subset D of the 2-dimensional differentiable
|
|
374
|
+
manifold R^2 in Join of Category of subobjects of sets and Category of
|
|
375
|
+
smooth manifolds over Real Field with 53 bits of precision
|
|
376
|
+
sage: id.parent() is Hom(D, D)
|
|
377
|
+
True
|
|
378
|
+
sage: id is Hom(D,D).one() # the identity element of the monoid Hom(D,D)
|
|
379
|
+
True
|
|
380
|
+
|
|
381
|
+
The identity map acting on a point::
|
|
382
|
+
|
|
383
|
+
sage: id(p)
|
|
384
|
+
Point on the 2-dimensional differentiable manifold R^2
|
|
385
|
+
sage: id(p) == p
|
|
386
|
+
True
|
|
387
|
+
sage: id(p) is p
|
|
388
|
+
True
|
|
389
|
+
|
|
390
|
+
The coordinate expression of the identity map::
|
|
391
|
+
|
|
392
|
+
sage: id.display()
|
|
393
|
+
Id_D: D → D
|
|
394
|
+
(x, y) ↦ (x, y)
|
|
395
|
+
|
|
396
|
+
The identity map is its own inverse::
|
|
397
|
+
|
|
398
|
+
sage: id^(-1) is id
|
|
399
|
+
True
|
|
400
|
+
sage: ~id is id
|
|
401
|
+
True
|
|
402
|
+
"""
|
|
403
|
+
def __init__(self, parent, coord_functions=None, name=None,
|
|
404
|
+
latex_name=None, is_isomorphism=False, is_identity=False):
|
|
405
|
+
r"""
|
|
406
|
+
Construct a differentiable map.
|
|
407
|
+
|
|
408
|
+
TESTS::
|
|
409
|
+
|
|
410
|
+
sage: M = Manifold(2, 'M')
|
|
411
|
+
sage: X.<x,y> = M.chart()
|
|
412
|
+
sage: N = Manifold(3, 'N')
|
|
413
|
+
sage: Y.<u,v,w> = N.chart()
|
|
414
|
+
sage: f = Hom(M,N)({(X,Y): (x+y, x*y, x-y)}, name='f') ; f
|
|
415
|
+
Differentiable map f from the 2-dimensional differentiable manifold
|
|
416
|
+
M to the 3-dimensional differentiable manifold N
|
|
417
|
+
sage: f.display()
|
|
418
|
+
f: M → N
|
|
419
|
+
(x, y) ↦ (u, v, w) = (x + y, x*y, x - y)
|
|
420
|
+
sage: TestSuite(f).run()
|
|
421
|
+
|
|
422
|
+
The identity map::
|
|
423
|
+
|
|
424
|
+
sage: f = Hom(M,M)({}, is_identity=True) ; f
|
|
425
|
+
Identity map Id_M of the 2-dimensional differentiable manifold M
|
|
426
|
+
sage: f.display()
|
|
427
|
+
Id_M: M → M
|
|
428
|
+
(x, y) ↦ (x, y)
|
|
429
|
+
sage: TestSuite(f).run()
|
|
430
|
+
"""
|
|
431
|
+
ContinuousMap.__init__(self, parent, coord_functions=coord_functions,
|
|
432
|
+
name=name, latex_name=latex_name,
|
|
433
|
+
is_isomorphism=is_isomorphism,
|
|
434
|
+
is_identity=is_identity)
|
|
435
|
+
|
|
436
|
+
#
|
|
437
|
+
# SageObject methods
|
|
438
|
+
#
|
|
439
|
+
|
|
440
|
+
def _repr_(self):
|
|
441
|
+
r"""
|
|
442
|
+
String representation of the object.
|
|
443
|
+
|
|
444
|
+
TESTS::
|
|
445
|
+
|
|
446
|
+
sage: M = Manifold(2, 'M')
|
|
447
|
+
sage: X.<x,y> = M.chart()
|
|
448
|
+
sage: N = Manifold(2, 'N')
|
|
449
|
+
sage: Y.<u,v> = N.chart()
|
|
450
|
+
sage: f = Hom(M,N)({(X,Y): (x+y,x*y)})
|
|
451
|
+
sage: f._repr_()
|
|
452
|
+
'Differentiable map from the 2-dimensional differentiable manifold M to
|
|
453
|
+
the 2-dimensional differentiable manifold N'
|
|
454
|
+
sage: f = Hom(M,N)({(X,Y): (x+y,x*y)}, name='f')
|
|
455
|
+
sage: f._repr_()
|
|
456
|
+
'Differentiable map f from the 2-dimensional differentiable manifold M to
|
|
457
|
+
the 2-dimensional differentiable manifold N'
|
|
458
|
+
sage: f = Hom(M,N)({(X,Y): (x+y,x-y)}, name='f', is_isomorphism=True)
|
|
459
|
+
sage: f._repr_()
|
|
460
|
+
'Diffeomorphism f from the 2-dimensional differentiable manifold M to
|
|
461
|
+
the 2-dimensional differentiable manifold N'
|
|
462
|
+
sage: f = Hom(M,M)({(X,X): (x+y,x-y)}, name='f', is_isomorphism=True)
|
|
463
|
+
sage: f._repr_()
|
|
464
|
+
'Diffeomorphism f of the 2-dimensional differentiable manifold M'
|
|
465
|
+
sage: f = Hom(M,M)({}, name='f', is_identity=True)
|
|
466
|
+
sage: f._repr_()
|
|
467
|
+
'Identity map f of the 2-dimensional differentiable manifold M'
|
|
468
|
+
"""
|
|
469
|
+
if self._is_identity:
|
|
470
|
+
return "Identity map " + self._name + \
|
|
471
|
+
" of the {}".format(self._domain)
|
|
472
|
+
if self._is_isomorphism:
|
|
473
|
+
description = "Diffeomorphism"
|
|
474
|
+
else:
|
|
475
|
+
description = "Differentiable map"
|
|
476
|
+
if self._name is not None:
|
|
477
|
+
description += " " + self._name
|
|
478
|
+
if self._domain == self._codomain:
|
|
479
|
+
if self._is_isomorphism:
|
|
480
|
+
description += " of the {}".format(self._domain)
|
|
481
|
+
else:
|
|
482
|
+
description += " from the {} to itself".format(self._domain)
|
|
483
|
+
else:
|
|
484
|
+
description += " from the {} to the {}".format(self._domain,
|
|
485
|
+
self._codomain)
|
|
486
|
+
return description
|
|
487
|
+
|
|
488
|
+
def _init_derived(self):
|
|
489
|
+
r"""
|
|
490
|
+
Initialize the derived quantities.
|
|
491
|
+
|
|
492
|
+
TESTS::
|
|
493
|
+
|
|
494
|
+
sage: M = Manifold(2, 'M')
|
|
495
|
+
sage: X.<x,y> = M.chart()
|
|
496
|
+
sage: f = M.diffeomorphism(M, [x+y, x-y])
|
|
497
|
+
sage: f._init_derived()
|
|
498
|
+
sage: f._restrictions
|
|
499
|
+
{}
|
|
500
|
+
sage: f._inverse
|
|
501
|
+
"""
|
|
502
|
+
ContinuousMap._init_derived(self)
|
|
503
|
+
# derived quantities of the mother class
|
|
504
|
+
self._diff = {}
|
|
505
|
+
# dict. of the coord. expressions of the differential
|
|
506
|
+
# keys: pair of charts
|
|
507
|
+
|
|
508
|
+
def _del_derived(self):
|
|
509
|
+
r"""
|
|
510
|
+
Delete the derived quantities.
|
|
511
|
+
|
|
512
|
+
TESTS::
|
|
513
|
+
|
|
514
|
+
sage: M = Manifold(2, 'M')
|
|
515
|
+
sage: X.<x,y> = M.chart()
|
|
516
|
+
sage: f = M.diffeomorphism(M, [x+y, x-y])
|
|
517
|
+
sage: f^(-1)
|
|
518
|
+
Diffeomorphism of the 2-dimensional differentiable manifold M
|
|
519
|
+
sage: f._inverse # was set by f^(-1)
|
|
520
|
+
Diffeomorphism of the 2-dimensional differentiable manifold M
|
|
521
|
+
sage: f._del_derived()
|
|
522
|
+
sage: f._inverse # has been set to None by _del_derived()
|
|
523
|
+
"""
|
|
524
|
+
ContinuousMap._del_derived(self) # derived quantities of the mother
|
|
525
|
+
# class
|
|
526
|
+
self._diff.clear()
|
|
527
|
+
|
|
528
|
+
def differential(self, point: ManifoldPoint) -> FiniteRankFreeModuleMorphism:
|
|
529
|
+
r"""
|
|
530
|
+
Return the differential of ``self`` at a given point.
|
|
531
|
+
|
|
532
|
+
If the differentiable map ``self`` is
|
|
533
|
+
|
|
534
|
+
.. MATH::
|
|
535
|
+
|
|
536
|
+
\Phi: M \longrightarrow N,
|
|
537
|
+
|
|
538
|
+
where `M` and `N` are differentiable manifolds, the *differential*
|
|
539
|
+
of `\Phi` at a point `p \in M` is the tangent space linear map:
|
|
540
|
+
|
|
541
|
+
.. MATH::
|
|
542
|
+
|
|
543
|
+
\mathrm{d}\Phi_p: T_p M \longrightarrow T_{\Phi(p)} N
|
|
544
|
+
|
|
545
|
+
defined by
|
|
546
|
+
|
|
547
|
+
.. MATH::
|
|
548
|
+
|
|
549
|
+
\begin{array}{rccc}
|
|
550
|
+
\forall v\in T_p M,\quad \mathrm{d}\Phi_p(v) :
|
|
551
|
+
& C^k(N) & \longrightarrow & \mathbb{R} \\
|
|
552
|
+
& f & \longmapsto & v(f\circ \Phi)
|
|
553
|
+
\end{array}
|
|
554
|
+
|
|
555
|
+
INPUT:
|
|
556
|
+
|
|
557
|
+
- ``point`` -- point `p` in the domain `M` of the differentiable
|
|
558
|
+
map `\Phi`
|
|
559
|
+
|
|
560
|
+
OUTPUT:
|
|
561
|
+
|
|
562
|
+
- `\mathrm{d}\Phi_p`, the differential of `\Phi` at `p`, as a
|
|
563
|
+
:class:`~sage.tensor.modules.free_module_morphism.FiniteRankFreeModuleMorphism`
|
|
564
|
+
|
|
565
|
+
EXAMPLES:
|
|
566
|
+
|
|
567
|
+
Differential of a differentiable map between a 2-dimensional manifold
|
|
568
|
+
and a 3-dimensional one::
|
|
569
|
+
|
|
570
|
+
sage: M = Manifold(2, 'M')
|
|
571
|
+
sage: X.<x,y> = M.chart()
|
|
572
|
+
sage: N = Manifold(3, 'N')
|
|
573
|
+
sage: Y.<u,v,w> = N.chart()
|
|
574
|
+
sage: Phi = M.diff_map(N, {(X,Y): (x-2*y, x*y, x^2-y^3)}, name='Phi',
|
|
575
|
+
....: latex_name = r'\Phi')
|
|
576
|
+
sage: p = M.point((2,-1), name='p')
|
|
577
|
+
sage: dPhip = Phi.differential(p) ; dPhip
|
|
578
|
+
Generic morphism:
|
|
579
|
+
From: Tangent space at Point p on the 2-dimensional differentiable manifold M
|
|
580
|
+
To: Tangent space at Point Phi(p) on the 3-dimensional differentiable manifold N
|
|
581
|
+
sage: latex(dPhip)
|
|
582
|
+
{\mathrm{d}\Phi}_{p}
|
|
583
|
+
sage: dPhip.parent()
|
|
584
|
+
Set of Morphisms from Tangent space at Point p on the 2-dimensional
|
|
585
|
+
differentiable manifold M to Tangent space at Point Phi(p) on the
|
|
586
|
+
3-dimensional differentiable manifold N in Category of finite
|
|
587
|
+
dimensional vector spaces over Symbolic Ring
|
|
588
|
+
|
|
589
|
+
The matrix of `\mathrm{d}\Phi_p` w.r.t. to the default bases of
|
|
590
|
+
`T_p M` and `T_{\Phi(p)} N`::
|
|
591
|
+
|
|
592
|
+
sage: dPhip.matrix()
|
|
593
|
+
[ 1 -2]
|
|
594
|
+
[-1 2]
|
|
595
|
+
[ 4 -3]
|
|
596
|
+
"""
|
|
597
|
+
image_point = self(point)
|
|
598
|
+
tsp_image = image_point._manifold.tangent_space(image_point)
|
|
599
|
+
tsp_source = point._manifold.tangent_space(point)
|
|
600
|
+
# Search for a common chart to perform the computation
|
|
601
|
+
chartp = None
|
|
602
|
+
|
|
603
|
+
# 1/ Search without any extra computation
|
|
604
|
+
for chart in point._coordinates:
|
|
605
|
+
for chart_pair in self._diff:
|
|
606
|
+
if chart == chart_pair[0]:
|
|
607
|
+
chartp = chart_pair
|
|
608
|
+
break
|
|
609
|
+
if chartp is not None:
|
|
610
|
+
break
|
|
611
|
+
else:
|
|
612
|
+
# 2/ Search with a coordinate transformation on the point
|
|
613
|
+
for chart_pair in self._diff:
|
|
614
|
+
try:
|
|
615
|
+
point.coord(chart_pair[0])
|
|
616
|
+
chartp = chart_pair
|
|
617
|
+
except ValueError:
|
|
618
|
+
pass
|
|
619
|
+
|
|
620
|
+
if chartp is None:
|
|
621
|
+
# 3/ Search with a coordinate evaluation of self
|
|
622
|
+
for chart1 in point._coordinates:
|
|
623
|
+
for chart2 in self._codomain.atlas():
|
|
624
|
+
try:
|
|
625
|
+
self.differential_functions(chart1, chart2)
|
|
626
|
+
chartp = (chart1, chart2)
|
|
627
|
+
break
|
|
628
|
+
except ValueError:
|
|
629
|
+
pass
|
|
630
|
+
if chartp is not None:
|
|
631
|
+
break
|
|
632
|
+
|
|
633
|
+
if chartp is None:
|
|
634
|
+
raise ValueError("no common chart have been found for the " +
|
|
635
|
+
"coordinate expressions of {} and {}".format(self, point))
|
|
636
|
+
|
|
637
|
+
diff_funct = self.differential_functions(*chartp)
|
|
638
|
+
chart1 = chartp[0]
|
|
639
|
+
chart2 = chartp[1]
|
|
640
|
+
coord_point = point.coord(chart1)
|
|
641
|
+
n1 = self._domain.dim()
|
|
642
|
+
n2 = self._codomain.dim()
|
|
643
|
+
matrix = [[diff_funct[i][j](*coord_point) for j in range(n1)]
|
|
644
|
+
for i in range(n2)]
|
|
645
|
+
bases = (chart1.frame().at(point), chart2.frame().at(image_point))
|
|
646
|
+
if self._name is not None and point._name is not None:
|
|
647
|
+
name = 'd%s_%s' % (self._name, point._name)
|
|
648
|
+
else:
|
|
649
|
+
name = None
|
|
650
|
+
if self._latex_name is not None and point._latex_name is not None:
|
|
651
|
+
latex_name = r'{\mathrm{d}%s}_{%s}' % (self._latex_name,
|
|
652
|
+
point._latex_name)
|
|
653
|
+
else:
|
|
654
|
+
latex_name = None
|
|
655
|
+
return tsp_source.hom(tsp_image, matrix, bases=bases,
|
|
656
|
+
name=name, latex_name=latex_name)
|
|
657
|
+
|
|
658
|
+
def differential_functions(self, chart1=None, chart2=None):
|
|
659
|
+
r"""
|
|
660
|
+
Return the coordinate expression of the differential of the
|
|
661
|
+
differentiable map with respect to a pair of charts.
|
|
662
|
+
|
|
663
|
+
If the differentiable map is
|
|
664
|
+
|
|
665
|
+
.. MATH::
|
|
666
|
+
|
|
667
|
+
\Phi: M \longrightarrow N,
|
|
668
|
+
|
|
669
|
+
where `M` and `N` are differentiable manifolds, the *differential*
|
|
670
|
+
of `\Phi` at a point `p \in M` is the tangent space linear map:
|
|
671
|
+
|
|
672
|
+
.. MATH::
|
|
673
|
+
|
|
674
|
+
\mathrm{d}\Phi_p: T_p M \longrightarrow T_{\Phi(p)} N
|
|
675
|
+
|
|
676
|
+
defined by
|
|
677
|
+
|
|
678
|
+
.. MATH::
|
|
679
|
+
|
|
680
|
+
\begin{array}{rccc}
|
|
681
|
+
\forall v\in T_p M,\quad \mathrm{d}\Phi_p(v) : & C^k(N) &
|
|
682
|
+
\longrightarrow & \mathbb{R}, \\
|
|
683
|
+
& f & \longmapsto & v(f\circ \Phi).
|
|
684
|
+
\end{array}
|
|
685
|
+
|
|
686
|
+
If the coordinate expression of `\Phi` is
|
|
687
|
+
|
|
688
|
+
.. MATH::
|
|
689
|
+
|
|
690
|
+
y^i = Y^i(x^1, \ldots, x^n), \quad 1 \leq i \leq m,
|
|
691
|
+
|
|
692
|
+
where `(x^1, \ldots, x^n)` are coordinates of a chart on `M` and
|
|
693
|
+
`(y^1, \ldots, y^m)` are coordinates of a chart on `\Phi(M)`, the
|
|
694
|
+
expression of the differential of `\Phi` with respect to these
|
|
695
|
+
coordinates is
|
|
696
|
+
|
|
697
|
+
.. MATH::
|
|
698
|
+
|
|
699
|
+
J_{ij} = \frac{\partial Y^i}{\partial x^j} \quad 1\leq i \leq m,
|
|
700
|
+
\qquad 1 \leq j \leq n.
|
|
701
|
+
|
|
702
|
+
`\left. J_{ij} \right|_p` is then the matrix of the linear map
|
|
703
|
+
`\mathrm{d}\Phi_p` with respect to the bases of `T_p M` and
|
|
704
|
+
`T_{\Phi(p)} N` associated to the above charts:
|
|
705
|
+
|
|
706
|
+
.. MATH::
|
|
707
|
+
|
|
708
|
+
\mathrm{d}\Phi_p\left( \left. \frac{\partial}{\partial x^j}
|
|
709
|
+
\right|_p \right) = \left. J_{ij} \right|_p \;
|
|
710
|
+
\left. \frac{\partial}{\partial y^i} \right| _{\Phi(p)}.
|
|
711
|
+
|
|
712
|
+
INPUT:
|
|
713
|
+
|
|
714
|
+
- ``chart1`` -- (default: ``None``) chart on the domain `M` of `\Phi`
|
|
715
|
+
(coordinates denoted by `(x^j)` above); if ``None``, the domain's
|
|
716
|
+
default chart is assumed
|
|
717
|
+
- ``chart2`` -- (default: ``None``) chart on the codomain of `\Phi`
|
|
718
|
+
(coordinates denoted by `(y^i)` above); if ``None``, the codomain's
|
|
719
|
+
default chart is assumed
|
|
720
|
+
|
|
721
|
+
OUTPUT:
|
|
722
|
+
|
|
723
|
+
- the functions `J_{ij}` as a double array, `J_{ij}` being
|
|
724
|
+
the element ``[i][j]`` represented by a
|
|
725
|
+
:class:`~sage.manifolds.chart_func.ChartFunction`
|
|
726
|
+
|
|
727
|
+
To get symbolic expressions, use the method
|
|
728
|
+
:meth:`jacobian_matrix` instead.
|
|
729
|
+
|
|
730
|
+
EXAMPLES:
|
|
731
|
+
|
|
732
|
+
Differential functions of a map between a 2-dimensional manifold
|
|
733
|
+
and a 3-dimensional one::
|
|
734
|
+
|
|
735
|
+
sage: M = Manifold(2, 'M')
|
|
736
|
+
sage: X.<x,y> = M.chart()
|
|
737
|
+
sage: N = Manifold(3, 'N')
|
|
738
|
+
sage: Y.<u,v,w> = N.chart()
|
|
739
|
+
sage: Phi = M.diff_map(N, {(X,Y): (x-2*y, x*y, x^2-y^3)}, name='Phi',
|
|
740
|
+
....: latex_name = r'\Phi')
|
|
741
|
+
sage: J = Phi.differential_functions(X, Y) ; J
|
|
742
|
+
[ 1 -2]
|
|
743
|
+
[ y x]
|
|
744
|
+
[ 2*x -3*y^2]
|
|
745
|
+
|
|
746
|
+
The result is cached::
|
|
747
|
+
|
|
748
|
+
sage: Phi.differential_functions(X, Y) is J
|
|
749
|
+
True
|
|
750
|
+
|
|
751
|
+
The elements of ``J`` are functions of the coordinates of
|
|
752
|
+
the chart ``X``::
|
|
753
|
+
|
|
754
|
+
sage: J[2][0]
|
|
755
|
+
2*x
|
|
756
|
+
sage: type(J[2][0])
|
|
757
|
+
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
|
|
758
|
+
|
|
759
|
+
sage: J[2][0].display()
|
|
760
|
+
(x, y) ↦ 2*x
|
|
761
|
+
|
|
762
|
+
In contrast, the method :meth:`jacobian_matrix` leads directly to
|
|
763
|
+
symbolic expressions::
|
|
764
|
+
|
|
765
|
+
sage: JJ = Phi.jacobian_matrix(X,Y) ; JJ
|
|
766
|
+
[ 1 -2]
|
|
767
|
+
[ y x]
|
|
768
|
+
[ 2*x -3*y^2]
|
|
769
|
+
sage: JJ[2,0]
|
|
770
|
+
2*x
|
|
771
|
+
sage: type(JJ[2,0])
|
|
772
|
+
<class 'sage.symbolic.expression.Expression'>
|
|
773
|
+
sage: bool( JJ[2,0] == J[2][0].expr() )
|
|
774
|
+
True
|
|
775
|
+
"""
|
|
776
|
+
dom1 = self._domain
|
|
777
|
+
dom2 = self._codomain
|
|
778
|
+
if chart1 is None:
|
|
779
|
+
chart1 = dom1._def_chart
|
|
780
|
+
if chart2 is None:
|
|
781
|
+
chart2 = dom2._def_chart
|
|
782
|
+
if (chart1, chart2) not in self._diff:
|
|
783
|
+
funct = self.coord_functions(chart1, chart2)
|
|
784
|
+
self._diff[(chart1, chart2)] = funct.jacobian()
|
|
785
|
+
return self._diff[(chart1, chart2)]
|
|
786
|
+
|
|
787
|
+
def jacobian_matrix(self, chart1=None, chart2=None):
|
|
788
|
+
r"""
|
|
789
|
+
Return the Jacobian matrix resulting from the coordinate expression
|
|
790
|
+
of the differentiable map with respect to a pair of charts.
|
|
791
|
+
|
|
792
|
+
If `\Phi` is the current differentiable map and its coordinate
|
|
793
|
+
expression is
|
|
794
|
+
|
|
795
|
+
.. MATH::
|
|
796
|
+
|
|
797
|
+
y^i = Y^i(x^1, \ldots, x^n), \quad 1 \leq i \leq m,
|
|
798
|
+
|
|
799
|
+
where `(x^1, \ldots, x^n)` are coordinates of a chart `X` on the
|
|
800
|
+
domain of `\Phi` and `(y^1, \ldots, y^m)` are coordinates of a chart
|
|
801
|
+
`Y` on the codomain of `\Phi`, the *Jacobian matrix* of the
|
|
802
|
+
differentiable map `\Phi` w.r.t. to charts `X` and `Y` is
|
|
803
|
+
|
|
804
|
+
.. MATH::
|
|
805
|
+
|
|
806
|
+
J = \left( \frac{\partial Y^i}{\partial x^j}
|
|
807
|
+
\right)_{\substack{1 \leq i \leq m \\ 1 \leq j \leq n}},
|
|
808
|
+
|
|
809
|
+
where `i` is the row index and `j` the column one.
|
|
810
|
+
|
|
811
|
+
INPUT:
|
|
812
|
+
|
|
813
|
+
- ``chart1`` -- (default: ``None``) chart `X` on the domain of
|
|
814
|
+
`\Phi`; if none is provided, the domain's default chart is assumed
|
|
815
|
+
- ``chart2`` -- (default: ``None``) chart `Y` on the codomain of
|
|
816
|
+
`\Phi`; if none is provided, the codomain's default chart is
|
|
817
|
+
assumed
|
|
818
|
+
|
|
819
|
+
OUTPUT: the matrix `J` defined above
|
|
820
|
+
|
|
821
|
+
EXAMPLES:
|
|
822
|
+
|
|
823
|
+
Jacobian matrix of a map between a 2-dimensional manifold and a
|
|
824
|
+
3-dimensional one::
|
|
825
|
+
|
|
826
|
+
sage: M = Manifold(2, 'M')
|
|
827
|
+
sage: X.<x,y> = M.chart()
|
|
828
|
+
sage: N = Manifold(3, 'N')
|
|
829
|
+
sage: Y.<u,v,w> = N.chart()
|
|
830
|
+
sage: Phi = M.diff_map(N, {(X,Y): (x-2*y, x*y, x^2-y^3)}, name='Phi',
|
|
831
|
+
....: latex_name = r'\Phi')
|
|
832
|
+
sage: Phi.display()
|
|
833
|
+
Phi: M → N
|
|
834
|
+
(x, y) ↦ (u, v, w) = (x - 2*y, x*y, -y^3 + x^2)
|
|
835
|
+
sage: J = Phi.jacobian_matrix(X, Y) ; J
|
|
836
|
+
[ 1 -2]
|
|
837
|
+
[ y x]
|
|
838
|
+
[ 2*x -3*y^2]
|
|
839
|
+
sage: J.parent()
|
|
840
|
+
Full MatrixSpace of 3 by 2 dense matrices over Symbolic Ring
|
|
841
|
+
"""
|
|
842
|
+
from sage.matrix.constructor import matrix
|
|
843
|
+
diff_funct = self.differential_functions(chart1, chart2)
|
|
844
|
+
n1 = self._domain.dim()
|
|
845
|
+
n2 = self._codomain.dim()
|
|
846
|
+
return matrix([[diff_funct[i][j].expr() for j in range(n1)]
|
|
847
|
+
for i in range(n2)])
|
|
848
|
+
|
|
849
|
+
def pullback(self, tensor_or_codomain_subset, name=None, latex_name=None):
|
|
850
|
+
r"""
|
|
851
|
+
Pullback operator associated with ``self``.
|
|
852
|
+
|
|
853
|
+
In what follows, let `\Phi` denote a differentiable map ``self``,
|
|
854
|
+
`M` its domain and `N` its codomain.
|
|
855
|
+
|
|
856
|
+
INPUT:
|
|
857
|
+
|
|
858
|
+
One of the following:
|
|
859
|
+
|
|
860
|
+
- ``tensor_or_codomain_subset`` -- one of the following:
|
|
861
|
+
|
|
862
|
+
- a :class:`~sage.manifolds.differentiable.tensorfield.TensorField`;
|
|
863
|
+
a fully covariant tensor field `T` on `N`, i.e. a tensor
|
|
864
|
+
field of type `(0, p)`, with `p` a positive or zero integer; the
|
|
865
|
+
case `p = 0` corresponds to a scalar field
|
|
866
|
+
- a :class:`~sage.manifolds.subset.ManifoldSubset` `S`
|
|
867
|
+
|
|
868
|
+
OUTPUT:
|
|
869
|
+
|
|
870
|
+
- (if the input is a tensor field `T`)
|
|
871
|
+
a :class:`~sage.manifolds.differentiable.tensorfield.TensorField`
|
|
872
|
+
representing a fully covariant tensor field on `M` that is the
|
|
873
|
+
pullback of `T` by `\Phi`
|
|
874
|
+
- (if the input is a manifold subset `S`)
|
|
875
|
+
a :class:`~sage.manifolds.subset.ManifoldSubset` that is the
|
|
876
|
+
preimage `\Phi^{-1}(S)`; same as :meth:`preimage`
|
|
877
|
+
|
|
878
|
+
EXAMPLES:
|
|
879
|
+
|
|
880
|
+
Pullback on `S^2` of a scalar field defined on `R^3`::
|
|
881
|
+
|
|
882
|
+
sage: M = Manifold(2, 'S^2', start_index=1)
|
|
883
|
+
sage: U = M.open_subset('U') # the complement of a meridian (domain of spherical coordinates)
|
|
884
|
+
sage: c_spher.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') # spherical coord. on U
|
|
885
|
+
sage: N = Manifold(3, 'R^3', r'\RR^3', start_index=1)
|
|
886
|
+
sage: c_cart.<x,y,z> = N.chart() # Cartesian coord. on R^3
|
|
887
|
+
sage: Phi = U.diff_map(N, (sin(th)*cos(ph), sin(th)*sin(ph), cos(th)),
|
|
888
|
+
....: name='Phi', latex_name=r'\Phi')
|
|
889
|
+
sage: f = N.scalar_field(x*y*z, name='f') ; f
|
|
890
|
+
Scalar field f on the 3-dimensional differentiable manifold R^3
|
|
891
|
+
sage: f.display()
|
|
892
|
+
f: R^3 → ℝ
|
|
893
|
+
(x, y, z) ↦ x*y*z
|
|
894
|
+
sage: pf = Phi.pullback(f) ; pf
|
|
895
|
+
Scalar field Phi^*(f) on the Open subset U of the 2-dimensional
|
|
896
|
+
differentiable manifold S^2
|
|
897
|
+
sage: pf.display()
|
|
898
|
+
Phi^*(f): U → ℝ
|
|
899
|
+
(th, ph) ↦ cos(ph)*cos(th)*sin(ph)*sin(th)^2
|
|
900
|
+
|
|
901
|
+
Pullback on `S^2` of the standard Euclidean metric on `R^3`::
|
|
902
|
+
|
|
903
|
+
sage: g = N.sym_bilin_form_field(name='g')
|
|
904
|
+
sage: g[1,1], g[2,2], g[3,3] = 1, 1, 1
|
|
905
|
+
sage: g.display()
|
|
906
|
+
g = dx⊗dx + dy⊗dy + dz⊗dz
|
|
907
|
+
sage: pg = Phi.pullback(g) ; pg
|
|
908
|
+
Field of symmetric bilinear forms Phi^*(g) on the Open subset U of
|
|
909
|
+
the 2-dimensional differentiable manifold S^2
|
|
910
|
+
sage: pg.display()
|
|
911
|
+
Phi^*(g) = dth⊗dth + sin(th)^2 dph⊗dph
|
|
912
|
+
|
|
913
|
+
Parallel computation::
|
|
914
|
+
|
|
915
|
+
sage: Parallelism().set('tensor', nproc=2)
|
|
916
|
+
sage: pg = Phi.pullback(g) ; pg
|
|
917
|
+
Field of symmetric bilinear forms Phi^*(g) on the Open subset U of
|
|
918
|
+
the 2-dimensional differentiable manifold S^2
|
|
919
|
+
sage: pg.display()
|
|
920
|
+
Phi^*(g) = dth⊗dth + sin(th)^2 dph⊗dph
|
|
921
|
+
sage: Parallelism().set('tensor', nproc=1) # switch off parallelization
|
|
922
|
+
|
|
923
|
+
|
|
924
|
+
Pullback on `S^2` of a 3-form on `R^3`::
|
|
925
|
+
|
|
926
|
+
sage: a = N.diff_form(3, name='A')
|
|
927
|
+
sage: a[1,2,3] = f
|
|
928
|
+
sage: a.display()
|
|
929
|
+
A = x*y*z dx∧dy∧dz
|
|
930
|
+
sage: pa = Phi.pullback(a) ; pa
|
|
931
|
+
3-form Phi^*(A) on the Open subset U of the 2-dimensional
|
|
932
|
+
differentiable manifold S^2
|
|
933
|
+
sage: pa.display() # should be zero (as any 3-form on a 2-dimensional manifold)
|
|
934
|
+
Phi^*(A) = 0
|
|
935
|
+
|
|
936
|
+
TESTS:
|
|
937
|
+
|
|
938
|
+
Check that :issue:`31904` is fixed::
|
|
939
|
+
|
|
940
|
+
sage: E.<x,y> = EuclideanSpace()
|
|
941
|
+
sage: polar.<r,ph> = E.polar_coordinates()
|
|
942
|
+
sage: g = E.metric()
|
|
943
|
+
sage: M = Manifold(1, 'M')
|
|
944
|
+
sage: Ct.<t> = M.chart()
|
|
945
|
+
sage: F = M.diff_map(E, coord_functions={(Ct, polar): (1 + cos(t), t)})
|
|
946
|
+
sage: gM = F.pullback(g)
|
|
947
|
+
sage: gM.display()
|
|
948
|
+
(2*cos(t) + 2) dt⊗dt
|
|
949
|
+
"""
|
|
950
|
+
if not hasattr(tensor_or_codomain_subset, '_domain'):
|
|
951
|
+
return super().pullback(tensor_or_codomain_subset,
|
|
952
|
+
name=name, latex_name=latex_name)
|
|
953
|
+
tensor = tensor_or_codomain_subset
|
|
954
|
+
|
|
955
|
+
from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal
|
|
956
|
+
from sage.tensor.modules.comp import (
|
|
957
|
+
CompFullyAntiSym,
|
|
958
|
+
CompFullySym,
|
|
959
|
+
Components,
|
|
960
|
+
CompWithSym,
|
|
961
|
+
)
|
|
962
|
+
|
|
963
|
+
def _pullback_chart(diff_map, tensor, chart1, chart2):
|
|
964
|
+
r"""
|
|
965
|
+
Helper function performing the pullback on chart domains
|
|
966
|
+
only.
|
|
967
|
+
|
|
968
|
+
INPUT:
|
|
969
|
+
|
|
970
|
+
- ``diff_map`` -- a restriction of ``self``, whose both
|
|
971
|
+
domain and codomain are chart domains, corresponding
|
|
972
|
+
respectively to ``chart1`` and ``chart2``
|
|
973
|
+
- ``tensor`` -- a covariant tensor field, whose domain is
|
|
974
|
+
the codomain of ``diff_map`` and whose components are known
|
|
975
|
+
in ``chart2.frame()``
|
|
976
|
+
- ``chart1`` -- chart on the domain of ``diff_map``
|
|
977
|
+
- ``chart2`` -- chart on the codomain of ``diff_map``
|
|
978
|
+
|
|
979
|
+
OUTPUT: the pull back of ``tensor`` by ``diff_map``
|
|
980
|
+
"""
|
|
981
|
+
dom1 = diff_map._domain
|
|
982
|
+
dom2 = diff_map._codomain
|
|
983
|
+
ncov = tensor._tensor_type[1]
|
|
984
|
+
resu_name = None
|
|
985
|
+
resu_latex_name = None
|
|
986
|
+
if diff_map._name is not None and tensor._name is not None:
|
|
987
|
+
resu_name = diff_map._name + '^*(' + tensor._name + ')'
|
|
988
|
+
if (diff_map._latex_name is not None and
|
|
989
|
+
tensor._latex_name is not None):
|
|
990
|
+
resu_latex_name = '{' + diff_map._latex_name + '}^*' \
|
|
991
|
+
+ tensor._latex_name
|
|
992
|
+
fmodule1 = dom1.vector_field_module()
|
|
993
|
+
ring1 = fmodule1._ring
|
|
994
|
+
si1 = fmodule1._sindex
|
|
995
|
+
of1 = fmodule1._output_formatter
|
|
996
|
+
si2 = dom2._sindex
|
|
997
|
+
resu = fmodule1.tensor((0, ncov), name=resu_name,
|
|
998
|
+
latex_name=resu_latex_name, sym=tensor._sym,
|
|
999
|
+
antisym=tensor._antisym)
|
|
1000
|
+
|
|
1001
|
+
nproc = Parallelism().get('tensor')
|
|
1002
|
+
ind_old_list = list(dom2.manifold().index_generator(ncov))
|
|
1003
|
+
|
|
1004
|
+
frame1 = chart1.frame()
|
|
1005
|
+
frame2 = chart2.frame()
|
|
1006
|
+
|
|
1007
|
+
tcomp = tensor._components[frame2]
|
|
1008
|
+
if isinstance(tcomp, CompFullySym):
|
|
1009
|
+
ptcomp = CompFullySym(ring1, frame1, ncov, start_index=si1,
|
|
1010
|
+
output_formatter=of1)
|
|
1011
|
+
elif isinstance(tcomp, CompFullyAntiSym):
|
|
1012
|
+
ptcomp = CompFullyAntiSym(ring1, frame1, ncov, start_index=si1,
|
|
1013
|
+
output_formatter=of1)
|
|
1014
|
+
elif isinstance(tcomp, CompWithSym):
|
|
1015
|
+
ptcomp = CompWithSym(ring1, frame1, ncov, start_index=si1,
|
|
1016
|
+
output_formatter=of1, sym=tcomp.sym,
|
|
1017
|
+
antisym=tcomp.antisym)
|
|
1018
|
+
else:
|
|
1019
|
+
ptcomp = Components(ring1, frame1, ncov, start_index=si1,
|
|
1020
|
+
output_formatter=of1)
|
|
1021
|
+
phi = diff_map._coord_expression[(chart1, chart2)]
|
|
1022
|
+
jacob = phi.jacobian()
|
|
1023
|
+
# X2 coordinates expressed in terms of X1 ones via the diff. map:
|
|
1024
|
+
coord2_1 = phi(*(chart1._xx))
|
|
1025
|
+
|
|
1026
|
+
if nproc != 1:
|
|
1027
|
+
# Parallel computation
|
|
1028
|
+
lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)]
|
|
1029
|
+
ind_list = list(ptcomp.non_redundant_index_generator())
|
|
1030
|
+
ind_step = max(1, (len(ind_list) // nproc) // 2)
|
|
1031
|
+
local_list = lol(ind_list, ind_step)
|
|
1032
|
+
# list of input parameters
|
|
1033
|
+
listParalInput = [(tcomp, chart1, chart2, coord2_1, jacob,
|
|
1034
|
+
ind_old_list, si1, si2, ncov, ind_part)
|
|
1035
|
+
for ind_part in local_list]
|
|
1036
|
+
|
|
1037
|
+
@parallel(p_iter='multiprocessing', ncpus=nproc)
|
|
1038
|
+
def paral_comp(tcomp, chart1, chart2, coord2_1, jacob,
|
|
1039
|
+
ind_old_list, si1, si2, ncov, local_list_ind):
|
|
1040
|
+
partial = []
|
|
1041
|
+
for ind_new in local_list_ind:
|
|
1042
|
+
res = 0
|
|
1043
|
+
for ind_old in ind_old_list:
|
|
1044
|
+
ff = tcomp[[ind_old]].coord_function(chart2)
|
|
1045
|
+
t = chart1.function(ff(*coord2_1))
|
|
1046
|
+
for i in range(ncov):
|
|
1047
|
+
t *= jacob[ind_old[i]-si2, ind_new[i]-si1]
|
|
1048
|
+
res += t
|
|
1049
|
+
partial.append([ind_new, res])
|
|
1050
|
+
return partial
|
|
1051
|
+
|
|
1052
|
+
for ii, val in paral_comp(listParalInput):
|
|
1053
|
+
for jj in val:
|
|
1054
|
+
ptcomp[[jj[0]]] = jj[1]
|
|
1055
|
+
|
|
1056
|
+
else:
|
|
1057
|
+
# Sequential computation
|
|
1058
|
+
for ind_new in ptcomp.non_redundant_index_generator():
|
|
1059
|
+
res = 0
|
|
1060
|
+
for ind_old in ind_old_list:
|
|
1061
|
+
ff = tcomp[[ind_old]].coord_function(chart2)
|
|
1062
|
+
t = chart1.function(ff(*coord2_1))
|
|
1063
|
+
for i in range(ncov):
|
|
1064
|
+
t *= jacob[ind_old[i]-si2, ind_new[i]-si1]
|
|
1065
|
+
res += t
|
|
1066
|
+
ptcomp[ind_new] = res
|
|
1067
|
+
|
|
1068
|
+
resu._components[frame1] = ptcomp
|
|
1069
|
+
return resu
|
|
1070
|
+
# End of function _pullback_chart
|
|
1071
|
+
|
|
1072
|
+
# Special case of the identity map:
|
|
1073
|
+
if self._is_identity:
|
|
1074
|
+
return tensor # no test for efficiency
|
|
1075
|
+
# Generic case:
|
|
1076
|
+
dom1 = self._domain
|
|
1077
|
+
dom2 = self._codomain
|
|
1078
|
+
tdom = tensor._domain
|
|
1079
|
+
if not tdom.is_subset(dom2):
|
|
1080
|
+
raise ValueError("the tensor field is not defined on the map codomain")
|
|
1081
|
+
(ncon, ncov) = tensor._tensor_type
|
|
1082
|
+
if ncon != 0:
|
|
1083
|
+
raise TypeError("the pullback cannot be taken on a tensor " +
|
|
1084
|
+
"with some contravariant part")
|
|
1085
|
+
resu_name = None
|
|
1086
|
+
resu_latex_name = None
|
|
1087
|
+
if self._name is not None and tensor._name is not None:
|
|
1088
|
+
resu_name = self._name + '^*(' + tensor._name + ')'
|
|
1089
|
+
if self._latex_name is not None and tensor._latex_name is not None:
|
|
1090
|
+
resu_latex_name = '{' + self._latex_name + '}^*' \
|
|
1091
|
+
+ tensor._latex_name
|
|
1092
|
+
if ncov == 0:
|
|
1093
|
+
# Case of a scalar field
|
|
1094
|
+
resu_fc = []
|
|
1095
|
+
for chart2 in tensor._express:
|
|
1096
|
+
for chart1 in dom1._atlas:
|
|
1097
|
+
if (chart1, chart2) in self._coord_expression:
|
|
1098
|
+
phi = self._coord_expression[(chart1, chart2)]
|
|
1099
|
+
coord1 = chart1._xx
|
|
1100
|
+
ff = tensor._express[chart2]
|
|
1101
|
+
resu_fc.append( chart1.function(ff(*(phi(*coord1)))) )
|
|
1102
|
+
dom_resu = resu_fc[0].parent()._chart.domain()
|
|
1103
|
+
for fc in resu_fc[1:]:
|
|
1104
|
+
dom_resu = dom_resu.union(fc.parent()._chart.domain())
|
|
1105
|
+
resu = dom_resu.scalar_field(name=resu_name,
|
|
1106
|
+
latex_name=resu_latex_name)
|
|
1107
|
+
for fc in resu_fc:
|
|
1108
|
+
resu._express[fc.parent()._chart] = fc
|
|
1109
|
+
else:
|
|
1110
|
+
# Case of tensor field of rank >= 1
|
|
1111
|
+
if tensor._vmodule._dest_map is not tdom.identity_map():
|
|
1112
|
+
raise TypeError("the pullback is defined only for tensor " +
|
|
1113
|
+
"fields on {}".format(dom2))
|
|
1114
|
+
resu_rst = []
|
|
1115
|
+
for chart_pair in self._coord_expression:
|
|
1116
|
+
chart1 = chart_pair[0]
|
|
1117
|
+
chart2 = chart_pair[1]
|
|
1118
|
+
ch2dom = chart2._domain
|
|
1119
|
+
if ch2dom.is_subset(tdom):
|
|
1120
|
+
self_r = self.restrict(chart1._domain, subcodomain=ch2dom)
|
|
1121
|
+
tensor_r = tensor.restrict(ch2dom)
|
|
1122
|
+
if chart2.frame() in tensor_r._components:
|
|
1123
|
+
resu_rst.append(_pullback_chart(self_r, tensor_r,
|
|
1124
|
+
chart1, chart2))
|
|
1125
|
+
dom_resu = resu_rst[0]._domain
|
|
1126
|
+
for rst in resu_rst[1:]:
|
|
1127
|
+
dom_resu = dom_resu.union(rst._domain)
|
|
1128
|
+
resu = dom_resu.tensor_field(0, ncov, name=resu_name,
|
|
1129
|
+
latex_name=resu_latex_name,
|
|
1130
|
+
sym=resu_rst[0]._sym,
|
|
1131
|
+
antisym=resu_rst[0]._antisym)
|
|
1132
|
+
for rst in resu_rst:
|
|
1133
|
+
if rst._domain is not resu._domain:
|
|
1134
|
+
resu._restrictions[rst._domain] = rst
|
|
1135
|
+
if isinstance(resu, TensorFieldParal):
|
|
1136
|
+
for rst in resu_rst:
|
|
1137
|
+
if rst._domain is resu._domain:
|
|
1138
|
+
for frame, comp in rst._components.items():
|
|
1139
|
+
resu._components[frame] = comp
|
|
1140
|
+
return resu
|
|
1141
|
+
|
|
1142
|
+
def pushforward(self, tensor):
|
|
1143
|
+
r"""
|
|
1144
|
+
Pushforward operator associated with ``self``.
|
|
1145
|
+
|
|
1146
|
+
In what follows, let `\Phi` denote the differentiable map, `M` its
|
|
1147
|
+
domain and `N` its codomain.
|
|
1148
|
+
|
|
1149
|
+
INPUT:
|
|
1150
|
+
|
|
1151
|
+
- ``tensor`` --
|
|
1152
|
+
:class:`~sage.manifolds.differentiable.tensorfield.TensorField`;
|
|
1153
|
+
a fully contrariant tensor field `T` on `M`, i.e. a tensor
|
|
1154
|
+
field of type `(p, 0)`, with `p` a positive integer
|
|
1155
|
+
|
|
1156
|
+
OUTPUT:
|
|
1157
|
+
|
|
1158
|
+
- a :class:`~sage.manifolds.differentiable.tensorfield.TensorField`
|
|
1159
|
+
representing a fully contravariant tensor field along `M` with
|
|
1160
|
+
values in `N`, which is the pushforward of `T` by `\Phi`
|
|
1161
|
+
|
|
1162
|
+
EXAMPLES:
|
|
1163
|
+
|
|
1164
|
+
Pushforward of a vector field on the 2-sphere `S^2` to the Euclidean
|
|
1165
|
+
3-space `\RR^3`, via the standard embedding of `S^2`::
|
|
1166
|
+
|
|
1167
|
+
sage: S2 = Manifold(2, 'S^2', start_index=1)
|
|
1168
|
+
sage: U = S2.open_subset('U') # domain of spherical coordinates
|
|
1169
|
+
sage: spher.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
|
|
1170
|
+
sage: R3 = Manifold(3, 'R^3', start_index=1)
|
|
1171
|
+
sage: cart.<x,y,z> = R3.chart()
|
|
1172
|
+
sage: Phi = U.diff_map(R3, {(spher, cart): [sin(th)*cos(ph),
|
|
1173
|
+
....: sin(th)*sin(ph), cos(th)]}, name='Phi', latex_name=r'\Phi')
|
|
1174
|
+
sage: v = U.vector_field(name='v')
|
|
1175
|
+
sage: v[:] = 0, 1
|
|
1176
|
+
sage: v.display()
|
|
1177
|
+
v = ∂/∂ph
|
|
1178
|
+
sage: pv = Phi.pushforward(v); pv
|
|
1179
|
+
Vector field Phi_*(v) along the Open subset U of the 2-dimensional
|
|
1180
|
+
differentiable manifold S^2 with values on the 3-dimensional
|
|
1181
|
+
differentiable manifold R^3
|
|
1182
|
+
sage: pv.display()
|
|
1183
|
+
Phi_*(v) = -sin(ph)*sin(th) ∂/∂x + cos(ph)*sin(th) ∂/∂y
|
|
1184
|
+
|
|
1185
|
+
Pushforward of a vector field on the real line to the `\RR^3`, via a
|
|
1186
|
+
helix embedding::
|
|
1187
|
+
|
|
1188
|
+
sage: R.<t> = manifolds.RealLine()
|
|
1189
|
+
sage: Psi = R.diff_map(R3, [cos(t), sin(t), t], name='Psi',
|
|
1190
|
+
....: latex_name=r'\Psi')
|
|
1191
|
+
sage: u = R.vector_field(name='u')
|
|
1192
|
+
sage: u[0] = 1
|
|
1193
|
+
sage: u.display()
|
|
1194
|
+
u = ∂/∂t
|
|
1195
|
+
sage: pu = Psi.pushforward(u); pu
|
|
1196
|
+
Vector field Psi_*(u) along the Real number line ℝ with values on
|
|
1197
|
+
the 3-dimensional differentiable manifold R^3
|
|
1198
|
+
sage: pu.display()
|
|
1199
|
+
Psi_*(u) = -sin(t) ∂/∂x + cos(t) ∂/∂y + ∂/∂z
|
|
1200
|
+
"""
|
|
1201
|
+
from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal
|
|
1202
|
+
from sage.tensor.modules.comp import (
|
|
1203
|
+
CompFullyAntiSym,
|
|
1204
|
+
CompFullySym,
|
|
1205
|
+
Components,
|
|
1206
|
+
CompWithSym,
|
|
1207
|
+
)
|
|
1208
|
+
vmodule = tensor.base_module()
|
|
1209
|
+
dest_map = vmodule.destination_map()
|
|
1210
|
+
dom1 = tensor.domain()
|
|
1211
|
+
ambient_dom1 = dest_map.codomain()
|
|
1212
|
+
if not ambient_dom1.is_subset(self._domain):
|
|
1213
|
+
raise ValueError("the {} does not take its ".format(tensor) +
|
|
1214
|
+
"values on the domain of the {}".format(self))
|
|
1215
|
+
(ncon, ncov) = tensor.tensor_type()
|
|
1216
|
+
if ncov != 0:
|
|
1217
|
+
raise ValueError("the pushforward cannot be taken on a tensor " +
|
|
1218
|
+
"with some covariant part")
|
|
1219
|
+
if ncon == 0:
|
|
1220
|
+
raise ValueError("the pushforward cannot be taken on a scalar " +
|
|
1221
|
+
"field")
|
|
1222
|
+
if dest_map != dom1.identity_map():
|
|
1223
|
+
raise NotImplementedError("the case of a non-trivial destination" +
|
|
1224
|
+
" map is not implemented yet")
|
|
1225
|
+
if not isinstance(tensor, TensorFieldParal):
|
|
1226
|
+
raise NotImplementedError("the case of a non-parallelizable " +
|
|
1227
|
+
"domain is not implemented yet")
|
|
1228
|
+
# A pair of charts (chart1, chart2) where the computation
|
|
1229
|
+
# is feasible is searched, privileging the default chart of the
|
|
1230
|
+
# map's domain for chart1
|
|
1231
|
+
chart1 = None
|
|
1232
|
+
chart2 = None
|
|
1233
|
+
def_chart1 = dom1.default_chart()
|
|
1234
|
+
def_chart2 = self._codomain.default_chart()
|
|
1235
|
+
if (def_chart1._frame in tensor._components
|
|
1236
|
+
and (def_chart1, def_chart2) in self._coord_expression):
|
|
1237
|
+
chart1 = def_chart1
|
|
1238
|
+
chart2 = def_chart2
|
|
1239
|
+
else:
|
|
1240
|
+
for (chart1n, chart2n) in self._coord_expression:
|
|
1241
|
+
if (chart2n == def_chart2
|
|
1242
|
+
and chart1n._frame in tensor._components):
|
|
1243
|
+
chart1 = chart1n
|
|
1244
|
+
chart2 = def_chart2
|
|
1245
|
+
break
|
|
1246
|
+
if chart2 is None:
|
|
1247
|
+
# It is not possible to have def_chart2 as chart for
|
|
1248
|
+
# expressing the result; any other chart is then looked for:
|
|
1249
|
+
for (chart1n, chart2n) in self._coord_expression:
|
|
1250
|
+
if chart1n._frame in tensor._components:
|
|
1251
|
+
chart1 = chart1n
|
|
1252
|
+
chart2 = chart2n
|
|
1253
|
+
break
|
|
1254
|
+
if chart1 is None:
|
|
1255
|
+
# Computations of components are attempted
|
|
1256
|
+
chart1 = dom1.default_chart()
|
|
1257
|
+
tensor.comp(chart1.frame())
|
|
1258
|
+
for chart2n in self._codomain.atlas():
|
|
1259
|
+
try:
|
|
1260
|
+
self.coord_functions(chart1, chart2n)
|
|
1261
|
+
chart2 = chart2n
|
|
1262
|
+
break
|
|
1263
|
+
except ValueError:
|
|
1264
|
+
pass
|
|
1265
|
+
else:
|
|
1266
|
+
raise ValueError("no pair of charts could be found to " +
|
|
1267
|
+
"compute the pushforward of " +
|
|
1268
|
+
"the {} by the {}".format(tensor, self))
|
|
1269
|
+
# Vector field module for the result:
|
|
1270
|
+
fmodule2 = dom1.vector_field_module(dest_map=self)
|
|
1271
|
+
|
|
1272
|
+
frame2 = fmodule2.basis(from_frame=chart2.frame())
|
|
1273
|
+
si1 = dom1.start_index()
|
|
1274
|
+
si2 = fmodule2._sindex
|
|
1275
|
+
ring2 = fmodule2._ring
|
|
1276
|
+
of2 = fmodule2._output_formatter
|
|
1277
|
+
# Computation at the component level:
|
|
1278
|
+
tcomp = tensor._components[chart1.frame()]
|
|
1279
|
+
# Construction of the pushforward components (ptcomp):
|
|
1280
|
+
if isinstance(tcomp, CompFullySym):
|
|
1281
|
+
ptcomp = CompFullySym(ring2, frame2, ncon, start_index=si2,
|
|
1282
|
+
output_formatter=of2)
|
|
1283
|
+
elif isinstance(tcomp, CompFullyAntiSym):
|
|
1284
|
+
ptcomp = CompFullyAntiSym(ring2, frame2, ncon, start_index=si2,
|
|
1285
|
+
output_formatter=of2)
|
|
1286
|
+
elif isinstance(tcomp, CompWithSym):
|
|
1287
|
+
ptcomp = CompWithSym(ring2, frame2, ncon, start_index=si2,
|
|
1288
|
+
output_formatter=of2, sym=tcomp._sym,
|
|
1289
|
+
antisym=tcomp._antisym)
|
|
1290
|
+
else:
|
|
1291
|
+
ptcomp = Components(ring2, frame2, ncon, start_index=si2,
|
|
1292
|
+
output_formatter=of2)
|
|
1293
|
+
# Computation of the pushforward components:
|
|
1294
|
+
jacob = self.differential_functions(chart1=chart1, chart2=chart2)
|
|
1295
|
+
si2 = chart2.domain().start_index()
|
|
1296
|
+
for ind_new in ptcomp.non_redundant_index_generator():
|
|
1297
|
+
res = 0
|
|
1298
|
+
for ind_old in dom1.index_generator(ncon):
|
|
1299
|
+
t = tcomp[[ind_old]].coord_function(chart1)
|
|
1300
|
+
for i in range(ncon):
|
|
1301
|
+
t *= jacob[ind_new[i]-si2, ind_old[i]-si1]
|
|
1302
|
+
res += t
|
|
1303
|
+
ptcomp[ind_new] = res
|
|
1304
|
+
# Name of the result:
|
|
1305
|
+
resu_name = None
|
|
1306
|
+
resu_latex_name = None
|
|
1307
|
+
if self._name is not None and tensor._name is not None:
|
|
1308
|
+
resu_name = self._name + '_*(' + tensor._name + ')'
|
|
1309
|
+
if self._latex_name is not None and tensor._latex_name is not None:
|
|
1310
|
+
resu_latex_name = '{' + self._latex_name + '}_*' \
|
|
1311
|
+
+ tensor._latex_name
|
|
1312
|
+
# Creation of the result with the components obtained above:
|
|
1313
|
+
resu = fmodule2.tensor_from_comp((ncon, 0), ptcomp, name=resu_name,
|
|
1314
|
+
latex_name=resu_latex_name)
|
|
1315
|
+
return resu
|