passagemath-symbolics 10.6.43__cp314-cp314t-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-symbolics might be problematic. Click here for more details.
- passagemath_symbolics/__init__.py +3 -0
- passagemath_symbolics-10.6.43.dist-info/METADATA +187 -0
- passagemath_symbolics-10.6.43.dist-info/RECORD +171 -0
- passagemath_symbolics-10.6.43.dist-info/WHEEL +5 -0
- passagemath_symbolics-10.6.43.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-x86_64-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-x86_64-linux-musl.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-x86_64-linux-musl.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-x86_64-linux-musl.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-x86_64-linux-musl.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,1658 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-symbolics
|
|
2
|
+
r"""
|
|
3
|
+
Differential Forms
|
|
4
|
+
|
|
5
|
+
Let `U` and `M` be two differentiable manifolds.
|
|
6
|
+
Given a positive integer `p` and a differentiable map `\Phi: U \rightarrow M`,
|
|
7
|
+
a *differential form of degree* `p`, or `p`-*form*,
|
|
8
|
+
*along* `U` *with values on* `M` is a field along `U` of alternating
|
|
9
|
+
multilinear forms of degree `p` in the tangent spaces to `M`.
|
|
10
|
+
The standard case of a differential form *on* a differentiable manifold
|
|
11
|
+
corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are
|
|
12
|
+
`\Phi` being an immersion and `\Phi` being a curve in `M` (`U` is then an open
|
|
13
|
+
interval of `\RR`).
|
|
14
|
+
|
|
15
|
+
Two classes implement differential forms, depending whether the manifold
|
|
16
|
+
`M` is parallelizable:
|
|
17
|
+
|
|
18
|
+
* :class:`DiffFormParal` when `M` is parallelizable
|
|
19
|
+
* :class:`DiffForm` when `M` is not assumed parallelizable.
|
|
20
|
+
|
|
21
|
+
AUTHORS:
|
|
22
|
+
|
|
23
|
+
- Eric Gourgoulhon, Michal Bejger (2013, 2014): initial version
|
|
24
|
+
- Joris Vankerschaver (2010): developed a previous class,
|
|
25
|
+
``DifferentialForm`` (cf. :issue:`24444`), which inspired the storage of the
|
|
26
|
+
nonzero components as a dictionary whose keys are the indices.
|
|
27
|
+
- Travis Scrimshaw (2016): review tweaks
|
|
28
|
+
|
|
29
|
+
REFERENCES:
|
|
30
|
+
|
|
31
|
+
- [KN1963]_
|
|
32
|
+
- [Lee2013]_
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
# *****************************************************************************
|
|
36
|
+
# Copyright (C) 2015 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
|
|
37
|
+
# Copyright (C) 2015 Michal Bejger <bejger@camk.edu.pl>
|
|
38
|
+
# Copyright (C) 2010 Joris Vankerschaver <joris.vankerschaver@gmail.com>
|
|
39
|
+
# Copyright (C) 2016 Travis Scrimshaw <tscrimsh@umn.edu>
|
|
40
|
+
#
|
|
41
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
42
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
43
|
+
# the License, or (at your option) any later version.
|
|
44
|
+
# https://www.gnu.org/licenses/
|
|
45
|
+
# *****************************************************************************
|
|
46
|
+
|
|
47
|
+
from __future__ import annotations
|
|
48
|
+
|
|
49
|
+
from typing import TYPE_CHECKING, Optional, Union
|
|
50
|
+
|
|
51
|
+
from sage.manifolds.differentiable.tensorfield import TensorField
|
|
52
|
+
from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal
|
|
53
|
+
from sage.misc.cachefunc import cached_method
|
|
54
|
+
from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm
|
|
55
|
+
|
|
56
|
+
if TYPE_CHECKING:
|
|
57
|
+
from sage.manifolds.differentiable.metric import PseudoRiemannianMetric
|
|
58
|
+
from sage.manifolds.differentiable.symplectic_form import SymplecticForm
|
|
59
|
+
from sage.manifolds.differentiable.vectorfield_module import VectorFieldModule
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class DiffForm(TensorField):
|
|
63
|
+
r"""
|
|
64
|
+
Differential form with values on a generic (i.e. a priori not
|
|
65
|
+
parallelizable) differentiable manifold.
|
|
66
|
+
|
|
67
|
+
Given a differentiable manifold `U`, a differentiable map
|
|
68
|
+
`\Phi: U \rightarrow M` to a differentiable manifold `M` and a positive
|
|
69
|
+
integer `p`, a *differential form of degree* `p` (or `p`-*form*)
|
|
70
|
+
*along* `U` *with values on* `M\supset\Phi(U)` is a differentiable map
|
|
71
|
+
|
|
72
|
+
.. MATH::
|
|
73
|
+
|
|
74
|
+
a:\ U \longrightarrow T^{(0,p)}M
|
|
75
|
+
|
|
76
|
+
(`T^{(0,p)}M` being the tensor bundle of type `(0,p)` over `M`) such that
|
|
77
|
+
|
|
78
|
+
.. MATH::
|
|
79
|
+
|
|
80
|
+
\forall x \in U,\quad a(x) \in \Lambda^p(T_{\Phi(x)}^* M) ,
|
|
81
|
+
|
|
82
|
+
where `T_{\Phi(x)}^* M` is the dual of the tangent space to `M` at
|
|
83
|
+
`\Phi(x)` and `\Lambda^p` stands for the exterior power of degree `p` (cf.
|
|
84
|
+
:class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule`).
|
|
85
|
+
In other words, `a(x)` is an alternating multilinear form of degree `p` of
|
|
86
|
+
the tangent vector space `T_{\Phi(x)} M`.
|
|
87
|
+
|
|
88
|
+
The standard case of a differential form *on* a
|
|
89
|
+
manifold `M` corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other
|
|
90
|
+
common cases are `\Phi` being an immersion and `\Phi` being a curve in `M`
|
|
91
|
+
(`U` is then an open interval of `\RR`).
|
|
92
|
+
|
|
93
|
+
.. NOTE::
|
|
94
|
+
|
|
95
|
+
If `M` is parallelizable, the class :class:`DiffFormParal`
|
|
96
|
+
must be used instead.
|
|
97
|
+
|
|
98
|
+
INPUT:
|
|
99
|
+
|
|
100
|
+
- ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector
|
|
101
|
+
fields along `U` with values on `M` via the map `\Phi`
|
|
102
|
+
- ``degree`` -- the degree of the differential form (i.e. its tensor rank)
|
|
103
|
+
- ``name`` -- (default: ``None``) name given to the differential form
|
|
104
|
+
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
|
|
105
|
+
differential form; if none is provided, the LaTeX symbol is set to
|
|
106
|
+
``name``
|
|
107
|
+
|
|
108
|
+
EXAMPLES:
|
|
109
|
+
|
|
110
|
+
Differential form of degree 2 on a non-parallelizable 2-dimensional
|
|
111
|
+
manifold::
|
|
112
|
+
|
|
113
|
+
sage: M = Manifold(2, 'M')
|
|
114
|
+
sage: U = M.open_subset('U') ; V = M.open_subset('V')
|
|
115
|
+
sage: M.declare_union(U,V) # M is the union of U and V
|
|
116
|
+
sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
|
|
117
|
+
sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), intersection_name='W',
|
|
118
|
+
....: restrictions1= x>0, restrictions2= u+v>0)
|
|
119
|
+
sage: uv_to_xy = xy_to_uv.inverse()
|
|
120
|
+
sage: W = U.intersection(V)
|
|
121
|
+
sage: eU = c_xy.frame() ; eV = c_uv.frame()
|
|
122
|
+
sage: a = M.diff_form(2, name='a') ; a
|
|
123
|
+
2-form a on the 2-dimensional differentiable manifold M
|
|
124
|
+
sage: a.parent()
|
|
125
|
+
Module Omega^2(M) of 2-forms on the 2-dimensional differentiable
|
|
126
|
+
manifold M
|
|
127
|
+
sage: a.degree()
|
|
128
|
+
2
|
|
129
|
+
|
|
130
|
+
Setting the components of ``a``::
|
|
131
|
+
|
|
132
|
+
sage: a[eU,0,1] = x*y^2 + 2*x
|
|
133
|
+
sage: a.add_comp_by_continuation(eV, W, c_uv)
|
|
134
|
+
sage: a.display(eU)
|
|
135
|
+
a = (x*y^2 + 2*x) dx∧dy
|
|
136
|
+
sage: a.display(eV)
|
|
137
|
+
a = (-1/16*u^3 + 1/16*u*v^2 - 1/16*v^3
|
|
138
|
+
+ 1/16*(u^2 - 8)*v - 1/2*u) du∧dv
|
|
139
|
+
|
|
140
|
+
A 1-form on ``M``::
|
|
141
|
+
|
|
142
|
+
sage: a = M.one_form(name='a') ; a
|
|
143
|
+
1-form a on the 2-dimensional differentiable manifold M
|
|
144
|
+
sage: a.parent()
|
|
145
|
+
Module Omega^1(M) of 1-forms on the 2-dimensional differentiable
|
|
146
|
+
manifold M
|
|
147
|
+
sage: a.degree()
|
|
148
|
+
1
|
|
149
|
+
|
|
150
|
+
Setting the components of the 1-form in a consistent way::
|
|
151
|
+
|
|
152
|
+
sage: a[eU,:] = [-y, x]
|
|
153
|
+
sage: a.add_comp_by_continuation(eV, W, c_uv)
|
|
154
|
+
sage: a.display(eU)
|
|
155
|
+
a = -y dx + x dy
|
|
156
|
+
sage: a.display(eV)
|
|
157
|
+
a = 1/2*v du - 1/2*u dv
|
|
158
|
+
|
|
159
|
+
It is also possible to set the components at the 1-form definition, via
|
|
160
|
+
a dictionary whose keys are the vector frames::
|
|
161
|
+
|
|
162
|
+
sage: a1 = M.one_form({eU: [-y, x], eV: [v/2, -u/2]}, name='a')
|
|
163
|
+
sage: a1 == a
|
|
164
|
+
True
|
|
165
|
+
|
|
166
|
+
The exterior derivative of the 1-form is a 2-form::
|
|
167
|
+
|
|
168
|
+
sage: da = a.exterior_derivative() ; da
|
|
169
|
+
2-form da on the 2-dimensional differentiable manifold M
|
|
170
|
+
sage: da.display(eU)
|
|
171
|
+
da = 2 dx∧dy
|
|
172
|
+
sage: da.display(eV)
|
|
173
|
+
da = -du∧dv
|
|
174
|
+
|
|
175
|
+
The exterior derivative can also be obtained by applying the function
|
|
176
|
+
``diff`` to a differentiable form::
|
|
177
|
+
|
|
178
|
+
sage: diff(a) is a.exterior_derivative()
|
|
179
|
+
True
|
|
180
|
+
|
|
181
|
+
Another 1-form defined by its components in ``eU``::
|
|
182
|
+
|
|
183
|
+
sage: b = M.one_form(1+x*y, x^2, frame=eU, name='b')
|
|
184
|
+
|
|
185
|
+
Since ``eU`` is the default vector frame on ``M``, it can be omitted
|
|
186
|
+
in the definition::
|
|
187
|
+
|
|
188
|
+
sage: b = M.one_form(1+x*y, x^2, name='b')
|
|
189
|
+
sage: b.add_comp_by_continuation(eV, W, c_uv)
|
|
190
|
+
|
|
191
|
+
Adding two 1-forms results in another 1-form::
|
|
192
|
+
|
|
193
|
+
sage: s = a + b ; s
|
|
194
|
+
1-form a+b on the 2-dimensional differentiable manifold M
|
|
195
|
+
sage: s.display(eU)
|
|
196
|
+
a+b = ((x - 1)*y + 1) dx + (x^2 + x) dy
|
|
197
|
+
sage: s.display(eV)
|
|
198
|
+
a+b = (1/4*u^2 + 1/4*(u + 2)*v + 1/2) du
|
|
199
|
+
+ (-1/4*u*v - 1/4*v^2 - 1/2*u + 1/2) dv
|
|
200
|
+
|
|
201
|
+
The exterior product of two 1-forms is a 2-form::
|
|
202
|
+
|
|
203
|
+
sage: s = a.wedge(b) ; s
|
|
204
|
+
2-form a∧b on the 2-dimensional differentiable manifold M
|
|
205
|
+
sage: s.display(eU)
|
|
206
|
+
a∧b = (-2*x^2*y - x) dx∧dy
|
|
207
|
+
sage: s.display(eV)
|
|
208
|
+
a∧b = (1/8*u^3 - 1/8*u*v^2 - 1/8*v^3 + 1/8*(u^2 + 2)*v + 1/4*u) du∧dv
|
|
209
|
+
|
|
210
|
+
Multiplying a 1-form by a scalar field results in another 1-form::
|
|
211
|
+
|
|
212
|
+
sage: f = M.scalar_field({c_xy: (x+y)^2, c_uv: u^2}, name='f')
|
|
213
|
+
sage: s = f*a ; s
|
|
214
|
+
1-form f*a on the 2-dimensional differentiable manifold M
|
|
215
|
+
sage: s.display(eU)
|
|
216
|
+
f*a = (-x^2*y - 2*x*y^2 - y^3) dx + (x^3 + 2*x^2*y + x*y^2) dy
|
|
217
|
+
sage: s.display(eV)
|
|
218
|
+
f*a = 1/2*u^2*v du - 1/2*u^3 dv
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
.. RUBRIC:: Examples with SymPy as the symbolic engine
|
|
222
|
+
|
|
223
|
+
From now on, we ask that all symbolic calculus on manifold `M` are
|
|
224
|
+
performed by SymPy::
|
|
225
|
+
|
|
226
|
+
sage: M.set_calculus_method('sympy')
|
|
227
|
+
|
|
228
|
+
We define a 2-form `a` as above::
|
|
229
|
+
|
|
230
|
+
sage: a = M.diff_form(2, name='a')
|
|
231
|
+
sage: a[eU,0,1] = x*y^2 + 2*x
|
|
232
|
+
sage: a.add_comp_by_continuation(eV, W, c_uv)
|
|
233
|
+
sage: a.display(eU)
|
|
234
|
+
a = (x*y**2 + 2*x) dx∧dy
|
|
235
|
+
sage: a.display(eV)
|
|
236
|
+
a = (-u**3/16 + u**2*v/16 + u*v**2/16 - u/2 - v**3/16 - v/2) du∧dv
|
|
237
|
+
|
|
238
|
+
A 1-form on ``M``::
|
|
239
|
+
|
|
240
|
+
sage: a = M.one_form(-y, x, name='a')
|
|
241
|
+
sage: a.add_comp_by_continuation(eV, W, c_uv)
|
|
242
|
+
sage: a.display(eU)
|
|
243
|
+
a = -y dx + x dy
|
|
244
|
+
sage: a.display(eV)
|
|
245
|
+
a = v/2 du - u/2 dv
|
|
246
|
+
|
|
247
|
+
The exterior derivative of ``a``::
|
|
248
|
+
|
|
249
|
+
sage: da = a.exterior_derivative()
|
|
250
|
+
sage: da.display(eU)
|
|
251
|
+
da = 2 dx∧dy
|
|
252
|
+
sage: da.display(eV)
|
|
253
|
+
da = -du∧dv
|
|
254
|
+
|
|
255
|
+
Another 1-form::
|
|
256
|
+
|
|
257
|
+
sage: b = M.one_form(1+x*y, x^2, name='b')
|
|
258
|
+
sage: b.add_comp_by_continuation(eV, W, c_uv)
|
|
259
|
+
|
|
260
|
+
Adding two 1-forms::
|
|
261
|
+
|
|
262
|
+
sage: s = a + b
|
|
263
|
+
sage: s.display(eU)
|
|
264
|
+
a+b = (x*y - y + 1) dx + x*(x + 1) dy
|
|
265
|
+
sage: s.display(eV)
|
|
266
|
+
a+b = (u**2/4 + u*v/4 + v/2 + 1/2) du + (-u*v/4 - u/2 - v**2/4 + 1/2) dv
|
|
267
|
+
|
|
268
|
+
The exterior product of two 1-forms::
|
|
269
|
+
|
|
270
|
+
sage: s = a.wedge(b)
|
|
271
|
+
sage: s.display(eU)
|
|
272
|
+
a∧b = x*(-2*x*y - 1) dx∧dy
|
|
273
|
+
sage: s.display(eV)
|
|
274
|
+
a∧b = (u**3/8 + u**2*v/8 - u*v**2/8 + u/4 - v**3/8 + v/4) du∧dv
|
|
275
|
+
|
|
276
|
+
Multiplying a 1-form by a scalar field::
|
|
277
|
+
|
|
278
|
+
sage: f = M.scalar_field({c_xy: (x+y)^2, c_uv: u^2}, name='f')
|
|
279
|
+
sage: s = f*a
|
|
280
|
+
sage: s.display(eU)
|
|
281
|
+
f*a = y*(-x**2 - 2*x*y - y**2) dx + x*(x**2 + 2*x*y + y**2) dy
|
|
282
|
+
sage: s.display(eV)
|
|
283
|
+
f*a = u**2*v/2 du - u**3/2 dv
|
|
284
|
+
"""
|
|
285
|
+
def __init__(self, vector_field_module, degree, name=None, latex_name=None):
|
|
286
|
+
r"""
|
|
287
|
+
Construct a differential form.
|
|
288
|
+
|
|
289
|
+
TESTS:
|
|
290
|
+
|
|
291
|
+
Construction via ``parent.element_class``, and not via a direct call
|
|
292
|
+
to ``DiffForm``, to fit with the category framework::
|
|
293
|
+
|
|
294
|
+
sage: M = Manifold(2, 'M')
|
|
295
|
+
sage: U = M.open_subset('U') ; V = M.open_subset('V')
|
|
296
|
+
sage: M.declare_union(U,V) # M is the union of U and V
|
|
297
|
+
sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
|
|
298
|
+
sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y),
|
|
299
|
+
....: intersection_name='W', restrictions1= x>0,
|
|
300
|
+
....: restrictions2= u+v>0)
|
|
301
|
+
sage: uv_to_xy = xy_to_uv.inverse()
|
|
302
|
+
sage: W = U.intersection(V)
|
|
303
|
+
sage: e_xy = c_xy.frame() ; e_uv = c_uv.frame()
|
|
304
|
+
sage: A = M.diff_form_module(2)
|
|
305
|
+
sage: XM = M.vector_field_module()
|
|
306
|
+
sage: a = A.element_class(XM, 2, name='a'); a
|
|
307
|
+
2-form a on the 2-dimensional differentiable manifold M
|
|
308
|
+
sage: a[e_xy,0,1] = x+y
|
|
309
|
+
sage: a.add_comp_by_continuation(e_uv, W, c_uv)
|
|
310
|
+
sage: TestSuite(a).run(skip='_test_pickling')
|
|
311
|
+
|
|
312
|
+
Construction with ``DifferentiableManifold.diff_form``::
|
|
313
|
+
|
|
314
|
+
sage: a1 = M.diff_form(2, name='a'); a1
|
|
315
|
+
2-form a on the 2-dimensional differentiable manifold M
|
|
316
|
+
sage: type(a1) == type(a)
|
|
317
|
+
True
|
|
318
|
+
sage: a1.parent() is a.parent()
|
|
319
|
+
True
|
|
320
|
+
|
|
321
|
+
.. TODO::
|
|
322
|
+
|
|
323
|
+
Fix ``_test_pickling`` (in the superclass :class:`TensorField`).
|
|
324
|
+
"""
|
|
325
|
+
TensorField.__init__(self, vector_field_module, (0, degree), name=name,
|
|
326
|
+
latex_name=latex_name, antisym=range(degree),
|
|
327
|
+
parent=vector_field_module.dual_exterior_power(degree))
|
|
328
|
+
self._init_derived() # initialization of derived quantities
|
|
329
|
+
|
|
330
|
+
def _repr_(self):
|
|
331
|
+
r"""
|
|
332
|
+
String representation of ``self``.
|
|
333
|
+
|
|
334
|
+
TESTS::
|
|
335
|
+
|
|
336
|
+
sage: M = Manifold(3, 'M')
|
|
337
|
+
sage: a = M.diff_form(2, name='a')
|
|
338
|
+
sage: a._repr_()
|
|
339
|
+
'2-form a on the 3-dimensional differentiable manifold M'
|
|
340
|
+
sage: repr(a) # indirect doctest
|
|
341
|
+
'2-form a on the 3-dimensional differentiable manifold M'
|
|
342
|
+
sage: a # indirect doctest
|
|
343
|
+
2-form a on the 3-dimensional differentiable manifold M
|
|
344
|
+
sage: b = M.diff_form(2)
|
|
345
|
+
sage: b._repr_()
|
|
346
|
+
'2-form on the 3-dimensional differentiable manifold M'
|
|
347
|
+
"""
|
|
348
|
+
description = "{}-form ".format(self._tensor_rank)
|
|
349
|
+
if self._name is not None:
|
|
350
|
+
description += self._name + " "
|
|
351
|
+
return self._final_repr(description)
|
|
352
|
+
|
|
353
|
+
def _new_instance(self):
|
|
354
|
+
r"""
|
|
355
|
+
Create an instance of the same class, of the same degree and on the
|
|
356
|
+
same domain.
|
|
357
|
+
|
|
358
|
+
TESTS::
|
|
359
|
+
|
|
360
|
+
sage: M = Manifold(3, 'M')
|
|
361
|
+
sage: a = M.diff_form(2, name='a')
|
|
362
|
+
sage: a1 = a._new_instance(); a1
|
|
363
|
+
2-form on the 3-dimensional differentiable manifold M
|
|
364
|
+
sage: type(a1) == type(a)
|
|
365
|
+
True
|
|
366
|
+
sage: a1.parent() is a.parent()
|
|
367
|
+
True
|
|
368
|
+
"""
|
|
369
|
+
return type(self)(self._vmodule, self._tensor_rank)
|
|
370
|
+
|
|
371
|
+
def _del_derived(self):
|
|
372
|
+
r"""
|
|
373
|
+
Delete the derived quantities.
|
|
374
|
+
|
|
375
|
+
TESTS::
|
|
376
|
+
|
|
377
|
+
sage: M = Manifold(3, 'M')
|
|
378
|
+
sage: a = M.diff_form(2, name='a')
|
|
379
|
+
sage: a._del_derived()
|
|
380
|
+
"""
|
|
381
|
+
TensorField._del_derived(self)
|
|
382
|
+
self.exterior_derivative.clear_cache()
|
|
383
|
+
|
|
384
|
+
@cached_method
|
|
385
|
+
def exterior_derivative(self) -> DiffForm:
|
|
386
|
+
r"""
|
|
387
|
+
Compute the exterior derivative of ``self``.
|
|
388
|
+
|
|
389
|
+
OUTPUT:
|
|
390
|
+
|
|
391
|
+
- instance of :class:`DiffForm` representing the exterior derivative
|
|
392
|
+
of the differential form
|
|
393
|
+
|
|
394
|
+
EXAMPLES:
|
|
395
|
+
|
|
396
|
+
Exterior derivative of a 1-form on the 2-sphere::
|
|
397
|
+
|
|
398
|
+
sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2
|
|
399
|
+
sage: U = M.open_subset('U') # complement of the North pole
|
|
400
|
+
sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
|
|
401
|
+
sage: V = M.open_subset('V') # complement of the South pole
|
|
402
|
+
sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
|
|
403
|
+
sage: M.declare_union(U,V) # S^2 is the union of U and V
|
|
404
|
+
sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)),
|
|
405
|
+
....: intersection_name='W', restrictions1= x^2+y^2!=0,
|
|
406
|
+
....: restrictions2= u^2+v^2!=0)
|
|
407
|
+
sage: uv_to_xy = xy_to_uv.inverse()
|
|
408
|
+
sage: e_xy = c_xy.frame(); e_uv = c_uv.frame()
|
|
409
|
+
|
|
410
|
+
The 1-form::
|
|
411
|
+
|
|
412
|
+
sage: a = M.one_form({e_xy: [-y^2, x^2]}, name='a')
|
|
413
|
+
sage: a.add_comp_by_continuation(e_uv, U.intersection(V), c_uv)
|
|
414
|
+
sage: a.display(e_xy)
|
|
415
|
+
a = -y^2 dx + x^2 dy
|
|
416
|
+
sage: a.display(e_uv)
|
|
417
|
+
a = -(2*u^3*v - u^2*v^2 + v^4)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) du
|
|
418
|
+
+ (u^4 - u^2*v^2 + 2*u*v^3)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) dv
|
|
419
|
+
|
|
420
|
+
Its exterior derivative::
|
|
421
|
+
|
|
422
|
+
sage: da = a.exterior_derivative(); da
|
|
423
|
+
2-form da on the 2-dimensional differentiable manifold M
|
|
424
|
+
sage: da.display(e_xy)
|
|
425
|
+
da = (2*x + 2*y) dx∧dy
|
|
426
|
+
sage: da.display(e_uv)
|
|
427
|
+
da = -2*(u + v)/(u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6) du∧dv
|
|
428
|
+
|
|
429
|
+
The result is cached, i.e. is not recomputed unless ``a`` is changed::
|
|
430
|
+
|
|
431
|
+
sage: a.exterior_derivative() is da
|
|
432
|
+
True
|
|
433
|
+
|
|
434
|
+
Instead of invoking the method :meth:`exterior_derivative`, one may
|
|
435
|
+
use the global function ``diff``::
|
|
436
|
+
|
|
437
|
+
sage: diff(a) is a.exterior_derivative()
|
|
438
|
+
True
|
|
439
|
+
|
|
440
|
+
Let us check Cartan's identity::
|
|
441
|
+
|
|
442
|
+
sage: v = M.vector_field({e_xy: [-y, x]}, name='v')
|
|
443
|
+
sage: v.add_comp_by_continuation(e_uv, U.intersection(V), c_uv)
|
|
444
|
+
sage: a.lie_der(v) == v.contract(diff(a)) + diff(a(v)) # long time
|
|
445
|
+
True
|
|
446
|
+
"""
|
|
447
|
+
from sage.tensor.modules.format_utilities import (
|
|
448
|
+
format_unop_latex,
|
|
449
|
+
format_unop_txt,
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
vmodule = self._vmodule # shortcut
|
|
453
|
+
rname = format_unop_txt("d", self._name)
|
|
454
|
+
rlname = format_unop_latex(r"\mathrm{d}", self._latex_name)
|
|
455
|
+
resu = vmodule.alternating_form(
|
|
456
|
+
self._tensor_rank + 1, name=rname, latex_name=rlname
|
|
457
|
+
)
|
|
458
|
+
for dom, rst in self._restrictions.items():
|
|
459
|
+
resu._restrictions[dom] = rst.exterior_derivative()
|
|
460
|
+
return resu
|
|
461
|
+
|
|
462
|
+
derivative = exterior_derivative # allows one to use functional notation,
|
|
463
|
+
# e.g. diff(a) for a.exterior_derivative()
|
|
464
|
+
|
|
465
|
+
def wedge(self, other: DiffForm) -> DiffForm:
|
|
466
|
+
r"""
|
|
467
|
+
Exterior product with another differential form.
|
|
468
|
+
|
|
469
|
+
INPUT:
|
|
470
|
+
|
|
471
|
+
- ``other`` -- another differential form (on the same manifold)
|
|
472
|
+
|
|
473
|
+
OUTPUT:
|
|
474
|
+
|
|
475
|
+
- instance of :class:`DiffForm` representing the exterior product
|
|
476
|
+
``self ∧ other``
|
|
477
|
+
|
|
478
|
+
EXAMPLES:
|
|
479
|
+
|
|
480
|
+
Exterior product of two 1-forms on the 2-sphere::
|
|
481
|
+
|
|
482
|
+
sage: M = Manifold(2, 'S^2', start_index=1) # the 2-dimensional sphere S^2
|
|
483
|
+
sage: U = M.open_subset('U') ; V = M.open_subset('V')
|
|
484
|
+
sage: M.declare_union(U,V) # S^2 is the union of U and V
|
|
485
|
+
sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() # stereographic coord. (North and South)
|
|
486
|
+
sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)),
|
|
487
|
+
....: intersection_name='W', restrictions1= x^2+y^2!=0,
|
|
488
|
+
....: restrictions2= u^2+v^2!=0)
|
|
489
|
+
sage: uv_to_xy = xy_to_uv.inverse()
|
|
490
|
+
sage: W = U.intersection(V) # The complement of the two poles
|
|
491
|
+
sage: e_xy = c_xy.frame() ; e_uv = c_uv.frame()
|
|
492
|
+
sage: a = M.one_form({e_xy: [y, x]}, name='a')
|
|
493
|
+
sage: a.add_comp_by_continuation(e_uv, W, c_uv)
|
|
494
|
+
sage: b = M.one_form({e_xy: [x^2 + y^2, y]}, name='b')
|
|
495
|
+
sage: b.add_comp_by_continuation(e_uv, W, c_uv)
|
|
496
|
+
sage: c = a.wedge(b); c
|
|
497
|
+
2-form a∧b on the 2-dimensional differentiable manifold S^2
|
|
498
|
+
sage: c.display(e_xy)
|
|
499
|
+
a∧b = (-x^3 - (x - 1)*y^2) dx∧dy
|
|
500
|
+
sage: c.display(e_uv)
|
|
501
|
+
a∧b = -(v^2 - u)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) du∧dv
|
|
502
|
+
|
|
503
|
+
If one of the two operands is unnamed, the result is unnamed too::
|
|
504
|
+
|
|
505
|
+
sage: b1 = M.diff_form(1) # no name set
|
|
506
|
+
sage: b1[e_xy,:] = x^2 + y^2, y
|
|
507
|
+
sage: b1.add_comp_by_continuation(e_uv, W, c_uv)
|
|
508
|
+
sage: c1 = a.wedge(b1); c1
|
|
509
|
+
2-form on the 2-dimensional differentiable manifold S^2
|
|
510
|
+
sage: c1.display(e_xy)
|
|
511
|
+
(-x^3 - (x - 1)*y^2) dx∧dy
|
|
512
|
+
|
|
513
|
+
To give a name to the result, one shall use the method
|
|
514
|
+
:meth:`~sage.manifolds.differentiable.tensorfield.TensorField.set_name`::
|
|
515
|
+
|
|
516
|
+
sage: c1.set_name('c'); c1
|
|
517
|
+
2-form c on the 2-dimensional differentiable manifold S^2
|
|
518
|
+
sage: c1.display(e_xy)
|
|
519
|
+
c = (-x^3 - (x - 1)*y^2) dx∧dy
|
|
520
|
+
|
|
521
|
+
Wedging with scalar fields yields the multiplication from right::
|
|
522
|
+
|
|
523
|
+
sage: f = M.scalar_field(x, name='f')
|
|
524
|
+
sage: f.add_expr_by_continuation(c_uv, W)
|
|
525
|
+
sage: t = a.wedge(f)
|
|
526
|
+
sage: t.display()
|
|
527
|
+
f*a = x*y dx + x^2 dy
|
|
528
|
+
"""
|
|
529
|
+
if other._tensor_rank == 0:
|
|
530
|
+
return self * other
|
|
531
|
+
from sage.tensor.modules.format_utilities import is_atomic
|
|
532
|
+
from sage.typeset.unicode_characters import unicode_wedge
|
|
533
|
+
if self._domain.is_subset(other._domain):
|
|
534
|
+
if not self._ambient_domain.is_subset(other._ambient_domain):
|
|
535
|
+
raise ValueError("incompatible ambient domains for exterior product")
|
|
536
|
+
elif other._domain.is_subset(self._domain):
|
|
537
|
+
if not other._ambient_domain.is_subset(self._ambient_domain):
|
|
538
|
+
raise ValueError("incompatible ambient domains for exterior product")
|
|
539
|
+
dom_resu = self._domain.intersection(other._domain)
|
|
540
|
+
ambient_dom_resu = self._ambient_domain.intersection(other._ambient_domain)
|
|
541
|
+
resu_degree = self._tensor_rank + other._tensor_rank
|
|
542
|
+
dest_map = self._vmodule._dest_map
|
|
543
|
+
dest_map_resu = dest_map.restrict(dom_resu,
|
|
544
|
+
subcodomain=ambient_dom_resu)
|
|
545
|
+
# Facilitate computations involving zero:
|
|
546
|
+
if resu_degree > ambient_dom_resu._dim:
|
|
547
|
+
return dom_resu.diff_form_module(resu_degree,
|
|
548
|
+
dest_map=dest_map_resu).zero()
|
|
549
|
+
if self._is_zero or other._is_zero:
|
|
550
|
+
return dom_resu.diff_form_module(resu_degree,
|
|
551
|
+
dest_map=dest_map_resu).zero()
|
|
552
|
+
if self is other and (self._tensor_rank % 2) == 1:
|
|
553
|
+
return dom_resu.diff_form_module(resu_degree,
|
|
554
|
+
dest_map=dest_map_resu).zero()
|
|
555
|
+
# Generic case:
|
|
556
|
+
self_r = self.restrict(dom_resu)
|
|
557
|
+
other_r = other.restrict(dom_resu)
|
|
558
|
+
if ambient_dom_resu.is_manifestly_parallelizable():
|
|
559
|
+
# call of the FreeModuleAltForm version:
|
|
560
|
+
return FreeModuleAltForm.wedge(self_r, other_r)
|
|
561
|
+
# otherwise, the result is created here:
|
|
562
|
+
resu_name = None
|
|
563
|
+
if self._name is not None and other._name is not None:
|
|
564
|
+
sname = self._name
|
|
565
|
+
oname = other._name
|
|
566
|
+
if not is_atomic(sname):
|
|
567
|
+
sname = '(' + sname + ')'
|
|
568
|
+
if not is_atomic(oname):
|
|
569
|
+
oname = '(' + oname + ')'
|
|
570
|
+
resu_name = sname + unicode_wedge + oname
|
|
571
|
+
resu_latex_name = None
|
|
572
|
+
if self._latex_name is not None and other._latex_name is not None:
|
|
573
|
+
slname = self._latex_name
|
|
574
|
+
olname = other._latex_name
|
|
575
|
+
if not is_atomic(slname):
|
|
576
|
+
slname = '(' + slname + ')'
|
|
577
|
+
if not is_atomic(olname):
|
|
578
|
+
olname = '(' + olname + ')'
|
|
579
|
+
resu_latex_name = slname + r'\wedge ' + olname
|
|
580
|
+
vmodule = dom_resu.vector_field_module(dest_map=dest_map_resu)
|
|
581
|
+
resu = vmodule.alternating_form(resu_degree, name=resu_name,
|
|
582
|
+
latex_name=resu_latex_name)
|
|
583
|
+
for dom in self_r._restrictions:
|
|
584
|
+
if dom in other_r._restrictions:
|
|
585
|
+
resu._restrictions[dom] = self_r._restrictions[dom].wedge(
|
|
586
|
+
other_r._restrictions[dom])
|
|
587
|
+
return resu
|
|
588
|
+
|
|
589
|
+
def degree(self) -> int:
|
|
590
|
+
r"""
|
|
591
|
+
Return the degree of ``self``.
|
|
592
|
+
|
|
593
|
+
OUTPUT: integer `p` such that the differential form is a `p`-form
|
|
594
|
+
|
|
595
|
+
EXAMPLES::
|
|
596
|
+
|
|
597
|
+
sage: M = Manifold(3, 'M')
|
|
598
|
+
sage: a = M.diff_form(2); a
|
|
599
|
+
2-form on the 3-dimensional differentiable manifold M
|
|
600
|
+
sage: a.degree()
|
|
601
|
+
2
|
|
602
|
+
sage: b = M.diff_form(1); b
|
|
603
|
+
1-form on the 3-dimensional differentiable manifold M
|
|
604
|
+
sage: b.degree()
|
|
605
|
+
1
|
|
606
|
+
"""
|
|
607
|
+
return self._tensor_rank
|
|
608
|
+
|
|
609
|
+
def hodge_dual(
|
|
610
|
+
self,
|
|
611
|
+
nondegenerate_tensor: Union[
|
|
612
|
+
PseudoRiemannianMetric, SymplecticForm, None
|
|
613
|
+
] = None,
|
|
614
|
+
minus_eigenvalues_convention: bool = False,
|
|
615
|
+
) -> DiffForm:
|
|
616
|
+
r"""
|
|
617
|
+
Compute the Hodge dual of the differential form with respect to some non-degenerate
|
|
618
|
+
bilinear form (Riemannian metric or symplectic form).
|
|
619
|
+
|
|
620
|
+
If the differential form is a `p`-form `A`, its *Hodge dual* with
|
|
621
|
+
respect to the non-degenerate form `g` is the
|
|
622
|
+
`(n-p)`-form `*A` defined by
|
|
623
|
+
|
|
624
|
+
.. MATH::
|
|
625
|
+
|
|
626
|
+
*A_{i_1\ldots i_{n-p}} = \frac{1}{p!} A^{k_1\ldots k_p}
|
|
627
|
+
\epsilon_{k_1\ldots k_p\, i_1\ldots i_{n-p}}
|
|
628
|
+
|
|
629
|
+
where `n` is the manifold's dimension, `\epsilon` is the volume
|
|
630
|
+
`n`-form associated with `g` (see
|
|
631
|
+
:meth:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric.volume_form`)
|
|
632
|
+
and the indices `k_1,\ldots, k_p` are raised with `g`.
|
|
633
|
+
If `g` is a pseudo-Riemannian metric, sometimes an additional multiplicative
|
|
634
|
+
factor of `(-1)^s` is introduced on the right-hand side,
|
|
635
|
+
where `s` is the number of negative eigenvalues of `g`.
|
|
636
|
+
This convention can be enforced by setting the option
|
|
637
|
+
``minus_eigenvalues_convention``.
|
|
638
|
+
|
|
639
|
+
INPUT:
|
|
640
|
+
|
|
641
|
+
- ``nondegenerate_tensor`` -- a non-degenerate bilinear form defined on the same manifold
|
|
642
|
+
as the current differential form; must be an instance of
|
|
643
|
+
:class:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric` or
|
|
644
|
+
:class:`~sage.manifolds.differentiable.symplectic_form.SymplecticForm`.
|
|
645
|
+
If none is provided, the ambient domain of ``self`` is supposed to be endowed
|
|
646
|
+
with a default metric and this metric is then used.
|
|
647
|
+
- ``minus_eigenvalues_convention`` -- if `true`, a factor of `(-1)^s` is
|
|
648
|
+
introduced with `s` being the number of negative eigenvalues of the
|
|
649
|
+
``nondegenerate_tensor``.
|
|
650
|
+
|
|
651
|
+
OUTPUT:
|
|
652
|
+
|
|
653
|
+
- the `(n-p)`-form `*A`
|
|
654
|
+
|
|
655
|
+
EXAMPLES:
|
|
656
|
+
|
|
657
|
+
Hodge dual of a 1-form on the 2-sphere equipped with the standard
|
|
658
|
+
metric: we first construct `\mathbb{S}^2` and its metric `g`::
|
|
659
|
+
|
|
660
|
+
sage: M = Manifold(2, 'S^2', start_index=1)
|
|
661
|
+
sage: U = M.open_subset('U') ; V = M.open_subset('V')
|
|
662
|
+
sage: M.declare_union(U,V) # S^2 is the union of U and V
|
|
663
|
+
sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart() # stereographic coord. (North and South)
|
|
664
|
+
sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)),
|
|
665
|
+
....: intersection_name='W', restrictions1= x^2+y^2!=0,
|
|
666
|
+
....: restrictions2= u^2+v^2!=0)
|
|
667
|
+
sage: uv_to_xy = xy_to_uv.inverse()
|
|
668
|
+
sage: W = U.intersection(V) # The complement of the two poles
|
|
669
|
+
sage: eU = c_xy.frame() ; eV = c_uv.frame()
|
|
670
|
+
sage: g = M.metric('g')
|
|
671
|
+
sage: g[eU,1,1], g[eU,2,2] = 4/(1+x^2+y^2)^2, 4/(1+x^2+y^2)^2
|
|
672
|
+
sage: g[eV,1,1], g[eV,2,2] = 4/(1+u^2+v^2)^2, 4/(1+u^2+v^2)^2
|
|
673
|
+
|
|
674
|
+
We endow `S^2` with the orientation defined by the stereographic
|
|
675
|
+
frame from the North pole, i.e. ``eU``; ``eV`` is then left-handed and
|
|
676
|
+
in order to define an orientation on the whole manifold, we introduce a
|
|
677
|
+
vector frame on ``V`` by swapping ``eV``'s vectors::
|
|
678
|
+
|
|
679
|
+
sage: f = V.vector_frame('f', (eV[2], eV[1]))
|
|
680
|
+
sage: M.set_orientation([eU, f])
|
|
681
|
+
|
|
682
|
+
Then we construct the 1-form and take its Hodge dual w.r.t. `g`::
|
|
683
|
+
|
|
684
|
+
sage: a = M.one_form({eU: [-y, x]}, name='a')
|
|
685
|
+
sage: a.add_comp_by_continuation(eV, W, c_uv)
|
|
686
|
+
sage: a.display(eU)
|
|
687
|
+
a = -y dx + x dy
|
|
688
|
+
sage: a.display(eV)
|
|
689
|
+
a = -v/(u^4 + 2*u^2*v^2 + v^4) du + u/(u^4 + 2*u^2*v^2 + v^4) dv
|
|
690
|
+
sage: sa = a.hodge_dual(g); sa
|
|
691
|
+
1-form *a on the 2-dimensional differentiable manifold S^2
|
|
692
|
+
sage: sa.display(eU)
|
|
693
|
+
*a = -x dx - y dy
|
|
694
|
+
sage: sa.display(eV)
|
|
695
|
+
*a = u/(u^4 + 2*u^2*v^2 + v^4) du + v/(u^4 + 2*u^2*v^2 + v^4) dv
|
|
696
|
+
|
|
697
|
+
Instead of calling the method :meth:`hodge_dual` on the differential
|
|
698
|
+
form, one can invoke the method
|
|
699
|
+
:meth:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric.hodge_star`
|
|
700
|
+
of the metric::
|
|
701
|
+
|
|
702
|
+
sage: a.hodge_dual(g) == g.hodge_star(a)
|
|
703
|
+
True
|
|
704
|
+
|
|
705
|
+
For a 1-form and a Riemannian metric in dimension 2, the Hodge dual
|
|
706
|
+
applied twice is minus the identity::
|
|
707
|
+
|
|
708
|
+
sage: ssa = sa.hodge_dual(g); ssa
|
|
709
|
+
1-form **a on the 2-dimensional differentiable manifold S^2
|
|
710
|
+
sage: ssa == -a
|
|
711
|
+
True
|
|
712
|
+
|
|
713
|
+
The Hodge dual of the metric volume 2-form is the constant scalar
|
|
714
|
+
field 1 (considered as a 0-form)::
|
|
715
|
+
|
|
716
|
+
sage: eps = g.volume_form(); eps
|
|
717
|
+
2-form eps_g on the 2-dimensional differentiable manifold S^2
|
|
718
|
+
sage: eps.display(eU)
|
|
719
|
+
eps_g = 4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dx∧dy
|
|
720
|
+
sage: eps.display(eV)
|
|
721
|
+
eps_g = -4/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) du∧dv
|
|
722
|
+
sage: seps = eps.hodge_dual(g); seps
|
|
723
|
+
Scalar field *eps_g on the 2-dimensional differentiable manifold S^2
|
|
724
|
+
sage: seps.display()
|
|
725
|
+
*eps_g: S^2 → ℝ
|
|
726
|
+
on U: (x, y) ↦ 1
|
|
727
|
+
on V: (u, v) ↦ 1
|
|
728
|
+
|
|
729
|
+
Hodge dual of a 1-form in the Euclidean space `R^3`::
|
|
730
|
+
|
|
731
|
+
sage: M = Manifold(3, 'M', start_index=1)
|
|
732
|
+
sage: X.<x,y,z> = M.chart()
|
|
733
|
+
sage: g = M.metric('g') # the Euclidean metric
|
|
734
|
+
sage: g[1,1], g[2,2], g[3,3] = 1, 1, 1
|
|
735
|
+
sage: var('Ax Ay Az')
|
|
736
|
+
(Ax, Ay, Az)
|
|
737
|
+
sage: a = M.one_form(Ax, Ay, Az, name='A')
|
|
738
|
+
sage: sa = a.hodge_dual(g) ; sa
|
|
739
|
+
2-form *A on the 3-dimensional differentiable manifold M
|
|
740
|
+
sage: sa.display()
|
|
741
|
+
*A = Az dx∧dy - Ay dx∧dz + Ax dy∧dz
|
|
742
|
+
sage: ssa = sa.hodge_dual(g) ; ssa
|
|
743
|
+
1-form **A on the 3-dimensional differentiable manifold M
|
|
744
|
+
sage: ssa.display()
|
|
745
|
+
**A = Ax dx + Ay dy + Az dz
|
|
746
|
+
sage: ssa == a # must hold for a Riemannian metric in dimension 3
|
|
747
|
+
True
|
|
748
|
+
|
|
749
|
+
See the documentation of
|
|
750
|
+
:meth:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric.hodge_star`
|
|
751
|
+
for more examples.
|
|
752
|
+
|
|
753
|
+
TESTS:
|
|
754
|
+
Fall back to use (ambient) metric::
|
|
755
|
+
|
|
756
|
+
sage: M = Manifold(3, 'M', start_index=1, structure='Riemannian')
|
|
757
|
+
sage: X.<x,y,z> = M.chart()
|
|
758
|
+
sage: g = M.metric()
|
|
759
|
+
sage: g[1,1], g[2,2], g[3,3] = 1, 1, 1
|
|
760
|
+
sage: var('Ax Ay Az')
|
|
761
|
+
(Ax, Ay, Az)
|
|
762
|
+
sage: a = M.one_form(Ax, Ay, Az, name='A')
|
|
763
|
+
sage: a.hodge_dual().display()
|
|
764
|
+
*A = Az dx∧dy - Ay dx∧dz + Ax dy∧dz
|
|
765
|
+
"""
|
|
766
|
+
from sage.functions.other import factorial
|
|
767
|
+
from sage.tensor.modules.format_utilities import (
|
|
768
|
+
format_unop_latex,
|
|
769
|
+
format_unop_txt,
|
|
770
|
+
)
|
|
771
|
+
|
|
772
|
+
if nondegenerate_tensor is None:
|
|
773
|
+
nondegenerate_tensor = self._vmodule._ambient_domain.metric()
|
|
774
|
+
|
|
775
|
+
p = self.tensor_type()[1]
|
|
776
|
+
# For performance reasons, we raise the indices of the volume form
|
|
777
|
+
# and not of the differential form; in the symplectic case this is wrong by
|
|
778
|
+
# a factor of (-1)^p, which will be corrected below
|
|
779
|
+
eps = nondegenerate_tensor.volume_form(p)
|
|
780
|
+
if p == 0:
|
|
781
|
+
common_domain = nondegenerate_tensor.domain().intersection(self.domain())
|
|
782
|
+
result = self.restrict(common_domain) * eps.restrict(common_domain)
|
|
783
|
+
else:
|
|
784
|
+
result = self.contract(*range(p), eps, *range(p))
|
|
785
|
+
if p > 1:
|
|
786
|
+
result = result / factorial(p)
|
|
787
|
+
if minus_eigenvalues_convention:
|
|
788
|
+
from sage.manifolds.differentiable.metric import PseudoRiemannianMetric
|
|
789
|
+
if isinstance(nondegenerate_tensor, PseudoRiemannianMetric):
|
|
790
|
+
result = result * nondegenerate_tensor._indic_signat
|
|
791
|
+
from sage.manifolds.differentiable.symplectic_form import SymplecticForm
|
|
792
|
+
if isinstance(nondegenerate_tensor, SymplecticForm):
|
|
793
|
+
# correction because we lifted the indices of the volume (see above)
|
|
794
|
+
result = result * (-1)**p
|
|
795
|
+
|
|
796
|
+
result.set_name(
|
|
797
|
+
name=format_unop_txt("*", self._name),
|
|
798
|
+
latex_name=format_unop_latex(r"\star ", self._latex_name),
|
|
799
|
+
)
|
|
800
|
+
return result
|
|
801
|
+
|
|
802
|
+
def interior_product(self, qvect):
|
|
803
|
+
r"""
|
|
804
|
+
Interior product with a multivector field.
|
|
805
|
+
|
|
806
|
+
If ``self`` is a differential form `A` of degree `p` and `B` is a
|
|
807
|
+
multivector field of degree `q\geq p` on the same manifold, the
|
|
808
|
+
interior product of `A` by `B` is the multivector field `\iota_A B` of
|
|
809
|
+
degree `q-p` defined by
|
|
810
|
+
|
|
811
|
+
.. MATH::
|
|
812
|
+
|
|
813
|
+
(\iota_A B)^{i_1\ldots i_{q-p}} = A_{k_1\ldots k_p}
|
|
814
|
+
B^{k_1\ldots k_p i_1\ldots i_{q-p}}
|
|
815
|
+
|
|
816
|
+
.. NOTE::
|
|
817
|
+
|
|
818
|
+
``A.interior_product(B)`` yields the same result as
|
|
819
|
+
``A.contract(0,..., p-1, B, 0,..., p-1)`` (cf.
|
|
820
|
+
:meth:`~sage.manifolds.differentiable.tensorfield.TensorField.contract`),
|
|
821
|
+
but ``interior_product`` is more efficient, the alternating
|
|
822
|
+
character of `A` being not used to reduce the computation in
|
|
823
|
+
:meth:`~sage.manifolds.differentiable.tensorfield.TensorField.contract`
|
|
824
|
+
|
|
825
|
+
INPUT:
|
|
826
|
+
|
|
827
|
+
- ``qvect`` -- multivector field `B` (instance of
|
|
828
|
+
:class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField`);
|
|
829
|
+
the degree of `B` must be at least equal to the degree of ``self``
|
|
830
|
+
|
|
831
|
+
OUTPUT:
|
|
832
|
+
|
|
833
|
+
- scalar field (case `p=q`) or
|
|
834
|
+
:class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField`
|
|
835
|
+
(case `p<q`) representing the interior product `\iota_A B`, where
|
|
836
|
+
`A` is ``self``
|
|
837
|
+
|
|
838
|
+
.. SEEALSO::
|
|
839
|
+
|
|
840
|
+
:meth:`~sage.manifolds.differentiable.multivectorfield.MultivectorField.interior_product`
|
|
841
|
+
for the interior product of a multivector field with a differential
|
|
842
|
+
form
|
|
843
|
+
|
|
844
|
+
EXAMPLES:
|
|
845
|
+
|
|
846
|
+
Interior product of a 1-form with a 2-vector field on the 2-sphere::
|
|
847
|
+
|
|
848
|
+
sage: M = Manifold(2, 'S^2', start_index=1) # the sphere S^2
|
|
849
|
+
sage: U = M.open_subset('U') ; V = M.open_subset('V')
|
|
850
|
+
sage: M.declare_union(U,V) # S^2 is the union of U and V
|
|
851
|
+
sage: c_xy.<x,y> = U.chart() # stereographic coord. North
|
|
852
|
+
sage: c_uv.<u,v> = V.chart() # stereographic coord. South
|
|
853
|
+
sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)),
|
|
854
|
+
....: intersection_name='W', restrictions1= x^2+y^2!=0,
|
|
855
|
+
....: restrictions2= u^2+v^2!=0)
|
|
856
|
+
sage: uv_to_xy = xy_to_uv.inverse()
|
|
857
|
+
sage: W = U.intersection(V) # The complement of the two poles
|
|
858
|
+
sage: e_xy = c_xy.frame() ; e_uv = c_uv.frame()
|
|
859
|
+
sage: a = M.one_form({e_xy: [y, x]}, name='a')
|
|
860
|
+
sage: a.add_comp_by_continuation(e_uv, W, c_uv)
|
|
861
|
+
sage: b = M.multivector_field(2, name='b')
|
|
862
|
+
sage: b[e_xy,1,2] = x*y
|
|
863
|
+
sage: b.add_comp_by_continuation(e_uv, W, c_uv)
|
|
864
|
+
sage: s = a.interior_product(b); s
|
|
865
|
+
Vector field i_a b on the 2-dimensional differentiable manifold S^2
|
|
866
|
+
sage: s.display(e_xy)
|
|
867
|
+
i_a b = -x^2*y ∂/∂x + x*y^2 ∂/∂y
|
|
868
|
+
sage: s.display(e_uv)
|
|
869
|
+
i_a b = (u^4*v - 3*u^2*v^3)/(u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6) ∂/∂u
|
|
870
|
+
+ (3*u^3*v^2 - u*v^4)/(u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6) ∂/∂v
|
|
871
|
+
sage: s == a.contract(b)
|
|
872
|
+
True
|
|
873
|
+
|
|
874
|
+
Interior product of a 2-form with a 2-vector field::
|
|
875
|
+
|
|
876
|
+
sage: a = M.diff_form(2, name='a')
|
|
877
|
+
sage: a[e_xy,1,2] = 4/(x^2+y^2+1)^2 # the standard area 2-form
|
|
878
|
+
sage: a.add_comp_by_continuation(e_uv, W, c_uv)
|
|
879
|
+
sage: s = a.interior_product(b); s
|
|
880
|
+
Scalar field i_a b on the 2-dimensional differentiable manifold S^2
|
|
881
|
+
sage: s.display()
|
|
882
|
+
i_a b: S^2 → ℝ
|
|
883
|
+
on U: (x, y) ↦ 8*x*y/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1)
|
|
884
|
+
on V: (u, v) ↦ 8*u*v/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1)
|
|
885
|
+
|
|
886
|
+
Some checks::
|
|
887
|
+
|
|
888
|
+
sage: s == a.contract(0, 1, b, 0, 1)
|
|
889
|
+
True
|
|
890
|
+
sage: s.restrict(U) == 2 * a[[e_xy,1,2]] * b[[e_xy,1,2]]
|
|
891
|
+
True
|
|
892
|
+
sage: s.restrict(V) == 2 * a[[e_uv,1,2]] * b[[e_uv,1,2]]
|
|
893
|
+
True
|
|
894
|
+
"""
|
|
895
|
+
from sage.tensor.modules.format_utilities import is_atomic
|
|
896
|
+
if self._domain.is_subset(qvect._domain):
|
|
897
|
+
if not self._ambient_domain.is_subset(qvect._ambient_domain):
|
|
898
|
+
raise ValueError("incompatible ambient domains for interior " +
|
|
899
|
+
"product")
|
|
900
|
+
elif qvect._domain.is_subset(self._domain):
|
|
901
|
+
if not qvect._ambient_domain.is_subset(self._ambient_domain):
|
|
902
|
+
raise ValueError("incompatible ambient domains for interior " +
|
|
903
|
+
"product")
|
|
904
|
+
dom_resu = self._domain.intersection(qvect._domain)
|
|
905
|
+
ambient_dom_resu = self._ambient_domain.intersection(qvect._ambient_domain)
|
|
906
|
+
self_r = self.restrict(dom_resu)
|
|
907
|
+
qvect_r = qvect.restrict(dom_resu)
|
|
908
|
+
if ambient_dom_resu.is_manifestly_parallelizable():
|
|
909
|
+
# call of the FreeModuleAltForm version:
|
|
910
|
+
return FreeModuleAltForm.interior_product(self_r, qvect_r)
|
|
911
|
+
# Otherwise, the result is created here:
|
|
912
|
+
# Name of the result
|
|
913
|
+
resu_name = None
|
|
914
|
+
if self._name is not None and qvect._name is not None:
|
|
915
|
+
sname = self._name
|
|
916
|
+
oname = qvect._name
|
|
917
|
+
if not is_atomic(sname):
|
|
918
|
+
sname = '(' + sname + ')'
|
|
919
|
+
if not is_atomic(oname):
|
|
920
|
+
oname = '(' + oname + ')'
|
|
921
|
+
resu_name = 'i_' + sname + ' ' + oname
|
|
922
|
+
resu_latex_name = None
|
|
923
|
+
if self._latex_name is not None and qvect._latex_name is not None:
|
|
924
|
+
slname = self._latex_name
|
|
925
|
+
olname = qvect._latex_name
|
|
926
|
+
if not is_atomic(olname):
|
|
927
|
+
olname = r'\left(' + olname + r'\right)'
|
|
928
|
+
resu_latex_name = r'\iota_{' + slname + '} ' + olname
|
|
929
|
+
# Domain and computation of the result
|
|
930
|
+
dest_map = self._vmodule._dest_map
|
|
931
|
+
dest_map_resu = dest_map.restrict(dom_resu,
|
|
932
|
+
subcodomain=ambient_dom_resu)
|
|
933
|
+
vmodule = dom_resu.vector_field_module(dest_map=dest_map_resu)
|
|
934
|
+
resu_degree = qvect._tensor_rank - self._tensor_rank
|
|
935
|
+
resu = vmodule.alternating_contravariant_tensor(resu_degree,
|
|
936
|
+
name=resu_name, latex_name=resu_latex_name)
|
|
937
|
+
for dom in self_r._restrictions:
|
|
938
|
+
if dom in qvect_r._restrictions:
|
|
939
|
+
resu._restrictions[dom] = \
|
|
940
|
+
self_r._restrictions[dom].interior_product(
|
|
941
|
+
qvect_r._restrictions[dom])
|
|
942
|
+
if resu_degree == 0:
|
|
943
|
+
if not resu._express: # only the restrictions to subdomains have
|
|
944
|
+
# been initialized
|
|
945
|
+
for chart in dom_resu.top_charts():
|
|
946
|
+
resu._express[chart] = \
|
|
947
|
+
resu.restrict(chart.domain()).coord_function(chart)
|
|
948
|
+
return resu
|
|
949
|
+
|
|
950
|
+
# *****************************************************************************
|
|
951
|
+
|
|
952
|
+
|
|
953
|
+
class DiffFormParal(FreeModuleAltForm, TensorFieldParal, DiffForm):
|
|
954
|
+
r"""
|
|
955
|
+
Differential form with values on a parallelizable manifold.
|
|
956
|
+
|
|
957
|
+
Given a differentiable manifold `U`, a differentiable map
|
|
958
|
+
`\Phi: U \rightarrow M` to a parallelizable manifold `M` and a positive
|
|
959
|
+
integer `p`, a *differential form of degree* `p` (or `p`-*form*)
|
|
960
|
+
*along* `U` *with values on* `M\supset\Phi(U)` is a differentiable map
|
|
961
|
+
|
|
962
|
+
.. MATH::
|
|
963
|
+
|
|
964
|
+
a:\ U \longrightarrow T^{(0,p)}M
|
|
965
|
+
|
|
966
|
+
(`T^{(0,p)}M` being the tensor bundle of type `(0,p)` over `M`) such that
|
|
967
|
+
|
|
968
|
+
.. MATH::
|
|
969
|
+
|
|
970
|
+
\forall x \in U,\quad a(x) \in \Lambda^p(T_{\Phi(x)}^* M) ,
|
|
971
|
+
|
|
972
|
+
where `T_{\Phi(x)}^* M` is the dual of the tangent space to `M` at
|
|
973
|
+
`\Phi(x)` and `\Lambda^p` stands for the exterior power of degree `p` (cf.
|
|
974
|
+
:class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule`).
|
|
975
|
+
In other words, `a(x)` is an alternating multilinear form of degree `p` of
|
|
976
|
+
the tangent vector space `T_{\Phi(x)} M`.
|
|
977
|
+
|
|
978
|
+
The standard case of a differential form *on* a manifold `M` corresponds
|
|
979
|
+
to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi`
|
|
980
|
+
being an immersion and `\Phi` being a curve in `M` (`U` is then an
|
|
981
|
+
open interval of `\RR`).
|
|
982
|
+
|
|
983
|
+
.. NOTE::
|
|
984
|
+
|
|
985
|
+
If `M` is not parallelizable, the class :class:`DiffForm` must
|
|
986
|
+
be used instead.
|
|
987
|
+
|
|
988
|
+
INPUT:
|
|
989
|
+
|
|
990
|
+
- ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector
|
|
991
|
+
fields along `U` with values on `M` via the map `\Phi`
|
|
992
|
+
- ``degree`` -- the degree of the differential form (i.e. its tensor rank)
|
|
993
|
+
- ``name`` -- (default: ``None``) name given to the differential form
|
|
994
|
+
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
|
|
995
|
+
differential form; if none is provided, the LaTeX symbol is set to
|
|
996
|
+
``name``
|
|
997
|
+
|
|
998
|
+
EXAMPLES:
|
|
999
|
+
|
|
1000
|
+
A 2-form on a 4-dimensional manifold::
|
|
1001
|
+
|
|
1002
|
+
sage: M = Manifold(4, 'M')
|
|
1003
|
+
sage: c_txyz.<t,x,y,z> = M.chart()
|
|
1004
|
+
sage: a = M.diff_form(2, name='a') ; a
|
|
1005
|
+
2-form a on the 4-dimensional differentiable manifold M
|
|
1006
|
+
sage: a.parent()
|
|
1007
|
+
Free module Omega^2(M) of 2-forms on the 4-dimensional differentiable
|
|
1008
|
+
manifold M
|
|
1009
|
+
|
|
1010
|
+
A differential form is a tensor field of purely covariant type::
|
|
1011
|
+
|
|
1012
|
+
sage: a.tensor_type()
|
|
1013
|
+
(0, 2)
|
|
1014
|
+
|
|
1015
|
+
It is antisymmetric, its components being
|
|
1016
|
+
:class:`~sage.tensor.modules.comp.CompFullyAntiSym`::
|
|
1017
|
+
|
|
1018
|
+
sage: a.symmetries()
|
|
1019
|
+
no symmetry; antisymmetry: (0, 1)
|
|
1020
|
+
sage: a[0,1] = 2
|
|
1021
|
+
sage: a[1,0]
|
|
1022
|
+
-2
|
|
1023
|
+
sage: a.comp()
|
|
1024
|
+
Fully antisymmetric 2-indices components w.r.t. Coordinate frame (M, (∂/∂t,∂/∂x,∂/∂y,∂/∂z))
|
|
1025
|
+
sage: type(a.comp())
|
|
1026
|
+
<class 'sage.tensor.modules.comp.CompFullyAntiSym'>
|
|
1027
|
+
|
|
1028
|
+
Setting a component with repeated indices to a nonzero value
|
|
1029
|
+
results in an error::
|
|
1030
|
+
|
|
1031
|
+
sage: a[1,1] = 3
|
|
1032
|
+
Traceback (most recent call last):
|
|
1033
|
+
...
|
|
1034
|
+
ValueError: by antisymmetry, the component cannot have a nonzero value
|
|
1035
|
+
for the indices (1, 1)
|
|
1036
|
+
sage: a[1,1] = 0 # OK, albeit useless
|
|
1037
|
+
sage: a[1,2] = 3 # OK
|
|
1038
|
+
|
|
1039
|
+
The expansion of a differential form with respect to a given coframe is
|
|
1040
|
+
displayed via the method
|
|
1041
|
+
:meth:`~sage.tensor.modules.free_module_alt_form.FreeModuleAltForm.display`::
|
|
1042
|
+
|
|
1043
|
+
sage: a.display() # expansion with respect to the default coframe (dt, dx, dy, dz)
|
|
1044
|
+
a = 2 dt∧dx + 3 dx∧dy
|
|
1045
|
+
sage: latex(a.display()) # output for the notebook
|
|
1046
|
+
a = 2 \mathrm{d} t\wedge \mathrm{d} x
|
|
1047
|
+
+ 3 \mathrm{d} x\wedge \mathrm{d} y
|
|
1048
|
+
|
|
1049
|
+
Differential forms can be added or subtracted::
|
|
1050
|
+
|
|
1051
|
+
sage: b = M.diff_form(2)
|
|
1052
|
+
sage: b[0,1], b[0,2], b[0,3] = (1,2,3)
|
|
1053
|
+
sage: s = a + b ; s
|
|
1054
|
+
2-form on the 4-dimensional differentiable manifold M
|
|
1055
|
+
sage: a[:], b[:], s[:]
|
|
1056
|
+
(
|
|
1057
|
+
[ 0 2 0 0] [ 0 1 2 3] [ 0 3 2 3]
|
|
1058
|
+
[-2 0 3 0] [-1 0 0 0] [-3 0 3 0]
|
|
1059
|
+
[ 0 -3 0 0] [-2 0 0 0] [-2 -3 0 0]
|
|
1060
|
+
[ 0 0 0 0], [-3 0 0 0], [-3 0 0 0]
|
|
1061
|
+
)
|
|
1062
|
+
sage: s = a - b ; s
|
|
1063
|
+
2-form on the 4-dimensional differentiable manifold M
|
|
1064
|
+
sage: s[:]
|
|
1065
|
+
[ 0 1 -2 -3]
|
|
1066
|
+
[-1 0 3 0]
|
|
1067
|
+
[ 2 -3 0 0]
|
|
1068
|
+
[ 3 0 0 0]
|
|
1069
|
+
|
|
1070
|
+
An example of 3-form is the volume element on `\RR^3` in Cartesian
|
|
1071
|
+
coordinates::
|
|
1072
|
+
|
|
1073
|
+
sage: M = Manifold(3, 'R3', latex_name=r'\RR^3', start_index=1)
|
|
1074
|
+
sage: c_cart.<x,y,z> = M.chart()
|
|
1075
|
+
sage: eps = M.diff_form(3, name='epsilon', latex_name=r'\epsilon')
|
|
1076
|
+
sage: eps[1,2,3] = 1 # the only independent component
|
|
1077
|
+
sage: eps[:] # all the components are set from the previous line:
|
|
1078
|
+
[[[0, 0, 0], [0, 0, 1], [0, -1, 0]], [[0, 0, -1], [0, 0, 0], [1, 0, 0]],
|
|
1079
|
+
[[0, 1, 0], [-1, 0, 0], [0, 0, 0]]]
|
|
1080
|
+
sage: eps.display()
|
|
1081
|
+
epsilon = dx∧dy∧dz
|
|
1082
|
+
|
|
1083
|
+
Spherical components of the volume element from the tensorial
|
|
1084
|
+
change-of-frame formula::
|
|
1085
|
+
|
|
1086
|
+
sage: c_spher.<r,th,ph> = M.chart(r'r:[0,+oo) th:[0,pi]:\theta ph:[0,2*pi):\phi')
|
|
1087
|
+
sage: spher_to_cart = c_spher.transition_map(c_cart,
|
|
1088
|
+
....: [r*sin(th)*cos(ph), r*sin(th)*sin(ph), r*cos(th)])
|
|
1089
|
+
sage: cart_to_spher = spher_to_cart.set_inverse(sqrt(x^2+y^2+z^2),
|
|
1090
|
+
....: atan2(sqrt(x^2+y^2),z), atan2(y, x))
|
|
1091
|
+
Check of the inverse coordinate transformation:
|
|
1092
|
+
r == r *passed*
|
|
1093
|
+
th == arctan2(r*sin(th), r*cos(th)) **failed**
|
|
1094
|
+
ph == arctan2(r*sin(ph)*sin(th), r*cos(ph)*sin(th)) **failed**
|
|
1095
|
+
x == x *passed*
|
|
1096
|
+
y == y *passed*
|
|
1097
|
+
z == z *passed*
|
|
1098
|
+
NB: a failed report can reflect a mere lack of simplification.
|
|
1099
|
+
sage: eps.comp(c_spher.frame()) # computation of the components in the spherical frame
|
|
1100
|
+
Fully antisymmetric 3-indices components w.r.t. Coordinate frame
|
|
1101
|
+
(R3, (∂/∂r,∂/∂th,∂/∂ph))
|
|
1102
|
+
sage: eps.comp(c_spher.frame())[1,2,3, c_spher]
|
|
1103
|
+
r^2*sin(th)
|
|
1104
|
+
sage: eps.display(c_spher.frame())
|
|
1105
|
+
epsilon = sqrt(x^2 + y^2 + z^2)*sqrt(x^2 + y^2) dr∧dth∧dph
|
|
1106
|
+
sage: eps.display(c_spher.frame(), c_spher)
|
|
1107
|
+
epsilon = r^2*sin(th) dr∧dth∧dph
|
|
1108
|
+
|
|
1109
|
+
As a shortcut of the above command, on can pass just the chart ``c_spher``
|
|
1110
|
+
to ``display``, the vector frame being then assumed to be the coordinate
|
|
1111
|
+
frame associated with the chart::
|
|
1112
|
+
|
|
1113
|
+
sage: eps.display(c_spher)
|
|
1114
|
+
epsilon = r^2*sin(th) dr∧dth∧dph
|
|
1115
|
+
|
|
1116
|
+
|
|
1117
|
+
The exterior product of two differential forms is performed via the method
|
|
1118
|
+
:meth:`~sage.tensor.modules.free_module_alt_form.FreeModuleAltForm.wedge`::
|
|
1119
|
+
|
|
1120
|
+
sage: a = M.one_form(x*y*z, -z*x, y*z, name='A')
|
|
1121
|
+
sage: b = M.one_form(cos(z), sin(x), cos(y), name='B')
|
|
1122
|
+
sage: ab = a.wedge(b) ; ab
|
|
1123
|
+
2-form A∧B on the 3-dimensional differentiable manifold R3
|
|
1124
|
+
sage: ab[:]
|
|
1125
|
+
[ 0 x*y*z*sin(x) + x*z*cos(z) x*y*z*cos(y) - y*z*cos(z)]
|
|
1126
|
+
[-x*y*z*sin(x) - x*z*cos(z) 0 -(x*cos(y) + y*sin(x))*z]
|
|
1127
|
+
[-x*y*z*cos(y) + y*z*cos(z) (x*cos(y) + y*sin(x))*z 0]
|
|
1128
|
+
sage: ab.display()
|
|
1129
|
+
A∧B = (x*y*z*sin(x) + x*z*cos(z)) dx∧dy + (x*y*z*cos(y) - y*z*cos(z)) dx∧dz
|
|
1130
|
+
- (x*cos(y) + y*sin(x))*z dy∧dz
|
|
1131
|
+
|
|
1132
|
+
Let us check the formula relating the exterior product to the tensor
|
|
1133
|
+
product for 1-forms::
|
|
1134
|
+
|
|
1135
|
+
sage: a.wedge(b) == a*b - b*a
|
|
1136
|
+
True
|
|
1137
|
+
|
|
1138
|
+
The tensor product of a 1-form and a 2-form is not a 3-form but a tensor
|
|
1139
|
+
field of type `(0,3)` with less symmetries::
|
|
1140
|
+
|
|
1141
|
+
sage: c = a*ab ; c
|
|
1142
|
+
Tensor field A⊗(A∧B) of type (0,3) on the 3-dimensional differentiable
|
|
1143
|
+
manifold R3
|
|
1144
|
+
sage: c.symmetries() # the antisymmetry is only w.r.t. the last 2 arguments:
|
|
1145
|
+
no symmetry; antisymmetry: (1, 2)
|
|
1146
|
+
sage: d = ab*a ; d
|
|
1147
|
+
Tensor field (A∧B)⊗A of type (0,3) on the 3-dimensional differentiable
|
|
1148
|
+
manifold R3
|
|
1149
|
+
sage: d.symmetries() # the antisymmetry is only w.r.t. the first 2 arguments:
|
|
1150
|
+
no symmetry; antisymmetry: (0, 1)
|
|
1151
|
+
|
|
1152
|
+
The exterior derivative of a differential form is obtained by means
|
|
1153
|
+
of the method :meth:`exterior_derivative`::
|
|
1154
|
+
|
|
1155
|
+
sage: da = a.exterior_derivative() ; da
|
|
1156
|
+
2-form dA on the 3-dimensional differentiable manifold R3
|
|
1157
|
+
sage: da.display()
|
|
1158
|
+
dA = -(x + 1)*z dx∧dy - x*y dx∧dz + (x + z) dy∧dz
|
|
1159
|
+
sage: db = b.exterior_derivative() ; db
|
|
1160
|
+
2-form dB on the 3-dimensional differentiable manifold R3
|
|
1161
|
+
sage: db.display()
|
|
1162
|
+
dB = cos(x) dx∧dy + sin(z) dx∧dz - sin(y) dy∧dz
|
|
1163
|
+
sage: dab = ab.exterior_derivative() ; dab
|
|
1164
|
+
3-form d(A∧B) on the 3-dimensional differentiable manifold R3
|
|
1165
|
+
|
|
1166
|
+
or by applying the function ``diff`` to the differential form::
|
|
1167
|
+
|
|
1168
|
+
sage: diff(a) is a.exterior_derivative()
|
|
1169
|
+
True
|
|
1170
|
+
|
|
1171
|
+
As a 3-form over a 3-dimensional manifold, ``d(A∧B)`` is necessarily
|
|
1172
|
+
proportional to the volume 3-form::
|
|
1173
|
+
|
|
1174
|
+
sage: dab == dab[[1,2,3]]/eps[[1,2,3]]*eps
|
|
1175
|
+
True
|
|
1176
|
+
|
|
1177
|
+
We may also check that the classical anti-derivation formula is fulfilled::
|
|
1178
|
+
|
|
1179
|
+
sage: dab == da.wedge(b) - a.wedge(db)
|
|
1180
|
+
True
|
|
1181
|
+
|
|
1182
|
+
The Lie derivative of a 2-form is a 2-form::
|
|
1183
|
+
|
|
1184
|
+
sage: v = M.vector_field(y*z, -x*z, x*y, name='v')
|
|
1185
|
+
sage: ab.lie_der(v) # long time
|
|
1186
|
+
2-form on the 3-dimensional differentiable manifold R3
|
|
1187
|
+
|
|
1188
|
+
Let us check Cartan formula, which expresses the Lie derivative in terms
|
|
1189
|
+
of exterior derivatives::
|
|
1190
|
+
|
|
1191
|
+
sage: ab.lie_der(v) == (v.contract(ab.exterior_derivative()) # long time
|
|
1192
|
+
....: + v.contract(ab).exterior_derivative())
|
|
1193
|
+
True
|
|
1194
|
+
|
|
1195
|
+
A 1-form on a `\RR^3`::
|
|
1196
|
+
|
|
1197
|
+
sage: om = M.one_form(name='omega', latex_name=r'\omega'); om
|
|
1198
|
+
1-form omega on the 3-dimensional differentiable manifold R3
|
|
1199
|
+
|
|
1200
|
+
A 1-form is of course a differential form::
|
|
1201
|
+
|
|
1202
|
+
sage: isinstance(om, sage.manifolds.differentiable.diff_form.DiffFormParal)
|
|
1203
|
+
True
|
|
1204
|
+
sage: om.parent()
|
|
1205
|
+
Free module Omega^1(R3) of 1-forms on the 3-dimensional differentiable
|
|
1206
|
+
manifold R3
|
|
1207
|
+
sage: om.tensor_type()
|
|
1208
|
+
(0, 1)
|
|
1209
|
+
|
|
1210
|
+
Setting the components with respect to the manifold's default frame::
|
|
1211
|
+
|
|
1212
|
+
sage: om[:] = (2*z, x, x-y)
|
|
1213
|
+
sage: om[:]
|
|
1214
|
+
[2*z, x, x - y]
|
|
1215
|
+
sage: om.display()
|
|
1216
|
+
omega = 2*z dx + x dy + (x - y) dz
|
|
1217
|
+
|
|
1218
|
+
A 1-form acts on vector fields::
|
|
1219
|
+
|
|
1220
|
+
sage: v = M.vector_field(x, 2*y, 3*z, name='V')
|
|
1221
|
+
sage: om(v)
|
|
1222
|
+
Scalar field omega(V) on the 3-dimensional differentiable manifold R3
|
|
1223
|
+
sage: om(v).display()
|
|
1224
|
+
omega(V): R3 → ℝ
|
|
1225
|
+
(x, y, z) ↦ 2*x*y + (5*x - 3*y)*z
|
|
1226
|
+
(r, th, ph) ↦ 2*r^2*cos(ph)*sin(ph)*sin(th)^2 + r^2*(5*cos(ph)
|
|
1227
|
+
- 3*sin(ph))*cos(th)*sin(th)
|
|
1228
|
+
sage: latex(om(v))
|
|
1229
|
+
\omega\left(V\right)
|
|
1230
|
+
|
|
1231
|
+
The tensor product of two 1-forms is a tensor field of type `(0,2)`::
|
|
1232
|
+
|
|
1233
|
+
sage: a = M.one_form(1, 2, 3, name='A')
|
|
1234
|
+
sage: b = M.one_form(6, 5, 4, name='B')
|
|
1235
|
+
sage: c = a*b ; c
|
|
1236
|
+
Tensor field A⊗B of type (0,2) on the 3-dimensional differentiable
|
|
1237
|
+
manifold R3
|
|
1238
|
+
sage: c[:]
|
|
1239
|
+
[ 6 5 4]
|
|
1240
|
+
[12 10 8]
|
|
1241
|
+
[18 15 12]
|
|
1242
|
+
sage: c.symmetries() # c has no symmetries:
|
|
1243
|
+
no symmetry; no antisymmetry
|
|
1244
|
+
"""
|
|
1245
|
+
def __init__(self, vector_field_module: VectorFieldModule, degree: int, name: Optional[str] = None,
|
|
1246
|
+
latex_name: Optional[str] = None):
|
|
1247
|
+
r"""
|
|
1248
|
+
Construct a differential form.
|
|
1249
|
+
|
|
1250
|
+
TESTS:
|
|
1251
|
+
|
|
1252
|
+
Construction via ``parent.element_class``, and not via a direct call
|
|
1253
|
+
to ``DiffFormParal``, to fit with the category framework::
|
|
1254
|
+
|
|
1255
|
+
sage: M = Manifold(2, 'M')
|
|
1256
|
+
sage: X.<x,y> = M.chart() # makes M parallelizable
|
|
1257
|
+
sage: A = M.diff_form_module(2)
|
|
1258
|
+
sage: XM = M.vector_field_module()
|
|
1259
|
+
sage: a = A.element_class(XM, 2, name='a'); a
|
|
1260
|
+
2-form a on the 2-dimensional differentiable manifold M
|
|
1261
|
+
sage: a[0,1] = x*y
|
|
1262
|
+
sage: TestSuite(a).run()
|
|
1263
|
+
|
|
1264
|
+
Construction via ``DifferentiableManifold.diff_form``::
|
|
1265
|
+
|
|
1266
|
+
sage: a1 = M.diff_form(2, name='a'); a1
|
|
1267
|
+
2-form a on the 2-dimensional differentiable manifold M
|
|
1268
|
+
sage: type(a1) == type(a)
|
|
1269
|
+
True
|
|
1270
|
+
sage: a1.parent() is a.parent()
|
|
1271
|
+
True
|
|
1272
|
+
|
|
1273
|
+
Initializing the components at the construction::
|
|
1274
|
+
|
|
1275
|
+
sage: a = M.diff_form(2, [[0, x*y], [-x*y, 0]], name='a')
|
|
1276
|
+
sage: a.display()
|
|
1277
|
+
a = x*y dx∧dy
|
|
1278
|
+
"""
|
|
1279
|
+
FreeModuleAltForm.__init__(self, vector_field_module, degree,
|
|
1280
|
+
name=name, latex_name=latex_name)
|
|
1281
|
+
# TensorFieldParal attributes:
|
|
1282
|
+
self._vmodule = vector_field_module
|
|
1283
|
+
self._domain = vector_field_module._domain
|
|
1284
|
+
self._ambient_domain = vector_field_module._ambient_domain
|
|
1285
|
+
# initialization of derived quantities:
|
|
1286
|
+
self._init_derived()
|
|
1287
|
+
|
|
1288
|
+
def _repr_(self):
|
|
1289
|
+
r"""
|
|
1290
|
+
String representation of ``self``.
|
|
1291
|
+
|
|
1292
|
+
TESTS::
|
|
1293
|
+
|
|
1294
|
+
sage: M = Manifold(3, 'M')
|
|
1295
|
+
sage: X.<x,y,z> = M.chart() # makes M parallelizable
|
|
1296
|
+
sage: a = M.diff_form(2, name='a')
|
|
1297
|
+
sage: a._repr_()
|
|
1298
|
+
'2-form a on the 3-dimensional differentiable manifold M'
|
|
1299
|
+
sage: repr(a) # indirect doctest
|
|
1300
|
+
'2-form a on the 3-dimensional differentiable manifold M'
|
|
1301
|
+
sage: a # indirect doctest
|
|
1302
|
+
2-form a on the 3-dimensional differentiable manifold M
|
|
1303
|
+
sage: b = M.diff_form(2)
|
|
1304
|
+
sage: b._repr_()
|
|
1305
|
+
'2-form on the 3-dimensional differentiable manifold M'
|
|
1306
|
+
"""
|
|
1307
|
+
description = "{}-form ".format(self._tensor_rank)
|
|
1308
|
+
if self._name is not None:
|
|
1309
|
+
description += self._name + " "
|
|
1310
|
+
return self._final_repr(description)
|
|
1311
|
+
|
|
1312
|
+
def _new_instance(self):
|
|
1313
|
+
r"""
|
|
1314
|
+
Create an instance of the same class, of the same degree and on the
|
|
1315
|
+
same domain.
|
|
1316
|
+
|
|
1317
|
+
TESTS::
|
|
1318
|
+
|
|
1319
|
+
sage: M = Manifold(3, 'M')
|
|
1320
|
+
sage: X.<x,y,z> = M.chart() # makes M parallelizable
|
|
1321
|
+
sage: a = M.diff_form(2, name='a')
|
|
1322
|
+
sage: a1 = a._new_instance(); a1
|
|
1323
|
+
2-form on the 3-dimensional differentiable manifold M
|
|
1324
|
+
sage: type(a1) == type(a)
|
|
1325
|
+
True
|
|
1326
|
+
sage: a1.parent() is a.parent()
|
|
1327
|
+
True
|
|
1328
|
+
"""
|
|
1329
|
+
return type(self)(self._fmodule, self._tensor_rank)
|
|
1330
|
+
|
|
1331
|
+
# This method is needed to redirect to the correct class (TensorFieldParal)
|
|
1332
|
+
def _init_derived(self):
|
|
1333
|
+
r"""
|
|
1334
|
+
Initialize the derived quantities of ``self``.
|
|
1335
|
+
|
|
1336
|
+
TESTS::
|
|
1337
|
+
|
|
1338
|
+
sage: M = Manifold(3, 'M')
|
|
1339
|
+
sage: X.<x,y,z> = M.chart() # makes M parallelizable
|
|
1340
|
+
sage: a = M.diff_form(2, name='a')
|
|
1341
|
+
sage: a._init_derived()
|
|
1342
|
+
"""
|
|
1343
|
+
TensorFieldParal._init_derived(self)
|
|
1344
|
+
|
|
1345
|
+
def _del_derived(self, del_restrictions: bool = True):
|
|
1346
|
+
r"""
|
|
1347
|
+
Delete the derived quantities.
|
|
1348
|
+
|
|
1349
|
+
INPUT:
|
|
1350
|
+
|
|
1351
|
+
- ``del_restrictions`` -- boolean (default: ``True``); determines whether the
|
|
1352
|
+
restrictions of ``self`` to subdomains are deleted
|
|
1353
|
+
|
|
1354
|
+
TESTS::
|
|
1355
|
+
|
|
1356
|
+
sage: M = Manifold(3, 'M')
|
|
1357
|
+
sage: X.<x,y,z> = M.chart() # makes M parallelizable
|
|
1358
|
+
sage: a = M.diff_form(2, name='a')
|
|
1359
|
+
sage: a._del_derived()
|
|
1360
|
+
"""
|
|
1361
|
+
TensorFieldParal._del_derived(self, del_restrictions=del_restrictions)
|
|
1362
|
+
self.exterior_derivative.clear_cache()
|
|
1363
|
+
|
|
1364
|
+
def __call__(self, *args):
|
|
1365
|
+
r"""
|
|
1366
|
+
Redefinition of
|
|
1367
|
+
:meth:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor.__call__`
|
|
1368
|
+
to allow for domain treatment.
|
|
1369
|
+
|
|
1370
|
+
TESTS::
|
|
1371
|
+
|
|
1372
|
+
sage: M = Manifold(2, 'M')
|
|
1373
|
+
sage: X.<x,y> = M.chart()
|
|
1374
|
+
sage: a = M.diff_form(2, name='a')
|
|
1375
|
+
sage: a[0,1] = x*y
|
|
1376
|
+
sage: a.display()
|
|
1377
|
+
a = x*y dx∧dy
|
|
1378
|
+
sage: u = M.vector_field(1+x, 2-y, name='u')
|
|
1379
|
+
sage: v = M.vector_field(-y, x, name='v')
|
|
1380
|
+
sage: s = a.__call__(u,v); s
|
|
1381
|
+
Scalar field a(u,v) on the 2-dimensional differentiable manifold M
|
|
1382
|
+
sage: s.display()
|
|
1383
|
+
a(u,v): M → ℝ
|
|
1384
|
+
(x, y) ↦ -x*y^3 + 2*x*y^2 + (x^3 + x^2)*y
|
|
1385
|
+
sage: s == a[[0,1]]*(u[[0]]*v[[1]] - u[[1]]*v[[0]])
|
|
1386
|
+
True
|
|
1387
|
+
sage: s == a(u,v) # indirect doctest
|
|
1388
|
+
True
|
|
1389
|
+
"""
|
|
1390
|
+
return TensorFieldParal.__call__(self, *args)
|
|
1391
|
+
|
|
1392
|
+
@cached_method
|
|
1393
|
+
def exterior_derivative(self) -> DiffFormParal:
|
|
1394
|
+
r"""
|
|
1395
|
+
Compute the exterior derivative of ``self``.
|
|
1396
|
+
|
|
1397
|
+
OUTPUT:
|
|
1398
|
+
|
|
1399
|
+
- a :class:`DiffFormParal` representing the exterior
|
|
1400
|
+
derivative of the differential form
|
|
1401
|
+
|
|
1402
|
+
EXAMPLES:
|
|
1403
|
+
|
|
1404
|
+
Exterior derivative of a 1-form on a 4-dimensional manifold::
|
|
1405
|
+
|
|
1406
|
+
sage: M = Manifold(4, 'M')
|
|
1407
|
+
sage: c_txyz.<t,x,y,z> = M.chart()
|
|
1408
|
+
sage: a = M.one_form(t*x*y*z, z*y**2, x*z**2, x**2 + y**2, name='A')
|
|
1409
|
+
sage: da = a.exterior_derivative() ; da
|
|
1410
|
+
2-form dA on the 4-dimensional differentiable manifold M
|
|
1411
|
+
sage: da.display()
|
|
1412
|
+
dA = -t*y*z dt∧dx - t*x*z dt∧dy - t*x*y dt∧dz
|
|
1413
|
+
+ (-2*y*z + z^2) dx∧dy + (-y^2 + 2*x) dx∧dz
|
|
1414
|
+
+ (-2*x*z + 2*y) dy∧dz
|
|
1415
|
+
sage: latex(da)
|
|
1416
|
+
\mathrm{d}A
|
|
1417
|
+
|
|
1418
|
+
The result is cached, i.e. is not recomputed unless ``a`` is changed::
|
|
1419
|
+
|
|
1420
|
+
sage: a.exterior_derivative() is da
|
|
1421
|
+
True
|
|
1422
|
+
|
|
1423
|
+
Instead of invoking the method :meth:`exterior_derivative`, one may
|
|
1424
|
+
use the global function ``diff``::
|
|
1425
|
+
|
|
1426
|
+
sage: diff(a) is a.exterior_derivative()
|
|
1427
|
+
True
|
|
1428
|
+
|
|
1429
|
+
The exterior derivative is nilpotent::
|
|
1430
|
+
|
|
1431
|
+
sage: dda = da.exterior_derivative() ; dda
|
|
1432
|
+
3-form ddA on the 4-dimensional differentiable manifold M
|
|
1433
|
+
sage: dda.display()
|
|
1434
|
+
ddA = 0
|
|
1435
|
+
sage: dda == 0
|
|
1436
|
+
True
|
|
1437
|
+
|
|
1438
|
+
Let us check Cartan's identity::
|
|
1439
|
+
|
|
1440
|
+
sage: v = M.vector_field(-y, x, t, z, name='v')
|
|
1441
|
+
sage: a.lie_der(v) == v.contract(diff(a)) + diff(a(v)) # long time
|
|
1442
|
+
True
|
|
1443
|
+
"""
|
|
1444
|
+
from sage.manifolds.differentiable.vectorframe import CoordFrame
|
|
1445
|
+
from sage.tensor.modules.comp import CompFullyAntiSym
|
|
1446
|
+
from sage.tensor.modules.format_utilities import (
|
|
1447
|
+
format_unop_latex,
|
|
1448
|
+
format_unop_txt,
|
|
1449
|
+
)
|
|
1450
|
+
fmodule = self._fmodule # shortcut
|
|
1451
|
+
rname = format_unop_txt('d', self._name)
|
|
1452
|
+
rlname = format_unop_latex(r'\mathrm{d}', self._latex_name)
|
|
1453
|
+
resu = fmodule.alternating_form(self._tensor_rank + 1,
|
|
1454
|
+
name=rname,
|
|
1455
|
+
latex_name=rlname)
|
|
1456
|
+
# 1/ List of all coordinate frames in which the components of self
|
|
1457
|
+
# are known
|
|
1458
|
+
coord_frames = []
|
|
1459
|
+
for frame in self._components:
|
|
1460
|
+
if isinstance(frame, CoordFrame):
|
|
1461
|
+
coord_frames.append(frame)
|
|
1462
|
+
if not coord_frames:
|
|
1463
|
+
# A coordinate frame is searched, at the price of a change of
|
|
1464
|
+
# frame, privileging the frame of the domain's default chart
|
|
1465
|
+
dom = self._domain
|
|
1466
|
+
def_coordf = dom._def_chart._frame
|
|
1467
|
+
for frame in self._components:
|
|
1468
|
+
if (frame, def_coordf) in dom._frame_changes:
|
|
1469
|
+
self.comp(def_coordf, from_basis=frame)
|
|
1470
|
+
coord_frames = [def_coordf]
|
|
1471
|
+
break
|
|
1472
|
+
if not coord_frames:
|
|
1473
|
+
for chart in dom._atlas:
|
|
1474
|
+
if chart != dom._def_chart: # the case def_chart is
|
|
1475
|
+
# treated above
|
|
1476
|
+
coordf = chart._frame
|
|
1477
|
+
for frame in self._components:
|
|
1478
|
+
if (frame, coordf) in dom._frame_changes:
|
|
1479
|
+
self.comp(coordf, from_basis=frame)
|
|
1480
|
+
coord_frames[coordf]
|
|
1481
|
+
break
|
|
1482
|
+
if coord_frames:
|
|
1483
|
+
break
|
|
1484
|
+
# 2/ The computation:
|
|
1485
|
+
for frame in coord_frames:
|
|
1486
|
+
chart = frame._chart
|
|
1487
|
+
sc = self._components[frame]
|
|
1488
|
+
dc = CompFullyAntiSym(fmodule._ring, frame,
|
|
1489
|
+
self._tensor_rank+1,
|
|
1490
|
+
start_index=fmodule._sindex,
|
|
1491
|
+
output_formatter=fmodule._output_formatter)
|
|
1492
|
+
for ind, val in sc._comp.items():
|
|
1493
|
+
for i in fmodule.irange():
|
|
1494
|
+
ind_d = (i,) + ind
|
|
1495
|
+
if len(ind_d) == len(set(ind_d)):
|
|
1496
|
+
# all indices are different
|
|
1497
|
+
dc[[ind_d]] += \
|
|
1498
|
+
val.coord_function(chart).diff(i).scalar_field()
|
|
1499
|
+
resu._components[frame] = dc
|
|
1500
|
+
return resu
|
|
1501
|
+
|
|
1502
|
+
derivative = exterior_derivative # allows one to use functional notation,
|
|
1503
|
+
# e.g. diff(a) for a.exterior_derivative()
|
|
1504
|
+
|
|
1505
|
+
def wedge(self, other):
|
|
1506
|
+
r"""
|
|
1507
|
+
Exterior product of ``self`` with another differential form.
|
|
1508
|
+
|
|
1509
|
+
INPUT:
|
|
1510
|
+
|
|
1511
|
+
- ``other`` -- another differential form
|
|
1512
|
+
|
|
1513
|
+
OUTPUT:
|
|
1514
|
+
|
|
1515
|
+
- instance of :class:`DiffFormParal` representing the exterior
|
|
1516
|
+
product ``self ∧ other``
|
|
1517
|
+
|
|
1518
|
+
EXAMPLES:
|
|
1519
|
+
|
|
1520
|
+
Exterior product of a 1-form and a 2-form on a 3-dimensional
|
|
1521
|
+
manifold::
|
|
1522
|
+
|
|
1523
|
+
sage: M = Manifold(3, 'M', start_index=1)
|
|
1524
|
+
sage: X.<x,y,z> = M.chart()
|
|
1525
|
+
sage: a = M.one_form(2, 1+x, y*z, name='a')
|
|
1526
|
+
sage: b = M.diff_form(2, name='b')
|
|
1527
|
+
sage: b[1,2], b[1,3], b[2,3] = y^2, z+x, z^2
|
|
1528
|
+
sage: a.display()
|
|
1529
|
+
a = 2 dx + (x + 1) dy + y*z dz
|
|
1530
|
+
sage: b.display()
|
|
1531
|
+
b = y^2 dx∧dy + (x + z) dx∧dz + z^2 dy∧dz
|
|
1532
|
+
sage: s = a.wedge(b); s
|
|
1533
|
+
3-form a∧b on the 3-dimensional differentiable manifold M
|
|
1534
|
+
sage: s.display()
|
|
1535
|
+
a∧b = (-x^2 + (y^3 - x - 1)*z + 2*z^2 - x) dx∧dy∧dz
|
|
1536
|
+
|
|
1537
|
+
Check::
|
|
1538
|
+
|
|
1539
|
+
sage: s[1,2,3] == a[1]*b[2,3] + a[2]*b[3,1] + a[3]*b[1,2]
|
|
1540
|
+
True
|
|
1541
|
+
|
|
1542
|
+
Wedging with scalar fields yields the multiplication from right::
|
|
1543
|
+
|
|
1544
|
+
sage: f = M.scalar_field(x, name='f')
|
|
1545
|
+
sage: t = a.wedge(f)
|
|
1546
|
+
sage: t.display()
|
|
1547
|
+
f*a = 2*x dx + (x^2 + x) dy + x*y*z dz
|
|
1548
|
+
"""
|
|
1549
|
+
if other._tensor_rank == 0:
|
|
1550
|
+
return self * other
|
|
1551
|
+
if self._domain.is_subset(other._domain):
|
|
1552
|
+
if not self._ambient_domain.is_subset(other._ambient_domain):
|
|
1553
|
+
raise ValueError("incompatible ambient domains for exterior " +
|
|
1554
|
+
"product")
|
|
1555
|
+
elif other._domain.is_subset(self._domain):
|
|
1556
|
+
if not other._ambient_domain.is_subset(self._ambient_domain):
|
|
1557
|
+
raise ValueError("incompatible ambient domains for exterior " +
|
|
1558
|
+
"product")
|
|
1559
|
+
dom_resu = self._domain.intersection(other._domain)
|
|
1560
|
+
self_r = self.restrict(dom_resu)
|
|
1561
|
+
other_r = other.restrict(dom_resu)
|
|
1562
|
+
return FreeModuleAltForm.wedge(self_r, other_r)
|
|
1563
|
+
|
|
1564
|
+
def interior_product(self, qvect):
|
|
1565
|
+
r"""
|
|
1566
|
+
Interior product with a multivector field.
|
|
1567
|
+
|
|
1568
|
+
If ``self`` is a differential form `A` of degree `p` and `B` is a
|
|
1569
|
+
multivector field of degree `q\geq p` on the same manifold, the
|
|
1570
|
+
interior product of `A` by `B` is the multivector field `\iota_A B` of
|
|
1571
|
+
degree `q-p` defined by
|
|
1572
|
+
|
|
1573
|
+
.. MATH::
|
|
1574
|
+
|
|
1575
|
+
(\iota_A B)^{i_1\ldots i_{q-p}} = A_{k_1\ldots k_p}
|
|
1576
|
+
B^{k_1\ldots k_p i_1\ldots i_{q-p}}
|
|
1577
|
+
|
|
1578
|
+
.. NOTE::
|
|
1579
|
+
|
|
1580
|
+
``A.interior_product(B)`` yields the same result as
|
|
1581
|
+
``A.contract(0,..., p-1, B, 0,..., p-1)`` (cf.
|
|
1582
|
+
:meth:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal.contract`),
|
|
1583
|
+
but ``interior_product`` is more efficient, the alternating
|
|
1584
|
+
character of `A` being not used to reduce the computation in
|
|
1585
|
+
:meth:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal.contract`
|
|
1586
|
+
|
|
1587
|
+
INPUT:
|
|
1588
|
+
|
|
1589
|
+
- ``qvect`` -- multivector field `B` (instance of
|
|
1590
|
+
:class:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal`);
|
|
1591
|
+
the degree of `B` must be at least equal to the degree of
|
|
1592
|
+
``self``
|
|
1593
|
+
|
|
1594
|
+
OUTPUT:
|
|
1595
|
+
|
|
1596
|
+
- scalar field (case `p=q`) or
|
|
1597
|
+
:class:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal`
|
|
1598
|
+
(case `p<q`) representing the interior product `\iota_A B`,
|
|
1599
|
+
where `A` is ``self``
|
|
1600
|
+
|
|
1601
|
+
.. SEEALSO::
|
|
1602
|
+
|
|
1603
|
+
:meth:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal.interior_product`
|
|
1604
|
+
for the interior product of a multivector field with a
|
|
1605
|
+
differential form
|
|
1606
|
+
|
|
1607
|
+
EXAMPLES:
|
|
1608
|
+
|
|
1609
|
+
Interior product of a 1-form with a 2-vector field on a
|
|
1610
|
+
3-dimensional manifold::
|
|
1611
|
+
|
|
1612
|
+
sage: M = Manifold(3, 'M', start_index=1)
|
|
1613
|
+
sage: X.<x,y,z> = M.chart()
|
|
1614
|
+
sage: a = M.one_form(2, 1+x, y*z, name='a')
|
|
1615
|
+
sage: b = M.multivector_field(2, name='b')
|
|
1616
|
+
sage: b[1,2], b[1,3], b[2,3] = y^2, z+x, -z^2
|
|
1617
|
+
sage: s = a.interior_product(b); s
|
|
1618
|
+
Vector field i_a b on the 3-dimensional differentiable
|
|
1619
|
+
manifold M
|
|
1620
|
+
sage: s.display()
|
|
1621
|
+
i_a b = (-(x + 1)*y^2 - x*y*z - y*z^2) ∂/∂x
|
|
1622
|
+
+ (y*z^3 + 2*y^2) ∂/∂y + (-(x + 1)*z^2 + 2*x + 2*z) ∂/∂z
|
|
1623
|
+
sage: s == a.contract(b)
|
|
1624
|
+
True
|
|
1625
|
+
|
|
1626
|
+
Interior product of a 2-form with a 2-vector field::
|
|
1627
|
+
|
|
1628
|
+
sage: a = M.diff_form(2, name='a')
|
|
1629
|
+
sage: a[1,2], a[1,3], a[2,3] = x*y, -3, z
|
|
1630
|
+
sage: s = a.interior_product(b); s
|
|
1631
|
+
Scalar field i_a b on the 3-dimensional differentiable manifold M
|
|
1632
|
+
sage: s.display()
|
|
1633
|
+
i_a b: M → ℝ
|
|
1634
|
+
(x, y, z) ↦ 2*x*y^3 - 2*z^3 - 6*x - 6*z
|
|
1635
|
+
sage: s == a.contract(0,1,b,0,1)
|
|
1636
|
+
True
|
|
1637
|
+
|
|
1638
|
+
TESTS:
|
|
1639
|
+
|
|
1640
|
+
Check that :issue:`33780` is fixed::
|
|
1641
|
+
|
|
1642
|
+
sage: v = X.frame()[1] # vector field d/dx
|
|
1643
|
+
sage: f = X.coframe()[2] # 1-form dy
|
|
1644
|
+
sage: f.interior_product(v)
|
|
1645
|
+
Scalar field zero on the 3-dimensional differentiable manifold M
|
|
1646
|
+
"""
|
|
1647
|
+
if self._domain.is_subset(qvect._domain):
|
|
1648
|
+
if not self._ambient_domain.is_subset(qvect._ambient_domain):
|
|
1649
|
+
raise ValueError("incompatible ambient domains for interior " +
|
|
1650
|
+
"product")
|
|
1651
|
+
elif qvect._domain.is_subset(self._domain):
|
|
1652
|
+
if not qvect._ambient_domain.is_subset(self._ambient_domain):
|
|
1653
|
+
raise ValueError("incompatible ambient domains for interior " +
|
|
1654
|
+
"product")
|
|
1655
|
+
dom_resu = self._domain.intersection(qvect._domain)
|
|
1656
|
+
self_r = self.restrict(dom_resu)
|
|
1657
|
+
qvect_r = qvect.restrict(dom_resu)
|
|
1658
|
+
return FreeModuleAltForm.interior_product(self_r, qvect_r)
|