passagemath-symbolics 10.6.37__cp310-cp310-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.
Files changed (171) hide show
  1. passagemath_symbolics/__init__.py +3 -0
  2. passagemath_symbolics-10.6.37.dist-info/METADATA +187 -0
  3. passagemath_symbolics-10.6.37.dist-info/RECORD +171 -0
  4. passagemath_symbolics-10.6.37.dist-info/WHEEL +5 -0
  5. passagemath_symbolics-10.6.37.dist-info/top_level.txt +3 -0
  6. sage/all__sagemath_symbolics.py +17 -0
  7. sage/calculus/all.py +14 -0
  8. sage/calculus/calculus.py +2826 -0
  9. sage/calculus/desolvers.py +1866 -0
  10. sage/calculus/predefined.py +51 -0
  11. sage/calculus/tests.py +225 -0
  12. sage/calculus/var.cpython-310-x86_64-linux-gnu.so +0 -0
  13. sage/calculus/var.pyx +401 -0
  14. sage/dynamics/all__sagemath_symbolics.py +6 -0
  15. sage/dynamics/complex_dynamics/all.py +5 -0
  16. sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
  17. sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-310-x86_64-linux-gnu.so +0 -0
  18. sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1035 -0
  19. sage/ext/all__sagemath_symbolics.py +1 -0
  20. sage/ext_data/kenzo/CP2.txt +45 -0
  21. sage/ext_data/kenzo/CP3.txt +349 -0
  22. sage/ext_data/kenzo/CP4.txt +4774 -0
  23. sage/ext_data/kenzo/README.txt +49 -0
  24. sage/ext_data/kenzo/S4.txt +20 -0
  25. sage/ext_data/magma/latex/latex.m +1021 -0
  26. sage/ext_data/magma/latex/latex.spec +1 -0
  27. sage/ext_data/magma/sage/basic.m +356 -0
  28. sage/ext_data/magma/sage/sage.spec +1 -0
  29. sage/ext_data/magma/spec +9 -0
  30. sage/geometry/all__sagemath_symbolics.py +8 -0
  31. sage/geometry/hyperbolic_space/all.py +5 -0
  32. sage/geometry/hyperbolic_space/hyperbolic_coercion.py +743 -0
  33. sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
  34. sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2409 -0
  35. sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
  36. sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1082 -0
  37. sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
  38. sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
  39. sage/geometry/riemannian_manifolds/all.py +7 -0
  40. sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
  41. sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
  42. sage/interfaces/all__sagemath_symbolics.py +1 -0
  43. sage/interfaces/magma.py +3017 -0
  44. sage/interfaces/magma_free.py +92 -0
  45. sage/interfaces/maple.py +1397 -0
  46. sage/interfaces/mathematica.py +1345 -0
  47. sage/interfaces/mathics.py +1312 -0
  48. sage/interfaces/sympy.py +1398 -0
  49. sage/interfaces/sympy_wrapper.py +197 -0
  50. sage/interfaces/tides.py +938 -0
  51. sage/libs/all__sagemath_symbolics.py +6 -0
  52. sage/manifolds/all.py +7 -0
  53. sage/manifolds/calculus_method.py +555 -0
  54. sage/manifolds/catalog.py +437 -0
  55. sage/manifolds/chart.py +4019 -0
  56. sage/manifolds/chart_func.py +3419 -0
  57. sage/manifolds/continuous_map.py +2183 -0
  58. sage/manifolds/continuous_map_image.py +155 -0
  59. sage/manifolds/differentiable/affine_connection.py +2475 -0
  60. sage/manifolds/differentiable/all.py +1 -0
  61. sage/manifolds/differentiable/automorphismfield.py +1383 -0
  62. sage/manifolds/differentiable/automorphismfield_group.py +604 -0
  63. sage/manifolds/differentiable/bundle_connection.py +1445 -0
  64. sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
  65. sage/manifolds/differentiable/chart.py +1241 -0
  66. sage/manifolds/differentiable/curve.py +1028 -0
  67. sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
  68. sage/manifolds/differentiable/degenerate.py +559 -0
  69. sage/manifolds/differentiable/degenerate_submanifold.py +1671 -0
  70. sage/manifolds/differentiable/diff_form.py +1658 -0
  71. sage/manifolds/differentiable/diff_form_module.py +1062 -0
  72. sage/manifolds/differentiable/diff_map.py +1315 -0
  73. sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
  74. sage/manifolds/differentiable/examples/all.py +1 -0
  75. sage/manifolds/differentiable/examples/euclidean.py +2517 -0
  76. sage/manifolds/differentiable/examples/real_line.py +897 -0
  77. sage/manifolds/differentiable/examples/sphere.py +1186 -0
  78. sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
  79. sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
  80. sage/manifolds/differentiable/integrated_curve.py +4035 -0
  81. sage/manifolds/differentiable/levi_civita_connection.py +841 -0
  82. sage/manifolds/differentiable/manifold.py +4254 -0
  83. sage/manifolds/differentiable/manifold_homset.py +1826 -0
  84. sage/manifolds/differentiable/metric.py +3032 -0
  85. sage/manifolds/differentiable/mixed_form.py +1507 -0
  86. sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
  87. sage/manifolds/differentiable/multivector_module.py +800 -0
  88. sage/manifolds/differentiable/multivectorfield.py +1520 -0
  89. sage/manifolds/differentiable/poisson_tensor.py +268 -0
  90. sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
  91. sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
  92. sage/manifolds/differentiable/scalarfield.py +1343 -0
  93. sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
  94. sage/manifolds/differentiable/symplectic_form.py +910 -0
  95. sage/manifolds/differentiable/symplectic_form_test.py +220 -0
  96. sage/manifolds/differentiable/tangent_space.py +412 -0
  97. sage/manifolds/differentiable/tangent_vector.py +616 -0
  98. sage/manifolds/differentiable/tensorfield.py +4665 -0
  99. sage/manifolds/differentiable/tensorfield_module.py +963 -0
  100. sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
  101. sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
  102. sage/manifolds/differentiable/vector_bundle.py +1728 -0
  103. sage/manifolds/differentiable/vectorfield.py +1717 -0
  104. sage/manifolds/differentiable/vectorfield_module.py +2445 -0
  105. sage/manifolds/differentiable/vectorframe.py +1832 -0
  106. sage/manifolds/family.py +270 -0
  107. sage/manifolds/local_frame.py +1490 -0
  108. sage/manifolds/manifold.py +3090 -0
  109. sage/manifolds/manifold_homset.py +452 -0
  110. sage/manifolds/operators.py +359 -0
  111. sage/manifolds/point.py +994 -0
  112. sage/manifolds/scalarfield.py +3718 -0
  113. sage/manifolds/scalarfield_algebra.py +629 -0
  114. sage/manifolds/section.py +3111 -0
  115. sage/manifolds/section_module.py +831 -0
  116. sage/manifolds/structure.py +229 -0
  117. sage/manifolds/subset.py +2764 -0
  118. sage/manifolds/subsets/all.py +1 -0
  119. sage/manifolds/subsets/closure.py +131 -0
  120. sage/manifolds/subsets/pullback.py +885 -0
  121. sage/manifolds/topological_submanifold.py +891 -0
  122. sage/manifolds/trivialization.py +733 -0
  123. sage/manifolds/utilities.py +1348 -0
  124. sage/manifolds/vector_bundle.py +1342 -0
  125. sage/manifolds/vector_bundle_fiber.py +332 -0
  126. sage/manifolds/vector_bundle_fiber_element.py +111 -0
  127. sage/matrix/all__sagemath_symbolics.py +1 -0
  128. sage/matrix/matrix_symbolic_dense.cpython-310-x86_64-linux-gnu.so +0 -0
  129. sage/matrix/matrix_symbolic_dense.pxd +6 -0
  130. sage/matrix/matrix_symbolic_dense.pyx +1022 -0
  131. sage/matrix/matrix_symbolic_sparse.cpython-310-x86_64-linux-gnu.so +0 -0
  132. sage/matrix/matrix_symbolic_sparse.pxd +6 -0
  133. sage/matrix/matrix_symbolic_sparse.pyx +1029 -0
  134. sage/modules/all__sagemath_symbolics.py +1 -0
  135. sage/modules/vector_callable_symbolic_dense.py +105 -0
  136. sage/modules/vector_symbolic_dense.py +116 -0
  137. sage/modules/vector_symbolic_sparse.py +118 -0
  138. sage/rings/all__sagemath_symbolics.py +4 -0
  139. sage/rings/asymptotic/all.py +6 -0
  140. sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
  141. sage/rings/asymptotic/asymptotic_ring.py +4858 -0
  142. sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4153 -0
  143. sage/rings/asymptotic/growth_group.py +5373 -0
  144. sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
  145. sage/rings/asymptotic/term_monoid.py +5237 -0
  146. sage/rings/function_field/all__sagemath_symbolics.py +2 -0
  147. sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
  148. sage/symbolic/all.py +15 -0
  149. sage/symbolic/assumptions.py +985 -0
  150. sage/symbolic/benchmark.py +93 -0
  151. sage/symbolic/callable.py +459 -0
  152. sage/symbolic/complexity_measures.py +35 -0
  153. sage/symbolic/constants.py +1287 -0
  154. sage/symbolic/expression_conversion_algebraic.py +310 -0
  155. sage/symbolic/expression_conversion_sympy.py +317 -0
  156. sage/symbolic/expression_conversions.py +1713 -0
  157. sage/symbolic/function_factory.py +355 -0
  158. sage/symbolic/integration/all.py +1 -0
  159. sage/symbolic/integration/external.py +270 -0
  160. sage/symbolic/integration/integral.py +1115 -0
  161. sage/symbolic/maxima_wrapper.py +162 -0
  162. sage/symbolic/operators.py +267 -0
  163. sage/symbolic/random_tests.py +462 -0
  164. sage/symbolic/relation.py +1907 -0
  165. sage/symbolic/ring.cpython-310-x86_64-linux-gnu.so +0 -0
  166. sage/symbolic/ring.pxd +5 -0
  167. sage/symbolic/ring.pyx +1396 -0
  168. sage/symbolic/subring.py +1025 -0
  169. sage/symbolic/symengine.py +19 -0
  170. sage/symbolic/tests.py +40 -0
  171. sage/symbolic/units.py +1470 -0
@@ -0,0 +1,1507 @@
1
+ # sage_setup: distribution = sagemath-symbolics
2
+ r"""
3
+ Mixed Differential Forms
4
+
5
+ Let `M` and `N` be differentiable manifolds and `\varphi : M \longrightarrow N`
6
+ a differentiable map. A *mixed differential form along* `\varphi` is an element
7
+ of the graded algebra represented by
8
+ :class:`~sage.manifolds.differentiable.mixed_form_algebra.MixedFormAlgebra`.
9
+ Its homogeneous components consist of differential forms along `\varphi`. Mixed
10
+ forms are useful to represent characteristic classes and perform computations
11
+ of such.
12
+
13
+ AUTHORS:
14
+
15
+ - Michael Jung (2019) : initial version
16
+ """
17
+ # *****************************************************************************
18
+ # Copyright (C) 2019 Michael Jung <micjung@uni-potsdam.de>
19
+ #
20
+ # Distributed under the terms of the GNU General Public License (GPL)
21
+ # as published by the Free Software Foundation; either version 2 of
22
+ # the License, or (at your option) any later version.
23
+ # https://www.gnu.org/licenses/
24
+ # *****************************************************************************
25
+
26
+ from sage.misc.cachefunc import cached_method
27
+ from sage.rings.integer import Integer
28
+ from sage.structure.element import AlgebraElement, ModuleElementWithMutability
29
+
30
+
31
+ class MixedForm(AlgebraElement, ModuleElementWithMutability):
32
+ r"""
33
+ An instance of this class is a mixed form along some differentiable map
34
+ `\varphi: M \to N` between two differentiable manifolds `M` and `N`. More
35
+ precisely, a mixed form `a` along `\varphi: M \to N` can be considered as a
36
+ differentiable map
37
+
38
+ .. MATH::
39
+
40
+ a: M \longrightarrow \bigoplus^n_{k=0} T^{(0,k)}N,
41
+
42
+ where `T^{(0,k)}` denotes the tensor bundle of type `(0,k)`, `\bigoplus`
43
+ the Whitney sum and `n` the dimension of `N`, such that
44
+
45
+ .. MATH::
46
+
47
+ \forall x\in M, \quad a(x) \in \bigoplus^n_{k=0} \Lambda^k\left( T_{\varphi(x)}^* N \right),
48
+
49
+ where `\Lambda^k(T^*_{\varphi(x)} N)` is the `k`-th exterior power of the
50
+ dual of the tangent space `T_{\varphi(x)} N`. Thus, a mixed differential
51
+ form `a` consists of homogeneous components `a_i`, `i=0,1, \dots, n`, where
52
+ the `i`-th homogeneous component represents a differential form of
53
+ degree `i`.
54
+
55
+ The standard case of a mixed form *on* `M` corresponds to `M=N` with
56
+ `\varphi = \mathrm{Id}_M`.
57
+
58
+ INPUT:
59
+
60
+ - ``parent`` -- graded algebra of mixed forms represented by
61
+ :class:`~sage.manifolds.differentiable.mixed_form_algebra.MixedFormAlgebra`
62
+ where the mixed form ``self`` shall belong to
63
+ - ``comp`` -- (default: ``None``) homogeneous components of the mixed form
64
+ as a list; if none is provided, the components are set to innocent unnamed
65
+ differential forms
66
+ - ``name`` -- (default: ``None``) name given to the mixed form
67
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
68
+ mixed form; if none is provided, the LaTeX symbol is set to ``name``
69
+
70
+ EXAMPLES:
71
+
72
+ Initialize a mixed form on a 2-dimensional parallelizable differentiable
73
+ manifold::
74
+
75
+ sage: M = Manifold(2, 'M')
76
+ sage: c_xy.<x,y> = M.chart()
77
+ sage: e_xy = c_xy.frame()
78
+ sage: A = M.mixed_form(name='A'); A
79
+ Mixed differential form A on the 2-dimensional differentiable manifold M
80
+ sage: A.parent()
81
+ Graded algebra Omega^*(M) of mixed differential forms on the
82
+ 2-dimensional differentiable manifold M
83
+
84
+ The default way to specify the `i`-th homogeneous component
85
+ of a mixed form is by accessing it via ``A[i]`` or using :meth:`set_comp`::
86
+
87
+ sage: A = M.mixed_form(name='A')
88
+ sage: A[0].set_expr(x) # scalar field
89
+ sage: A.set_comp(1)[0] = y*x
90
+ sage: A.set_comp(2)[0,1] = y^2*x
91
+ sage: A.display() # display names
92
+ A = A_0 + A_1 + A_2
93
+ sage: A.display_expansion() # display expansion in basis
94
+ A = x + x*y dx + x*y^2 dx∧dy
95
+
96
+ Another way to define the homogeneous components is using predefined
97
+ differential forms::
98
+
99
+ sage: f = M.scalar_field(x, name='f'); f
100
+ Scalar field f on the 2-dimensional differentiable manifold M
101
+ sage: omega = M.diff_form(1, name='omega'); omega
102
+ 1-form omega on the 2-dimensional differentiable manifold M
103
+ sage: omega[e_xy,0] = y*x; omega.display()
104
+ omega = x*y dx
105
+ sage: eta = M.diff_form(2, name='eta'); eta
106
+ 2-form eta on the 2-dimensional differentiable manifold M
107
+ sage: eta[e_xy,0,1] = y^2*x; eta.display()
108
+ eta = x*y^2 dx∧dy
109
+
110
+ The components of a mixed form ``B`` can then be set as follows::
111
+
112
+ sage: B = M.mixed_form(name='B')
113
+ sage: B[:] = [f, omega, eta]; B.display() # display names
114
+ B = f + omega + eta
115
+ sage: B.display_expansion() # display in coordinates
116
+ B = x + x*y dx + x*y^2 dx∧dy
117
+ sage: B[0]
118
+ Scalar field f on the 2-dimensional differentiable manifold M
119
+ sage: B[1]
120
+ 1-form omega on the 2-dimensional differentiable manifold M
121
+ sage: B[2]
122
+ 2-form eta on the 2-dimensional differentiable manifold M
123
+
124
+ As we can see, the names are applied. However note that the differential
125
+ forms are different instances::
126
+
127
+ sage: f is B[0]
128
+ False
129
+
130
+ Alternatively, the components can be determined from scratch::
131
+
132
+ sage: B = M.mixed_form([f, omega, eta], name='B')
133
+ sage: B.display()
134
+ B = f + omega + eta
135
+
136
+ Mixed forms are elements of an algebra so they can be added, and multiplied
137
+ via the wedge product::
138
+
139
+ sage: C = x*A; C
140
+ Mixed differential form x∧A on the 2-dimensional differentiable
141
+ manifold M
142
+ sage: C.display_expansion()
143
+ x∧A = x^2 + x^2*y dx + x^2*y^2 dx∧dy
144
+ sage: D = A+C; D
145
+ Mixed differential form A+x∧A on the 2-dimensional differentiable
146
+ manifold M
147
+ sage: D.display_expansion()
148
+ A+x∧A = x^2 + x + (x^2 + x)*y dx + (x^2 + x)*y^2 dx∧dy
149
+ sage: E = A*C; E
150
+ Mixed differential form A∧(x∧A) on the 2-dimensional differentiable
151
+ manifold M
152
+ sage: E.display_expansion()
153
+ A∧(x∧A) = x^3 + 2*x^3*y dx + 2*x^3*y^2 dx∧dy
154
+
155
+ Coercions are fully implemented::
156
+
157
+ sage: F = omega*A
158
+ sage: F.display_expansion()
159
+ omega∧A = x^2*y dx
160
+ sage: G = omega+A
161
+ sage: G.display_expansion()
162
+ omega+A = x + 2*x*y dx + x*y^2 dx∧dy
163
+
164
+ Moreover, it is possible to compute the exterior derivative of a
165
+ mixed form::
166
+
167
+ sage: dA = A.exterior_derivative(); dA.display()
168
+ dA = zero + dA_0 + dA_1
169
+ sage: dA.display_expansion()
170
+ dA = dx - x dx∧dy
171
+
172
+ Initialize a mixed form on a 2-dimensional non-parallelizable differentiable
173
+ manifold::
174
+
175
+ sage: M = Manifold(2, 'M')
176
+ sage: U = M.open_subset('U') ; V = M.open_subset('V')
177
+ sage: M.declare_union(U,V) # M is the union of U and V
178
+ sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
179
+ sage: transf = c_xy.transition_map(c_uv, (x+y, x-y),
180
+ ....: intersection_name='W', restrictions1= x>0,
181
+ ....: restrictions2= u+v>0)
182
+ sage: inv = transf.inverse()
183
+ sage: W = U.intersection(V)
184
+ sage: e_xy = c_xy.frame(); e_uv = c_uv.frame() # define frames
185
+ sage: A = M.mixed_form(name='A')
186
+ sage: A[0].set_expr(x, c_xy)
187
+ sage: A[0].display()
188
+ A_0: M → ℝ
189
+ on U: (x, y) ↦ x
190
+ on W: (u, v) ↦ 1/2*u + 1/2*v
191
+ sage: A[1][0] = y*x; A[1].display(e_xy)
192
+ A_1 = x*y dx
193
+ sage: A[2][e_uv,0,1] = u*v^2; A[2].display(e_uv)
194
+ A_2 = u*v^2 du∧dv
195
+ sage: A.add_comp_by_continuation(e_uv, W, c_uv)
196
+ sage: A.display_expansion(e_uv)
197
+ A = 1/2*u + 1/2*v + (1/8*u^2 - 1/8*v^2) du + (1/8*u^2 - 1/8*v^2) dv + u*v^2 du∧dv
198
+ sage: A.add_comp_by_continuation(e_xy, W, c_xy)
199
+ sage: A.display_expansion(e_xy)
200
+ A = x + x*y dx + (-2*x^3 + 2*x^2*y + 2*x*y^2 - 2*y^3) dx∧dy
201
+
202
+ Since zero and one are special elements, their components cannot be
203
+ changed::
204
+
205
+ sage: z = M.mixed_form_algebra().zero()
206
+ sage: z[0] = 1
207
+ Traceback (most recent call last):
208
+ ...
209
+ ValueError: the components of an immutable element cannot be changed
210
+ sage: one = M.mixed_form_algebra().one()
211
+ sage: one[0] = 0
212
+ Traceback (most recent call last):
213
+ ...
214
+ ValueError: the components of an immutable element cannot be changed
215
+ """
216
+ def __init__(self, parent, name=None, latex_name=None):
217
+ r"""
218
+ Construct a mixed form.
219
+
220
+ TESTS::
221
+
222
+ sage: M = Manifold(2, 'M')
223
+ sage: U = M.open_subset('U') ; V = M.open_subset('V')
224
+ sage: M.declare_union(U,V)
225
+ sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
226
+ sage: transf = c_xy.transition_map(c_uv, (x+y, x-y),
227
+ ....: intersection_name='W', restrictions1= x>0,
228
+ ....: restrictions2= u+v>0)
229
+ sage: inv = transf.inverse()
230
+ sage: W = U.intersection(V)
231
+ sage: e_xy = c_xy.frame(); e_uv = c_uv.frame()
232
+ sage: omega = M.diff_form(1, name='omega')
233
+ sage: omega[e_xy,0] = y*x
234
+ sage: omega.add_comp_by_continuation(e_uv, W, c_uv)
235
+ sage: eta = M.diff_form(2, name='eta')
236
+ sage: eta[e_uv,0,1] = u*v^2
237
+ sage: eta.add_comp_by_continuation(e_xy, W, c_xy)
238
+ sage: A = M.mixed_form_algebra()
239
+ sage: F = A([x, omega, eta], name='F')
240
+ sage: TestSuite(F).run(skip='_test_pickling')
241
+ """
242
+ if parent is None:
243
+ raise ValueError("a parent must be provided")
244
+ # Add this element (instance) to the set of parent algebra:
245
+ AlgebraElement.__init__(self, parent)
246
+ # Get the underlying vector field module:
247
+ vmodule = parent._vmodule
248
+ # Define attributes:
249
+ self._vmodule = vmodule
250
+ self._dest_map = vmodule._dest_map
251
+ self._domain = vmodule._domain
252
+ self._ambient_domain = vmodule._ambient_domain
253
+ self._max_deg = vmodule._ambient_domain.dim()
254
+ self._is_zero = False # a priori, may be changed below or via
255
+ # method __bool__()
256
+ self._comp = None # initialized on demand; see _init_comp
257
+ # Set names:
258
+ self._name = name
259
+ if latex_name is None:
260
+ self._latex_name = self._name
261
+ else:
262
+ self._latex_name = latex_name
263
+
264
+ def _init_comp(self):
265
+ r"""
266
+ Initialize homogeneous components of ``self``.
267
+
268
+ TESTS::
269
+
270
+ sage: M = Manifold(2, 'M')
271
+ sage: A = M.mixed_form(name='A')
272
+ sage: A._comp is None
273
+ True
274
+ sage: A._init_comp()
275
+ sage: A._comp
276
+ [Scalar field A_0 on the 2-dimensional differentiable manifold M,
277
+ 1-form A_1 on the 2-dimensional differentiable manifold M,
278
+ 2-form A_2 on the 2-dimensional differentiable manifold M]
279
+ """
280
+ self._comp = []
281
+ for i in self.irange():
282
+ comp_name, comp_latex_name = None, None
283
+ if self._name is not None:
284
+ comp_name = f"{self._name}_{i}"
285
+ if self._latex_name is not None:
286
+ comp_latex_name = '{' + self._latex_name + '}_{' + str(i) + '}'
287
+ diff_form = self._domain.diff_form
288
+ self._comp.append(diff_form(i, name=comp_name,
289
+ latex_name=comp_latex_name))
290
+
291
+ def _repr_(self):
292
+ r"""
293
+ String representation of ``self``.
294
+
295
+ TESTS::
296
+
297
+ sage: M = Manifold(3, 'M')
298
+ sage: F = M.mixed_form(name='F')
299
+ sage: F._repr_()
300
+ 'Mixed differential form F on the 3-dimensional differentiable
301
+ manifold M'
302
+ sage: repr(F) # indirect doctest
303
+ 'Mixed differential form F on the 3-dimensional differentiable
304
+ manifold M'
305
+
306
+ Check whether :issue:`31784` is fixed::
307
+
308
+ sage: E3 = EuclideanSpace(3)
309
+ sage: S2 = E3.sphere()
310
+ sage: iota = S2.embedding()
311
+ sage: Omega = S2.mixed_form_algebra(dest_map=iota)
312
+ sage: Omega(1)
313
+ Mixed differential form one along the 2-sphere S^2 of radius 1
314
+ smoothly embedded in the Euclidean space E^3 with values on the
315
+ Euclidean space E^3 via the map iota
316
+ """
317
+ desc = "Mixed differential form "
318
+ if self._name is not None:
319
+ desc += self._name + " "
320
+ if self._dest_map is self._domain.identity_map():
321
+ desc += f"on the {self._domain}"
322
+ else:
323
+ desc += f"along the {self._domain} with values on the {self._ambient_domain} "
324
+ if self._dest_map._name is None:
325
+ dm_name = "unnamed map"
326
+ else:
327
+ dm_name = self._dest_map._name
328
+ desc += "via the map " + dm_name
329
+ return desc
330
+
331
+ def _latex_(self):
332
+ r"""
333
+ Return a LaTeX representation of the object.
334
+
335
+ TESTS::
336
+
337
+ sage: M = Manifold(3, 'M', latex_name=r'\mathcal{M}')
338
+ sage: omega = M.mixed_form(name='omega', latex_name=r'\omega')
339
+ sage: omega._latex_()
340
+ '\\omega'
341
+ sage: latex(omega) # indirect doctest
342
+ \omega
343
+ """
344
+ if self._name is None:
345
+ return r'\text{' + repr(self) + r'}'
346
+ else:
347
+ return self._latex_name
348
+
349
+ def _new_instance(self, name=None, latex_name=None):
350
+ r"""
351
+ Return a new instance of ``self``.
352
+
353
+ TESTS::
354
+
355
+ sage: M = Manifold(2, 'M')
356
+ sage: F = M.mixed_form(name='F')
357
+ sage: F1 = F._new_instance(); F1
358
+ Mixed differential form on the 2-dimensional differentiable
359
+ manifold M
360
+ sage: type(F1) == type(F)
361
+ True
362
+ sage: F1.parent() is F.parent()
363
+ True
364
+ """
365
+ return type(self)(self.parent(), name=name, latex_name=latex_name)
366
+
367
+ def display_expansion(self, frame=None, chart=None, from_chart=None):
368
+ r"""
369
+ Display the expansion in a particular basis and chart of mixed forms.
370
+
371
+ The output is either text-formatted (console mode) or LaTeX-formatted
372
+ (notebook mode).
373
+
374
+ INPUT:
375
+
376
+ - ``frame`` -- (default: ``None``) vector frame with respect to
377
+ which the mixed form is expanded; if ``None``, only the names
378
+ of the components are displayed
379
+ - ``chart`` -- (default: ``None``) chart with respect to which the
380
+ components of the mixed form in the selected frame are expressed;
381
+ if ``None``, the default chart of the vector frame domain is assumed
382
+
383
+ EXAMPLES:
384
+
385
+ Display the expansion of a mixed form on a 2-dimensional
386
+ non-parallelizable differentiable manifold::
387
+
388
+ sage: M = Manifold(2, 'M')
389
+ sage: U = M.open_subset('U') ; V = M.open_subset('V')
390
+ sage: M.declare_union(U,V) # M is the union of U and V
391
+ sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
392
+ sage: transf = c_xy.transition_map(c_uv, (x-y, x+y),
393
+ ....: intersection_name='W', restrictions1= x>0,
394
+ ....: restrictions2= u+v>0)
395
+ sage: inv = transf.inverse()
396
+ sage: W = U.intersection(V)
397
+ sage: e_xy = c_xy.frame(); e_uv = c_uv.frame() # define frames
398
+ sage: omega = M.diff_form(1, name='omega')
399
+ sage: omega[e_xy,0] = x; omega.display(e_xy)
400
+ omega = x dx
401
+ sage: omega.add_comp_by_continuation(e_uv, W, c_uv) # continuation onto M
402
+ sage: eta = M.diff_form(2, name='eta')
403
+ sage: eta[e_uv,0,1] = u*v; eta.display(e_uv)
404
+ eta = u*v du∧dv
405
+ sage: eta.add_comp_by_continuation(e_xy, W, c_xy) # continuation onto M
406
+ sage: F = M.mixed_form([0, omega, eta], name='F'); F
407
+ Mixed differential form F on the 2-dimensional differentiable
408
+ manifold M
409
+ sage: F.display() # display names of homogeneous components
410
+ F = zero + omega + eta
411
+ sage: F.display_expansion(e_uv)
412
+ F = (1/4*u + 1/4*v) du + (1/4*u + 1/4*v) dv + u*v du∧dv
413
+ sage: F.display_expansion(e_xy)
414
+ F = x dx + (2*x^2 - 2*y^2) dx∧dy
415
+ """
416
+ from sage.misc.latex import latex
417
+ from sage.tensor.modules.format_utilities import FormattedExpansion, is_atomic
418
+ from sage.typeset.unicode_characters import unicode_wedge
419
+ # In case, no frame is given:
420
+ if frame is None:
421
+ frame = self._domain._def_frame
422
+ # In case, no chart is given:
423
+ if chart is None:
424
+ chart = frame._chart
425
+ # Check names:
426
+ if self._name is not None:
427
+ resu_txt = self._name + " = "
428
+ else:
429
+ resu_txt = ""
430
+ if self._latex_name is not None:
431
+ resu_latex = self._latex_name + r" = "
432
+ else:
433
+ resu_latex = ""
434
+ # Get terms
435
+ terms_txt = []
436
+ terms_latex = []
437
+ # Scalar field term:
438
+ if not self[0].is_trivial_zero():
439
+ terms_txt.append(repr(self[0].expr(chart, from_chart)))
440
+ terms_latex.append(latex(self[0].expr(chart, from_chart)))
441
+ # Differential form terms:
442
+ for j in self.irange(1):
443
+ rst = self[j].restrict(frame._domain, dest_map=frame._dest_map)
444
+ basis, format_spec = rst._preparse_display(basis=frame,
445
+ format_spec=chart)
446
+ cobasis = basis.dual_basis()
447
+ comp = rst.comp(basis)
448
+ for ind in comp.non_redundant_index_generator():
449
+ ind_arg = ind + (format_spec,)
450
+ coef = comp[ind_arg]
451
+ # Check whether the coefficient is zero, preferably via
452
+ # the fast method is_trivial_zero():
453
+ if hasattr(coef, 'is_trivial_zero'):
454
+ zero_coef = coef.is_trivial_zero()
455
+ else:
456
+ zero_coef = coef == 0
457
+ if not zero_coef:
458
+ bases_txt = []
459
+ bases_latex = []
460
+ for k in range(rst._tensor_rank):
461
+ bases_txt.append(cobasis[ind[k]]._name)
462
+ bases_latex.append(latex(cobasis[ind[k]]))
463
+ basis_term_txt = unicode_wedge.join(bases_txt)
464
+ basis_term_latex = r"\wedge ".join(bases_latex)
465
+ coef_txt = repr(coef)
466
+ if coef_txt == "1":
467
+ terms_txt.append(basis_term_txt)
468
+ terms_latex.append(basis_term_latex)
469
+ elif coef_txt == "-1":
470
+ terms_txt.append("-" + basis_term_txt)
471
+ terms_latex.append("-" + basis_term_latex)
472
+ else:
473
+ coef_latex = latex(coef)
474
+ if is_atomic(coef_txt):
475
+ terms_txt.append(coef_txt + " " + basis_term_txt)
476
+ else:
477
+ terms_txt.append("(" + coef_txt + ") " +
478
+ basis_term_txt)
479
+ if is_atomic(coef_latex):
480
+ terms_latex.append(coef_latex + basis_term_latex)
481
+ else:
482
+ terms_latex.append(r"\left(" + coef_latex +
483
+ r"\right)" + basis_term_latex)
484
+ if not terms_txt:
485
+ resu_txt += "0"
486
+ else:
487
+ resu_txt += terms_txt[0]
488
+ for term in terms_txt[1:]:
489
+ if term[0] == "-":
490
+ resu_txt += " - " + term[1:]
491
+ else:
492
+ resu_txt += " + " + term
493
+ if not terms_latex:
494
+ resu_latex += "0"
495
+ else:
496
+ resu_latex += terms_latex[0]
497
+ for term in terms_latex[1:]:
498
+ if term[0] == "-":
499
+ resu_latex += term
500
+ else:
501
+ resu_latex += "+" + term
502
+ return FormattedExpansion(resu_txt, resu_latex)
503
+
504
+ disp_exp = display_expansion
505
+ display_exp = display_expansion
506
+
507
+ def display(self):
508
+ r"""
509
+ Display the homogeneous components of the mixed form.
510
+
511
+ The output is either text-formatted (console mode) or LaTeX-formatted
512
+ (notebook mode).
513
+
514
+ EXAMPLES::
515
+
516
+ sage: M = Manifold(2, 'M')
517
+ sage: f = M.scalar_field(name='f')
518
+ sage: omega = M.diff_form(1, name='omega')
519
+ sage: eta = M.diff_form(2, name='eta')
520
+ sage: F = M.mixed_form([f, omega, eta], name='F'); F
521
+ Mixed differential form F on the 2-dimensional differentiable
522
+ manifold M
523
+ sage: F.display() # display names of homogeneous components
524
+ F = f + omega + eta
525
+ """
526
+ from sage.misc.latex import latex
527
+ from sage.tensor.modules.format_utilities import FormattedExpansion
528
+ # Mixed form name:
529
+ if self._name is not None:
530
+ resu_txt = self._name + " = "
531
+ else:
532
+ resu_txt = ""
533
+ if self._latex_name is not None:
534
+ resu_latex = self._latex_name + r" = "
535
+ else:
536
+ resu_latex = ""
537
+ # Scalar field:
538
+ if self[0]._name is None:
539
+ resu_txt += "(unnamed scalar field) "
540
+ else:
541
+ resu_txt += self[0]._name
542
+ if self[0]._latex_name is None:
543
+ resu_latex += r"\text{(unnamed scalar field)}"
544
+ else:
545
+ resu_latex += latex(self[0])
546
+ # Differential forms:
547
+ for j in self.irange(1):
548
+ if self[j]._name is None:
549
+ resu_txt += " + (unnamed " + str(j) + "-form)"
550
+ else:
551
+ resu_txt += " + " + self[j]._name
552
+ if self[j]._latex_name is None:
553
+ resu_latex += r"+\text{(unnamed " + str(j) + r"-form)}"
554
+ else:
555
+ resu_latex += r"+" + latex(self[j])
556
+ return FormattedExpansion(resu_txt, resu_latex)
557
+
558
+ disp = display
559
+
560
+ def set_name(self, name=None, latex_name=None, apply_to_comp=True):
561
+ r"""
562
+ Redefine the string and LaTeX representation of the object.
563
+
564
+ INPUT:
565
+
566
+ - ``name`` -- (default: ``None``) name given to the mixed form
567
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
568
+ mixed form; if none is provided, the LaTeX symbol is set to ``name``
569
+ - ``apply_to_comp`` -- boolean (default: ``True``); if ``True`` all homogeneous
570
+ components will be renamed accordingly. If ``False`` only the mixed
571
+ form will be renamed
572
+
573
+ EXAMPLES:
574
+
575
+ Rename a mixed form::
576
+
577
+ sage: M = Manifold(4, 'M')
578
+ sage: F = M.mixed_form(name='dummy', latex_name=r'\ugly'); F
579
+ Mixed differential form dummy on the 4-dimensional differentiable
580
+ manifold M
581
+ sage: latex(F)
582
+ \ugly
583
+ sage: F.set_name(name='F', latex_name=r'\mathcal{F}'); F
584
+ Mixed differential form F on the 4-dimensional differentiable
585
+ manifold M
586
+ sage: latex(F)
587
+ \mathcal{F}
588
+
589
+ If not stated otherwise, all homogeneous components are renamed
590
+ accordingly::
591
+
592
+ sage: F.display()
593
+ F = F_0 + F_1 + F_2 + F_3 + F_4
594
+
595
+ Setting the argument ``set_all`` to ``False`` prevents the renaming
596
+ in the homogeneous components::
597
+
598
+ sage: F.set_name(name='eta', latex_name=r'\eta', apply_to_comp=False)
599
+ sage: F.display()
600
+ eta = F_0 + F_1 + F_2 + F_3 + F_4
601
+
602
+ To rename a homogeneous component individually, we simply access the
603
+ homogeneous component and use its
604
+ :meth:`~sage.manifolds.differentiable.tensorfield.set_name` method::
605
+
606
+ sage: F[0].set_name(name='g'); F.display()
607
+ eta = g + F_1 + F_2 + F_3 + F_4
608
+ """
609
+ if self.is_immutable():
610
+ raise ValueError("the name of an immutable element "
611
+ "cannot be changed")
612
+ if name is not None:
613
+ self._name = name
614
+ if latex_name is None:
615
+ self._latex_name = self._name
616
+ if latex_name is not None:
617
+ self._latex_name = latex_name
618
+ if apply_to_comp:
619
+ for i in self.irange():
620
+ comp_name, comp_latex_name = None, None
621
+ if self._name is not None:
622
+ comp_name = f"{self._name}_{i}"
623
+ if self._latex_name is not None:
624
+ comp_latex_name = '{' + self._latex_name + '}_{' + str(i) + '}'
625
+ self[i].set_name(name=comp_name, latex_name=comp_latex_name)
626
+
627
+ def __bool__(self):
628
+ r"""
629
+ Return ``True`` if ``self`` is nonzero and ``False`` otherwise.
630
+
631
+ This method is called by :meth:`is_zero`.
632
+
633
+ EXAMPLES:
634
+
635
+ Mixed form defined by parts on a 2-dimensional manifold::
636
+
637
+ sage: M = Manifold(2, 'M')
638
+ sage: U = M.open_subset('U')
639
+ sage: c_xy.<x,y> = U.chart()
640
+ sage: V = M.open_subset('V')
641
+ sage: c_uv.<u,v> = V.chart()
642
+ sage: M.declare_union(U,V) # M is the union of U and V
643
+ sage: F = M.mixed_form(name='F')
644
+ sage: FU = U.mixed_form(name='F')
645
+ sage: FV = V.mixed_form(name='F')
646
+ sage: FU[:] = [0,0,0]
647
+ sage: FV[:] = [0,0,0]
648
+ sage: F.set_restriction(FU)
649
+ sage: F.set_restriction(FV)
650
+ sage: bool(F)
651
+ False
652
+ sage: F.is_zero() # indirect doctest
653
+ True
654
+ sage: FU[0] = 1
655
+ sage: F.set_restriction(FU)
656
+ sage: bool(F)
657
+ True
658
+ sage: F.is_zero() # indirect doctest
659
+ False
660
+ """
661
+ if self._is_zero:
662
+ return False
663
+ if any(bool(form) for form in self):
664
+ self._is_zero = False
665
+ return True
666
+ self._is_zero = True
667
+ return False
668
+
669
+ def _richcmp_(self, other, op):
670
+ r"""
671
+ Comparison method for sage objects.
672
+
673
+ INPUT:
674
+
675
+ - ``other`` -- a mixed form
676
+ - ``op`` -- comparison operator for which ``self`` and ``other`` shall
677
+ be compared with
678
+
679
+ TESTS::
680
+
681
+ sage: M = Manifold(2, 'M')
682
+ sage: U = M.open_subset('U') ; V = M.open_subset('V')
683
+ sage: M.declare_union(U,V) # M is the union of U and V
684
+ sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
685
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y),
686
+ ....: intersection_name='W', restrictions1= x>0,
687
+ ....: restrictions2= u+v>0)
688
+ sage: uv_to_xy = xy_to_uv.inverse()
689
+ sage: W = U.intersection(V)
690
+ sage: e_xy = c_xy.frame(); e_uv = c_uv.frame()
691
+ sage: f = M.scalar_field(x, name='f')
692
+ sage: f.add_expr_by_continuation(c_uv, W)
693
+ sage: eta = M.diff_form(1, name='eta')
694
+ sage: eta[e_xy,0] = x+y
695
+ sage: eta.add_comp_by_continuation(e_uv, W, c_uv)
696
+ sage: F = M.mixed_form([f, eta, 0])
697
+ sage: F == F
698
+ True
699
+ sage: F == F.copy()
700
+ True
701
+ sage: G = M.mixed_form()
702
+ sage: G.set_restriction(F.restrict(U))
703
+ sage: F == G # False since G has not been defined on V
704
+ False
705
+ sage: G.set_restriction(F.restrict(V))
706
+ sage: F == G # ``True`` now
707
+ True
708
+ sage: H = M.mixed_form([f, 0, 0])
709
+ sage: F != H # this is fixed by issue #30108
710
+ True
711
+ sage: F.parent().zero() == 0
712
+ True
713
+ """
714
+ from sage.structure.richcmp import op_EQ, op_NE
715
+ if op == op_NE:
716
+ return not self == other
717
+ elif op == op_EQ:
718
+ # Compare all elements separately:
719
+ return all(self[j] == other[j] for j in self.irange())
720
+ # Fall back on default implementation:
721
+ return super()._richcmp_(self, other, op)
722
+
723
+ def _add_(self, other):
724
+ r"""
725
+ Addition of two mixed forms.
726
+
727
+ INPUT:
728
+
729
+ - ``other`` -- a mixed form, in the same algebra as ``self``
730
+
731
+ OUTPUT:
732
+
733
+ - the mixed form resulting from the addition of ``self``
734
+ and ``other``
735
+
736
+ TESTS::
737
+
738
+ sage: M = Manifold(2, 'M')
739
+ sage: U = M.open_subset('U') ; V = M.open_subset('V')
740
+ sage: M.declare_union(U,V) # M is the union of U and V
741
+ sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
742
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y),
743
+ ....: intersection_name='W', restrictions1= x>0,
744
+ ....: restrictions2= u+v>0)
745
+ sage: uv_to_xy = xy_to_uv.inverse()
746
+ sage: W = U.intersection(V)
747
+ sage: e_xy = c_xy.frame(); e_uv = c_uv.frame()
748
+ sage: f = M.scalar_field(x, name='f')
749
+ sage: f.add_expr_by_continuation(c_uv, W) # continuation onto M
750
+ sage: a = M.diff_form(1, name='a')
751
+ sage: a[e_xy,0] = x
752
+ sage: a.add_comp_by_continuation(e_uv, W, c_uv) # continuation onto M
753
+ sage: A = M.mixed_form([f, a, 0], name='A')
754
+ sage: g = M.scalar_field(u, name='g', chart=c_uv)
755
+ sage: g.add_expr_by_continuation(c_xy, W) # continuation onto M
756
+ sage: b = M.diff_form(1, name='b')
757
+ sage: b[e_uv,1] = v
758
+ sage: b.add_comp_by_continuation(e_xy, W, c_xy) # continuation onto M
759
+ sage: B = M.mixed_form([g, b, 0], name='B')
760
+ sage: C = A._add_(B); C
761
+ Mixed differential form A+B on the 2-dimensional differentiable
762
+ manifold M
763
+ sage: A.display_expansion(e_uv)
764
+ A = 1/2*u + 1/2*v + (1/4*u + 1/4*v) du + (1/4*u + 1/4*v) dv
765
+ sage: B.display_expansion(e_xy)
766
+ B = x + y + (x - y) dx + (-x + y) dy
767
+ sage: C.display_expansion(e_xy)
768
+ A+B = 2*x + y + (2*x - y) dx + (-x + y) dy
769
+ sage: C.display_expansion(e_uv)
770
+ A+B = 3/2*u + 1/2*v + (1/4*u + 1/4*v) du + (1/4*u + 5/4*v) dv
771
+ sage: C == A + B # indirect doctest
772
+ True
773
+ sage: Z = A.parent().zero(); Z
774
+ Mixed differential form zero on the 2-dimensional differentiable
775
+ manifold M
776
+ sage: A._add_(Z) == A
777
+ True
778
+ sage: Z._add_(A) == A
779
+ True
780
+ """
781
+ # Case zero:
782
+ if self._is_zero:
783
+ return other
784
+ if other._is_zero:
785
+ return self
786
+ # Generic case:
787
+ resu = self._new_instance()
788
+ resu._comp = [self[j] + other[j] for j in self.irange()]
789
+ # Compose name:
790
+ if self._name is not None and other._name is not None:
791
+ resu._name = self._name + '+' + other._name
792
+ if self._latex_name is not None and other._latex_name is not None:
793
+ resu._latex_name = self._latex_name + '+' + other._latex_name
794
+ return resu
795
+
796
+ def _sub_(self, other):
797
+ r"""
798
+ Subtraction of two mixed forms.
799
+
800
+ INPUT:
801
+
802
+ - ``other`` -- a mixed form, in the same algebra as ``self``
803
+
804
+ OUTPUT:
805
+
806
+ - the mixed form resulting from the subtraction of ``self``
807
+ and ``other``
808
+
809
+ TESTS::
810
+
811
+ sage: M = Manifold(2, 'M')
812
+ sage: U = M.open_subset('U') ; V = M.open_subset('V')
813
+ sage: M.declare_union(U,V) # M is the union of U and V
814
+ sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
815
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y),
816
+ ....: intersection_name='W', restrictions1= x>0,
817
+ ....: restrictions2= u+v>0)
818
+ sage: uv_to_xy = xy_to_uv.inverse()
819
+ sage: W = U.intersection(V)
820
+ sage: e_xy = c_xy.frame(); e_uv = c_uv.frame()
821
+ sage: f = M.scalar_field(x, name='f')
822
+ sage: f.add_expr_by_continuation(c_uv, W) # continuation onto M
823
+ sage: a = M.diff_form(1, name='a')
824
+ sage: a[e_xy,0] = x
825
+ sage: a.add_comp_by_continuation(e_uv, W, c_uv) # continuation onto M
826
+ sage: A = M.mixed_form([f, a, 0], name='A')
827
+ sage: g = M.scalar_field(u, name='g', chart=c_uv)
828
+ sage: g.add_expr_by_continuation(c_xy, W) # continuation onto M
829
+ sage: b = M.diff_form(1, name='b')
830
+ sage: b[e_uv,1] = v
831
+ sage: b.add_comp_by_continuation(e_xy, W, c_xy) # continuation onto M
832
+ sage: B = M.mixed_form([g, b, 0], name='B')
833
+ sage: C = A._sub_(B); C
834
+ Mixed differential form A-B on the 2-dimensional differentiable
835
+ manifold M
836
+ sage: A.display_expansion(e_uv)
837
+ A = 1/2*u + 1/2*v + (1/4*u + 1/4*v) du + (1/4*u + 1/4*v) dv
838
+ sage: B.display_expansion(e_xy)
839
+ B = x + y + (x - y) dx + (-x + y) dy
840
+ sage: C.display_expansion(e_xy)
841
+ A-B = -y + y dx + (x - y) dy
842
+ sage: C.display_expansion(e_uv)
843
+ A-B = -1/2*u + 1/2*v + (1/4*u + 1/4*v) du + (1/4*u - 3/4*v) dv
844
+ sage: C == A - B # indirect doctest
845
+ True
846
+ sage: Z = A.parent().zero(); Z
847
+ Mixed differential form zero on the 2-dimensional differentiable
848
+ manifold M
849
+ sage: A._sub_(Z) == A
850
+ True
851
+ sage: Z._sub_(A) == -A
852
+ True
853
+ """
854
+ # Case zero:
855
+ if self._is_zero:
856
+ return -other
857
+ if other._is_zero:
858
+ return self
859
+ # Generic case:
860
+ resu = self._new_instance()
861
+ resu._comp = [self[j] - other[j] for j in self.irange()]
862
+ # Compose name:
863
+ from sage.tensor.modules.format_utilities import is_atomic
864
+
865
+ if self._name is not None and other._name is not None:
866
+ sname = self._name
867
+ oname = other._name
868
+ if not is_atomic(oname):
869
+ oname = '(' + oname + ')'
870
+ resu._name = sname + '-' + oname
871
+ if self._latex_name is not None and other._latex_name is not None:
872
+ slname = self._latex_name
873
+ olname = other._latex_name
874
+ if not is_atomic(olname):
875
+ olname = '(' + olname + ')'
876
+ resu._latex_name = slname + '-' + olname
877
+ return resu
878
+
879
+ def wedge(self, other):
880
+ r"""
881
+ Wedge product on the graded algebra of mixed forms.
882
+
883
+ More precisely, the wedge product is a bilinear map
884
+
885
+ .. MATH::
886
+
887
+ \wedge: \Omega^k(M,\varphi) \times \Omega^l(M,\varphi) \to \Omega^{k+l}(M,\varphi),
888
+
889
+ where `\Omega^k(M,\varphi)` denotes the space of differential forms of
890
+ degree `k` along `\varphi`. By bilinear extension, this induces a map
891
+
892
+ .. MATH::
893
+
894
+ \wedge: \Omega^*(M,\varphi) \times \Omega^*(M,\varphi) \to \Omega^*(M,\varphi) ``
895
+
896
+ and equips `\Omega^*(M,\varphi)` with a multiplication such that it
897
+ becomes a graded algebra.
898
+
899
+ INPUT:
900
+
901
+ - ``other`` -- mixed form in the same algebra as ``self``
902
+
903
+ OUTPUT:
904
+
905
+ - the mixed form resulting from the wedge product of ``self``
906
+ with ``other``
907
+
908
+ EXAMPLES:
909
+
910
+ Initialize a mixed form on a 3-dimensional manifold::
911
+
912
+ sage: M = Manifold(3, 'M')
913
+ sage: c_xyz.<x,y,z> = M.chart()
914
+ sage: f = M.scalar_field(x, name='f')
915
+ sage: f.display()
916
+ f: M → ℝ
917
+ (x, y, z) ↦ x
918
+ sage: g = M.scalar_field(y, name='g')
919
+ sage: g.display()
920
+ g: M → ℝ
921
+ (x, y, z) ↦ y
922
+ sage: omega = M.diff_form(1, name='omega')
923
+ sage: omega[0] = x
924
+ sage: omega.display()
925
+ omega = x dx
926
+ sage: eta = M.diff_form(1, name='eta')
927
+ sage: eta[1] = y
928
+ sage: eta.display()
929
+ eta = y dy
930
+ sage: mu = M.diff_form(2, name='mu')
931
+ sage: mu[0,2] = z
932
+ sage: mu.display()
933
+ mu = z dx∧dz
934
+ sage: A = M.mixed_form([f, omega, mu, 0], name='A')
935
+ sage: A.display_expansion()
936
+ A = x + x dx + z dx∧dz
937
+ sage: B = M.mixed_form([g, eta, mu, 0], name='B')
938
+ sage: B.display_expansion()
939
+ B = y + y dy + z dx∧dz
940
+
941
+ The wedge product of ``A`` and ``B`` yields::
942
+
943
+ sage: C = A.wedge(B); C
944
+ Mixed differential form A∧B on the 3-dimensional differentiable
945
+ manifold M
946
+ sage: C.display_expansion()
947
+ A∧B = x*y + x*y dx + x*y dy + x*y dx∧dy + (x + y)*z dx∧dz - y*z dx∧dy∧dz
948
+ sage: D = B.wedge(A); D # Don't even try, it's not commutative!
949
+ Mixed differential form B∧A on the 3-dimensional differentiable
950
+ manifold M
951
+ sage: D.display_expansion() # I told you so!
952
+ B∧A = x*y + x*y dx + x*y dy - x*y dx∧dy + (x + y)*z dx∧dz - y*z dx∧dy∧dz
953
+
954
+ Alternatively, the multiplication symbol can be used::
955
+
956
+ sage: A*B
957
+ Mixed differential form A∧B on the 3-dimensional differentiable
958
+ manifold M
959
+ sage: A*B == C
960
+ True
961
+
962
+ Yet, the multiplication includes coercions::
963
+
964
+ sage: E = x*A; E.display_expansion()
965
+ x∧A = x^2 + x^2 dx + x*z dx∧dz
966
+ sage: F = A*eta; F.display_expansion()
967
+ A∧eta = x*y dy + x*y dx∧dy - y*z dx∧dy∧dz
968
+ """
969
+ # Case zero:
970
+ if self._is_zero or other._is_zero:
971
+ return self.parent().zero()
972
+ # Case one:
973
+ if self is self.parent().one():
974
+ return other
975
+ if other is self.parent().one():
976
+ return self
977
+ # Generic case:
978
+ resu = self._new_instance()
979
+ resu._comp = [sum(self[k].wedge(other[j - k]) for k in range(j + 1))
980
+ for j in self.irange()]
981
+ # Compose name:
982
+ from sage.tensor.modules.format_utilities import (
983
+ format_mul_latex,
984
+ format_mul_txt,
985
+ )
986
+ from sage.typeset.unicode_characters import unicode_wedge
987
+ resu._name = format_mul_txt(self._name, unicode_wedge, other._name)
988
+ resu._latex_name = format_mul_latex(self._latex_name, r'\wedge ',
989
+ other._latex_name)
990
+ return resu
991
+
992
+ _mul_ = wedge
993
+
994
+ def _lmul_(self, other):
995
+ r"""
996
+ Scalar multiplication operator: return ``number * self`` or
997
+ ``self * number``.
998
+
999
+ INPUT:
1000
+
1001
+ - ``other`` -- an element of the symbolic ring
1002
+
1003
+ OUTPUT:
1004
+
1005
+ - the mixed form resulting from the wedge product of ``self``
1006
+ with ``other``
1007
+
1008
+ TESTS::
1009
+
1010
+ sage: M = Manifold(2, 'M')
1011
+ sage: c_xy.<x,y> = M.chart()
1012
+ sage: omega = M.diff_form(1, name='omega')
1013
+ sage: omega[0] = y*x; omega.display()
1014
+ omega = x*y dx
1015
+ sage: F = M.mixed_form([0, omega, 0], name='F')
1016
+ sage: A = x*F*y; A
1017
+ Mixed differential form y∧(x∧F) on the 2-dimensional
1018
+ differentiable manifold M
1019
+ sage: A.display_expansion()
1020
+ y∧(x∧F) = x^2*y^2 dx
1021
+ """
1022
+ try:
1023
+ if other.is_trivial_zero():
1024
+ return self.parent().zero()
1025
+ if (other - 1).is_trivial_zero():
1026
+ return self
1027
+ except AttributeError:
1028
+ # in case base ring is not SR:
1029
+ if other == 0:
1030
+ return self.parent().zero()
1031
+ if other == 1:
1032
+ return self
1033
+ resu = self._new_instance()
1034
+ resu._comp = [other * form for form in self]
1035
+ # Compose name:
1036
+ from sage.misc.latex import latex
1037
+ from sage.tensor.modules.format_utilities import (
1038
+ format_mul_latex,
1039
+ format_mul_txt,
1040
+ )
1041
+ from sage.typeset.unicode_characters import unicode_wedge
1042
+ resu._name = format_mul_txt(repr(other), unicode_wedge, self._name)
1043
+ resu._latex_name = format_mul_latex(latex(other), r'\wedge ',
1044
+ self._latex_name)
1045
+ return resu
1046
+
1047
+ @cached_method
1048
+ def exterior_derivative(self):
1049
+ r"""
1050
+ Compute the exterior derivative of ``self``.
1051
+
1052
+ More precisely, the *exterior derivative* on `\Omega^k(M,\varphi)` is a
1053
+ linear map
1054
+
1055
+ .. MATH::
1056
+
1057
+ \mathrm{d}_{k} : \Omega^k(M,\varphi) \to \Omega^{k+1}(M,\varphi),
1058
+
1059
+ where `\Omega^k(M,\varphi)` denotes the space of differential forms of
1060
+ degree `k` along `\varphi`
1061
+ (see :meth:`~sage.manifolds.differentiable.diff_form.DiffForm.exterior_derivative`
1062
+ for further information). By linear extension, this induces a map on
1063
+ `\Omega^*(M,\varphi)`:
1064
+
1065
+ .. MATH::
1066
+
1067
+ \mathrm{d}: \Omega^*(M,\varphi) \to \Omega^*(M,\varphi).
1068
+
1069
+ OUTPUT:
1070
+
1071
+ - a :class:`MixedForm` representing the exterior
1072
+ derivative of the mixed form
1073
+
1074
+ EXAMPLES:
1075
+
1076
+ Exterior derivative of a mixed form on a 3-dimensional manifold::
1077
+
1078
+ sage: M = Manifold(3, 'M', start_index=1)
1079
+ sage: c_xyz.<x,y,z> = M.chart()
1080
+ sage: f = M.scalar_field(z^2, name='f')
1081
+ sage: f.disp()
1082
+ f: M → ℝ
1083
+ (x, y, z) ↦ z^2
1084
+ sage: a = M.diff_form(2, 'a')
1085
+ sage: a[1,2], a[1,3], a[2,3] = z+y^2, z+x, x^2
1086
+ sage: a.disp()
1087
+ a = (y^2 + z) dx∧dy + (x + z) dx∧dz + x^2 dy∧dz
1088
+ sage: F = M.mixed_form([f, 0, a, 0], name='F'); F.display()
1089
+ F = f + zero + a + zero
1090
+ sage: dF = F.exterior_derivative()
1091
+ sage: dF.display()
1092
+ dF = zero + df + dzero + da
1093
+ sage: dF = F.exterior_derivative()
1094
+ sage: dF.display_expansion()
1095
+ dF = 2*z dz + (2*x + 1) dx∧dy∧dz
1096
+
1097
+ Due to long calculation times, the result is cached::
1098
+
1099
+ sage: F.exterior_derivative() is dF
1100
+ True
1101
+ """
1102
+ resu = self._new_instance()
1103
+ resu[0] = self._domain.zero_scalar_field()
1104
+ resu[1:] = [self[j].exterior_derivative()
1105
+ for j in range(self._max_deg)]
1106
+ # Compose name:
1107
+ from sage.tensor.modules.format_utilities import (
1108
+ format_unop_latex,
1109
+ format_unop_txt,
1110
+ )
1111
+ resu._name = format_unop_txt('d', self._name)
1112
+ resu._latex_name = format_unop_latex(r'\mathrm{d}', self._latex_name)
1113
+ return resu
1114
+
1115
+ derivative = exterior_derivative
1116
+
1117
+ def copy(self, name=None, latex_name=None):
1118
+ r"""
1119
+ Return an exact copy of ``self``.
1120
+
1121
+ .. NOTE::
1122
+
1123
+ The name and names of the components are not copied.
1124
+
1125
+ INPUT:
1126
+
1127
+ - ``name`` -- (default: ``None``) name given to the copy
1128
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
1129
+ copy; if none is provided, the LaTeX symbol is set to ``name``
1130
+
1131
+ EXAMPLES:
1132
+
1133
+ Initialize a 2-dimensional manifold and differential forms::
1134
+
1135
+ sage: M = Manifold(2, 'M')
1136
+ sage: U = M.open_subset('U') ; V = M.open_subset('V')
1137
+ sage: M.declare_union(U,V) # M is the union of U and V
1138
+ sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
1139
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y),
1140
+ ....: intersection_name='W', restrictions1= x>0,
1141
+ ....: restrictions2= u+v>0)
1142
+ sage: uv_to_xy = xy_to_uv.inverse()
1143
+ sage: W = U.intersection(V)
1144
+ sage: e_xy = c_xy.frame(); e_uv = c_uv.frame()
1145
+ sage: f = M.scalar_field(x, name='f', chart=c_xy)
1146
+ sage: f.add_expr_by_continuation(c_uv, W)
1147
+ sage: f.display()
1148
+ f: M → ℝ
1149
+ on U: (x, y) ↦ x
1150
+ on V: (u, v) ↦ 1/2*u + 1/2*v
1151
+ sage: omega = M.diff_form(1, name='omega')
1152
+ sage: omega[e_xy,0] = x
1153
+ sage: omega.add_comp_by_continuation(e_uv, W, c_uv)
1154
+ sage: omega.display()
1155
+ omega = x dx
1156
+ sage: A = M.mixed_form([f, omega, 0], name='A'); A.display()
1157
+ A = f + omega + zero
1158
+ sage: A.display_expansion(e_uv)
1159
+ A = 1/2*u + 1/2*v + (1/4*u + 1/4*v) du + (1/4*u + 1/4*v) dv
1160
+
1161
+ An exact copy is made. The copy is an entirely new instance and has a
1162
+ different name, but has the very same values::
1163
+
1164
+ sage: B = A.copy(); B.display()
1165
+ (unnamed scalar field) + (unnamed 1-form) + (unnamed 2-form)
1166
+ sage: B.display_expansion(e_uv)
1167
+ 1/2*u + 1/2*v + (1/4*u + 1/4*v) du + (1/4*u + 1/4*v) dv
1168
+ sage: A == B
1169
+ True
1170
+ sage: A is B
1171
+ False
1172
+ """
1173
+ resu = self._new_instance()
1174
+ resu._comp = [form.copy() for form in self]
1175
+ resu.set_name(name=name, latex_name=latex_name)
1176
+ resu._is_zero = self._is_zero # a priori
1177
+
1178
+ return resu
1179
+
1180
+ def __setitem__(self, index, values):
1181
+ r"""
1182
+ Set a component with respect to some vector frame.
1183
+
1184
+ - ``index`` -- list of indices; if ``[:]`` is provided, all the
1185
+ components are set
1186
+ - ``values`` -- the values to be set
1187
+
1188
+ TESTS::
1189
+
1190
+ sage: M = Manifold(2, 'M')
1191
+ sage: c_xy.<x,y> = M.chart()
1192
+ sage: f = M.scalar_field(x, name='f')
1193
+ sage: a = M.diff_form(1, name='a')
1194
+ sage: a[0] = y
1195
+ sage: b = M.diff_form(2, name='b')
1196
+ sage: b[0,1] = x*y
1197
+ sage: A = M.mixed_form([f, 0, 0], name='A'); A.display()
1198
+ A = f + zero + zero
1199
+ sage: A[1:3] = [a, b]; A.display()
1200
+ A = f + a + b
1201
+ sage: A.display_expansion()
1202
+ A = x + y dx + x*y dx∧dy
1203
+ """
1204
+ if self.is_immutable():
1205
+ raise ValueError("the components of an immutable element "
1206
+ "cannot be changed")
1207
+ if isinstance(index, (int, Integer)):
1208
+ start, stop, step = index, index + 1, 1
1209
+ elif isinstance(index, slice):
1210
+ start, stop, step = index.indices(self._max_deg + 1)
1211
+ else:
1212
+ raise TypeError("index must be int, Integer or slice")
1213
+ if isinstance(values, list):
1214
+ form_list = values
1215
+ else:
1216
+ form_list = [values]
1217
+ if len(form_list) != len(range(start, stop, step)):
1218
+ raise IndexError("either input or index out of range")
1219
+ for deg, j in zip(range(start, stop, step), range(len(form_list))):
1220
+ dmodule = self._domain.diff_form_module(deg, self._dest_map)
1221
+ form = dmodule(form_list[j])
1222
+ self[deg].copy_from(form) # keep the names
1223
+ self[deg].set_name(name=form._name, latex_name=form._latex_name)
1224
+ self._is_zero = False # a priori
1225
+
1226
+ def __getitem__(self, deg):
1227
+ r"""
1228
+ Return a component with respect to some frame.
1229
+
1230
+ INPUT:
1231
+
1232
+ - ``deg`` -- slice of which degrees shall be returned
1233
+
1234
+ TESTS::
1235
+
1236
+ sage: M = Manifold(2, 'M')
1237
+ sage: c_xy.<x,y> = M.chart()
1238
+ sage: f = M.scalar_field(name='f')
1239
+ sage: a = M.diff_form(1, name='a')
1240
+ sage: b = M.diff_form(2, name='b')
1241
+ sage: A = M.mixed_form([f, a, b], name='A'); A.display()
1242
+ A = f + a + b
1243
+ sage: A.__getitem__(0)
1244
+ Scalar field f on the 2-dimensional differentiable manifold M
1245
+ sage: A.__getitem__(1)
1246
+ 1-form a on the 2-dimensional differentiable manifold M
1247
+ sage: A.__getitem__(2)
1248
+ 2-form b on the 2-dimensional differentiable manifold M
1249
+ sage: A.__getitem__(slice(0,3,1))
1250
+ [Scalar field f on the 2-dimensional differentiable manifold M,
1251
+ 1-form a on the 2-dimensional differentiable manifold M,
1252
+ 2-form b on the 2-dimensional differentiable manifold M]
1253
+ """
1254
+ if self._comp is None:
1255
+ self._init_comp()
1256
+ return self._comp[deg]
1257
+
1258
+ def set_restriction(self, rst):
1259
+ r"""
1260
+ Set a (component-wise) restriction of ``self`` to some subdomain.
1261
+
1262
+ INPUT:
1263
+
1264
+ - ``rst`` -- :class:`MixedForm` of the same type as ``self``, defined on
1265
+ a subdomain of the domain of ``self``
1266
+
1267
+ EXAMPLES:
1268
+
1269
+ Initialize the 2-sphere::
1270
+
1271
+ sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2
1272
+ sage: U = M.open_subset('U') # complement of the North pole
1273
+ sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
1274
+ sage: V = M.open_subset('V') # complement of the South pole
1275
+ sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
1276
+ sage: M.declare_union(U,V) # S^2 is the union of U and V
1277
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)),
1278
+ ....: intersection_name='W', restrictions1= x^2+y^2!=0,
1279
+ ....: restrictions2= u^2+v^2!=0)
1280
+ sage: uv_to_xy = xy_to_uv.inverse()
1281
+ sage: W = U.intersection(V)
1282
+ sage: e_xy = c_xy.frame(); e_uv = c_uv.frame()
1283
+
1284
+ And define some forms on the subset ``U``::
1285
+
1286
+ sage: f = U.scalar_field(x, name='f', chart=c_xy)
1287
+ sage: omega = U.diff_form(1, name='omega')
1288
+ sage: omega[e_xy,0] = y
1289
+ sage: AU = U.mixed_form([f, omega, 0], name='A'); AU
1290
+ Mixed differential form A on the Open subset U of the 2-dimensional
1291
+ differentiable manifold M
1292
+ sage: AU.display_expansion(e_xy)
1293
+ A = x + y dx
1294
+
1295
+ A mixed form on ``M`` can be specified by some mixed form on a subset::
1296
+
1297
+ sage: A = M.mixed_form(name='A'); A
1298
+ Mixed differential form A on the 2-dimensional differentiable
1299
+ manifold M
1300
+ sage: A.set_restriction(AU)
1301
+ sage: A.display_expansion(e_xy)
1302
+ A = x + y dx
1303
+ sage: A.add_comp_by_continuation(e_uv, W, c_uv)
1304
+ sage: A.display_expansion(e_uv)
1305
+ A = u/(u^2 + v^2) - (u^2*v - v^3)/(u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6) du - 2*u*v^2/(u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6) dv
1306
+ sage: A.restrict(U) == AU
1307
+ True
1308
+ """
1309
+ if not isinstance(rst, MixedForm):
1310
+ raise TypeError("the argument must be a mixed form")
1311
+ if not rst._domain.is_subset(self._domain):
1312
+ raise ValueError("the specified domain is not a subset of "
1313
+ "the domain of definition of the mixed form")
1314
+ for j in self.irange():
1315
+ self[j].set_restriction(rst[j])
1316
+ self._is_zero = False # a priori
1317
+
1318
+ def restrict(self, subdomain, dest_map=None):
1319
+ r"""
1320
+ Return the restriction of ``self`` to some subdomain.
1321
+
1322
+ INPUT:
1323
+
1324
+ - ``subdomain`` --
1325
+ :class:`~sage.manifolds.differentiable.manifold.DifferentiableManifold`;
1326
+ open subset `U` of the domain of ``self``
1327
+ - ``dest_map`` --
1328
+ :class:`~sage.manifolds.differentiable.diff_map.DiffMap`
1329
+ (default: ``None``); destination map `\Psi:\ U \rightarrow V`,
1330
+ where `V` is an open subset of the manifold `N` where the mixed form
1331
+ takes it values; if ``None``, the restriction of `\Phi` to `U` is
1332
+ used, `\Phi` being the differentiable map `S \rightarrow M` associated
1333
+ with the mixed form
1334
+
1335
+ OUTPUT: :class:`MixedForm` representing the restriction
1336
+
1337
+ EXAMPLES:
1338
+
1339
+ Initialize the 2-sphere::
1340
+
1341
+ sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2
1342
+ sage: U = M.open_subset('U') # complement of the North pole
1343
+ sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
1344
+ sage: V = M.open_subset('V') # complement of the South pole
1345
+ sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
1346
+ sage: M.declare_union(U,V) # S^2 is the union of U and V
1347
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)),
1348
+ ....: intersection_name='W', restrictions1= x^2+y^2!=0,
1349
+ ....: restrictions2= u^2+v^2!=0)
1350
+ sage: uv_to_xy = xy_to_uv.inverse()
1351
+ sage: W = U.intersection(V)
1352
+ sage: e_xy = c_xy.frame(); e_uv = c_uv.frame()
1353
+
1354
+ And predefine some forms::
1355
+
1356
+ sage: f = M.scalar_field(x^2, name='f', chart=c_xy)
1357
+ sage: f.add_expr_by_continuation(c_uv, W)
1358
+ sage: omega = M.diff_form(1, name='omega')
1359
+ sage: omega[e_xy,0] = y^2
1360
+ sage: omega.add_comp_by_continuation(e_uv, W, c_uv)
1361
+ sage: eta = M.diff_form(2, name='eta')
1362
+ sage: eta[e_xy,0,1] = x^2*y^2
1363
+ sage: eta.add_comp_by_continuation(e_uv, W, c_uv)
1364
+
1365
+ Now, a mixed form can be restricted to some subdomain::
1366
+
1367
+ sage: F = M.mixed_form([f, omega, eta], name='F')
1368
+ sage: FV = F.restrict(V); FV
1369
+ Mixed differential form F on the Open subset V of the 2-dimensional
1370
+ differentiable manifold M
1371
+ sage: FV[:]
1372
+ [Scalar field f on the Open subset V of the 2-dimensional
1373
+ differentiable manifold M,
1374
+ 1-form omega on the Open subset V of the 2-dimensional
1375
+ differentiable manifold M,
1376
+ 2-form eta on the Open subset V of the 2-dimensional
1377
+ differentiable manifold M]
1378
+ sage: FV.display_expansion(e_uv)
1379
+ F = u^2/(u^4 + 2*u^2*v^2 + v^4) - (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 - 2*u*v^3/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) dv - u^2*v^2/(u^12 + 6*u^10*v^2 + 15*u^8*v^4 + 20*u^6*v^6 + 15*u^4*v^8 + 6*u^2*v^10 + v^12) du∧dv
1380
+ """
1381
+ resu = type(self)(subdomain.mixed_form_algebra(dest_map=dest_map),
1382
+ name=self._name, latex_name=self._latex_name)
1383
+ resu[0] = self[0].restrict(subdomain)
1384
+ resu[1:] = [self[j].restrict(subdomain, dest_map)
1385
+ for j in self.irange(1)]
1386
+ return resu
1387
+
1388
+ def add_comp_by_continuation(self, frame, subdomain, chart=None):
1389
+ r"""
1390
+ Set components with respect to a vector frame by continuation of the
1391
+ coordinate expression of the components in a subframe.
1392
+
1393
+ The continuation is performed by demanding that the components have
1394
+ the same coordinate expression as those on the restriction of the
1395
+ frame to a given subdomain.
1396
+
1397
+ INPUT:
1398
+
1399
+ - ``frame`` -- vector frame `e` in which the components are to be set
1400
+ - ``subdomain`` -- open subset of `e`'s domain in which the
1401
+ components are known or can be evaluated from other components
1402
+ - ``chart`` -- (default: ``None``) coordinate chart on `e`'s domain in
1403
+ which the extension of the expression of the components is to be
1404
+ performed; if ``None``, the default's chart of `e`'s domain is
1405
+ assumed
1406
+
1407
+ EXAMPLES:
1408
+
1409
+ Mixed form defined by differential forms with components on different
1410
+ parts of the 2-sphere::
1411
+
1412
+ sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2
1413
+ sage: U = M.open_subset('U') # complement of the North pole
1414
+ sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
1415
+ sage: V = M.open_subset('V') # complement of the South pole
1416
+ sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
1417
+ sage: M.declare_union(U,V) # S^2 is the union of U and V
1418
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)),
1419
+ ....: intersection_name='W', restrictions1= x^2+y^2!=0,
1420
+ ....: restrictions2= u^2+v^2!=0)
1421
+ sage: uv_to_xy = xy_to_uv.inverse()
1422
+ sage: W = U.intersection(V)
1423
+ sage: e_xy = c_xy.frame(); e_uv = c_uv.frame()
1424
+ sage: F = M.mixed_form(name='F') # No predefined components, here
1425
+ sage: F[0] = M.scalar_field(x, name='f')
1426
+ sage: F[1] = M.diff_form(1, {e_xy: [x,0]}, name='omega')
1427
+ sage: F[2].set_name(name='eta')
1428
+ sage: F[2][e_uv,0,1] = u*v
1429
+ sage: F.add_comp_by_continuation(e_uv, W, c_uv)
1430
+ sage: F.add_comp_by_continuation(e_xy, W, c_xy) # Now, F is fully defined
1431
+ sage: F.display_expansion(e_xy)
1432
+ F = x + x dx - x*y/(x^8 + 4*x^6*y^2 + 6*x^4*y^4 + 4*x^2*y^6 + y^8) dx∧dy
1433
+ sage: F.display_expansion(e_uv)
1434
+ F = u/(u^2 + v^2) - (u^3 - u*v^2)/(u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6) du - 2*u^2*v/(u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6) dv + u*v du∧dv
1435
+ """
1436
+ if chart is None:
1437
+ chart = frame._chart
1438
+ self[0].add_expr_by_continuation(chart, subdomain)
1439
+ for j in self.irange(1):
1440
+ self[j].add_comp_by_continuation(frame, subdomain, chart)
1441
+
1442
+ def irange(self, start=None):
1443
+ r"""
1444
+ Single index generator.
1445
+
1446
+ INPUT:
1447
+
1448
+ - ``start`` -- (default: ``None``) initial value `i_0` of the index
1449
+ between 0 and `n`, where `n` is the manifold's dimension; if none is
1450
+ provided, the value 0 is assumed
1451
+
1452
+ OUTPUT:
1453
+
1454
+ - an iterable index, starting from `i_0` and ending at
1455
+ `n`, where `n` is the manifold's dimension
1456
+
1457
+ EXAMPLES::
1458
+
1459
+ sage: M = Manifold(3, 'M')
1460
+ sage: a = M.mixed_form(name='a')
1461
+ sage: list(a.irange())
1462
+ [0, 1, 2, 3]
1463
+ sage: list(a.irange(2))
1464
+ [2, 3]
1465
+ """
1466
+ return self.parent().irange(start=start)
1467
+
1468
+ def set_comp(self, i):
1469
+ r"""
1470
+ Return the `i`-th homogeneous component for assignment.
1471
+
1472
+ EXAMPLES::
1473
+
1474
+ sage: M = Manifold(2, 'M')
1475
+ sage: X.<x,y> = M.chart()
1476
+ sage: A = M.mixed_form(name='A')
1477
+ sage: A.set_comp(0).set_expr(x^2) # scalar field
1478
+ sage: A.set_comp(1)[:] = [-y, x]
1479
+ sage: A.set_comp(2)[0,1] = x-y
1480
+ sage: A.display()
1481
+ A = A_0 + A_1 + A_2
1482
+ sage: A.display_expansion()
1483
+ A = x^2 - y dx + x dy + (x - y) dx∧dy
1484
+ """
1485
+ return self[i]
1486
+
1487
+ def set_immutable(self):
1488
+ r"""
1489
+ Set ``self`` and homogeneous components of ``self`` immutable.
1490
+
1491
+ EXAMPLES::
1492
+
1493
+ sage: M = Manifold(2, 'M')
1494
+ sage: X.<x,y> = M.chart()
1495
+ sage: f = M.scalar_field(x^2, name='f')
1496
+ sage: A = M.mixed_form([f, 0, 0], name='A')
1497
+ sage: A.set_immutable()
1498
+ sage: A.is_immutable()
1499
+ True
1500
+ sage: A[0].is_immutable()
1501
+ True
1502
+ sage: f.is_immutable()
1503
+ False
1504
+ """
1505
+ for form in self:
1506
+ form.set_immutable()
1507
+ super().set_immutable()