passagemath-symbolics 10.8.1a1__cp311-cp311-macosx_13_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. passagemath_symbolics/.dylibs/libgmp.10.dylib +0 -0
  2. passagemath_symbolics/__init__.py +3 -0
  3. passagemath_symbolics-10.8.1a1.dist-info/METADATA +186 -0
  4. passagemath_symbolics-10.8.1a1.dist-info/RECORD +182 -0
  5. passagemath_symbolics-10.8.1a1.dist-info/WHEEL +6 -0
  6. passagemath_symbolics-10.8.1a1.dist-info/top_level.txt +3 -0
  7. sage/all__sagemath_symbolics.py +17 -0
  8. sage/calculus/all.py +14 -0
  9. sage/calculus/calculus.py +2838 -0
  10. sage/calculus/desolvers.py +1864 -0
  11. sage/calculus/predefined.py +51 -0
  12. sage/calculus/tests.py +225 -0
  13. sage/calculus/var.cpython-311-darwin.so +0 -0
  14. sage/calculus/var.pyx +401 -0
  15. sage/dynamics/all__sagemath_symbolics.py +6 -0
  16. sage/dynamics/complex_dynamics/all.py +5 -0
  17. sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
  18. sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-311-darwin.so +0 -0
  19. sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1034 -0
  20. sage/ext/all__sagemath_symbolics.py +1 -0
  21. sage/ext_data/kenzo/CP2.txt +45 -0
  22. sage/ext_data/kenzo/CP3.txt +349 -0
  23. sage/ext_data/kenzo/CP4.txt +4774 -0
  24. sage/ext_data/kenzo/README.txt +49 -0
  25. sage/ext_data/kenzo/S4.txt +20 -0
  26. sage/ext_data/magma/latex/latex.m +1021 -0
  27. sage/ext_data/magma/latex/latex.spec +1 -0
  28. sage/ext_data/magma/sage/basic.m +356 -0
  29. sage/ext_data/magma/sage/sage.spec +1 -0
  30. sage/ext_data/magma/spec +9 -0
  31. sage/geometry/all__sagemath_symbolics.py +8 -0
  32. sage/geometry/hyperbolic_space/all.py +5 -0
  33. sage/geometry/hyperbolic_space/hyperbolic_coercion.py +755 -0
  34. sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
  35. sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2419 -0
  36. sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
  37. sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1083 -0
  38. sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
  39. sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
  40. sage/geometry/riemannian_manifolds/all.py +7 -0
  41. sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
  42. sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
  43. sage/interfaces/all__sagemath_symbolics.py +1 -0
  44. sage/interfaces/magma.py +2991 -0
  45. sage/interfaces/magma_free.py +90 -0
  46. sage/interfaces/maple.py +1402 -0
  47. sage/interfaces/mathematica.py +1345 -0
  48. sage/interfaces/mathics.py +1312 -0
  49. sage/interfaces/sympy.py +1398 -0
  50. sage/interfaces/sympy_wrapper.py +197 -0
  51. sage/interfaces/tides.py +938 -0
  52. sage/libs/all__sagemath_symbolics.py +6 -0
  53. sage/manifolds/all.py +7 -0
  54. sage/manifolds/calculus_method.py +553 -0
  55. sage/manifolds/catalog.py +437 -0
  56. sage/manifolds/chart.py +4010 -0
  57. sage/manifolds/chart_func.py +3416 -0
  58. sage/manifolds/continuous_map.py +2183 -0
  59. sage/manifolds/continuous_map_image.py +155 -0
  60. sage/manifolds/differentiable/affine_connection.py +2475 -0
  61. sage/manifolds/differentiable/all.py +1 -0
  62. sage/manifolds/differentiable/automorphismfield.py +1383 -0
  63. sage/manifolds/differentiable/automorphismfield_group.py +604 -0
  64. sage/manifolds/differentiable/bundle_connection.py +1445 -0
  65. sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
  66. sage/manifolds/differentiable/chart.py +1241 -0
  67. sage/manifolds/differentiable/curve.py +1028 -0
  68. sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
  69. sage/manifolds/differentiable/degenerate.py +559 -0
  70. sage/manifolds/differentiable/degenerate_submanifold.py +1668 -0
  71. sage/manifolds/differentiable/diff_form.py +1660 -0
  72. sage/manifolds/differentiable/diff_form_module.py +1062 -0
  73. sage/manifolds/differentiable/diff_map.py +1315 -0
  74. sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
  75. sage/manifolds/differentiable/examples/all.py +1 -0
  76. sage/manifolds/differentiable/examples/euclidean.py +2517 -0
  77. sage/manifolds/differentiable/examples/real_line.py +897 -0
  78. sage/manifolds/differentiable/examples/sphere.py +1186 -0
  79. sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
  80. sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
  81. sage/manifolds/differentiable/integrated_curve.py +4035 -0
  82. sage/manifolds/differentiable/levi_civita_connection.py +841 -0
  83. sage/manifolds/differentiable/manifold.py +4254 -0
  84. sage/manifolds/differentiable/manifold_homset.py +1826 -0
  85. sage/manifolds/differentiable/metric.py +3032 -0
  86. sage/manifolds/differentiable/mixed_form.py +1507 -0
  87. sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
  88. sage/manifolds/differentiable/multivector_module.py +800 -0
  89. sage/manifolds/differentiable/multivectorfield.py +1522 -0
  90. sage/manifolds/differentiable/poisson_tensor.py +268 -0
  91. sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
  92. sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
  93. sage/manifolds/differentiable/scalarfield.py +1343 -0
  94. sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
  95. sage/manifolds/differentiable/symplectic_form.py +912 -0
  96. sage/manifolds/differentiable/symplectic_form_test.py +220 -0
  97. sage/manifolds/differentiable/tangent_space.py +412 -0
  98. sage/manifolds/differentiable/tangent_vector.py +616 -0
  99. sage/manifolds/differentiable/tensorfield.py +4665 -0
  100. sage/manifolds/differentiable/tensorfield_module.py +963 -0
  101. sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
  102. sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
  103. sage/manifolds/differentiable/vector_bundle.py +1725 -0
  104. sage/manifolds/differentiable/vectorfield.py +1717 -0
  105. sage/manifolds/differentiable/vectorfield_module.py +2445 -0
  106. sage/manifolds/differentiable/vectorframe.py +1832 -0
  107. sage/manifolds/family.py +270 -0
  108. sage/manifolds/local_frame.py +1490 -0
  109. sage/manifolds/manifold.py +3090 -0
  110. sage/manifolds/manifold_homset.py +452 -0
  111. sage/manifolds/operators.py +359 -0
  112. sage/manifolds/point.py +994 -0
  113. sage/manifolds/scalarfield.py +3718 -0
  114. sage/manifolds/scalarfield_algebra.py +629 -0
  115. sage/manifolds/section.py +3111 -0
  116. sage/manifolds/section_module.py +831 -0
  117. sage/manifolds/structure.py +229 -0
  118. sage/manifolds/subset.py +2721 -0
  119. sage/manifolds/subsets/all.py +1 -0
  120. sage/manifolds/subsets/closure.py +131 -0
  121. sage/manifolds/subsets/pullback.py +883 -0
  122. sage/manifolds/topological_submanifold.py +891 -0
  123. sage/manifolds/trivialization.py +733 -0
  124. sage/manifolds/utilities.py +1348 -0
  125. sage/manifolds/vector_bundle.py +1347 -0
  126. sage/manifolds/vector_bundle_fiber.py +332 -0
  127. sage/manifolds/vector_bundle_fiber_element.py +111 -0
  128. sage/matrix/all__sagemath_symbolics.py +1 -0
  129. sage/matrix/matrix_symbolic_dense.cpython-311-darwin.so +0 -0
  130. sage/matrix/matrix_symbolic_dense.pxd +6 -0
  131. sage/matrix/matrix_symbolic_dense.pyx +1030 -0
  132. sage/matrix/matrix_symbolic_sparse.cpython-311-darwin.so +0 -0
  133. sage/matrix/matrix_symbolic_sparse.pxd +6 -0
  134. sage/matrix/matrix_symbolic_sparse.pyx +1038 -0
  135. sage/modules/all__sagemath_symbolics.py +1 -0
  136. sage/modules/vector_callable_symbolic_dense.py +105 -0
  137. sage/modules/vector_symbolic_dense.py +116 -0
  138. sage/modules/vector_symbolic_sparse.py +118 -0
  139. sage/rings/all__sagemath_symbolics.py +4 -0
  140. sage/rings/asymptotic/all.py +6 -0
  141. sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
  142. sage/rings/asymptotic/asymptotic_ring.py +4858 -0
  143. sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4106 -0
  144. sage/rings/asymptotic/growth_group.py +5373 -0
  145. sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
  146. sage/rings/asymptotic/term_monoid.py +5205 -0
  147. sage/rings/function_field/all__sagemath_symbolics.py +2 -0
  148. sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
  149. sage/symbolic/all.py +15 -0
  150. sage/symbolic/assumptions.py +987 -0
  151. sage/symbolic/benchmark.py +93 -0
  152. sage/symbolic/callable.py +456 -0
  153. sage/symbolic/callable.pyi +66 -0
  154. sage/symbolic/comparison_impl.pyi +38 -0
  155. sage/symbolic/complexity_measures.py +35 -0
  156. sage/symbolic/constants.py +1286 -0
  157. sage/symbolic/constants_c_impl.pyi +10 -0
  158. sage/symbolic/expression_conversion_algebraic.py +310 -0
  159. sage/symbolic/expression_conversion_sympy.py +317 -0
  160. sage/symbolic/expression_conversions.py +1727 -0
  161. sage/symbolic/function_factory.py +355 -0
  162. sage/symbolic/function_factory.pyi +41 -0
  163. sage/symbolic/getitem_impl.pyi +24 -0
  164. sage/symbolic/integration/all.py +1 -0
  165. sage/symbolic/integration/external.py +271 -0
  166. sage/symbolic/integration/integral.py +1075 -0
  167. sage/symbolic/maxima_wrapper.py +162 -0
  168. sage/symbolic/operators.py +267 -0
  169. sage/symbolic/operators.pyi +61 -0
  170. sage/symbolic/pynac_constant_impl.pyi +13 -0
  171. sage/symbolic/pynac_function_impl.pyi +8 -0
  172. sage/symbolic/random_tests.py +461 -0
  173. sage/symbolic/relation.py +2062 -0
  174. sage/symbolic/ring.cpython-311-darwin.so +0 -0
  175. sage/symbolic/ring.pxd +5 -0
  176. sage/symbolic/ring.pyi +110 -0
  177. sage/symbolic/ring.pyx +1393 -0
  178. sage/symbolic/series_impl.pyi +10 -0
  179. sage/symbolic/subring.py +1025 -0
  180. sage/symbolic/symengine.py +19 -0
  181. sage/symbolic/tests.py +40 -0
  182. sage/symbolic/units.py +1468 -0
@@ -0,0 +1,1660 @@
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:
944
+ # only the restrictions to subdomains have
945
+ # been initialized
946
+ for chart in dom_resu.top_charts():
947
+ resu._express[chart] = \
948
+ resu.restrict(chart.domain()).coord_function(chart)
949
+ return resu
950
+
951
+ # *****************************************************************************
952
+
953
+
954
+ class DiffFormParal(FreeModuleAltForm, TensorFieldParal, DiffForm):
955
+ r"""
956
+ Differential form with values on a parallelizable manifold.
957
+
958
+ Given a differentiable manifold `U`, a differentiable map
959
+ `\Phi: U \rightarrow M` to a parallelizable manifold `M` and a positive
960
+ integer `p`, a *differential form of degree* `p` (or `p`-*form*)
961
+ *along* `U` *with values on* `M\supset\Phi(U)` is a differentiable map
962
+
963
+ .. MATH::
964
+
965
+ a:\ U \longrightarrow T^{(0,p)}M
966
+
967
+ (`T^{(0,p)}M` being the tensor bundle of type `(0,p)` over `M`) such that
968
+
969
+ .. MATH::
970
+
971
+ \forall x \in U,\quad a(x) \in \Lambda^p(T_{\Phi(x)}^* M) ,
972
+
973
+ where `T_{\Phi(x)}^* M` is the dual of the tangent space to `M` at
974
+ `\Phi(x)` and `\Lambda^p` stands for the exterior power of degree `p` (cf.
975
+ :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule`).
976
+ In other words, `a(x)` is an alternating multilinear form of degree `p` of
977
+ the tangent vector space `T_{\Phi(x)} M`.
978
+
979
+ The standard case of a differential form *on* a manifold `M` corresponds
980
+ to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi`
981
+ being an immersion and `\Phi` being a curve in `M` (`U` is then an
982
+ open interval of `\RR`).
983
+
984
+ .. NOTE::
985
+
986
+ If `M` is not parallelizable, the class :class:`DiffForm` must
987
+ be used instead.
988
+
989
+ INPUT:
990
+
991
+ - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector
992
+ fields along `U` with values on `M` via the map `\Phi`
993
+ - ``degree`` -- the degree of the differential form (i.e. its tensor rank)
994
+ - ``name`` -- (default: ``None``) name given to the differential form
995
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
996
+ differential form; if none is provided, the LaTeX symbol is set to
997
+ ``name``
998
+
999
+ EXAMPLES:
1000
+
1001
+ A 2-form on a 4-dimensional manifold::
1002
+
1003
+ sage: M = Manifold(4, 'M')
1004
+ sage: c_txyz.<t,x,y,z> = M.chart()
1005
+ sage: a = M.diff_form(2, name='a') ; a
1006
+ 2-form a on the 4-dimensional differentiable manifold M
1007
+ sage: a.parent()
1008
+ Free module Omega^2(M) of 2-forms on the 4-dimensional differentiable
1009
+ manifold M
1010
+
1011
+ A differential form is a tensor field of purely covariant type::
1012
+
1013
+ sage: a.tensor_type()
1014
+ (0, 2)
1015
+
1016
+ It is antisymmetric, its components being
1017
+ :class:`~sage.tensor.modules.comp.CompFullyAntiSym`::
1018
+
1019
+ sage: a.symmetries()
1020
+ no symmetry; antisymmetry: (0, 1)
1021
+ sage: a[0,1] = 2
1022
+ sage: a[1,0]
1023
+ -2
1024
+ sage: a.comp()
1025
+ Fully antisymmetric 2-indices components w.r.t. Coordinate frame (M, (∂/∂t,∂/∂x,∂/∂y,∂/∂z))
1026
+ sage: type(a.comp())
1027
+ <class 'sage.tensor.modules.comp.CompFullyAntiSym'>
1028
+
1029
+ Setting a component with repeated indices to a nonzero value
1030
+ results in an error::
1031
+
1032
+ sage: a[1,1] = 3
1033
+ Traceback (most recent call last):
1034
+ ...
1035
+ ValueError: by antisymmetry, the component cannot have a nonzero value
1036
+ for the indices (1, 1)
1037
+ sage: a[1,1] = 0 # OK, albeit useless
1038
+ sage: a[1,2] = 3 # OK
1039
+
1040
+ The expansion of a differential form with respect to a given coframe is
1041
+ displayed via the method
1042
+ :meth:`~sage.tensor.modules.free_module_alt_form.FreeModuleAltForm.display`::
1043
+
1044
+ sage: a.display() # expansion with respect to the default coframe (dt, dx, dy, dz)
1045
+ a = 2 dt∧dx + 3 dx∧dy
1046
+ sage: latex(a.display()) # output for the notebook
1047
+ a = 2 \mathrm{d} t\wedge \mathrm{d} x
1048
+ + 3 \mathrm{d} x\wedge \mathrm{d} y
1049
+
1050
+ Differential forms can be added or subtracted::
1051
+
1052
+ sage: b = M.diff_form(2)
1053
+ sage: b[0,1], b[0,2], b[0,3] = (1,2,3)
1054
+ sage: s = a + b ; s
1055
+ 2-form on the 4-dimensional differentiable manifold M
1056
+ sage: a[:], b[:], s[:]
1057
+ (
1058
+ [ 0 2 0 0] [ 0 1 2 3] [ 0 3 2 3]
1059
+ [-2 0 3 0] [-1 0 0 0] [-3 0 3 0]
1060
+ [ 0 -3 0 0] [-2 0 0 0] [-2 -3 0 0]
1061
+ [ 0 0 0 0], [-3 0 0 0], [-3 0 0 0]
1062
+ )
1063
+ sage: s = a - b ; s
1064
+ 2-form on the 4-dimensional differentiable manifold M
1065
+ sage: s[:]
1066
+ [ 0 1 -2 -3]
1067
+ [-1 0 3 0]
1068
+ [ 2 -3 0 0]
1069
+ [ 3 0 0 0]
1070
+
1071
+ An example of 3-form is the volume element on `\RR^3` in Cartesian
1072
+ coordinates::
1073
+
1074
+ sage: M = Manifold(3, 'R3', latex_name=r'\RR^3', start_index=1)
1075
+ sage: c_cart.<x,y,z> = M.chart()
1076
+ sage: eps = M.diff_form(3, name='epsilon', latex_name=r'\epsilon')
1077
+ sage: eps[1,2,3] = 1 # the only independent component
1078
+ sage: eps[:] # all the components are set from the previous line:
1079
+ [[[0, 0, 0], [0, 0, 1], [0, -1, 0]], [[0, 0, -1], [0, 0, 0], [1, 0, 0]],
1080
+ [[0, 1, 0], [-1, 0, 0], [0, 0, 0]]]
1081
+ sage: eps.display()
1082
+ epsilon = dx∧dy∧dz
1083
+
1084
+ Spherical components of the volume element from the tensorial
1085
+ change-of-frame formula::
1086
+
1087
+ sage: c_spher.<r,th,ph> = M.chart(r'r:[0,+oo) th:[0,pi]:\theta ph:[0,2*pi):\phi')
1088
+ sage: spher_to_cart = c_spher.transition_map(c_cart,
1089
+ ....: [r*sin(th)*cos(ph), r*sin(th)*sin(ph), r*cos(th)])
1090
+ sage: cart_to_spher = spher_to_cart.set_inverse(sqrt(x^2+y^2+z^2),
1091
+ ....: atan2(sqrt(x^2+y^2),z), atan2(y, x))
1092
+ Check of the inverse coordinate transformation:
1093
+ r == r *passed*
1094
+ th == arctan2(r*sin(th), r*cos(th)) **failed**
1095
+ ph == arctan2(r*sin(ph)*sin(th), r*cos(ph)*sin(th)) **failed**
1096
+ x == x *passed*
1097
+ y == y *passed*
1098
+ z == z *passed*
1099
+ NB: a failed report can reflect a mere lack of simplification.
1100
+ sage: eps.comp(c_spher.frame()) # computation of the components in the spherical frame
1101
+ Fully antisymmetric 3-indices components w.r.t. Coordinate frame
1102
+ (R3, (∂/∂r,∂/∂th,∂/∂ph))
1103
+ sage: eps.comp(c_spher.frame())[1,2,3, c_spher]
1104
+ r^2*sin(th)
1105
+ sage: eps.display(c_spher.frame())
1106
+ epsilon = sqrt(x^2 + y^2 + z^2)*sqrt(x^2 + y^2) dr∧dth∧dph
1107
+ sage: eps.display(c_spher.frame(), c_spher)
1108
+ epsilon = r^2*sin(th) dr∧dth∧dph
1109
+
1110
+ As a shortcut of the above command, on can pass just the chart ``c_spher``
1111
+ to ``display``, the vector frame being then assumed to be the coordinate
1112
+ frame associated with the chart::
1113
+
1114
+ sage: eps.display(c_spher)
1115
+ epsilon = r^2*sin(th) dr∧dth∧dph
1116
+
1117
+
1118
+ The exterior product of two differential forms is performed via the method
1119
+ :meth:`~sage.tensor.modules.free_module_alt_form.FreeModuleAltForm.wedge`::
1120
+
1121
+ sage: a = M.one_form(x*y*z, -z*x, y*z, name='A')
1122
+ sage: b = M.one_form(cos(z), sin(x), cos(y), name='B')
1123
+ sage: ab = a.wedge(b) ; ab
1124
+ 2-form A∧B on the 3-dimensional differentiable manifold R3
1125
+ sage: ab[:]
1126
+ [ 0 x*y*z*sin(x) + x*z*cos(z) x*y*z*cos(y) - y*z*cos(z)]
1127
+ [-x*y*z*sin(x) - x*z*cos(z) 0 -(x*cos(y) + y*sin(x))*z]
1128
+ [-x*y*z*cos(y) + y*z*cos(z) (x*cos(y) + y*sin(x))*z 0]
1129
+ sage: ab.display()
1130
+ A∧B = (x*y*z*sin(x) + x*z*cos(z)) dx∧dy + (x*y*z*cos(y) - y*z*cos(z)) dx∧dz
1131
+ - (x*cos(y) + y*sin(x))*z dy∧dz
1132
+
1133
+ Let us check the formula relating the exterior product to the tensor
1134
+ product for 1-forms::
1135
+
1136
+ sage: a.wedge(b) == a*b - b*a
1137
+ True
1138
+
1139
+ The tensor product of a 1-form and a 2-form is not a 3-form but a tensor
1140
+ field of type `(0,3)` with less symmetries::
1141
+
1142
+ sage: c = a*ab ; c
1143
+ Tensor field A⊗(A∧B) of type (0,3) on the 3-dimensional differentiable
1144
+ manifold R3
1145
+ sage: c.symmetries() # the antisymmetry is only w.r.t. the last 2 arguments:
1146
+ no symmetry; antisymmetry: (1, 2)
1147
+ sage: d = ab*a ; d
1148
+ Tensor field (A∧B)⊗A of type (0,3) on the 3-dimensional differentiable
1149
+ manifold R3
1150
+ sage: d.symmetries() # the antisymmetry is only w.r.t. the first 2 arguments:
1151
+ no symmetry; antisymmetry: (0, 1)
1152
+
1153
+ The exterior derivative of a differential form is obtained by means
1154
+ of the method :meth:`exterior_derivative`::
1155
+
1156
+ sage: da = a.exterior_derivative() ; da
1157
+ 2-form dA on the 3-dimensional differentiable manifold R3
1158
+ sage: da.display()
1159
+ dA = -(x + 1)*z dx∧dy - x*y dx∧dz + (x + z) dy∧dz
1160
+ sage: db = b.exterior_derivative() ; db
1161
+ 2-form dB on the 3-dimensional differentiable manifold R3
1162
+ sage: db.display()
1163
+ dB = cos(x) dx∧dy + sin(z) dx∧dz - sin(y) dy∧dz
1164
+ sage: dab = ab.exterior_derivative() ; dab
1165
+ 3-form d(A∧B) on the 3-dimensional differentiable manifold R3
1166
+
1167
+ or by applying the function ``diff`` to the differential form::
1168
+
1169
+ sage: diff(a) is a.exterior_derivative()
1170
+ True
1171
+
1172
+ As a 3-form over a 3-dimensional manifold, ``d(A∧B)`` is necessarily
1173
+ proportional to the volume 3-form::
1174
+
1175
+ sage: dab == dab[[1,2,3]]/eps[[1,2,3]]*eps
1176
+ True
1177
+
1178
+ We may also check that the classical anti-derivation formula is fulfilled::
1179
+
1180
+ sage: dab == da.wedge(b) - a.wedge(db)
1181
+ True
1182
+
1183
+ The Lie derivative of a 2-form is a 2-form::
1184
+
1185
+ sage: v = M.vector_field(y*z, -x*z, x*y, name='v')
1186
+ sage: ab.lie_der(v) # long time
1187
+ 2-form on the 3-dimensional differentiable manifold R3
1188
+
1189
+ Let us check Cartan formula, which expresses the Lie derivative in terms
1190
+ of exterior derivatives::
1191
+
1192
+ sage: ab.lie_der(v) == (v.contract(ab.exterior_derivative()) # long time
1193
+ ....: + v.contract(ab).exterior_derivative())
1194
+ True
1195
+
1196
+ A 1-form on a `\RR^3`::
1197
+
1198
+ sage: om = M.one_form(name='omega', latex_name=r'\omega'); om
1199
+ 1-form omega on the 3-dimensional differentiable manifold R3
1200
+
1201
+ A 1-form is of course a differential form::
1202
+
1203
+ sage: isinstance(om, sage.manifolds.differentiable.diff_form.DiffFormParal)
1204
+ True
1205
+ sage: om.parent()
1206
+ Free module Omega^1(R3) of 1-forms on the 3-dimensional differentiable
1207
+ manifold R3
1208
+ sage: om.tensor_type()
1209
+ (0, 1)
1210
+
1211
+ Setting the components with respect to the manifold's default frame::
1212
+
1213
+ sage: om[:] = (2*z, x, x-y)
1214
+ sage: om[:]
1215
+ [2*z, x, x - y]
1216
+ sage: om.display()
1217
+ omega = 2*z dx + x dy + (x - y) dz
1218
+
1219
+ A 1-form acts on vector fields::
1220
+
1221
+ sage: v = M.vector_field(x, 2*y, 3*z, name='V')
1222
+ sage: om(v)
1223
+ Scalar field omega(V) on the 3-dimensional differentiable manifold R3
1224
+ sage: om(v).display()
1225
+ omega(V): R3 → ℝ
1226
+ (x, y, z) ↦ 2*x*y + (5*x - 3*y)*z
1227
+ (r, th, ph) ↦ 2*r^2*cos(ph)*sin(ph)*sin(th)^2 + r^2*(5*cos(ph)
1228
+ - 3*sin(ph))*cos(th)*sin(th)
1229
+ sage: latex(om(v))
1230
+ \omega\left(V\right)
1231
+
1232
+ The tensor product of two 1-forms is a tensor field of type `(0,2)`::
1233
+
1234
+ sage: a = M.one_form(1, 2, 3, name='A')
1235
+ sage: b = M.one_form(6, 5, 4, name='B')
1236
+ sage: c = a*b ; c
1237
+ Tensor field A⊗B of type (0,2) on the 3-dimensional differentiable
1238
+ manifold R3
1239
+ sage: c[:]
1240
+ [ 6 5 4]
1241
+ [12 10 8]
1242
+ [18 15 12]
1243
+ sage: c.symmetries() # c has no symmetries:
1244
+ no symmetry; no antisymmetry
1245
+ """
1246
+ def __init__(self, vector_field_module: VectorFieldModule, degree: int, name: Optional[str] = None,
1247
+ latex_name: Optional[str] = None):
1248
+ r"""
1249
+ Construct a differential form.
1250
+
1251
+ TESTS:
1252
+
1253
+ Construction via ``parent.element_class``, and not via a direct call
1254
+ to ``DiffFormParal``, to fit with the category framework::
1255
+
1256
+ sage: M = Manifold(2, 'M')
1257
+ sage: X.<x,y> = M.chart() # makes M parallelizable
1258
+ sage: A = M.diff_form_module(2)
1259
+ sage: XM = M.vector_field_module()
1260
+ sage: a = A.element_class(XM, 2, name='a'); a
1261
+ 2-form a on the 2-dimensional differentiable manifold M
1262
+ sage: a[0,1] = x*y
1263
+ sage: TestSuite(a).run()
1264
+
1265
+ Construction via ``DifferentiableManifold.diff_form``::
1266
+
1267
+ sage: a1 = M.diff_form(2, name='a'); a1
1268
+ 2-form a on the 2-dimensional differentiable manifold M
1269
+ sage: type(a1) == type(a)
1270
+ True
1271
+ sage: a1.parent() is a.parent()
1272
+ True
1273
+
1274
+ Initializing the components at the construction::
1275
+
1276
+ sage: a = M.diff_form(2, [[0, x*y], [-x*y, 0]], name='a')
1277
+ sage: a.display()
1278
+ a = x*y dx∧dy
1279
+ """
1280
+ FreeModuleAltForm.__init__(self, vector_field_module, degree,
1281
+ name=name, latex_name=latex_name)
1282
+ # TensorFieldParal attributes:
1283
+ self._vmodule = vector_field_module
1284
+ self._domain = vector_field_module._domain
1285
+ self._ambient_domain = vector_field_module._ambient_domain
1286
+ # initialization of derived quantities:
1287
+ self._init_derived()
1288
+
1289
+ def _repr_(self):
1290
+ r"""
1291
+ String representation of ``self``.
1292
+
1293
+ TESTS::
1294
+
1295
+ sage: M = Manifold(3, 'M')
1296
+ sage: X.<x,y,z> = M.chart() # makes M parallelizable
1297
+ sage: a = M.diff_form(2, name='a')
1298
+ sage: a._repr_()
1299
+ '2-form a on the 3-dimensional differentiable manifold M'
1300
+ sage: repr(a) # indirect doctest
1301
+ '2-form a on the 3-dimensional differentiable manifold M'
1302
+ sage: a # indirect doctest
1303
+ 2-form a on the 3-dimensional differentiable manifold M
1304
+ sage: b = M.diff_form(2)
1305
+ sage: b._repr_()
1306
+ '2-form on the 3-dimensional differentiable manifold M'
1307
+ """
1308
+ description = "{}-form ".format(self._tensor_rank)
1309
+ if self._name is not None:
1310
+ description += self._name + " "
1311
+ return self._final_repr(description)
1312
+
1313
+ def _new_instance(self):
1314
+ r"""
1315
+ Create an instance of the same class, of the same degree and on the
1316
+ same domain.
1317
+
1318
+ TESTS::
1319
+
1320
+ sage: M = Manifold(3, 'M')
1321
+ sage: X.<x,y,z> = M.chart() # makes M parallelizable
1322
+ sage: a = M.diff_form(2, name='a')
1323
+ sage: a1 = a._new_instance(); a1
1324
+ 2-form on the 3-dimensional differentiable manifold M
1325
+ sage: type(a1) == type(a)
1326
+ True
1327
+ sage: a1.parent() is a.parent()
1328
+ True
1329
+ """
1330
+ return type(self)(self._fmodule, self._tensor_rank)
1331
+
1332
+ # This method is needed to redirect to the correct class (TensorFieldParal)
1333
+ def _init_derived(self):
1334
+ r"""
1335
+ Initialize the derived quantities of ``self``.
1336
+
1337
+ TESTS::
1338
+
1339
+ sage: M = Manifold(3, 'M')
1340
+ sage: X.<x,y,z> = M.chart() # makes M parallelizable
1341
+ sage: a = M.diff_form(2, name='a')
1342
+ sage: a._init_derived()
1343
+ """
1344
+ TensorFieldParal._init_derived(self)
1345
+
1346
+ def _del_derived(self, del_restrictions: bool = True):
1347
+ r"""
1348
+ Delete the derived quantities.
1349
+
1350
+ INPUT:
1351
+
1352
+ - ``del_restrictions`` -- boolean (default: ``True``); determines whether the
1353
+ restrictions of ``self`` to subdomains are deleted
1354
+
1355
+ TESTS::
1356
+
1357
+ sage: M = Manifold(3, 'M')
1358
+ sage: X.<x,y,z> = M.chart() # makes M parallelizable
1359
+ sage: a = M.diff_form(2, name='a')
1360
+ sage: a._del_derived()
1361
+ """
1362
+ TensorFieldParal._del_derived(self, del_restrictions=del_restrictions)
1363
+ self.exterior_derivative.clear_cache()
1364
+
1365
+ def __call__(self, *args):
1366
+ r"""
1367
+ Redefinition of
1368
+ :meth:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor.__call__`
1369
+ to allow for domain treatment.
1370
+
1371
+ TESTS::
1372
+
1373
+ sage: M = Manifold(2, 'M')
1374
+ sage: X.<x,y> = M.chart()
1375
+ sage: a = M.diff_form(2, name='a')
1376
+ sage: a[0,1] = x*y
1377
+ sage: a.display()
1378
+ a = x*y dx∧dy
1379
+ sage: u = M.vector_field(1+x, 2-y, name='u')
1380
+ sage: v = M.vector_field(-y, x, name='v')
1381
+ sage: s = a.__call__(u,v); s
1382
+ Scalar field a(u,v) on the 2-dimensional differentiable manifold M
1383
+ sage: s.display()
1384
+ a(u,v): M → ℝ
1385
+ (x, y) ↦ -x*y^3 + 2*x*y^2 + (x^3 + x^2)*y
1386
+ sage: s == a[[0,1]]*(u[[0]]*v[[1]] - u[[1]]*v[[0]])
1387
+ True
1388
+ sage: s == a(u,v) # indirect doctest
1389
+ True
1390
+ """
1391
+ return TensorFieldParal.__call__(self, *args)
1392
+
1393
+ @cached_method
1394
+ def exterior_derivative(self) -> DiffFormParal:
1395
+ r"""
1396
+ Compute the exterior derivative of ``self``.
1397
+
1398
+ OUTPUT:
1399
+
1400
+ - a :class:`DiffFormParal` representing the exterior
1401
+ derivative of the differential form
1402
+
1403
+ EXAMPLES:
1404
+
1405
+ Exterior derivative of a 1-form on a 4-dimensional manifold::
1406
+
1407
+ sage: M = Manifold(4, 'M')
1408
+ sage: c_txyz.<t,x,y,z> = M.chart()
1409
+ sage: a = M.one_form(t*x*y*z, z*y**2, x*z**2, x**2 + y**2, name='A')
1410
+ sage: da = a.exterior_derivative() ; da
1411
+ 2-form dA on the 4-dimensional differentiable manifold M
1412
+ sage: da.display()
1413
+ dA = -t*y*z dt∧dx - t*x*z dt∧dy - t*x*y dt∧dz
1414
+ + (-2*y*z + z^2) dx∧dy + (-y^2 + 2*x) dx∧dz
1415
+ + (-2*x*z + 2*y) dy∧dz
1416
+ sage: latex(da)
1417
+ \mathrm{d}A
1418
+
1419
+ The result is cached, i.e. is not recomputed unless ``a`` is changed::
1420
+
1421
+ sage: a.exterior_derivative() is da
1422
+ True
1423
+
1424
+ Instead of invoking the method :meth:`exterior_derivative`, one may
1425
+ use the global function ``diff``::
1426
+
1427
+ sage: diff(a) is a.exterior_derivative()
1428
+ True
1429
+
1430
+ The exterior derivative is nilpotent::
1431
+
1432
+ sage: dda = da.exterior_derivative() ; dda
1433
+ 3-form ddA on the 4-dimensional differentiable manifold M
1434
+ sage: dda.display()
1435
+ ddA = 0
1436
+ sage: dda == 0
1437
+ True
1438
+
1439
+ Let us check Cartan's identity::
1440
+
1441
+ sage: v = M.vector_field(-y, x, t, z, name='v')
1442
+ sage: a.lie_der(v) == v.contract(diff(a)) + diff(a(v)) # long time
1443
+ True
1444
+ """
1445
+ from sage.manifolds.differentiable.vectorframe import CoordFrame
1446
+ from sage.tensor.modules.comp import CompFullyAntiSym
1447
+ from sage.tensor.modules.format_utilities import (
1448
+ format_unop_latex,
1449
+ format_unop_txt,
1450
+ )
1451
+ fmodule = self._fmodule # shortcut
1452
+ rname = format_unop_txt('d', self._name)
1453
+ rlname = format_unop_latex(r'\mathrm{d}', self._latex_name)
1454
+ resu = fmodule.alternating_form(self._tensor_rank + 1,
1455
+ name=rname,
1456
+ latex_name=rlname)
1457
+ # 1/ List of all coordinate frames in which the components of self
1458
+ # are known
1459
+ coord_frames = []
1460
+ for frame in self._components:
1461
+ if isinstance(frame, CoordFrame):
1462
+ coord_frames.append(frame)
1463
+ if not coord_frames:
1464
+ # A coordinate frame is searched, at the price of a change of
1465
+ # frame, privileging the frame of the domain's default chart
1466
+ dom = self._domain
1467
+ def_coordf = dom._def_chart._frame
1468
+ for frame in self._components:
1469
+ if (frame, def_coordf) in dom._frame_changes:
1470
+ self.comp(def_coordf, from_basis=frame)
1471
+ coord_frames = [def_coordf]
1472
+ break
1473
+ if not coord_frames:
1474
+ for chart in dom._atlas:
1475
+ if chart != dom._def_chart:
1476
+ # the case def_chart is
1477
+ # treated above
1478
+ coordf = chart._frame
1479
+ for frame in self._components:
1480
+ if (frame, coordf) in dom._frame_changes:
1481
+ self.comp(coordf, from_basis=frame)
1482
+ coord_frames[coordf]
1483
+ break
1484
+ if coord_frames:
1485
+ break
1486
+ # 2/ The computation:
1487
+ for frame in coord_frames:
1488
+ chart = frame._chart
1489
+ sc = self._components[frame]
1490
+ dc = CompFullyAntiSym(fmodule._ring, frame,
1491
+ self._tensor_rank + 1,
1492
+ start_index=fmodule._sindex,
1493
+ output_formatter=fmodule._output_formatter)
1494
+ for ind, val in sc._comp.items():
1495
+ for i in fmodule.irange():
1496
+ ind_d = (i,) + ind
1497
+ if len(ind_d) == len(set(ind_d)):
1498
+ # all indices are different
1499
+ dc[[ind_d]] += \
1500
+ val.coord_function(chart).diff(i).scalar_field()
1501
+ resu._components[frame] = dc
1502
+ return resu
1503
+
1504
+ derivative = exterior_derivative # allows one to use functional notation,
1505
+ # e.g. diff(a) for a.exterior_derivative()
1506
+
1507
+ def wedge(self, other):
1508
+ r"""
1509
+ Exterior product of ``self`` with another differential form.
1510
+
1511
+ INPUT:
1512
+
1513
+ - ``other`` -- another differential form
1514
+
1515
+ OUTPUT:
1516
+
1517
+ - instance of :class:`DiffFormParal` representing the exterior
1518
+ product ``self ∧ other``
1519
+
1520
+ EXAMPLES:
1521
+
1522
+ Exterior product of a 1-form and a 2-form on a 3-dimensional
1523
+ manifold::
1524
+
1525
+ sage: M = Manifold(3, 'M', start_index=1)
1526
+ sage: X.<x,y,z> = M.chart()
1527
+ sage: a = M.one_form(2, 1+x, y*z, name='a')
1528
+ sage: b = M.diff_form(2, name='b')
1529
+ sage: b[1,2], b[1,3], b[2,3] = y^2, z+x, z^2
1530
+ sage: a.display()
1531
+ a = 2 dx + (x + 1) dy + y*z dz
1532
+ sage: b.display()
1533
+ b = y^2 dx∧dy + (x + z) dx∧dz + z^2 dy∧dz
1534
+ sage: s = a.wedge(b); s
1535
+ 3-form a∧b on the 3-dimensional differentiable manifold M
1536
+ sage: s.display()
1537
+ a∧b = (-x^2 + (y^3 - x - 1)*z + 2*z^2 - x) dx∧dy∧dz
1538
+
1539
+ Check::
1540
+
1541
+ sage: s[1,2,3] == a[1]*b[2,3] + a[2]*b[3,1] + a[3]*b[1,2]
1542
+ True
1543
+
1544
+ Wedging with scalar fields yields the multiplication from right::
1545
+
1546
+ sage: f = M.scalar_field(x, name='f')
1547
+ sage: t = a.wedge(f)
1548
+ sage: t.display()
1549
+ f*a = 2*x dx + (x^2 + x) dy + x*y*z dz
1550
+ """
1551
+ if other._tensor_rank == 0:
1552
+ return self * other
1553
+ if self._domain.is_subset(other._domain):
1554
+ if not self._ambient_domain.is_subset(other._ambient_domain):
1555
+ raise ValueError("incompatible ambient domains for exterior " +
1556
+ "product")
1557
+ elif other._domain.is_subset(self._domain):
1558
+ if not other._ambient_domain.is_subset(self._ambient_domain):
1559
+ raise ValueError("incompatible ambient domains for exterior " +
1560
+ "product")
1561
+ dom_resu = self._domain.intersection(other._domain)
1562
+ self_r = self.restrict(dom_resu)
1563
+ other_r = other.restrict(dom_resu)
1564
+ return FreeModuleAltForm.wedge(self_r, other_r)
1565
+
1566
+ def interior_product(self, qvect):
1567
+ r"""
1568
+ Interior product with a multivector field.
1569
+
1570
+ If ``self`` is a differential form `A` of degree `p` and `B` is a
1571
+ multivector field of degree `q\geq p` on the same manifold, the
1572
+ interior product of `A` by `B` is the multivector field `\iota_A B` of
1573
+ degree `q-p` defined by
1574
+
1575
+ .. MATH::
1576
+
1577
+ (\iota_A B)^{i_1\ldots i_{q-p}} = A_{k_1\ldots k_p}
1578
+ B^{k_1\ldots k_p i_1\ldots i_{q-p}}
1579
+
1580
+ .. NOTE::
1581
+
1582
+ ``A.interior_product(B)`` yields the same result as
1583
+ ``A.contract(0,..., p-1, B, 0,..., p-1)`` (cf.
1584
+ :meth:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal.contract`),
1585
+ but ``interior_product`` is more efficient, the alternating
1586
+ character of `A` being not used to reduce the computation in
1587
+ :meth:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal.contract`
1588
+
1589
+ INPUT:
1590
+
1591
+ - ``qvect`` -- multivector field `B` (instance of
1592
+ :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal`);
1593
+ the degree of `B` must be at least equal to the degree of
1594
+ ``self``
1595
+
1596
+ OUTPUT:
1597
+
1598
+ - scalar field (case `p=q`) or
1599
+ :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal`
1600
+ (case `p<q`) representing the interior product `\iota_A B`,
1601
+ where `A` is ``self``
1602
+
1603
+ .. SEEALSO::
1604
+
1605
+ :meth:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal.interior_product`
1606
+ for the interior product of a multivector field with a
1607
+ differential form
1608
+
1609
+ EXAMPLES:
1610
+
1611
+ Interior product of a 1-form with a 2-vector field on a
1612
+ 3-dimensional manifold::
1613
+
1614
+ sage: M = Manifold(3, 'M', start_index=1)
1615
+ sage: X.<x,y,z> = M.chart()
1616
+ sage: a = M.one_form(2, 1+x, y*z, name='a')
1617
+ sage: b = M.multivector_field(2, name='b')
1618
+ sage: b[1,2], b[1,3], b[2,3] = y^2, z+x, -z^2
1619
+ sage: s = a.interior_product(b); s
1620
+ Vector field i_a b on the 3-dimensional differentiable
1621
+ manifold M
1622
+ sage: s.display()
1623
+ i_a b = (-(x + 1)*y^2 - x*y*z - y*z^2) ∂/∂x
1624
+ + (y*z^3 + 2*y^2) ∂/∂y + (-(x + 1)*z^2 + 2*x + 2*z) ∂/∂z
1625
+ sage: s == a.contract(b)
1626
+ True
1627
+
1628
+ Interior product of a 2-form with a 2-vector field::
1629
+
1630
+ sage: a = M.diff_form(2, name='a')
1631
+ sage: a[1,2], a[1,3], a[2,3] = x*y, -3, z
1632
+ sage: s = a.interior_product(b); s
1633
+ Scalar field i_a b on the 3-dimensional differentiable manifold M
1634
+ sage: s.display()
1635
+ i_a b: M → ℝ
1636
+ (x, y, z) ↦ 2*x*y^3 - 2*z^3 - 6*x - 6*z
1637
+ sage: s == a.contract(0,1,b,0,1)
1638
+ True
1639
+
1640
+ TESTS:
1641
+
1642
+ Check that :issue:`33780` is fixed::
1643
+
1644
+ sage: v = X.frame()[1] # vector field d/dx
1645
+ sage: f = X.coframe()[2] # 1-form dy
1646
+ sage: f.interior_product(v)
1647
+ Scalar field zero on the 3-dimensional differentiable manifold M
1648
+ """
1649
+ if self._domain.is_subset(qvect._domain):
1650
+ if not self._ambient_domain.is_subset(qvect._ambient_domain):
1651
+ raise ValueError("incompatible ambient domains for interior " +
1652
+ "product")
1653
+ elif qvect._domain.is_subset(self._domain):
1654
+ if not qvect._ambient_domain.is_subset(self._ambient_domain):
1655
+ raise ValueError("incompatible ambient domains for interior " +
1656
+ "product")
1657
+ dom_resu = self._domain.intersection(qvect._domain)
1658
+ self_r = self.restrict(dom_resu)
1659
+ qvect_r = qvect.restrict(dom_resu)
1660
+ return FreeModuleAltForm.interior_product(self_r, qvect_r)