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,1717 @@
1
+ # sage_setup: distribution = sagemath-symbolics
2
+ r"""
3
+ Vector Fields
4
+
5
+ Given two differentiable manifolds `U` and `M` over the same topological field
6
+ `K` and a differentiable map
7
+
8
+ .. MATH::
9
+
10
+ \Phi:\ U \longrightarrow M,
11
+
12
+ we define a *vector field along* `U` *with values on* `M` to be a
13
+ differentiable map
14
+
15
+ .. MATH::
16
+
17
+ v:\ U \longrightarrow TM
18
+
19
+ (`TM` being the tangent bundle of `M`) such that
20
+
21
+ .. MATH::
22
+
23
+ \forall p \in U,\ v(p) \in T_{\Phi(p)}M.
24
+
25
+ The standard case of vector fields *on* a differentiable manifold corresponds
26
+ to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi`
27
+ being an immersion and `\Phi` being a curve in `M` (`U` is then an open
28
+ interval of `\RR`).
29
+
30
+ Vector fields are implemented via two classes: :class:`VectorFieldParal` and
31
+ :class:`VectorField`, depending respectively whether the manifold `M`
32
+ is parallelizable or not, i.e. whether the bundle `TM` is trivial or not.
33
+
34
+
35
+ AUTHORS:
36
+
37
+ - Eric Gourgoulhon, Michal Bejger (2013-2015) : initial version
38
+ - Marco Mancini (2015): parallelization of vector field plots
39
+ - Travis Scrimshaw (2016): review tweaks
40
+ - Eric Gourgoulhon (2017): vector fields inherit from multivector fields
41
+ - Eric Gourgoulhon (2018): dot and cross products, operators norm and curl
42
+
43
+ REFERENCES:
44
+
45
+ - [KN1963]_
46
+ - [Lee2013]_
47
+ - [ONe1983]_
48
+ - [BG1988]_
49
+ """
50
+
51
+ # *****************************************************************************
52
+ # Copyright (C) 2015, 2017 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
53
+ # Copyright (C) 2015 Michal Bejger <bejger@camk.edu.pl>
54
+ # Copyright (C) 2015 Marco Mancini <marco.mancini@obspm.fr>
55
+ # Copyright (C) 2016 Travis Scrimshaw <tscrimsh@umn.edu>
56
+ #
57
+ # Distributed under the terms of the GNU General Public License (GPL)
58
+ # as published by the Free Software Foundation; either version 2 of
59
+ # the License, or (at your option) any later version.
60
+ # https://www.gnu.org/licenses/
61
+ # *****************************************************************************
62
+
63
+ from sage.manifolds.differentiable.multivectorfield import (
64
+ MultivectorField,
65
+ MultivectorFieldParal,
66
+ )
67
+ from sage.misc.decorators import options
68
+ from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement
69
+
70
+
71
+ class VectorField(MultivectorField):
72
+ r"""
73
+ Vector field along a differentiable manifold.
74
+
75
+ An instance of this class is a vector field along a differentiable
76
+ manifold `U` with values on a differentiable manifold `M`, via a
77
+ differentiable map `U \rightarrow M`. More precisely, given a
78
+ differentiable map
79
+
80
+ .. MATH::
81
+
82
+ \Phi:\ U \longrightarrow M,
83
+
84
+ a *vector field along* `U` *with values on* `M` is a differentiable map
85
+
86
+ .. MATH::
87
+
88
+ v:\ U \longrightarrow TM
89
+
90
+ (`TM` being the tangent bundle of `M`) such that
91
+
92
+ .. MATH::
93
+
94
+ \forall p \in U,\ v(p) \in T_{\Phi(p)}M.
95
+
96
+ The standard case of vector fields *on* a differentiable manifold
97
+ corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are
98
+ `\Phi` being an immersion and `\Phi` being a curve in `M` (`U` is then an
99
+ open interval of `\RR`).
100
+
101
+ .. NOTE::
102
+
103
+ If `M` is parallelizable, then
104
+ :class:`~sage.manifolds.differentiable.vectorfield.VectorFieldParal`
105
+ *must* be used instead.
106
+
107
+ INPUT:
108
+
109
+ - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector
110
+ fields along `U` with values on `M\supset\Phi(U)`
111
+ - ``name`` -- (default: ``None``) name given to the vector field
112
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the vector
113
+ field; if none is provided, the LaTeX symbol is set to ``name``
114
+
115
+ EXAMPLES:
116
+
117
+ A vector field on a non-parallelizable 2-dimensional manifold::
118
+
119
+ sage: M = Manifold(2, 'M')
120
+ sage: U = M.open_subset('U') ; V = M.open_subset('V')
121
+ sage: M.declare_union(U,V) # M is the union of U and V
122
+ sage: c_xy.<x,y> = U.chart() ; c_tu.<t,u> = V.chart()
123
+ sage: transf = c_xy.transition_map(c_tu, (x+y, x-y), intersection_name='W',
124
+ ....: restrictions1= x>0, restrictions2= t+u>0)
125
+ sage: inv = transf.inverse()
126
+ sage: W = U.intersection(V)
127
+ sage: eU = c_xy.frame() ; eV = c_tu.frame()
128
+ sage: c_tuW = c_tu.restrict(W) ; eVW = c_tuW.frame()
129
+ sage: v = M.vector_field(name='v') ; v
130
+ Vector field v on the 2-dimensional differentiable manifold M
131
+ sage: v.parent()
132
+ Module X(M) of vector fields on the 2-dimensional differentiable
133
+ manifold M
134
+
135
+ The vector field is first defined on the domain `U` by means of its
136
+ components with respect to the frame ``eU``::
137
+
138
+ sage: v[eU,:] = [-y, 1+x]
139
+
140
+ The components with respect to the frame ``eV`` are then deduced
141
+ by continuation of the components with respect to the frame ``eVW``
142
+ on the domain `W = U \cap V`, expressed in terms on the coordinates
143
+ covering `V`::
144
+
145
+ sage: v[eV,0] = v[eVW,0,c_tuW].expr()
146
+ sage: v[eV,1] = v[eVW,1,c_tuW].expr()
147
+
148
+ At this stage, the vector field is fully defined on the whole manifold::
149
+
150
+ sage: v.display(eU)
151
+ v = -y ∂/∂x + (x + 1) ∂/∂y
152
+ sage: v.display(eV)
153
+ v = (u + 1) ∂/∂t + (-t - 1) ∂/∂u
154
+
155
+ The vector field acting on scalar fields::
156
+
157
+ sage: f = M.scalar_field({c_xy: (x+y)^2, c_tu: t^2}, name='f')
158
+ sage: s = v(f) ; s
159
+ Scalar field v(f) on the 2-dimensional differentiable manifold M
160
+ sage: s.display()
161
+ v(f): M → ℝ
162
+ on U: (x, y) ↦ 2*x^2 - 2*y^2 + 2*x + 2*y
163
+ on V: (t, u) ↦ 2*t*u + 2*t
164
+
165
+ Some checks::
166
+
167
+ sage: v(f) == f.differential()(v)
168
+ True
169
+ sage: v(f) == f.lie_der(v)
170
+ True
171
+
172
+ The result is defined on the intersection of the vector field's
173
+ domain and the scalar field's one::
174
+
175
+ sage: s = v(f.restrict(U)) ; s
176
+ Scalar field v(f) on the Open subset U of the 2-dimensional
177
+ differentiable manifold M
178
+ sage: s == v(f).restrict(U)
179
+ True
180
+ sage: s = v(f.restrict(W)) ; s
181
+ Scalar field v(f) on the Open subset W of the 2-dimensional
182
+ differentiable manifold M
183
+ sage: s.display()
184
+ v(f): W → ℝ
185
+ (x, y) ↦ 2*x^2 - 2*y^2 + 2*x + 2*y
186
+ (t, u) ↦ 2*t*u + 2*t
187
+ sage: s = v.restrict(U)(f) ; s
188
+ Scalar field v(f) on the Open subset U of the 2-dimensional
189
+ differentiable manifold M
190
+ sage: s.display()
191
+ v(f): U → ℝ
192
+ (x, y) ↦ 2*x^2 - 2*y^2 + 2*x + 2*y
193
+ on W: (t, u) ↦ 2*t*u + 2*t
194
+ sage: s = v.restrict(U)(f.restrict(V)) ; s
195
+ Scalar field v(f) on the Open subset W of the 2-dimensional
196
+ differentiable manifold M
197
+ sage: s.display()
198
+ v(f): W → ℝ
199
+ (x, y) ↦ 2*x^2 - 2*y^2 + 2*x + 2*y
200
+ (t, u) ↦ 2*t*u + 2*t
201
+ """
202
+ def __init__(self, vector_field_module, name=None, latex_name=None):
203
+ r"""
204
+ Construct a vector field with values on a non-parallelizable manifold.
205
+
206
+ TESTS:
207
+
208
+ Construction via ``parent.element_class``, and not via a direct call
209
+ to ``VectorField``, to fit with the category framework::
210
+
211
+ sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2
212
+ sage: U = M.open_subset('U') # complement of the North pole
213
+ sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
214
+ sage: V = M.open_subset('V') # complement of the South pole
215
+ sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
216
+ sage: M.declare_union(U,V) # S^2 is the union of U and V
217
+ sage: XM = M.vector_field_module()
218
+ sage: a = XM.element_class(XM, name='a'); a
219
+ Vector field a on the 2-dimensional differentiable manifold M
220
+ sage: a[c_xy.frame(),:] = [x, y]
221
+ sage: a[c_uv.frame(),:] = [-u, -v]
222
+ sage: TestSuite(a).run(skip='_test_pickling')
223
+
224
+ Construction with ``DifferentiableManifold.vector_field``::
225
+
226
+ sage: a1 = M.vector_field(name='a'); a1
227
+ Vector field a on the 2-dimensional differentiable manifold M
228
+ sage: type(a1) == type(a)
229
+ True
230
+
231
+ .. TODO::
232
+
233
+ Fix ``_test_pickling`` (in the superclass :class:`TensorField`).
234
+ """
235
+ MultivectorField.__init__(self, vector_field_module, 1, name=name,
236
+ latex_name=latex_name)
237
+ # Initialization of derived quantities:
238
+ MultivectorField._init_derived(self)
239
+ # Initialization of list of quantities depending on self:
240
+ self._init_dependencies()
241
+
242
+ def _repr_(self):
243
+ r"""
244
+ Return a string representation of ``self``.
245
+
246
+ TESTS::
247
+
248
+ sage: M = Manifold(2, 'M')
249
+ sage: v = M.vector_field(name='v')
250
+ sage: v._repr_()
251
+ 'Vector field v on the 2-dimensional differentiable manifold M'
252
+ sage: repr(v) # indirect doctest
253
+ 'Vector field v on the 2-dimensional differentiable manifold M'
254
+ sage: v # indirect doctest
255
+ Vector field v on the 2-dimensional differentiable manifold M
256
+ """
257
+ description = "Vector field "
258
+ if self._name is not None:
259
+ description += self._name + " "
260
+ return self._final_repr(description)
261
+
262
+ def _new_instance(self):
263
+ r"""
264
+ Create an instance of the same class as ``self`` on the same module.
265
+
266
+ TESTS::
267
+
268
+ sage: M = Manifold(2, 'M')
269
+ sage: v = M.vector_field(name='v')
270
+ sage: u = v._new_instance(); u
271
+ Vector field on the 2-dimensional differentiable manifold M
272
+ sage: u.parent() is v.parent()
273
+ True
274
+ """
275
+ return type(self)(self._vmodule)
276
+
277
+ def _init_dependencies(self):
278
+ r"""
279
+ Initialize list of quantities that depend on ``self``.
280
+
281
+ TESTS::
282
+
283
+ sage: M = Manifold(2, 'M')
284
+ sage: v = M.vector_field(name='v')
285
+ sage: v._init_dependencies()
286
+ """
287
+ self._lie_der_along_self = {}
288
+
289
+ def _del_dependencies(self):
290
+ r"""
291
+ Clear list of quantities that depend on ``self``.
292
+
293
+ TESTS::
294
+
295
+ sage: M = Manifold(2, 'M')
296
+ sage: v = M.vector_field(name='v')
297
+ sage: v._del_dependencies()
298
+ """
299
+ if self._lie_der_along_self != {}:
300
+ for tens in self._lie_der_along_self.values():
301
+ del tens._lie_derivatives[id(self)]
302
+ self._lie_der_along_self.clear()
303
+
304
+ def __call__(self, scalar):
305
+ r"""
306
+ Action on a scalar field (or on a 1-form).
307
+
308
+ INPUT:
309
+
310
+ - ``scalar`` -- scalar field `f`
311
+
312
+ OUTPUT:
313
+
314
+ - scalar field representing the derivative of `f` along the vector
315
+ field, i.e. `v^i \frac{\partial f}{\partial x^i}`
316
+
317
+ TESTS::
318
+
319
+ sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2
320
+ sage: U = M.open_subset('U') # complement of the North pole
321
+ sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
322
+ sage: V = M.open_subset('V') # complement of the South pole
323
+ sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
324
+ sage: M.declare_union(U,V) # S^2 is the union of U and V
325
+ sage: a = M.vector_field({c_xy.frame(): [x, y],
326
+ ....: c_uv.frame(): [-u, -v]}, name='a')
327
+ sage: f = M.scalar_field({c_xy: atan(x^2+y^2),
328
+ ....: c_uv: pi/2-atan(u^2+v^2)}, name='f')
329
+ sage: s = a.__call__(f); s
330
+ Scalar field a(f) on the 2-dimensional differentiable manifold M
331
+ sage: s.display()
332
+ a(f): M → ℝ
333
+ on U: (x, y) ↦ 2*(x^2 + y^2)/(x^4 + 2*x^2*y^2 + y^4 + 1)
334
+ on V: (u, v) ↦ 2*(u^2 + v^2)/(u^4 + 2*u^2*v^2 + v^4 + 1)
335
+ sage: s == f.differential()(a)
336
+ True
337
+ """
338
+ if scalar._tensor_type == (0,1):
339
+ # This is actually the action of the vector field on a 1-form,
340
+ # as a tensor field of type (1,0):
341
+ return scalar(self)
342
+ if scalar._tensor_type != (0,0):
343
+ raise TypeError("the argument must be a scalar field")
344
+ resu = scalar.differential()(self)
345
+ if not resu.is_immutable():
346
+ if self._name is not None and scalar._name is not None:
347
+ name = f"{self._name}({scalar._name})"
348
+ else:
349
+ name = None
350
+ if self._latex_name is not None and scalar._latex_name is not None:
351
+ latex_name = fr"{self._latex_name}\left({scalar._latex_name}\right)"
352
+ else:
353
+ latex_name = None
354
+ resu.set_name(name=name, latex_name=latex_name)
355
+ return resu
356
+
357
+ @options(max_range=8, scale=1, color='blue')
358
+ def plot(self, chart=None, ambient_coords=None, mapping=None,
359
+ chart_domain=None, fixed_coords=None, ranges=None,
360
+ number_values=None, steps=None,
361
+ parameters=None, label_axes=True, **extra_options):
362
+ r"""
363
+ Plot the vector field in a Cartesian graph based on the coordinates
364
+ of some ambient chart.
365
+
366
+ The vector field is drawn in terms of two (2D graphics) or three
367
+ (3D graphics) coordinates of a given chart, called hereafter the
368
+ *ambient chart*.
369
+ The vector field's base points `p` (or their images `\Phi(p)` by some
370
+ differentiable mapping `\Phi`) must lie in the ambient chart's domain.
371
+
372
+ INPUT:
373
+
374
+ - ``chart`` -- (default: ``None``) the ambient chart (see above); if
375
+ ``None``, the default chart of the vector field's domain is used
376
+
377
+ - ``ambient_coords`` -- (default: ``None``) tuple containing the 2
378
+ or 3 coordinates of the ambient chart in terms of which the plot
379
+ is performed; if ``None``, all the coordinates of the ambient
380
+ chart are considered
381
+
382
+ - ``mapping`` -- :class:`~sage.manifolds.differentiable.diff_map.DiffMap`
383
+ (default: ``None``); differentiable map `\Phi` providing the link
384
+ between the vector field's domain and the ambient chart ``chart``;
385
+ if ``None``, the identity map is assumed
386
+
387
+ - ``chart_domain`` -- (default: ``None``) chart on the vector field's
388
+ domain to define the points at which vector arrows are to be plotted;
389
+ if ``None``, the default chart of the vector field's domain is used
390
+
391
+ - ``fixed_coords`` -- (default: ``None``) dictionary with keys the
392
+ coordinates of ``chart_domain`` that are kept fixed and with values
393
+ the value of these coordinates; if ``None``, all the coordinates of
394
+ ``chart_domain`` are used
395
+
396
+ - ``ranges`` -- (default: ``None``) dictionary with keys the
397
+ coordinates of ``chart_domain`` to be used and values tuples
398
+ ``(x_min, x_max)`` specifying the coordinate range for the plot;
399
+ if ``None``, the entire coordinate range declared during the
400
+ construction of ``chart_domain`` is considered (with ``-Infinity``
401
+ replaced by ``-max_range`` and ``+Infinity`` by ``max_range``)
402
+
403
+ - ``number_values`` -- (default: ``None``) either an integer or a
404
+ dictionary with keys the coordinates of ``chart_domain`` to be
405
+ used and values the number of values of the coordinate for sampling
406
+ the part of the vector field's domain involved in the plot ; if
407
+ ``number_values`` is a single integer, it represents the number of
408
+ values for all coordinates; if ``number_values`` is ``None``, it is
409
+ set to 9 for a 2D plot and to 5 for a 3D plot
410
+
411
+ - ``steps`` -- (default: ``None``) dictionary with keys the
412
+ coordinates of ``chart_domain`` to be used and values the step
413
+ between each constant value of the coordinate; if ``None``, the
414
+ step is computed from the coordinate range (specified in ``ranges``)
415
+ and ``number_values``; on the contrary, if the step is provided
416
+ for some coordinate, the corresponding number of values is deduced
417
+ from it and the coordinate range
418
+
419
+ - ``parameters`` -- (default: ``None``) dictionary giving the numerical
420
+ values of the parameters that may appear in the coordinate expression
421
+ of the vector field (see example below)
422
+
423
+ - ``label_axes`` -- boolean (default: ``True``); determining whether
424
+ the labels of the coordinate axes of ``chart`` shall be added to
425
+ the graph; can be set to ``False`` if the graph is 3D and must be
426
+ superposed with another graph
427
+
428
+ - ``color`` -- (default: ``'blue'``) color of the arrows representing
429
+ the vectors
430
+
431
+ - ``max_range`` -- (default: 8) numerical value substituted to
432
+ ``+Infinity`` if the latter is the upper bound of the range of a
433
+ coordinate for which the plot is performed over the entire coordinate
434
+ range (i.e. for which no specific plot range has been set in
435
+ ``ranges``); similarly ``-max_range`` is the numerical valued
436
+ substituted for ``-Infinity``
437
+
438
+ - ``scale`` -- (default: 1) value by which the lengths of the arrows
439
+ representing the vectors is multiplied
440
+
441
+ - ``**extra_options`` -- extra options for the arrow plot, like
442
+ ``linestyle``, ``width`` or ``arrowsize`` (see
443
+ :func:`~sage.plot.arrow.arrow2d` and
444
+ :func:`~sage.plot.plot3d.shapes.arrow3d` for details)
445
+
446
+ OUTPUT:
447
+
448
+ - a graphic object, either an instance of
449
+ :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on
450
+ 2 coordinates of ``chart``) or an instance of
451
+ :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e.
452
+ based on 3 coordinates of ``chart``)
453
+
454
+ EXAMPLES:
455
+
456
+ Plot of a vector field on a 2-dimensional manifold::
457
+
458
+ sage: M = Manifold(2, 'M')
459
+ sage: X.<x,y> = M.chart()
460
+ sage: v = M.vector_field(-y, x, name='v')
461
+ sage: v.display()
462
+ v = -y ∂/∂x + x ∂/∂y
463
+ sage: v.plot() # needs sage.plot
464
+ Graphics object consisting of 80 graphics primitives
465
+
466
+ .. PLOT::
467
+
468
+ M = Manifold(2, 'M')
469
+ X = M.chart('x y'); x, y = X[:]
470
+ v = M.vector_field(-y, x, name='v')
471
+ g = v.plot()
472
+ sphinx_plot(g)
473
+
474
+ Plot with various options::
475
+
476
+ sage: v.plot(scale=0.5, color='green', linestyle='--', width=1, # needs sage.plot
477
+ ....: arrowsize=6)
478
+ Graphics object consisting of 80 graphics primitives
479
+
480
+ .. PLOT::
481
+
482
+ M = Manifold(2, 'M')
483
+ X = M.chart('x y'); x, y = X[:]
484
+ v = M.vector_field(-y, x, name='v')
485
+ g = v.plot(scale=0.5, color='green', linestyle='--', width=1, arrowsize=6)
486
+ sphinx_plot(g)
487
+
488
+ ::
489
+
490
+ sage: v.plot(max_range=4, number_values=5, scale=0.5) # needs sage.plot
491
+ Graphics object consisting of 24 graphics primitives
492
+
493
+ .. PLOT::
494
+
495
+ M = Manifold(2, 'M')
496
+ X = M.chart('x y'); x, y = X[:]
497
+ v = M.vector_field(-y, x, name='v')
498
+ g = v.plot(max_range=4, number_values=5, scale=0.5)
499
+ sphinx_plot(g)
500
+
501
+ Plot using parallel computation::
502
+
503
+ sage: Parallelism().set(nproc=2)
504
+ sage: v.plot(scale=0.5, number_values=10, linestyle='--', width=1, # needs sage.plot
505
+ ....: arrowsize=6)
506
+ Graphics object consisting of 100 graphics primitives
507
+
508
+ .. PLOT::
509
+
510
+ M = Manifold(2, 'M')
511
+ X = M.chart('x y'); x, y = X[:]
512
+ v = M.vector_field(-y, x, name='v')
513
+ g = v.plot(scale=0.5, number_values=10, linestyle='--', width=1, arrowsize=6)
514
+ sphinx_plot(g)
515
+
516
+ ::
517
+
518
+ sage: Parallelism().set(nproc=1) # switch off parallelization
519
+
520
+ Plots along a line of fixed coordinate::
521
+
522
+ sage: v.plot(fixed_coords={x: -2}) # needs sage.plot
523
+ Graphics object consisting of 9 graphics primitives
524
+
525
+ .. PLOT::
526
+
527
+ M = Manifold(2, 'M')
528
+ X = M.chart('x y'); x, y = X[:]
529
+ v = M.vector_field(-y, x, name='v')
530
+ g = v.plot(fixed_coords={x: -2})
531
+ sphinx_plot(g)
532
+
533
+ ::
534
+
535
+ sage: v.plot(fixed_coords={y: 1}) # needs sage.plot
536
+ Graphics object consisting of 9 graphics primitives
537
+
538
+ .. PLOT::
539
+
540
+ M = Manifold(2, 'M')
541
+ X = M.chart('x y'); x, y = X[:]
542
+ v = M.vector_field(-y, x, name='v')
543
+ g = v.plot(fixed_coords={y: 1})
544
+ sphinx_plot(g)
545
+
546
+ Let us now consider a vector field on a 4-dimensional manifold::
547
+
548
+ sage: M = Manifold(4, 'M')
549
+ sage: X.<t,x,y,z> = M.chart()
550
+ sage: v = M.vector_field((t/8)^2, -t*y/4, t*x/4, t*z/4, name='v')
551
+ sage: v.display()
552
+ v = 1/64*t^2 ∂/∂t - 1/4*t*y ∂/∂x + 1/4*t*x ∂/∂y + 1/4*t*z ∂/∂z
553
+
554
+ We cannot make a 4D plot directly::
555
+
556
+ sage: v.plot() # needs sage.plot
557
+ Traceback (most recent call last):
558
+ ...
559
+ ValueError: the number of ambient coordinates must be either 2 or 3, not 4
560
+
561
+ Rather, we have to select some coordinates for the plot, via
562
+ the argument ``ambient_coords``. For instance, for a 3D plot::
563
+
564
+ sage: v.plot(ambient_coords=(x, y, z), fixed_coords={t: 1}, # long time, needs sage.plot
565
+ ....: number_values=4)
566
+ Graphics3d Object
567
+
568
+ .. PLOT::
569
+
570
+ M = Manifold(4, 'M')
571
+ X = M.chart('t x y z') ; t,x,y,z = X[:]
572
+ v = M.vector_field((t/8)**2, -t*y/4, t*x/4, t*z/4, name='v')
573
+ sphinx_plot(v.plot(ambient_coords=(x, y, z), fixed_coords={t: 1},
574
+ number_values=4))
575
+
576
+ ::
577
+
578
+ sage: v.plot(ambient_coords=(x, y, t), fixed_coords={z: 0}, # long time, needs sage.plot
579
+ ....: ranges={x: (-2,2), y: (-2,2), t: (-1, 4)},
580
+ ....: number_values=4)
581
+ Graphics3d Object
582
+
583
+ .. PLOT::
584
+
585
+ M = Manifold(4, 'M')
586
+ X = M.chart('t x y z'); t,x,y,z = X[:]
587
+ v = M.vector_field((t/8)**2, -t*y/4, t*x/4, t*z/4, name='v')
588
+ sphinx_plot(v.plot(ambient_coords=(x, y, t), fixed_coords={z: 0},
589
+ ranges={x: (-2,2), y: (-2,2), t: (-1, 4)},
590
+ number_values=4))
591
+
592
+ or, for a 2D plot::
593
+
594
+ sage: v.plot(ambient_coords=(x, y), fixed_coords={t: 1, z: 0}) # long time, needs sage.plot
595
+ Graphics object consisting of 80 graphics primitives
596
+
597
+ .. PLOT::
598
+
599
+ M = Manifold(4, 'M')
600
+ X = M.chart('t x y z'); t,x,y,z = X[:]
601
+ v = M.vector_field((t/8)**2, -t*y/4, t*x/4, t*z/4, name='v')
602
+ g = v.plot(ambient_coords=(x, y), fixed_coords={t: 1, z: 0})
603
+ sphinx_plot(g)
604
+
605
+ ::
606
+
607
+ sage: v.plot(ambient_coords=(x, t), fixed_coords={y: 1, z: 0}) # long time, needs sage.plot
608
+ Graphics object consisting of 72 graphics primitives
609
+
610
+ .. PLOT::
611
+
612
+ M = Manifold(4, 'M')
613
+ X = M.chart('t x y z'); t,x,y,z = X[:]
614
+ v = M.vector_field((t/8)**2, -t*y/4, t*x/4, t*z/4, name='v')
615
+ g = v.plot(ambient_coords=(x, t), fixed_coords={y: 1, z: 0})
616
+ sphinx_plot(g)
617
+
618
+ An example of plot via a differential mapping: plot of a vector field
619
+ tangent to a 2-sphere viewed in `\RR^3`::
620
+
621
+ sage: S2 = Manifold(2, 'S^2')
622
+ sage: U = S2.open_subset('U') # the open set covered by spherical coord.
623
+ sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
624
+ sage: R3 = Manifold(3, 'R^3')
625
+ sage: X3.<x,y,z> = R3.chart()
626
+ sage: F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph),
627
+ ....: sin(th)*sin(ph), cos(th)]}, name='F')
628
+ sage: F.display() # the standard embedding of S^2 into R^3
629
+ F: S^2 → R^3
630
+ on U: (th, ph) ↦ (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th))
631
+ sage: v = XS.frame()[1] ; v # the coordinate vector ∂/∂phi
632
+ Vector field ∂/∂ph on the Open subset U of the 2-dimensional
633
+ differentiable manifold S^2
634
+ sage: graph_v = v.plot(chart=X3, mapping=F, label_axes=False) # needs sage.plot
635
+ sage: graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9) # needs sage.plot
636
+ sage: graph_v + graph_S2 # needs sage.plot
637
+ Graphics3d Object
638
+
639
+ .. PLOT::
640
+
641
+ S2 = Manifold(2, 'S^2')
642
+ U = S2.open_subset('U')
643
+ XS = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
644
+ th, ph = XS[:]
645
+ R3 = Manifold(3, 'R^3')
646
+ X3 = R3.chart('x y z')
647
+ F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), sin(th)*sin(ph),
648
+ cos(th)]}, name='F')
649
+ v = XS.frame()[1]
650
+ graph_v = v.plot(chart=X3, mapping=F, label_axes=False)
651
+ graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9)
652
+ sphinx_plot(graph_v + graph_S2)
653
+
654
+ Note that the default values of some arguments of the method ``plot``
655
+ are stored in the dictionary ``plot.options``::
656
+
657
+ sage: v.plot.options # random (dictionary output)
658
+ {'color': 'blue', 'max_range': 8, 'scale': 1}
659
+
660
+ so that they can be adjusted by the user::
661
+
662
+ sage: v.plot.options['color'] = 'red'
663
+
664
+ From now on, all plots of vector fields will use red as the default
665
+ color. To restore the original default options, it suffices to type::
666
+
667
+ sage: v.plot.reset()
668
+ """
669
+ from sage.manifolds.chart import RealChart
670
+ from sage.manifolds.utilities import set_axes_labels
671
+ from sage.misc.functional import numerical_approx
672
+ from sage.misc.latex import latex
673
+ from sage.parallel.decorate import parallel
674
+ from sage.parallel.parallelism import Parallelism
675
+ from sage.plot.graphics import Graphics
676
+ from sage.rings.infinity import Infinity
677
+
678
+ #
679
+ # 1/ Treatment of input parameters
680
+ # -----------------------------
681
+ max_range = extra_options.pop("max_range")
682
+ scale = extra_options.pop("scale")
683
+ color = extra_options.pop("color")
684
+ if chart is None:
685
+ chart = self._domain.default_chart()
686
+ elif not isinstance(chart, RealChart):
687
+ raise TypeError("{} is not a chart on a real ".format(chart) +
688
+ "manifold")
689
+ if chart_domain is None:
690
+ chart_domain = self._domain.default_chart()
691
+ elif not isinstance(chart_domain, RealChart):
692
+ raise TypeError("{} is not a chart on a ".format(chart_domain) +
693
+ "real manifold")
694
+ elif not chart_domain.domain().is_subset(self._domain):
695
+ raise ValueError("the domain of {} is not ".format(chart_domain) +
696
+ "included in the domain of {}".format(self))
697
+ coords_full = tuple(chart_domain[:]) # all coordinates of chart_domain
698
+ if fixed_coords is None:
699
+ coords = coords_full
700
+ else:
701
+ fixed_coord_list = fixed_coords.keys()
702
+ coords = []
703
+ for coord in coords_full:
704
+ if coord not in fixed_coord_list:
705
+ coords.append(coord)
706
+ coords = tuple(coords)
707
+ if ambient_coords is None:
708
+ ambient_coords = chart[:]
709
+ elif not isinstance(ambient_coords, tuple):
710
+ ambient_coords = tuple(ambient_coords)
711
+ nca = len(ambient_coords)
712
+ if nca != 2 and nca != 3:
713
+ raise ValueError("the number of ambient coordinates must be " +
714
+ "either 2 or 3, not {}".format(nca))
715
+ if ranges is None:
716
+ ranges = {}
717
+ ranges0 = {}
718
+ for coord in coords:
719
+ if coord in ranges:
720
+ ranges0[coord] = (numerical_approx(ranges[coord][0]),
721
+ numerical_approx(ranges[coord][1]))
722
+ else:
723
+ bounds = chart_domain._bounds[coords_full.index(coord)]
724
+ xmin0 = bounds[0][0]
725
+ xmax0 = bounds[1][0]
726
+ if xmin0 == -Infinity:
727
+ xmin = numerical_approx(-max_range)
728
+ elif bounds[0][1]:
729
+ xmin = numerical_approx(xmin0)
730
+ else:
731
+ xmin = numerical_approx(xmin0 + 1.e-3)
732
+ if xmax0 == Infinity:
733
+ xmax = numerical_approx(max_range)
734
+ elif bounds[1][1]:
735
+ xmax = numerical_approx(xmax0)
736
+ else:
737
+ xmax = numerical_approx(xmax0 - 1.e-3)
738
+ ranges0[coord] = (xmin, xmax)
739
+ ranges = ranges0
740
+ if number_values is None:
741
+ if nca == 2: # 2D plot
742
+ number_values = 9
743
+ else: # 3D plot
744
+ number_values = 5
745
+ if not isinstance(number_values, dict):
746
+ number_values0 = {}
747
+ for coord in coords:
748
+ number_values0[coord] = number_values
749
+ number_values = number_values0
750
+ if steps is None:
751
+ steps = {}
752
+ for coord in coords:
753
+ if coord not in steps:
754
+ steps[coord] = (ranges[coord][1] - ranges[coord][0]) / \
755
+ (number_values[coord]-1)
756
+ else:
757
+ number_values[coord] = 1 + int(
758
+ (ranges[coord][1] - ranges[coord][0]) / steps[coord])
759
+ #
760
+ # 2/ Plots
761
+ # -----
762
+ dom = chart_domain.domain()
763
+ vector = self.restrict(dom)
764
+ if vector.parent().destination_map() is dom.identity_map():
765
+ if mapping is not None:
766
+ vector = mapping.pushforward(vector)
767
+ mapping = None
768
+ nc = len(coords_full)
769
+ ncp = len(coords)
770
+ xx = [0] * nc
771
+ if fixed_coords is not None:
772
+ if len(fixed_coords) != nc - ncp:
773
+ raise ValueError("bad number of fixed coordinates")
774
+ for fc, val in fixed_coords.items():
775
+ xx[coords_full.index(fc)] = val
776
+ ind_coord = []
777
+ for coord in coords:
778
+ ind_coord.append(coords_full.index(coord))
779
+
780
+ resu = Graphics()
781
+ ind = [0] * ncp
782
+ ind_max = [0] * ncp
783
+ ind_max[0] = number_values[coords[0]]
784
+ xmin = [ranges[cd][0] for cd in coords]
785
+ step_tab = [steps[cd] for cd in coords]
786
+
787
+ nproc = Parallelism().get('tensor')
788
+ if nproc != 1 and nca == 2:
789
+ # parallel plot construct : Only for 2D plot (at moment) !
790
+
791
+ # creation of the list of parameters
792
+ list_xx = []
793
+
794
+ while ind != ind_max:
795
+ for i in range(ncp):
796
+ xx[ind_coord[i]] = xmin[i] + ind[i] * step_tab[i]
797
+
798
+ if chart_domain.valid_coordinates(*xx, tolerance=1e-13,
799
+ parameters=parameters):
800
+
801
+ # needed a xx*1 to copy the list by value
802
+ list_xx.append(xx*1)
803
+
804
+ # Next index:
805
+ ret = 1
806
+ for pos in range(ncp-1,-1,-1):
807
+ imax = number_values[coords[pos]] - 1
808
+ if ind[pos] != imax:
809
+ ind[pos] += ret
810
+ ret = 0
811
+ elif ret == 1:
812
+ if pos == 0:
813
+ ind[pos] = imax + 1 # end point reached
814
+ else:
815
+ ind[pos] = 0
816
+ ret = 1
817
+
818
+ lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)]
819
+ ind_step = max(1, int(len(list_xx)/nproc/2))
820
+ local_list = lol(list_xx,ind_step)
821
+
822
+ # definition of the list of input parameters
823
+ listParalInput = [(vector, dom, ind_part,
824
+ chart_domain, chart,
825
+ ambient_coords, mapping,
826
+ scale, color, parameters,
827
+ extra_options)
828
+ for ind_part in local_list]
829
+
830
+ # definition of the parallel function
831
+ @parallel(p_iter='multiprocessing', ncpus=nproc)
832
+ def add_point_plot(vector, dom, xx_list, chart_domain, chart,
833
+ ambient_coords, mapping, scale, color,
834
+ parameters, extra_options):
835
+ count = 0
836
+ for xx in xx_list:
837
+ point = dom(xx, chart=chart_domain)
838
+ part = vector.at(point).plot(chart=chart,
839
+ ambient_coords=ambient_coords,
840
+ mapping=mapping,scale=scale,
841
+ color=color, print_label=False,
842
+ parameters=parameters,
843
+ **extra_options)
844
+ if count == 0:
845
+ local_resu = part
846
+ else:
847
+ local_resu += part
848
+ count += 1
849
+ return local_resu
850
+
851
+ # parallel execution and reconstruction of the plot
852
+ for ii, val in add_point_plot(listParalInput):
853
+ resu += val
854
+
855
+ else:
856
+ # sequential plot
857
+ while ind != ind_max:
858
+ for i in range(ncp):
859
+ xx[ind_coord[i]] = xmin[i] + ind[i]*step_tab[i]
860
+ if chart_domain.valid_coordinates(*xx, tolerance=1e-13,
861
+ parameters=parameters):
862
+ point = dom(xx, chart=chart_domain)
863
+ resu += vector.at(point).plot(chart=chart,
864
+ ambient_coords=ambient_coords,
865
+ mapping=mapping, scale=scale,
866
+ color=color, print_label=False,
867
+ parameters=parameters,
868
+ **extra_options)
869
+ # Next index:
870
+ ret = 1
871
+ for pos in range(ncp-1, -1, -1):
872
+ imax = number_values[coords[pos]] - 1
873
+ if ind[pos] != imax:
874
+ ind[pos] += ret
875
+ ret = 0
876
+ elif ret == 1:
877
+ if pos == 0:
878
+ ind[pos] = imax + 1 # end point reached
879
+ else:
880
+ ind[pos] = 0
881
+ ret = 1
882
+
883
+ if label_axes:
884
+ if nca == 2: # 2D graphic
885
+ # We update the dictionary _extra_kwds (options to be passed
886
+ # to show()), instead of using the method
887
+ # Graphics.axes_labels() since the latter is not robust w.r.t.
888
+ # graph addition
889
+ resu._extra_kwds['axes_labels'] = [r'$'+latex(ac)+r'$'
890
+ for ac in ambient_coords]
891
+ else: # 3D graphic
892
+ labels = [str(ac) for ac in ambient_coords]
893
+ resu = set_axes_labels(resu, *labels)
894
+ return resu
895
+
896
+ def bracket(self, other):
897
+ """
898
+ Return the Lie bracket ``[self, other]``.
899
+
900
+ INPUT:
901
+
902
+ - ``other`` -- a :class:`VectorField`
903
+
904
+ OUTPUT: the :class:`VectorField` ``[self, other]``
905
+
906
+ EXAMPLES::
907
+
908
+ sage: M = Manifold(3, 'M')
909
+ sage: X.<x,y,z> = M.chart()
910
+ sage: v = -X.frame()[0] + 2*X.frame()[1] - (x^2 - y)*X.frame()[2]
911
+ sage: w = (z + y) * X.frame()[1] - X.frame()[2]
912
+ sage: vw = v.bracket(w); vw
913
+ Vector field on the 3-dimensional differentiable manifold M
914
+ sage: vw.display()
915
+ (-x^2 + y + 2) ∂/∂y + (-y - z) ∂/∂z
916
+
917
+ Some checks::
918
+
919
+ sage: vw == - w.bracket(v)
920
+ True
921
+ sage: f = M.scalar_field({X: x+y*z})
922
+ sage: vw(f) == v(w(f)) - w(v(f))
923
+ True
924
+ sage: vw == w.lie_derivative(v)
925
+ True
926
+ """
927
+ # Call of the Schouten-Nijenhuis bracket
928
+ return MultivectorField.bracket(self, other)
929
+
930
+ def curl(self, metric=None):
931
+ r"""
932
+ Return the curl of ``self`` with respect to a given metric, assuming
933
+ that the domain of ``self`` is 3-dimensional.
934
+
935
+ If ``self`` is a vector field `v` on a 3-dimensional differentiable
936
+ orientable manifold `M`, the curl of `v` with respect to a metric `g`
937
+ on `M` is the vector field defined by
938
+
939
+ .. MATH::
940
+
941
+ \mathrm{curl}\, v = (*(\mathrm{d} v^\flat))^\sharp
942
+
943
+ where `v^\flat` is the 1-form associated to `v` by the metric `g` (see
944
+ :meth:`~sage.manifolds.differentiable.tensorfield.TensorField.down`),
945
+ `*(\mathrm{d} v^\flat)` is the Hodge dual with respect to `g` of the
946
+ 2-form `\mathrm{d} v^\flat` (exterior derivative of `v^\flat`) (see
947
+ :meth:`~sage.manifolds.differentiable.diff_form.DiffForm.hodge_dual`)
948
+ and
949
+ `(*(\mathrm{d} v^\flat))^\sharp` is corresponding vector field by
950
+ `g`-duality (see
951
+ :meth:`~sage.manifolds.differentiable.tensorfield.TensorField.up`).
952
+
953
+ An alternative expression of the curl is
954
+
955
+ .. MATH::
956
+
957
+ (\mathrm{curl}\, v)^i = \epsilon^{ijk} \nabla_j v_k
958
+
959
+ where `\nabla` is the Levi-Civita connection of `g` (cf.
960
+ :class:`~sage.manifolds.differentiable.levi_civita_connection.LeviCivitaConnection`)
961
+ and `\epsilon` the volume 3-form (Levi-Civita tensor) of `g` (cf.
962
+ :meth:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric.volume_form`)
963
+
964
+ .. NOTE::
965
+
966
+ The method ``curl`` is meaningful only if ``self`` is a vector
967
+ field on a 3-dimensional manifold.
968
+
969
+ INPUT:
970
+
971
+ - ``metric`` -- (default: ``None``) the pseudo-Riemannian metric `g`
972
+ involved in the definition of the curl; if none is provided, the
973
+ domain of ``self`` is supposed to be endowed with a default metric
974
+ (i.e. is supposed to be pseudo-Riemannian manifold, see
975
+ :class:`~sage.manifolds.differentiable.pseudo_riemannian.PseudoRiemannianManifold`)
976
+ and the latter is used to define the curl
977
+
978
+ OUTPUT: instance of :class:`VectorField` representing the curl of ``self``
979
+
980
+ EXAMPLES:
981
+
982
+ Curl of a vector field in the Euclidean 3-space::
983
+
984
+ sage: M.<x,y,z> = EuclideanSpace()
985
+ sage: v = M.vector_field(-y, x, 0, name='v')
986
+ sage: v.display()
987
+ v = -y e_x + x e_y
988
+ sage: s = v.curl(); s
989
+ Vector field curl(v) on the Euclidean space E^3
990
+ sage: s.display()
991
+ curl(v) = 2 e_z
992
+
993
+ The function :func:`~sage.manifolds.operators.curl` from the
994
+ :mod:`~sage.manifolds.operators` module can be used instead of the
995
+ method :meth:`curl`::
996
+
997
+ sage: from sage.manifolds.operators import curl
998
+ sage: curl(v) == s
999
+ True
1000
+
1001
+ If one prefers the notation ``rot`` over ``curl``, it suffices to do::
1002
+
1003
+ sage: from sage.manifolds.operators import curl as rot
1004
+ sage: rot(v) == s
1005
+ True
1006
+
1007
+ The curl of a gradient vanishes identically::
1008
+
1009
+ sage: f = M.scalar_field(function('F')(x,y,z))
1010
+ sage: gradf = f.gradient()
1011
+ sage: gradf.display()
1012
+ d(F)/dx e_x + d(F)/dy e_y + d(F)/dz e_z
1013
+ sage: s = curl(gradf); s
1014
+ Vector field on the Euclidean space E^3
1015
+ sage: s.display()
1016
+ 0
1017
+ """
1018
+ if self._domain.dim() < 3:
1019
+ raise ValueError("the curl is not defined in dimension lower " +
1020
+ "than 3")
1021
+ default_metric = metric is None
1022
+ if default_metric:
1023
+ metric = self._domain.metric()
1024
+ der = self.down(metric).exterior_derivative() # 2-form d(v^\flat)
1025
+ resu = der.hodge_dual(metric).up(metric)
1026
+ if self._name is not None:
1027
+ if default_metric:
1028
+ resu._name = "curl({})".format(self._name)
1029
+ resu._latex_name = r"\mathrm{curl}\left(" + self._latex_name + \
1030
+ r"\right)"
1031
+ else:
1032
+ resu._name = "curl_{}({})".format(metric._name, self._name)
1033
+ resu._latex_name = r"\mathrm{curl}_{" + metric._latex_name + \
1034
+ r"}\left(" + self._latex_name + r"\right)"
1035
+ # The name is propagated to possible restrictions of self:
1036
+ for restrict in resu._restrictions.values():
1037
+ restrict.set_name(resu._name, latex_name=resu._latex_name)
1038
+ return resu
1039
+
1040
+ def dot_product(self, other, metric=None):
1041
+ r"""
1042
+ Return the scalar product of ``self`` with another vector field (with
1043
+ respect to a given metric).
1044
+
1045
+ If ``self`` is the vector field `u` and other is the vector field `v`,
1046
+ the *scalar product of* `u` *by* `v` with respect to a given
1047
+ pseudo-Riemannian metric `g` is the scalar field `s` defined by
1048
+
1049
+ .. MATH::
1050
+
1051
+ s = u\cdot v = g(u,v) = g_{ij} u^i v^j
1052
+
1053
+ INPUT:
1054
+
1055
+ - ``other`` -- a vector field, defined on the same domain as ``self``
1056
+ - ``metric`` -- (default: ``None``) the pseudo-Riemannian metric `g`
1057
+ involved in the definition of the scalar product; if none is
1058
+ provided, the domain of ``self`` is supposed to be endowed with a
1059
+ default metric (i.e. is supposed to be pseudo-Riemannian manifold,
1060
+ see
1061
+ :class:`~sage.manifolds.differentiable.pseudo_riemannian.PseudoRiemannianManifold`)
1062
+ and the latter is used to define the scalar product
1063
+
1064
+ OUTPUT:
1065
+
1066
+ - instance of
1067
+ :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField`
1068
+ representing the scalar product of ``self`` by ``other``.
1069
+
1070
+ EXAMPLES:
1071
+
1072
+ Scalar product in the Euclidean plane::
1073
+
1074
+ sage: M.<x,y> = EuclideanSpace()
1075
+ sage: u = M.vector_field(x, y, name='u')
1076
+ sage: v = M.vector_field(y, x, name='v')
1077
+ sage: s = u.dot_product(v); s
1078
+ Scalar field u.v on the Euclidean plane E^2
1079
+ sage: s.display()
1080
+ u.v: E^2 → ℝ
1081
+ (x, y) ↦ 2*x*y
1082
+
1083
+ A shortcut alias of ``dot_product`` is ``dot``::
1084
+
1085
+ sage: u.dot(v) == s
1086
+ True
1087
+
1088
+ A test of orthogonality::
1089
+
1090
+ sage: v[:] = -y, x
1091
+ sage: u.dot_product(v) == 0
1092
+ True
1093
+
1094
+ Scalar product with respect to a metric that is not the default one::
1095
+
1096
+ sage: h = M.riemannian_metric('h')
1097
+ sage: h[1,1], h[2,2] = 1/(1+y^2), 1/(1+x^2)
1098
+ sage: s = u.dot_product(v, metric=h); s
1099
+ Scalar field h(u,v) on the Euclidean plane E^2
1100
+ sage: s.display()
1101
+ h(u,v): E^2 → ℝ
1102
+ (x, y) ↦ -(x^3*y - x*y^3)/((x^2 + 1)*y^2 + x^2 + 1)
1103
+
1104
+ Scalar product of two vector fields along a curve (a lemniscate of
1105
+ Gerono)::
1106
+
1107
+ sage: R.<t> = manifolds.RealLine()
1108
+ sage: C = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='C')
1109
+ sage: u = C.tangent_vector_field(name='u')
1110
+ sage: u.display()
1111
+ u = cos(t) e_x + (2*cos(t)^2 - 1) e_y
1112
+ sage: I = C.domain(); I
1113
+ Real interval (0, 2*pi)
1114
+ sage: v = I.vector_field(cos(t), -1, dest_map=C, name='v')
1115
+ sage: v.display()
1116
+ v = cos(t) e_x - e_y
1117
+ sage: s = u.dot_product(v); s
1118
+ Scalar field u.v on the Real interval (0, 2*pi)
1119
+ sage: s.display()
1120
+ u.v: (0, 2*pi) → ℝ
1121
+ t ↦ sin(t)^2
1122
+
1123
+ Scalar product between a vector field along the curve and a vector
1124
+ field on the ambient Euclidean plane::
1125
+
1126
+ sage: e_x = M.cartesian_frame()[1]
1127
+ sage: s = u.dot_product(e_x); s
1128
+ Scalar field u.e_x on the Real interval (0, 2*pi)
1129
+ sage: s.display()
1130
+ u.e_x: (0, 2*pi) → ℝ
1131
+ t ↦ cos(t)
1132
+ """
1133
+ default_metric = metric is None
1134
+ if default_metric:
1135
+ metric = self._ambient_domain.metric()
1136
+ dest_map = self.parent().destination_map()
1137
+ if dest_map != metric.parent().base_module().destination_map():
1138
+ metric = metric.along(dest_map)
1139
+ if dest_map != other.parent().destination_map():
1140
+ other = other.along(dest_map)
1141
+ resu = metric(self, other)
1142
+ # From the above operation the name of resu is "g(u,v')" where
1143
+ # g = metric._name, u = self._name, v = other._name
1144
+ # For a default metric, we change it to "u.v":
1145
+ if (default_metric and self._name is not None and
1146
+ other._name is not None):
1147
+ resu._name = "{}.{}".format(self._name, other._name)
1148
+ resu._latex_name = "{" + self._latex_name + r"}\cdot{" + \
1149
+ other._latex_name + "}"
1150
+ # The name is propagated to possible restrictions of self:
1151
+ for restrict in resu._restrictions.values():
1152
+ restrict.set_name(resu._name, latex_name=resu._latex_name)
1153
+ return resu
1154
+
1155
+ dot = dot_product
1156
+
1157
+ def norm(self, metric=None):
1158
+ r"""
1159
+ Return the norm of ``self`` (with respect to a given metric).
1160
+
1161
+ The *norm* of a vector field `v` with respect to a given
1162
+ pseudo-Riemannian metric `g` is the scalar field `\|v\|` defined by
1163
+
1164
+ .. MATH::
1165
+
1166
+ \|v\| = \sqrt{g(v,v)}
1167
+
1168
+ .. NOTE::
1169
+
1170
+ If the metric `g` is not positive definite, it may be that `\|v\|`
1171
+ takes imaginary values.
1172
+
1173
+ INPUT:
1174
+
1175
+ - ``metric`` -- (default: ``None``) the pseudo-Riemannian metric `g`
1176
+ involved in the definition of the norm; if none is
1177
+ provided, the domain of ``self`` is supposed to be endowed with a
1178
+ default metric (i.e. is supposed to be pseudo-Riemannian manifold,
1179
+ see
1180
+ :class:`~sage.manifolds.differentiable.pseudo_riemannian.PseudoRiemannianManifold`)
1181
+ and the latter is used to define the norm
1182
+
1183
+ OUTPUT:
1184
+
1185
+ - instance of
1186
+ :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField`
1187
+ representing the norm of ``self``.
1188
+
1189
+ EXAMPLES:
1190
+
1191
+ Norm in the Euclidean plane::
1192
+
1193
+ sage: M.<x,y> = EuclideanSpace()
1194
+ sage: v = M.vector_field(-y, x, name='v')
1195
+ sage: s = v.norm(); s
1196
+ Scalar field |v| on the Euclidean plane E^2
1197
+ sage: s.display()
1198
+ |v|: E^2 → ℝ
1199
+ (x, y) ↦ sqrt(x^2 + y^2)
1200
+
1201
+ The global function :func:`~sage.misc.functional.norm` can be used
1202
+ instead of the method ``norm()``::
1203
+
1204
+ sage: norm(v) == s
1205
+ True
1206
+
1207
+ Norm with respect to a metric that is not the default one::
1208
+
1209
+ sage: h = M.riemannian_metric('h')
1210
+ sage: h[1,1], h[2,2] = 1/(1+y^2), 1/(1+x^2)
1211
+ sage: s = v.norm(metric=h); s
1212
+ Scalar field |v|_h on the Euclidean plane E^2
1213
+ sage: s.display()
1214
+ |v|_h: E^2 → ℝ
1215
+ (x, y) ↦ sqrt((2*x^2 + 1)*y^2 + x^2)/(sqrt(x^2 + 1)*sqrt(y^2 + 1))
1216
+
1217
+ Norm of the tangent vector field to a curve (a lemniscate of Gerono)::
1218
+
1219
+ sage: R.<t> = manifolds.RealLine()
1220
+ sage: C = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='C')
1221
+ sage: v = C.tangent_vector_field()
1222
+ sage: v.display()
1223
+ C' = cos(t) e_x + (2*cos(t)^2 - 1) e_y
1224
+ sage: s = v.norm(); s
1225
+ Scalar field |C'| on the Real interval (0, 2*pi)
1226
+ sage: s.display()
1227
+ |C'|: (0, 2*pi) → ℝ
1228
+ t ↦ sqrt(4*cos(t)^4 - 3*cos(t)^2 + 1)
1229
+ """
1230
+ default_metric = metric is None
1231
+ if default_metric:
1232
+ metric = self._ambient_domain.metric()
1233
+ dest_map = self.parent().destination_map()
1234
+ if dest_map != metric.parent().base_module().destination_map():
1235
+ metric = metric.along(dest_map)
1236
+ resu = metric(self, self).sqrt()
1237
+ if self._name is not None:
1238
+ if default_metric:
1239
+ resu._name = "|{}|".format(self._name)
1240
+ resu._latex_name = r"\left\|" + self._latex_name + \
1241
+ r"\right\|"
1242
+ else:
1243
+ resu._name = "|{}|_{}".format(self._name, metric._name)
1244
+ resu._latex_name = r"\left\|" + self._latex_name + \
1245
+ r"\right\| _{" + metric._latex_name + "}"
1246
+ # The name is propagated to possible restrictions of self:
1247
+ for restrict in resu._restrictions.values():
1248
+ restrict.set_name(resu._name, latex_name=resu._latex_name)
1249
+ return resu
1250
+
1251
+ def cross_product(self, other, metric=None):
1252
+ r"""
1253
+ Return the cross product of ``self`` with another vector field (with
1254
+ respect to a given metric), assuming that the domain of ``self`` is
1255
+ 3-dimensional.
1256
+
1257
+ If ``self`` is a vector field `u` on a 3-dimensional differentiable
1258
+ orientable manifold `M` and ``other`` is a vector field `v` on `M`,
1259
+ the *cross product* (also called *vector product*) *of* `u` *by* `v`
1260
+ with respect to a pseudo-Riemannian metric `g` on `M` is the vector
1261
+ field `w = u\times v` defined by
1262
+
1263
+ .. MATH::
1264
+
1265
+ w^i = \epsilon^i_{\phantom{i} jk} u^j v^k
1266
+ = g^{il} \epsilon_{ljk} u^j v^k
1267
+
1268
+ where `\epsilon` is the volume 3-form (Levi-Civita tensor) of `g` (cf.
1269
+ :meth:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric.volume_form`)
1270
+
1271
+ .. NOTE::
1272
+
1273
+ The method ``cross_product`` is meaningful only if for vector fields on a
1274
+ 3-dimensional manifold.
1275
+
1276
+ INPUT:
1277
+
1278
+ - ``other`` -- a vector field, defined on the same domain as ``self``
1279
+ - ``metric`` -- (default: ``None``) the pseudo-Riemannian metric `g`
1280
+ involved in the definition of the cross product; if none is
1281
+ provided, the domain of ``self`` is supposed to be endowed with a
1282
+ default metric (i.e. is supposed to be pseudo-Riemannian manifold,
1283
+ see
1284
+ :class:`~sage.manifolds.differentiable.pseudo_riemannian.PseudoRiemannianManifold`)
1285
+ and the latter is used to define the cross product
1286
+
1287
+ OUTPUT:
1288
+
1289
+ - instance of :class:`VectorField` representing the cross product of
1290
+ ``self`` by ``other``.
1291
+
1292
+ EXAMPLES:
1293
+
1294
+ Cross product in the Euclidean 3-space::
1295
+
1296
+ sage: M.<x,y,z> = EuclideanSpace()
1297
+ sage: u = M.vector_field(-y, x, 0, name='u')
1298
+ sage: v = M.vector_field(x, y, 0, name='v')
1299
+ sage: w = u.cross_product(v); w
1300
+ Vector field u x v on the Euclidean space E^3
1301
+ sage: w.display()
1302
+ u x v = (-x^2 - y^2) e_z
1303
+
1304
+ A shortcut alias of ``cross_product`` is ``cross``::
1305
+
1306
+ sage: u.cross(v) == w
1307
+ True
1308
+
1309
+ The cross product of a vector field with itself is zero::
1310
+
1311
+ sage: u.cross_product(u).display()
1312
+ u x u = 0
1313
+
1314
+ Cross product with respect to a metric that is not the default one::
1315
+
1316
+ sage: h = M.riemannian_metric('h')
1317
+ sage: h[1,1], h[2,2], h[3,3] = 1/(1+y^2), 1/(1+z^2), 1/(1+x^2)
1318
+ sage: w = u.cross_product(v, metric=h); w
1319
+ Vector field on the Euclidean space E^3
1320
+ sage: w.display()
1321
+ -(x^2 + y^2)*sqrt(x^2 + 1)/(sqrt(y^2 + 1)*sqrt(z^2 + 1)) e_z
1322
+
1323
+ Cross product of two vector fields along a curve (arc of a helix)::
1324
+
1325
+ sage: R.<t> = manifolds.RealLine()
1326
+ sage: C = M.curve((cos(t), sin(t), t), (t, 0, 2*pi), name='C')
1327
+ sage: u = C.tangent_vector_field()
1328
+ sage: u.display()
1329
+ C' = -sin(t) e_x + cos(t) e_y + e_z
1330
+ sage: I = C.domain(); I
1331
+ Real interval (0, 2*pi)
1332
+ sage: v = I.vector_field(-cos(t), sin(t), 0, dest_map=C)
1333
+ sage: v.display()
1334
+ -cos(t) e_x + sin(t) e_y
1335
+ sage: w = u.cross_product(v); w
1336
+ Vector field along the Real interval (0, 2*pi) with values on the
1337
+ Euclidean space E^3
1338
+ sage: w.parent().destination_map()
1339
+ Curve C in the Euclidean space E^3
1340
+ sage: w.display()
1341
+ -sin(t) e_x - cos(t) e_y + (2*cos(t)^2 - 1) e_z
1342
+
1343
+ Cross product between a vector field along the curve and a vector field
1344
+ on the ambient Euclidean space::
1345
+
1346
+ sage: e_x = M.cartesian_frame()[1]
1347
+ sage: w = u.cross_product(e_x); w
1348
+ Vector field C' x e_x along the Real interval (0, 2*pi) with values
1349
+ on the Euclidean space E^3
1350
+ sage: w.display()
1351
+ C' x e_x = e_y - cos(t) e_z
1352
+ """
1353
+ if self._ambient_domain.dim() != 3:
1354
+ raise ValueError("the cross product is not defined in dimension " +
1355
+ "different from 3")
1356
+ default_metric = metric is None
1357
+ if default_metric:
1358
+ metric = self._ambient_domain.metric()
1359
+ dest_map = self.parent().destination_map()
1360
+ if dest_map == metric.parent().base_module().destination_map():
1361
+ eps = metric.volume_form(1)
1362
+ else:
1363
+ eps = metric.volume_form(1).along(dest_map)
1364
+ if dest_map != other.parent().destination_map():
1365
+ other = other.along(dest_map)
1366
+ resu = eps.contract(1, 2, self.wedge(other), 0, 1) / 2
1367
+ # The result is named "u x v" only for a default metric:
1368
+ if (default_metric and self._name is not None and
1369
+ other._name is not None):
1370
+ resu._name = "{} x {}".format(self._name, other._name)
1371
+ resu._latex_name = "{" + self._latex_name + r"}\times{" + \
1372
+ other._latex_name + "}"
1373
+ # The name is propagated to possible restrictions of self:
1374
+ for restrict in resu._restrictions.values():
1375
+ restrict.set_name(resu._name, latex_name=resu._latex_name)
1376
+ return resu
1377
+
1378
+ cross = cross_product
1379
+
1380
+ #******************************************************************************
1381
+
1382
+
1383
+ class VectorFieldParal(FiniteRankFreeModuleElement, MultivectorFieldParal,
1384
+ VectorField):
1385
+ r"""
1386
+ Vector field along a differentiable manifold, with values on a
1387
+ parallelizable manifold.
1388
+
1389
+ An instance of this class is a vector field along a differentiable
1390
+ manifold `U` with values on a parallelizable manifold `M`, via a
1391
+ differentiable map `\Phi: U \rightarrow M`. More precisely, given
1392
+ a differentiable map
1393
+
1394
+ .. MATH::
1395
+
1396
+ \Phi:\ U \longrightarrow M,
1397
+
1398
+ a *vector field along* `U` *with values on* `M` is a differentiable map
1399
+
1400
+ .. MATH::
1401
+
1402
+ v:\ U \longrightarrow TM
1403
+
1404
+ (`TM` being the tangent bundle of `M`) such that
1405
+
1406
+ .. MATH::
1407
+
1408
+ \forall p \in U,\ v(p) \in T_{\Phi(p)}M.
1409
+
1410
+ The standard case of vector fields *on* a differentiable manifold
1411
+ corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases
1412
+ are `\Phi` being an immersion and `\Phi` being a curve in `M` (`U`
1413
+ is then an open interval of `\RR`).
1414
+
1415
+ .. NOTE::
1416
+
1417
+ If `M` is not parallelizable, then
1418
+ :class:`~sage.manifolds.differentiable.vectorfield.VectorField`
1419
+ *must* be used instead.
1420
+
1421
+ INPUT:
1422
+
1423
+ - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector
1424
+ fields along `U` with values on `M\supset\Phi(U)`
1425
+ - ``name`` -- (default: ``None``) name given to the vector field
1426
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the vector
1427
+ field; if none is provided, the LaTeX symbol is set to ``name``
1428
+
1429
+ EXAMPLES:
1430
+
1431
+ A vector field on a parallelizable 3-dimensional manifold::
1432
+
1433
+ sage: M = Manifold(3, 'M')
1434
+ sage: c_xyz.<x,y,z> = M.chart()
1435
+ sage: v = M.vector_field(name='V') ; v
1436
+ Vector field V on the 3-dimensional differentiable manifold M
1437
+ sage: latex(v)
1438
+ V
1439
+
1440
+ Vector fields are considered as elements of a module over the ring
1441
+ (algebra) of scalar fields on `M`::
1442
+
1443
+ sage: v.parent()
1444
+ Free module X(M) of vector fields on the 3-dimensional differentiable
1445
+ manifold M
1446
+ sage: v.parent().base_ring()
1447
+ Algebra of differentiable scalar fields on the 3-dimensional
1448
+ differentiable manifold M
1449
+ sage: v.parent() is M.vector_field_module()
1450
+ True
1451
+
1452
+ A vector field is a tensor field of rank 1 and of type `(1,0)`::
1453
+
1454
+ sage: v.tensor_rank()
1455
+ 1
1456
+ sage: v.tensor_type()
1457
+ (1, 0)
1458
+
1459
+ Components of a vector field with respect to a given frame::
1460
+
1461
+ sage: e = M.vector_frame('e') ; M.set_default_frame(e)
1462
+ sage: v[0], v[1], v[2] = (1+y, 4*x*z, 9) # components on M's default frame (e)
1463
+ sage: v.comp()
1464
+ 1-index components w.r.t. Vector frame (M, (e_0,e_1,e_2))
1465
+
1466
+ The totality of the components are accessed via the operator ``[:]``::
1467
+
1468
+ sage: v[:] = (1+y, 4*x*z, 9)
1469
+ sage: v[:]
1470
+ [y + 1, 4*x*z, 9]
1471
+
1472
+ The components are also read on the expansion on the frame ``e``,
1473
+ as provided by the method
1474
+ :meth:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor.display`::
1475
+
1476
+ sage: v.display() # expansion in the default frame
1477
+ V = (y + 1) e_0 + 4*x*z e_1 + 9 e_2
1478
+
1479
+ A subset of the components can be accessed by using slice notation::
1480
+
1481
+ sage: v[1:] = (-2, -x*y)
1482
+ sage: v[:]
1483
+ [y + 1, -2, -x*y]
1484
+ sage: v[:2]
1485
+ [y + 1, -2]
1486
+
1487
+ Components in another frame::
1488
+
1489
+ sage: f = M.vector_frame('f')
1490
+ sage: for i in range(3):
1491
+ ....: v.set_comp(f)[i] = (i+1)**3 * c_xyz[i]
1492
+ sage: v.comp(f)[2]
1493
+ 27*z
1494
+ sage: v[f, 2] # equivalent to above
1495
+ 27*z
1496
+ sage: v.display(f)
1497
+ V = x f_0 + 8*y f_1 + 27*z f_2
1498
+
1499
+ One can set the components at the vector definition::
1500
+
1501
+ sage: v = M.vector_field(1+y, 4*x*z, 9, name='V')
1502
+ sage: v.display()
1503
+ V = (y + 1) e_0 + 4*x*z e_1 + 9 e_2
1504
+
1505
+ If the components regard a vector frame different from the default one,
1506
+ the vector frame has to be specified via the argument ``frame``::
1507
+
1508
+ sage: v = M.vector_field(x, 8*y, 27*z, frame=f, name='V')
1509
+ sage: v.display(f)
1510
+ V = x f_0 + 8*y f_1 + 27*z f_2
1511
+
1512
+ For providing the components in various frames, one may use a dictionary::
1513
+
1514
+ sage: v = M.vector_field({e: [1+y, -2, -x*y], f: [x, 8*y, 27*z]},
1515
+ ....: name='V')
1516
+ sage: v.display(e)
1517
+ V = (y + 1) e_0 - 2 e_1 - x*y e_2
1518
+ sage: v.display(f)
1519
+ V = x f_0 + 8*y f_1 + 27*z f_2
1520
+
1521
+ It is also possible to construct a vector field from a vector of symbolic
1522
+ expressions (or any other iterable)::
1523
+
1524
+ sage: v = M.vector_field(vector([1+y, 4*x*z, 9]), name='V')
1525
+ sage: v.display()
1526
+ V = (y + 1) e_0 + 4*x*z e_1 + 9 e_2
1527
+
1528
+ The range of the indices depends on the convention set for the manifold::
1529
+
1530
+ sage: M = Manifold(3, 'M', start_index=1)
1531
+ sage: c_xyz.<x,y,z> = M.chart()
1532
+ sage: e = M.vector_frame('e') ; M.set_default_frame(e)
1533
+ sage: v = M.vector_field(1+y, 4*x*z, 9, name='V')
1534
+ sage: v[0]
1535
+ Traceback (most recent call last):
1536
+ ...
1537
+ IndexError: index out of range: 0 not in [1, 3]
1538
+ sage: v[1] # OK
1539
+ y + 1
1540
+
1541
+ A vector field acts on scalar fields (derivation along the vector field)::
1542
+
1543
+ sage: M = Manifold(2, 'M')
1544
+ sage: c_cart.<x,y> = M.chart()
1545
+ sage: f = M.scalar_field(x*y^2, name='f')
1546
+ sage: v = M.vector_field(-y, x, name='v')
1547
+ sage: v.display()
1548
+ v = -y ∂/∂x + x ∂/∂y
1549
+ sage: v(f)
1550
+ Scalar field v(f) on the 2-dimensional differentiable manifold M
1551
+ sage: v(f).expr()
1552
+ 2*x^2*y - y^3
1553
+ sage: latex(v(f))
1554
+ v\left(f\right)
1555
+
1556
+ Example of a vector field associated with a non-trivial map `\Phi`;
1557
+ a vector field along a curve in `M`::
1558
+
1559
+ sage: R = Manifold(1, 'R')
1560
+ sage: T.<t> = R.chart() # canonical chart on R
1561
+ sage: Phi = R.diff_map(M, [cos(t), sin(t)], name='Phi') ; Phi
1562
+ Differentiable map Phi from the 1-dimensional differentiable manifold R
1563
+ to the 2-dimensional differentiable manifold M
1564
+ sage: Phi.display()
1565
+ Phi: R → M
1566
+ t ↦ (x, y) = (cos(t), sin(t))
1567
+ sage: w = R.vector_field(-sin(t), cos(t), dest_map=Phi, name='w') ; w
1568
+ Vector field w along the 1-dimensional differentiable manifold R with
1569
+ values on the 2-dimensional differentiable manifold M
1570
+ sage: w.parent()
1571
+ Free module X(R,Phi) of vector fields along the 1-dimensional
1572
+ differentiable manifold R mapped into the 2-dimensional differentiable
1573
+ manifold M
1574
+ sage: w.display()
1575
+ w = -sin(t) ∂/∂x + cos(t) ∂/∂y
1576
+
1577
+ Value at a given point::
1578
+
1579
+ sage: p = R((0,), name='p') ; p
1580
+ Point p on the 1-dimensional differentiable manifold R
1581
+ sage: w.at(p)
1582
+ Tangent vector w at Point Phi(p) on the 2-dimensional differentiable
1583
+ manifold M
1584
+ sage: w.at(p).display()
1585
+ w = ∂/∂y
1586
+ sage: w.at(p) == v.at(Phi(p))
1587
+ True
1588
+ """
1589
+ def __init__(self, vector_field_module, name=None, latex_name=None):
1590
+ r"""
1591
+ Construct a vector field with values on a parallelizable manifold.
1592
+
1593
+ TESTS:
1594
+
1595
+ Construction via ``parent.element_class``, and not via a direct call
1596
+ to ``VectorFieldParal``, to fit with the category framework::
1597
+
1598
+ sage: M = Manifold(2, 'M')
1599
+ sage: X.<x,y> = M.chart() # makes M parallelizable
1600
+ sage: XM = M.vector_field_module() # the parent
1601
+ sage: v = XM.element_class(XM, name='v'); v
1602
+ Vector field v on the 2-dimensional differentiable manifold M
1603
+ sage: v[:] = (-y, x)
1604
+ sage: v.display()
1605
+ v = -y ∂/∂x + x ∂/∂y
1606
+ sage: TestSuite(v).run()
1607
+
1608
+ Construction via ``DifferentiableManifold.vector_field``::
1609
+
1610
+ sage: u = M.vector_field(1+x, 1-y, name='u'); u
1611
+ Vector field u on the 2-dimensional differentiable manifold M
1612
+ sage: type(u) == type(v)
1613
+ True
1614
+ sage: u.parent() is v.parent()
1615
+ True
1616
+ sage: TestSuite(u).run()
1617
+ """
1618
+ FiniteRankFreeModuleElement.__init__(self, vector_field_module,
1619
+ name=name, latex_name=latex_name)
1620
+ # MultivectorFieldParal attributes:
1621
+ self._domain = vector_field_module._domain
1622
+ self._ambient_domain = vector_field_module._ambient_domain
1623
+ # VectorField attributes:
1624
+ self._vmodule = vector_field_module
1625
+ # Initialization of derived quantities:
1626
+ MultivectorFieldParal._init_derived(self)
1627
+ VectorField._init_derived(self)
1628
+ # Initialization of list of quantities depending on self:
1629
+ self._init_dependencies()
1630
+
1631
+ def _repr_(self) :
1632
+ r"""
1633
+ String representation of ``self``.
1634
+
1635
+ TESTS::
1636
+
1637
+ sage: M = Manifold(2, 'M')
1638
+ sage: X.<x,y> = M.chart() # makes M parallelizable
1639
+ sage: v = M.vector_field(name='v')
1640
+ sage: v._repr_()
1641
+ 'Vector field v on the 2-dimensional differentiable manifold M'
1642
+ sage: repr(v) # indirect doctest
1643
+ 'Vector field v on the 2-dimensional differentiable manifold M'
1644
+ sage: v # indirect doctest
1645
+ Vector field v on the 2-dimensional differentiable manifold M
1646
+ """
1647
+ return VectorField._repr_(self)
1648
+
1649
+ def _new_instance(self):
1650
+ r"""
1651
+ Create an instance of the same class as ``self`` on the same module.
1652
+
1653
+ TESTS::
1654
+
1655
+ sage: M = Manifold(2, 'M')
1656
+ sage: X.<x,y> = M.chart() # makes M parallelizable
1657
+ sage: v = M.vector_field(name='v')
1658
+ sage: u = v._new_instance(); u
1659
+ Vector field on the 2-dimensional differentiable manifold M
1660
+ sage: u.parent() is v.parent()
1661
+ True
1662
+ """
1663
+ return type(self)(self._fmodule)
1664
+
1665
+ def _del_derived(self, del_restrictions=True):
1666
+ r"""
1667
+ Delete the derived quantities.
1668
+
1669
+ INPUT:
1670
+
1671
+ - ``del_restrictions`` -- boolean (default: ``True``); determines whether
1672
+ the restrictions of ``self`` to subdomains are deleted
1673
+
1674
+ TESTS::
1675
+
1676
+ sage: M = Manifold(2, 'M')
1677
+ sage: X.<x,y> = M.chart() # makes M parallelizable
1678
+ sage: v = M.vector_field(name='v')
1679
+ sage: v._del_derived()
1680
+ """
1681
+ MultivectorFieldParal._del_derived(self,
1682
+ del_restrictions=del_restrictions)
1683
+ VectorField._del_derived(self)
1684
+ self._del_dependencies()
1685
+
1686
+ def __call__(self, scalar):
1687
+ r"""
1688
+ Action on a scalar field.
1689
+
1690
+ INPUT:
1691
+
1692
+ - ``scalar`` -- scalar field `f`
1693
+
1694
+ OUTPUT:
1695
+
1696
+ - scalar field representing the derivative of `f` along the vector
1697
+ field, i.e. `v^i \frac{\partial f}{\partial x^i}`
1698
+
1699
+ EXAMPLES:
1700
+
1701
+ Action of a vector field on a scalar field on a 2-dimensional
1702
+ manifold::
1703
+
1704
+ sage: M = Manifold(2, 'M')
1705
+ sage: c_cart.<x,y> = M.chart()
1706
+ sage: f = M.scalar_field(x*y^2)
1707
+ sage: v = M.vector_field(-y, x)
1708
+ sage: v(f)
1709
+ Scalar field on the 2-dimensional differentiable manifold M
1710
+ sage: v(f).display()
1711
+ M → ℝ
1712
+ (x, y) ↦ 2*x^2*y - y^3
1713
+ """
1714
+ # This method enforces VectorField.__call__
1715
+ # instead of FiniteRankFreeModuleElement.__call__, which would have
1716
+ # been inheritated otherwise
1717
+ return VectorField.__call__(self, scalar)