passagemath-symbolics 10.8.1a1__cp314-cp314t-musllinux_1_2_aarch64.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 (181) hide show
  1. passagemath_symbolics/__init__.py +3 -0
  2. passagemath_symbolics-10.8.1a1.dist-info/METADATA +186 -0
  3. passagemath_symbolics-10.8.1a1.dist-info/RECORD +181 -0
  4. passagemath_symbolics-10.8.1a1.dist-info/WHEEL +5 -0
  5. passagemath_symbolics-10.8.1a1.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 +2838 -0
  9. sage/calculus/desolvers.py +1864 -0
  10. sage/calculus/predefined.py +51 -0
  11. sage/calculus/tests.py +225 -0
  12. sage/calculus/var.cpython-314t-aarch64-linux-musl.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-314t-aarch64-linux-musl.so +0 -0
  18. sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1034 -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 +755 -0
  33. sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
  34. sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2419 -0
  35. sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
  36. sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1083 -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 +2991 -0
  44. sage/interfaces/magma_free.py +90 -0
  45. sage/interfaces/maple.py +1402 -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 +553 -0
  54. sage/manifolds/catalog.py +437 -0
  55. sage/manifolds/chart.py +4010 -0
  56. sage/manifolds/chart_func.py +3416 -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 +1668 -0
  70. sage/manifolds/differentiable/diff_form.py +1660 -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 +1522 -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 +912 -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 +1725 -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 +2721 -0
  118. sage/manifolds/subsets/all.py +1 -0
  119. sage/manifolds/subsets/closure.py +131 -0
  120. sage/manifolds/subsets/pullback.py +883 -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 +1347 -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-314t-aarch64-linux-musl.so +0 -0
  129. sage/matrix/matrix_symbolic_dense.pxd +6 -0
  130. sage/matrix/matrix_symbolic_dense.pyx +1030 -0
  131. sage/matrix/matrix_symbolic_sparse.cpython-314t-aarch64-linux-musl.so +0 -0
  132. sage/matrix/matrix_symbolic_sparse.pxd +6 -0
  133. sage/matrix/matrix_symbolic_sparse.pyx +1038 -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 +4106 -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 +5205 -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 +987 -0
  150. sage/symbolic/benchmark.py +93 -0
  151. sage/symbolic/callable.py +456 -0
  152. sage/symbolic/callable.pyi +66 -0
  153. sage/symbolic/comparison_impl.pyi +38 -0
  154. sage/symbolic/complexity_measures.py +35 -0
  155. sage/symbolic/constants.py +1286 -0
  156. sage/symbolic/constants_c_impl.pyi +10 -0
  157. sage/symbolic/expression_conversion_algebraic.py +310 -0
  158. sage/symbolic/expression_conversion_sympy.py +317 -0
  159. sage/symbolic/expression_conversions.py +1727 -0
  160. sage/symbolic/function_factory.py +355 -0
  161. sage/symbolic/function_factory.pyi +41 -0
  162. sage/symbolic/getitem_impl.pyi +24 -0
  163. sage/symbolic/integration/all.py +1 -0
  164. sage/symbolic/integration/external.py +271 -0
  165. sage/symbolic/integration/integral.py +1075 -0
  166. sage/symbolic/maxima_wrapper.py +162 -0
  167. sage/symbolic/operators.py +267 -0
  168. sage/symbolic/operators.pyi +61 -0
  169. sage/symbolic/pynac_constant_impl.pyi +13 -0
  170. sage/symbolic/pynac_function_impl.pyi +8 -0
  171. sage/symbolic/random_tests.py +461 -0
  172. sage/symbolic/relation.py +2062 -0
  173. sage/symbolic/ring.cpython-314t-aarch64-linux-musl.so +0 -0
  174. sage/symbolic/ring.pxd +5 -0
  175. sage/symbolic/ring.pyi +110 -0
  176. sage/symbolic/ring.pyx +1393 -0
  177. sage/symbolic/series_impl.pyi +10 -0
  178. sage/symbolic/subring.py +1025 -0
  179. sage/symbolic/symengine.py +19 -0
  180. sage/symbolic/tests.py +40 -0
  181. sage/symbolic/units.py +1468 -0
@@ -0,0 +1,1840 @@
1
+ # sage_setup: distribution = sagemath-symbolics
2
+ # sage.doctest: needs sage.combinat
3
+ r"""
4
+ Characteristic cohomology classes
5
+
6
+ A *characteristic class* `\kappa` is a natural transformation that
7
+ associates with each vector bundle `E \to M` a cohomology class
8
+ `\kappa(E) \in H^*(M;R)` such that for any continuous map `f\colon N \to M`
9
+ from another topological manifold `N`, the *naturality condition* is
10
+ satisfied:
11
+
12
+ .. MATH::
13
+
14
+ f^*\kappa(E) = \kappa(f^* E) \in H^*(N;R)
15
+
16
+ The cohomology class `\kappa(E)` is called *characteristic cohomology class*.
17
+ Roughly speaking, characteristic cohomology classes measure the non-triviality
18
+ of vector bundles.
19
+
20
+ One way to obtain and compute characteristic classes in the de Rham cohomology
21
+ with coefficients in the ring `\CC` is via the so-called *Chern-Weil theory*
22
+ using the curvature of a differentiable vector bundle.
23
+
24
+ For that let `\nabla` be a connection on `E`, `e` a local frame on
25
+ `E` and `\Omega` be the corresponding curvature matrix
26
+ (see: :meth:`~sage.manifolds.differentiable.bundle_connection.BundleConnection.curvature_form`).
27
+
28
+ Namely, if `P: \mathrm{Mat}_{n \times n}(\CC) \to \CC` is an invariant
29
+ polynomial, the object
30
+
31
+ .. MATH::
32
+
33
+ \left[ P \left( \Omega \right) \right] \in H^{2*}_{\mathrm{dR}}(M, \CC)
34
+
35
+ is well-defined, independent of the choice of `\nabla` (the proof can be
36
+ found in [Roe1988]_ pp. 31) and fulfills the naturality condition.
37
+ This is the foundation of the Chern-Weil theory and the following definitions.
38
+
39
+ .. NOTE::
40
+
41
+ This documentation is rich of examples, but sparse in explanations. Please
42
+ consult the references for more details.
43
+
44
+ AUTHORS:
45
+
46
+ - Michael Jung (2019) : initial version
47
+ - Michael Jung (2021) : new algorithm; complete refactoring
48
+
49
+ REFERENCES:
50
+
51
+ - [Mil1974]_
52
+ - [Roe1988]_
53
+
54
+ Contents
55
+ --------
56
+
57
+ We consider the following three types of classes:
58
+
59
+ - :ref:`additive`
60
+ - :ref:`multiplicative`
61
+ - :ref:`Pfaffian`
62
+
63
+ .. _additive:
64
+
65
+ Additive Classes
66
+ ----------------
67
+
68
+ In the **complex** case, let `f` be a holomorphic function around zero. Then
69
+ we call
70
+
71
+ .. MATH::
72
+
73
+ \left[\mathrm{tr}\left( f\left( \frac{\Omega}{2 \pi i} \right)
74
+ \right)\right] \in H^{2*}_{\mathrm{dR}}(M, \CC)
75
+
76
+ the *additive characteristic class associated to* `f` of the complex vector
77
+ bundle `E`.
78
+
79
+ Important and predefined additive classes are:
80
+
81
+ - *Chern Character* with `f(x) = \exp(x)`
82
+
83
+ In the **real** case, let `g` be a holomorphic function around zero with
84
+ `g(0)=0`. Then we call
85
+
86
+ .. MATH::
87
+
88
+ \left[\mathrm{tr}\left( \frac{1}{2} g\left( -\frac{\Omega^2}{4 \pi^2}
89
+ \right) \right)\right] \in H^{4*}_{\mathrm{dR}}(M, \CC)
90
+
91
+ the *additive characteristic class associated to* `g` of the **real** vector
92
+ bundle `E`.
93
+
94
+ EXAMPLES:
95
+
96
+ Consider the **Chern character** on some 2-dimensional spacetime::
97
+
98
+ sage: M = Manifold(2, 'M', structure='Lorentzian')
99
+ sage: X.<t,x> = M.chart()
100
+ sage: E = M.vector_bundle(1, 'E', field='complex'); E
101
+ Differentiable complex vector bundle E -> M of rank 1 over the base space
102
+ 2-dimensional Lorentzian manifold M
103
+ sage: e = E.local_frame('e')
104
+
105
+ Let us define the connection `\nabla^E` in terms of an electro-magnetic
106
+ potential `A(t)`::
107
+
108
+ sage: nab = E.bundle_connection('nabla^E', latex_name=r'\nabla^E')
109
+ sage: omega = M.one_form(name='omega')
110
+ sage: A = function('A')
111
+ sage: nab.set_connection_form(0, 0)[1] = I*A(t)
112
+ sage: nab[0, 0].display()
113
+ connection (0,0) of bundle connection nabla^E w.r.t. Local frame
114
+ (E|_M, (e_0)) = I*A(t) dx
115
+ sage: nab.set_immutable()
116
+
117
+ The Chern character is then given by::
118
+
119
+ sage: ch = E.characteristic_cohomology_class('ChernChar'); ch
120
+ Characteristic cohomology class ch(E) of the Differentiable complex vector
121
+ bundle E -> M of rank 1 over the base space 2-dimensional Lorentzian
122
+ manifold M
123
+
124
+ The corresponding characteristic form w.r.t. the bundle connection can be
125
+ obtained via :meth:`get_form`::
126
+
127
+ sage: ch_form = ch.get_form(nab); ch_form.display_expansion()
128
+ ch(E, nabla^E) = 1 + 1/2*d(A)/dt/pi dt∧dx
129
+
130
+ .. _multiplicative:
131
+
132
+ Multiplicative Classes
133
+ ----------------------
134
+
135
+ In the **complex** case, let `f` be a holomorphic function around zero.
136
+ Then we call
137
+
138
+ .. MATH::
139
+
140
+ \left[\det\left( f\left( \frac{\Omega}{2 \pi i} \right)
141
+ \right)\right] \in H^{2*}_{\mathrm{dR}}(M, \CC)
142
+
143
+ the *multiplicative characteristic class associated to* `f` of the complex
144
+ vector bundle `E`.
145
+
146
+ Important and predefined multiplicative classes on complex vector bundles are:
147
+
148
+ - *Chern class* with `f(x) = 1+x`
149
+ - *Todd class* with `f(x) = \frac{x}{1-\exp(-x)}`
150
+
151
+ In the **real** case, let `g` be a holomorphic function around zero with
152
+ `g(0)=1`. Then we call
153
+
154
+ .. MATH::
155
+
156
+ \left[\det\left( \sqrt{ g \left( -\frac{\Omega^2}{4 \pi^2} \right) } \right)
157
+ \right] \in H^{4*}_{\mathrm{dR}}(M, \CC)
158
+
159
+ the *multiplicative characteristic class associated to* `g` on the **real**
160
+ vector bundle `E`.
161
+
162
+ Important and predefined multiplicative classes on real vector bundles are:
163
+
164
+ - *Pontryagin class* with `g(x) = 1+x`
165
+ - `\hat{A}` *class* with `g(x) = \frac{\sqrt{x}/2}{\sinh(\sqrt{x}/2)}`
166
+ - *Hirzebruch class* with `g(x) = \frac{\sqrt{x}}{\tanh(\sqrt{x})}`
167
+
168
+ EXAMPLES:
169
+
170
+ We consider the **Chern class** of the tautological line bundle `\gamma^1` over
171
+ `\CC\mathbf{P}^1`::
172
+
173
+ sage: M = Manifold(2, 'CP^1', start_index=1)
174
+ sage: U = M.open_subset('U')
175
+ sage: c_cart.<x,y> = U.chart() # homogeneous coordinates in real terms
176
+ sage: c_comp.<z, zbar> = U.chart(r'z:z zbar:\bar{z}') # complexification
177
+ sage: cart_to_comp = c_cart.transition_map(c_comp, (x+I*y, x-I*y))
178
+ sage: comp_to_cart = cart_to_comp.inverse()
179
+ sage: E = M.vector_bundle(1, 'gamma^1', field='complex')
180
+ sage: e = E.local_frame('e', domain=U)
181
+
182
+ To apply the Chern-Weil approach, we need a bundle connection in terms of a
183
+ connection one form. To achieve this, we take the connection induced from the
184
+ hermitian metric on the trivial bundle
185
+ `\CC^2 \times \CC\mathbf{P}^1 \supset \gamma^1`. In this the frame `e`
186
+ corresponds to the section `[z:1] \mapsto (z,1)` and its magnitude-squared
187
+ is given by `1+|z|^2`::
188
+
189
+ sage: nab = E.bundle_connection('nabla')
190
+ sage: omega = U.one_form(name='omega')
191
+ sage: omega[c_comp.frame(),1,c_comp] = zbar/(1+z*zbar)
192
+ sage: nab[e, 1, 1] = omega
193
+ sage: nab.set_immutable()
194
+
195
+ Now, the Chern class can be constructed::
196
+
197
+ sage: c = E.characteristic_cohomology_class('Chern'); c
198
+ Characteristic cohomology class c(gamma^1) of the Differentiable complex
199
+ vector bundle gamma^1 -> CP^1 of rank 1 over the base space 2-dimensional
200
+ differentiable manifold CP^1
201
+ sage: c_form = c.get_form(nab)
202
+ sage: c_form.display_expansion(c_comp.frame(), chart=c_comp)
203
+ c(gamma^1, nabla) = 1 + 1/2*I/(pi + pi*z^2*zbar^2 + 2*pi*z*zbar) dz∧dzbar
204
+
205
+ Since `U` and `\CC\mathbf{P}^1` differ only by a point and therefore a null
206
+ set, it is enough to integrate the top form over the domain `U`::
207
+
208
+ sage: integrate(integrate(c_form[2][[1,2]].expr(c_cart), x, -infinity, infinity).full_simplify(),
209
+ ....: y, -infinity, infinity)
210
+ 1
211
+
212
+ The result shows that `c_1(\gamma^1)` generates the second integer
213
+ cohomology of `\CC\mathbf{P}^1`.
214
+
215
+ .. _Pfaffian:
216
+
217
+ Pfaffian Classes
218
+ ----------------
219
+
220
+ Usually, there is no such thing as "Pfaffian classes" in literature. However,
221
+ using the matrix' Pfaffian and inspired by the aforementioned definitions,
222
+ such classes can be defined as follows.
223
+
224
+ Let `E` be a real vector bundle of rank `2n` and `f` an odd real function
225
+ being analytic at zero. Furthermore, let `\Omega` be skew-symmetric, which
226
+ certainly will be true if `\nabla` is metric and `e` is orthonormal. Then
227
+ we call
228
+
229
+ .. MATH::
230
+
231
+ \left[\mathrm{Pf}\left( f\left( \frac{\Omega}{2 \pi} \right) \right)\right]
232
+ \in H^{2n*}(M,\RR)
233
+
234
+ the *Pfaffian class associated to f*.
235
+
236
+ The most important Pfaffian class is the *Euler class* which is simply given by
237
+ `f(x)=x`.
238
+
239
+ EXAMPLES:
240
+
241
+ We consider the **Euler class** of `S^2`::
242
+
243
+ sage: M.<x,y> = manifolds.Sphere(2, coordinates='stereographic')
244
+ sage: TM = M.tangent_bundle()
245
+ sage: e_class = TM.characteristic_cohomology_class('Euler'); e_class
246
+ Characteristic cohomology class e(TS^2) of the Tangent bundle TS^2 over the
247
+ 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3
248
+
249
+ To compute a particular representative of the Euler class, we need to determine
250
+ a connection, which is in this case given by the standard metric::
251
+
252
+ sage: g = M.metric('g') # standard metric on S2, long time
253
+ sage: nab = g.connection() # long time
254
+ sage: nab.set_immutable() # long time
255
+
256
+ Now the representative of the Euler class with respect to the connection
257
+ `\nabla_g` induced by the standard metric can be computed::
258
+
259
+ sage: e_class_form = e_class.get_form(nab) # long time
260
+ sage: e_class_form.display_expansion() # long time
261
+ e(TS^2, nabla_g) = 2/(pi + pi*x^4 + pi*y^4 + 2*pi*x^2 + 2*(pi + pi*x^2)*y^2) dx∧dy
262
+
263
+ Let us check whether this form represents the Euler class correctly::
264
+
265
+ sage: # long time
266
+ sage: expr = e_class_form[2][[1,2]].expr()
267
+ sage: expr = integrate(expr, x, -infinity, infinity)
268
+ sage: expr = expr.simplify_full()
269
+ sage: integrate(expr, y, -infinity, infinity)
270
+ 2
271
+
272
+ As we can see, the integral coincides with the Euler characteristic of `S^2` so
273
+ that our form actually represents the Euler class appropriately.
274
+ """
275
+
276
+ # *****************************************************************************
277
+ # Copyright (C) 2021 Michael Jung <m.jung at vu.nl>
278
+ #
279
+ # Distributed under the terms of the GNU General Public License (GPL)
280
+ # as published by the Free Software Foundation; either version 2 of
281
+ # the License, or (at your option) any later version.
282
+ # https://www.gnu.org/licenses/
283
+ # *****************************************************************************
284
+
285
+ from sage.algebras.finite_gca import FiniteGCAlgebra
286
+ from sage.manifolds.differentiable.affine_connection import AffineConnection
287
+ from sage.manifolds.differentiable.bundle_connection import BundleConnection
288
+ from sage.manifolds.differentiable.levi_civita_connection import LeviCivitaConnection
289
+ from sage.misc.abstract_method import abstract_method
290
+ from sage.misc.cachefunc import cached_method
291
+ from sage.misc.fast_methods import Singleton
292
+ from sage.modules.with_basis.indexed_element import IndexedFreeModuleElement
293
+ from sage.rings.polynomial.polynomial_element import Polynomial
294
+ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
295
+ from sage.structure.sage_object import SageObject
296
+ from sage.symbolic.expression import Expression
297
+
298
+
299
+ class CharacteristicCohomologyClassRingElement(IndexedFreeModuleElement):
300
+ r"""
301
+ Characteristic cohomology class.
302
+
303
+ Let `E \to M` be a real/complex vector bundle of rank `k`. A characteristic
304
+ cohomology class of `E` is generated by either
305
+
306
+ - Chern classes if `E` is complex,
307
+ - Pontryagin classes if `E` is real,
308
+ - Pontryagin classes and the Euler class if `E` is real and orientable,
309
+
310
+ via the Chern-Weil homomorphism.
311
+
312
+ For details about the ring structure, see
313
+ :class:`CharacteristicCohomologyClassRing`.
314
+
315
+ To construct a characteristic cohomology class, please use
316
+ :func:`CharacteristicCohomologyClass`.
317
+
318
+ EXAMPLES::
319
+
320
+ sage: M = Manifold(12, 'M')
321
+ sage: TM = M.tangent_bundle()
322
+ sage: CR = TM.characteristic_cohomology_class_ring()
323
+ sage: p1, p2, p3 = CR.gens()
324
+ sage: p1*p2+p3
325
+ Characteristic cohomology class (p_1⌣p_2 + p_3)(TM) of the Tangent
326
+ bundle TM over the 12-dimensional differentiable manifold M
327
+ sage: A = TM.characteristic_cohomology_class('AHat'); A
328
+ Characteristic cohomology class A^(TM) of the Tangent bundle TM over
329
+ the 12-dimensional differentiable manifold M
330
+ sage: A == 1 - p1/24 + (7*p1^2-4*p2)/5760 + (44*p1*p2-31*p1^3-16*p3)/967680
331
+ True
332
+ """
333
+ def __init__(self, parent, x, name=None, latex_name=None):
334
+ r"""
335
+ Construct a characteristic cohomology class.
336
+
337
+ TESTS::
338
+
339
+ sage: M = Manifold(8, 'M')
340
+ sage: TM = M.tangent_bundle()
341
+ sage: p = TM.characteristic_cohomology_class('Pontryagin')
342
+ sage: TestSuite(p).run()
343
+ """
344
+ self._name = name
345
+ if latex_name is None:
346
+ self._latex_name = self._name
347
+ else:
348
+ self._latex_name = latex_name
349
+ self._mixed_forms = {} # dict. of characteristic forms of self
350
+ # (key: bundle connection)
351
+ super().__init__(parent, x)
352
+
353
+ def _repr_(self):
354
+ r"""
355
+ String representation of the object.
356
+
357
+ TESTS::
358
+
359
+ sage: M = Manifold(8, 'M')
360
+ sage: TM = M.tangent_bundle()
361
+ sage: p = TM.characteristic_cohomology_class('Pontryagin')
362
+ sage: p._repr_()
363
+ 'Characteristic cohomology class p(TM) of the Tangent bundle TM
364
+ over the 8-dimensional differentiable manifold M'
365
+ sage: p # indirect doctest
366
+ Characteristic cohomology class p(TM) of the Tangent bundle TM over
367
+ the 8-dimensional differentiable manifold M
368
+
369
+ ::
370
+
371
+ sage: x = var('x')
372
+ sage: k = TM.characteristic_cohomology_class(1+x^2, class_type='multiplicative')
373
+ sage: k._repr_()
374
+ 'Characteristic cohomology class (1 + p_1^2 - 2*p_2)(TM) of the
375
+ Tangent bundle TM over the 8-dimensional differentiable manifold M'
376
+ sage: k # indirect doctest
377
+ Characteristic cohomology class (1 + p_1^2 - 2*p_2)(TM) of the
378
+ Tangent bundle TM over the 8-dimensional differentiable manifold M
379
+ """
380
+ if self._name is None:
381
+ name = f'({super()._repr_()})'
382
+ else:
383
+ name = self._name
384
+ vbundle = self.parent()._vbundle
385
+ name = f'{name}({vbundle._name})'
386
+ return f'Characteristic cohomology class {name} of the {vbundle}'
387
+
388
+ def _latex_(self):
389
+ r"""
390
+ LaTeX representation of the object.
391
+
392
+ TESTS::
393
+
394
+ sage: M = Manifold(8, 'M')
395
+ sage: TM = M.tangent_bundle()
396
+ sage: p = TM.characteristic_cohomology_class('Pontryagin')
397
+ sage: p._latex_()
398
+ 'p\\left(TM\\right)'
399
+ sage: latex(p) # indirect doctest
400
+ p\left(TM\right)
401
+
402
+ ::
403
+
404
+ sage: x = var('x')
405
+ sage: k = TM.characteristic_cohomology_class(1+x^2, class_type='multiplicative')
406
+ sage: k._latex_()
407
+ '\\left(1 + p_1^{2} - 2 p_2\\right)\\left(TM\\right)'
408
+ sage: latex(k)
409
+ \left(1 + p_1^{2} - 2 p_2\right)\left(TM\right)
410
+ """
411
+ if self._latex_name is None:
412
+ latex = r'\left(' + super()._latex_() + r'\right)'
413
+ else:
414
+ latex = self._latex_name
415
+ vbundle = self.parent()._vbundle
416
+ latex += r'\left(' + vbundle._latex_name + r'\right)'
417
+ return latex
418
+
419
+ def get_form(self, nab):
420
+ r"""
421
+ Return the characteristic form of ``self``.
422
+
423
+ INPUT:
424
+
425
+ - ``nab`` -- get the characteristic form w.r.t. to the
426
+ connection ``nab``
427
+
428
+ OUTPUT:
429
+
430
+ - an instance of
431
+ :class:`sage.manifolds.differentiable.mixed_form.MixedForm`
432
+
433
+ EXAMPLES:
434
+
435
+ Trivial characteristic form on Euclidean space::
436
+
437
+ sage: M = manifolds.EuclideanSpace(4)
438
+ sage: TM = M.tangent_bundle()
439
+ sage: one = TM.characteristic_cohomology_class_ring().one()
440
+ sage: g = M.metric()
441
+ sage: nab = g.connection()
442
+ sage: nab.set_immutable()
443
+ sage: one.get_form(nab)
444
+ Mixed differential form one on the 4-dimensional Euclidean space E^4
445
+
446
+ Pontryagin form on the 4-sphere::
447
+
448
+ sage: M = manifolds.Sphere(4)
449
+ sage: TM = M.tangent_bundle()
450
+ sage: p = TM.characteristic_cohomology_class('Pontryagin'); p
451
+ Characteristic cohomology class p(TS^4) of the Tangent bundle TS^4
452
+ over the 4-sphere S^4 of radius 1 smoothly embedded in the
453
+ 5-dimensional Euclidean space E^5
454
+ sage: g = M.metric() # long time
455
+ sage: nab = g.connection() # long time
456
+ sage: nab.set_immutable() # long time
457
+ sage: p_form = p.get_form(nab); p_form # long time
458
+ Mixed differential form p(TS^4, nabla_g) on the 4-sphere S^4 of
459
+ radius 1 smoothly embedded in the 5-dimensional Euclidean space E^5
460
+ sage: p_form.display_expansion() # long time
461
+ p(TS^4, nabla_g) = 1
462
+ """
463
+ if nab not in self._mixed_forms:
464
+ dom = nab._domain
465
+ A = dom.mixed_form_algebra()
466
+
467
+ # trivial cases
468
+ if self == 1:
469
+ self._mixed_forms[nab] = A(dom._one_scalar_field)
470
+ elif self == 0:
471
+ self._mixed_forms[nab] = A(dom._zero_scalar_field)
472
+ else: # non-trivial case
473
+ from functools import reduce
474
+
475
+ parent = self.parent()
476
+ algorithm = parent._algorithm
477
+
478
+ grading = parent.print_options()['sorting_key']
479
+ res = [dom.diff_form_module(i).zero()
480
+ for i in range(dom._dim + 1)]
481
+ for ind, c in self:
482
+ deg = grading(ind)
483
+ gen_pow = [algorithm.get_gen_pow(nab, i, ind[i])
484
+ for i in range(len(ind))]
485
+ res[deg] += c * reduce(lambda x, y: x.wedge(y), gen_pow)
486
+
487
+ res = A(res) # convert result into mixed form
488
+
489
+ # preparse names
490
+ vbundle = parent._vbundle
491
+ if self._name is None:
492
+ name = f'({super()._repr_()})'
493
+ else:
494
+ name = self._name
495
+ if self._latex_name is None:
496
+ latex_name = r'\left(' + super()._latex_() + r'\right)'
497
+ else:
498
+ latex_name = self._latex_name
499
+ # appendix
500
+ append_name = f'({vbundle._name}, {nab._name})'
501
+ append_latex_name = r'\left(' + vbundle._latex_name
502
+ append_latex_name += ', ' + nab._latex_name + r'\right)'
503
+
504
+ # set names of components
505
+ from sage.arith.misc import gcd
506
+
507
+ step = gcd(parent._degrees) # step size of (possibly) nonzero
508
+ for i in range(dom._dim // step + 1):
509
+ # enumerate (possibly) nonzero components
510
+ comp_name = name + f'_{i}' + append_name
511
+ comp_latex_name = latex_name + r'_{' + str(i) + '}'
512
+ comp_latex_name += append_latex_name
513
+ res[step * i].set_name(name=comp_name,
514
+ latex_name=comp_latex_name)
515
+
516
+ # set global names
517
+ res._name = name + append_name
518
+ res._latex_name = latex_name + append_latex_name
519
+
520
+ res.set_immutable()
521
+
522
+ self._mixed_forms[nab] = res # cache result in dict
523
+
524
+ return self._mixed_forms[nab]
525
+
526
+ def representative(self, nab=None):
527
+ r"""
528
+ Return any representative of ``self``.
529
+
530
+ INPUT:
531
+
532
+ - ``nab`` -- (default: ``None``) if stated, return the representative
533
+ w.r.t. to the connection ``nab``; otherwise an arbitrary already
534
+ computed representative will be chosen.
535
+
536
+ OUTPUT:
537
+
538
+ - an instance of
539
+ :class:`sage.manifolds.differentiable.mixed_form.MixedForm`
540
+
541
+ EXAMPLES:
542
+
543
+ Define the 4-dimensional Euclidean space::
544
+
545
+ sage: M = manifolds.EuclideanSpace(4)
546
+ sage: TM = M.tangent_bundle()
547
+ sage: one = TM.characteristic_cohomology_class_ring().one()
548
+
549
+ No characteristic form has been computed so far, thus we get an error::
550
+
551
+ sage: one.representative()
552
+ Traceback (most recent call last):
553
+ ...
554
+ AttributeError: cannot pick a representative
555
+
556
+ Get a characteristic form::
557
+
558
+ sage: g = M.metric()
559
+ sage: nab = g.connection()
560
+ sage: nab.set_immutable()
561
+ sage: one.get_form(nab)
562
+ Mixed differential form one on the 4-dimensional Euclidean space E^4
563
+
564
+ Now, the result is cached and `representative` returns a form::
565
+
566
+ sage: one.representative()
567
+ Mixed differential form one on the 4-dimensional Euclidean space E^4
568
+
569
+ Alternatively, the option ``nab`` can be used to return the
570
+ characteristic form w.r.t. a fixed connection::
571
+
572
+ sage: one.representative(nab)
573
+ Mixed differential form one on the 4-dimensional Euclidean space E^4
574
+
575
+ .. SEEALSO::
576
+
577
+ :meth:`CharacteristicCohomologyClassRingElement.get_form`
578
+ """
579
+ if nab is None:
580
+ if not self._mixed_forms:
581
+ raise AttributeError('cannot pick a representative')
582
+ return next(iter(self._mixed_forms.values()))
583
+ return self.get_form(nab)
584
+
585
+ def set_name(self, name=None, latex_name=None):
586
+ r"""
587
+ Set (or change) the text name and LaTeX name of the characteristic
588
+ class.
589
+
590
+ INPUT:
591
+
592
+ - ``name`` -- (string; default: ``None``) name given to the
593
+ characteristic cohomology class
594
+ - ``latex_name`` -- (string; default: ``None``) LaTeX symbol to denote
595
+ the characteristic cohomology class; if ``None`` while ``name`` is
596
+ provided, the LaTeX symbol is set to ``name``
597
+
598
+ EXAMPLES::
599
+
600
+ sage: M = Manifold(8, 'M')
601
+ sage: TM = M.tangent_bundle()
602
+ sage: x = var('x')
603
+ sage: k = TM.characteristic_cohomology_class(1+x^2,
604
+ ....: class_type='multiplicative'); k
605
+ Characteristic cohomology class (1 + p_1^2 - 2*p_2)(TM) of the
606
+ Tangent bundle TM over the 8-dimensional differentiable manifold M
607
+ sage: k.set_name(name='k', latex_name=r'\kappa')
608
+ sage: k
609
+ Characteristic cohomology class k(TM) of the Tangent bundle TM over
610
+ the 8-dimensional differentiable manifold M
611
+ sage: latex(k)
612
+ \kappa\left(TM\right)
613
+ """
614
+ if name is not None:
615
+ self._name = name
616
+ if latex_name is None:
617
+ self._latex_name = self._name
618
+ if latex_name is not None:
619
+ self._latex_name = latex_name
620
+
621
+
622
+ class CharacteristicCohomologyClassRing(FiniteGCAlgebra):
623
+ r"""
624
+ Characteristic cohomology class ring.
625
+
626
+ Let `E \to M` be a real or complex vector bundle of rank `k` and `R` be a
627
+ torsion-free subring of `\CC`.
628
+
629
+ Let `BG` be the classifying space of the group `G`. As for vector bundles,
630
+ we consider
631
+
632
+ - `G = O(k)` if `E` is real,
633
+ - `G = SO(k)` if `E` is real and oriented,
634
+ - `G = U(k)` if `E` is complex.
635
+
636
+ The cohomology ring `H^*(BG; R)` can be explicitly expressed for the
637
+ aforementioned cases:
638
+
639
+ .. MATH::
640
+
641
+ H^*(BG; R) \cong \begin{cases}
642
+ R[c_1, \ldots c_k] & \text{if } G = U(k), \\
643
+ R[p_1, \ldots p_{\lfloor \frac{k}{2}\rfloor}] & \text{if } G = O(k), \\
644
+ R[p_1, \ldots p_k, e] \big/ (p_k-e^2) & \text{if } G = SO(2k), \\
645
+ R[p_1, \ldots p_k, e] & \text{if } G = SO(2k+1). \\
646
+ \end{cases}
647
+
648
+ The Chern-Weil homomorphism relates the generators in the de Rham
649
+ cohomology as follows. If `\Omega` is a curvature form matrix on `E`, for
650
+ the Chern classes we get
651
+
652
+ .. MATH::
653
+
654
+ \left[ \det\left( 1 + \frac{t \Omega}{2 \pi i} \right) \right] = 1 +
655
+ \sum^k_{n=1} c_n(E) t^n,
656
+
657
+ for the Pontryagin classes we have
658
+
659
+ .. MATH::
660
+
661
+ \left[ \det\left( 1 - \frac{t \Omega}{2 \pi} \right) \right] = 1 +
662
+ \sum^{\lfloor\frac{k}{2} \rfloor}_{n=1} p_n(E) t^n,
663
+
664
+ and for the Euler class we obtain
665
+
666
+ .. MATH::
667
+
668
+ \left[ \mathrm{Pf}\left(\frac{\Omega}{2 \pi} \right) \right] = e(E).
669
+
670
+ Consequently, the cohomology ring `H^*(BG; R)` is mapped (not
671
+ necessarily injectively) to a subring of `H^*_\mathrm{dR}(M, \CC)` via
672
+ the Chern-Weil homomorphism. This implementation attempts to represent this
673
+ subring.
674
+
675
+ .. NOTE::
676
+
677
+ Some generators might have torsion in `H^*(BG; R)` giving a zero
678
+ element in the de Rham cohomology. Those generators are still
679
+ considered in the implementation. Generators whose degree exceed the
680
+ dimension of the base space, however, are ignored.
681
+
682
+ INPUT:
683
+
684
+ - ``base`` -- base ring
685
+ - ``vbundle`` -- vector bundle
686
+
687
+ EXAMPLES:
688
+
689
+ Characteristic cohomology class ring over the tangent bundle of an
690
+ 8-dimensional manifold::
691
+
692
+ sage: M = Manifold(8, 'M')
693
+ sage: TM = M.tangent_bundle()
694
+ sage: CR = TM.characteristic_cohomology_class_ring(); CR
695
+ Algebra of characteristic cohomology classes of the Tangent bundle TM
696
+ over the 8-dimensional differentiable manifold M
697
+ sage: CR.gens()
698
+ (Characteristic cohomology class (p_1)(TM) of the Tangent bundle TM over
699
+ the 8-dimensional differentiable manifold M,
700
+ Characteristic cohomology class (p_2)(TM) of the Tangent bundle TM
701
+ over the 8-dimensional differentiable manifold M)
702
+
703
+ The default base ring is `\QQ`::
704
+
705
+ sage: CR.base_ring()
706
+ Rational Field
707
+
708
+ Characteristic cohomology class ring over a complex vector bundle::
709
+
710
+ sage: M = Manifold(4, 'M')
711
+ sage: E = M.vector_bundle(2, 'E', field='complex')
712
+ sage: CR_E = E.characteristic_cohomology_class_ring(); CR_E
713
+ Algebra of characteristic cohomology classes of the Differentiable
714
+ complex vector bundle E -> M of rank 2 over the base space
715
+ 4-dimensional differentiable manifold M
716
+ sage: CR_E.gens()
717
+ (Characteristic cohomology class (c_1)(E) of the Differentiable complex
718
+ vector bundle E -> M of rank 2 over the base space 4-dimensional
719
+ differentiable manifold M,
720
+ Characteristic cohomology class (c_2)(E) of the Differentiable
721
+ complex vector bundle E -> M of rank 2 over the base space
722
+ 4-dimensional differentiable manifold M)
723
+
724
+ Characteristic cohomology class ring over an oriented manifold::
725
+
726
+ sage: S2 = manifolds.Sphere(2, coordinates='stereographic')
727
+ sage: TS2 = S2.tangent_bundle()
728
+ sage: S2.has_orientation()
729
+ True
730
+ sage: CR = TS2.characteristic_cohomology_class_ring()
731
+ sage: CR.gens()
732
+ (Characteristic cohomology class (e)(TS^2) of the Tangent bundle TS^2
733
+ over the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean
734
+ space E^3,)
735
+ """
736
+ Element = CharacteristicCohomologyClassRingElement
737
+
738
+ def __init__(self, base, vbundle):
739
+ r"""
740
+ Construct a characteristic cohomology ring.
741
+
742
+ TESTS::
743
+
744
+ sage: M = Manifold(8, 'M')
745
+ sage: TM = M.tangent_bundle()
746
+ sage: CR = TM.characteristic_cohomology_class_ring()
747
+ sage: TestSuite(CR).run()
748
+ """
749
+ self._vbundle = vbundle
750
+ self._domain = vbundle._base_space
751
+ dim = self._domain._dim
752
+ rk = vbundle._rank
753
+ if vbundle._field_type == 'complex':
754
+ ran = min(rk, dim // 2)
755
+ names = [f'c_{i}' for i in range(1, ran + 1)]
756
+ degrees = [2 * i for i in range(1, ran + 1)]
757
+ self._algorithm = ChernAlgorithm()
758
+ elif vbundle._field_type == 'real':
759
+ ran = min(rk // 2, dim // 4)
760
+ names = [f'p_{i}' for i in range(1, ran + 1)]
761
+ degrees = [4 * i for i in range(1, ran + 1)]
762
+ self._algorithm = PontryaginAlgorithm()
763
+ if vbundle.has_orientation():
764
+ # add Euler class generator
765
+ # Euler should be first entry; see `PontryaginEulerAlgorithm`
766
+ names = ['e'] + names
767
+ degrees = [rk] + degrees
768
+ self._algorithm = PontryaginEulerAlgorithm()
769
+ # TODO: add relation e^2=p_k for dim=2*k
770
+ else:
771
+ raise TypeError(f'Characteristic cohomology classes not supported '
772
+ f'for vector bundles with '
773
+ f'field type {vbundle._field_type}')
774
+
775
+ if not names or not degrees:
776
+ raise ValueError('cannot find any generators')
777
+
778
+ names = tuple(names) # hashable
779
+ degrees = tuple(degrees) # hashable
780
+ super().__init__(base=base, names=names, degrees=degrees,
781
+ max_degree=dim, mul_symbol='⌣',
782
+ mul_latex_symbol=r'\smile')
783
+
784
+ def _element_constructor_(self, x, **kwargs):
785
+ r"""
786
+ Convert ``x`` into ``self``.
787
+
788
+ TESTS::
789
+
790
+ sage: M = Manifold(8, 'M')
791
+ sage: TM = M.tangent_bundle()
792
+ sage: CR = TM.characteristic_cohomology_class_ring()
793
+ sage: p = CR('Pontryagin'); p
794
+ Characteristic cohomology class p(TM) of the Tangent bundle TM over
795
+ the 8-dimensional differentiable manifold M
796
+ sage: CR(p, name='pontr')
797
+ Characteristic cohomology class pontr(TM) of the Tangent bundle
798
+ TM over the 8-dimensional differentiable manifold M
799
+ """
800
+ if isinstance(x, (str, Expression, Polynomial)):
801
+ return self._build_element(x, **kwargs)
802
+
803
+ R = self.base_ring()
804
+
805
+ if x in R:
806
+ one_basis = self.one_basis()
807
+ d = {one_basis: R(x)}
808
+ elif isinstance(x, CharacteristicCohomologyClassRingElement):
809
+ d = x._monomial_coefficients
810
+ # x is an element of the basis enumerated set;
811
+ # This is a very ugly way of testing this
812
+ elif ((hasattr(self._indices, 'element_class') and
813
+ isinstance(self._indices.element_class, type) and
814
+ isinstance(x, self._indices.element_class)) or
815
+ self.parent()(x) == self._indices):
816
+ d = {x: R.one()}
817
+ elif x in self._indices:
818
+ d = {self._indices(x): R.one()}
819
+ else:
820
+ raise TypeError(f"do not know how to make x (= {x}) "
821
+ f"an element of self (={self})")
822
+ name, latex_name = kwargs.get('name'), kwargs.get('latex_name')
823
+ return self.element_class(self, d, name=name, latex_name=latex_name)
824
+
825
+ @cached_method
826
+ def _build_element(self, *args, **kwargs):
827
+ r"""
828
+ Construct a characteristic cohomology class.
829
+
830
+ The result is cached.
831
+
832
+ INPUT:
833
+
834
+ - ``val`` -- the input data corresponding to the characteristic class
835
+ using the Chern-Weil homomorphism; this argument can be either a
836
+ symbolic expression, a polynomial or one of the following predefined
837
+ classes:
838
+
839
+ - ``'Chern'`` -- total Chern class,
840
+ - ``'ChernChar'`` -- Chern character,
841
+ - ``'Todd'`` -- Todd class,
842
+ - ``'Pontryagin'`` -- total Pontryagin class,
843
+ - ``'Hirzebruch'`` -- Hirzebruch class,
844
+ - ``'AHat'`` -- `\hat{A}` class,
845
+ - ``'Euler'`` -- Euler class.
846
+
847
+ - ``name`` -- (default: ``None``) string representation given to the
848
+ characteristic class; if ``None`` the default algebra representation or
849
+ predefined name is used
850
+ - ``latex_name`` -- (default: ``None``) LaTeX name given to the
851
+ characteristic class; if ``None`` the value of ``name`` is used
852
+ - ``class_type`` -- (default: ``None``) class type of the characteristic
853
+ cohomology class; the following options are possible:
854
+
855
+ - ``'multiplicative'`` -- returns a class of multiplicative type
856
+ - ``'additive'`` -- returns a class of additive type
857
+ - ``'Pfaffian'`` -- returns a class of Pfaffian type
858
+
859
+ This argument must be stated if ``val`` is a polynomial or symbolic
860
+ expression.
861
+
862
+ EXAMPLES:
863
+
864
+ Total Pontryagin class of an 8-dimensional manifold::
865
+
866
+ sage: M = Manifold(8, 'M')
867
+ sage: TM = M.tangent_bundle()
868
+ sage: p = TM.characteristic_cohomology_class('Pontryagin'); p
869
+ Characteristic cohomology class p(TM) of the Tangent bundle TM over the
870
+ 8-dimensional differentiable manifold M
871
+
872
+ Define a multiplicative class (see :func:`multiplicative_sequence`)::
873
+
874
+ sage: P.<x> = PolynomialRing(QQ)
875
+ sage: f = 1 + x - x^2
876
+ sage: f_class = TM.characteristic_cohomology_class(f, class_type='multiplicative'); f_class
877
+ Characteristic cohomology class (1 + p_1 - p_1^2 + 3*p_2)(TM) of the
878
+ Tangent bundle TM over the 8-dimensional differentiable manifold M
879
+
880
+ Pass a symbolic expression, whose Taylor expansion at zero will be used::
881
+
882
+ sage: M = Manifold(8, 'M')
883
+ sage: TM = M.tangent_bundle()
884
+ sage: x = var('x')
885
+ sage: f = cos(x)
886
+ sage: f_class = TM.characteristic_cohomology_class(f, class_type='multiplicative'); f_class
887
+ Characteristic cohomology class (1 - 1/2*p_1^2 + p_2)(TM) of the Tangent
888
+ bundle TM over the 8-dimensional differentiable manifold M
889
+ """
890
+ name, latex_name = kwargs.get('name'), kwargs.get('latex_name')
891
+ base_ring = self.base_ring()
892
+ class_type = kwargs.get('class_type')
893
+ vbundle = self._vbundle
894
+ val = args[0]
895
+ dim = vbundle._base_space._dim
896
+
897
+ # predefined classes accessible via class names
898
+ if isinstance(val, str):
899
+ from sage.arith.misc import bernoulli, factorial
900
+
901
+ P = PolynomialRing(base_ring, 'x')
902
+ x = P.gen()
903
+ if val == 'Chern':
904
+ if vbundle._field_type != 'complex':
905
+ raise ValueError(f'total Chern class not defined on {vbundle}')
906
+ if name is None:
907
+ name = 'c'
908
+ class_type = 'multiplicative'
909
+ val = 1 + x
910
+ elif val == 'Pontryagin':
911
+ if vbundle._field_type != 'real':
912
+ raise ValueError(f'total Pontryagin class not defined on {vbundle}')
913
+ if name is None:
914
+ name = 'p'
915
+ class_type = 'multiplicative'
916
+ val = 1 + x
917
+ elif val == 'ChernChar':
918
+ if vbundle._field_type != 'complex':
919
+ raise ValueError(f'Chern character not defined on {vbundle}')
920
+ if name is None:
921
+ name = 'ch'
922
+ if latex_name is None:
923
+ latex_name = r'\mathrm{ch}'
924
+ class_type = 'additive'
925
+ coeff = [1 / factorial(k) for k in
926
+ range(dim // 2 + 1)] # exp(x)
927
+ val = P(coeff)
928
+ elif val == 'Todd':
929
+ if vbundle._field_type != 'complex':
930
+ raise ValueError(f'Todd class not defined on {vbundle}')
931
+ if name is None:
932
+ name = 'Td'
933
+ if latex_name is None:
934
+ latex_name = r'\mathrm{Td}'
935
+ class_type = 'multiplicative'
936
+ val = 1 + x / 2
937
+ for k in range(1, dim // 2 + 1):
938
+ val += (-1) ** (k + 1) / factorial(2 * k) * bernoulli(
939
+ 2 * k) * x ** (2 * k)
940
+ elif val == 'Hirzebruch':
941
+ if vbundle._field_type != 'real':
942
+ raise ValueError(f'Hirzebruch class not defined on {vbundle}')
943
+ if name is None:
944
+ name = 'L'
945
+ if latex_name is None:
946
+ latex_name = 'L'
947
+ class_type = 'multiplicative'
948
+ coeff = [2 ** (2 * k) * bernoulli(2 * k) / factorial(2 * k)
949
+ for k in range(dim // 4 + 1)]
950
+ val = P(coeff)
951
+ elif val == 'AHat':
952
+ if vbundle._field_type != 'real':
953
+ raise ValueError(f'AHat class not defined on {vbundle}')
954
+ if name is None:
955
+ name = 'A^'
956
+ if latex_name is None:
957
+ latex_name = r'\hat{A}'
958
+ class_type = 'multiplicative'
959
+ coeff = [- (2 ** (2 * k) - 2) / 2 ** (2 * k) * bernoulli(
960
+ 2 * k) / factorial(2 * k)
961
+ for k in range(dim // 4 + 1)]
962
+ val = P(coeff)
963
+ elif val == 'Euler':
964
+ if vbundle._field_type != 'real' or not vbundle.has_orientation():
965
+ raise ValueError(f'Euler class not defined on {vbundle}')
966
+ if name is None:
967
+ name = 'e'
968
+ class_type = 'Pfaffian'
969
+ val = x
970
+ else:
971
+ raise ValueError(f'predefined class "{val}" unknown')
972
+
973
+ # turn symbolic expression into a polynomial via Taylor expansion
974
+ if isinstance(val, Expression):
975
+ x = val.default_variable()
976
+ P = PolynomialRing(base_ring, x)
977
+
978
+ if vbundle._field_type == 'real':
979
+ pow_range = dim // 4
980
+ elif vbundle._field_type == 'complex':
981
+ pow_range = dim // 2
982
+ else:
983
+ raise ValueError(f'field type of {vbundle} must be real or complex')
984
+
985
+ val = P(val.taylor(x, 0, pow_range))
986
+
987
+ # turn polynomial into a characteristic cohomology class via sequences
988
+ if isinstance(val, Polynomial):
989
+ if class_type is None:
990
+ raise TypeError(f'class_type must be stated if {val} '
991
+ f'is a polynomial')
992
+ n = self.ngens()
993
+ s = 0 # shift; important in case of Euler class generator
994
+ if self._algorithm is PontryaginEulerAlgorithm():
995
+ s = 1 # skip Euler class
996
+ n -= 1 # ignore Euler class
997
+
998
+ if class_type == 'additive':
999
+ sym = additive_sequence(val, vbundle._rank, n)
1000
+ elif class_type == 'multiplicative':
1001
+ sym = multiplicative_sequence(val, n)
1002
+ elif class_type == 'Pfaffian':
1003
+ P = val.parent()
1004
+ x = P.gen()
1005
+ val = (val(x) - val(-x)) / 2 # project to odd functions
1006
+ val = P([(-1) ** k * val[2 * k + 1] for k in range(n + 1)])
1007
+ sym = multiplicative_sequence(val, n)
1008
+ else:
1009
+ raise AttributeError('unknown class type')
1010
+
1011
+ d = {}
1012
+ w_vec = self._weighted_vectors
1013
+ for p, c in sym:
1014
+ vec = [0] * self.ngens()
1015
+ if class_type == 'Pfaffian':
1016
+ vec[0] = 1 # always multiply with e
1017
+ for i in p:
1018
+ vec[i - 1 + s] += 1
1019
+ key = w_vec(vec)
1020
+ d[key] = c
1021
+ res = self._from_dict(d)
1022
+ res.set_name(name=name, latex_name=latex_name)
1023
+ return res
1024
+
1025
+ # Nothing worked? Then something went wrong!
1026
+ raise ValueError(f'cannot convert {val} into an element of {self}')
1027
+
1028
+ def _repr_(self):
1029
+ r"""
1030
+ String representation of the object.
1031
+
1032
+ TESTS::
1033
+
1034
+ sage: M = Manifold(8, 'M')
1035
+ sage: TM = M.tangent_bundle()
1036
+ sage: CR = TM.characteristic_cohomology_class_ring()
1037
+ sage: CR._repr_()
1038
+ 'Algebra of characteristic cohomology classes of the Tangent bundle
1039
+ TM over the 8-dimensional differentiable manifold M'
1040
+ sage: CR # indirect doctest
1041
+ Algebra of characteristic cohomology classes of the Tangent bundle
1042
+ TM over the 8-dimensional differentiable manifold M
1043
+ """
1044
+ vbundle = self._vbundle
1045
+ repr = f'Algebra of characteristic cohomology classes of the {vbundle}'
1046
+ return repr
1047
+
1048
+
1049
+ # *****************************************************************************
1050
+ # ALGORITHMS
1051
+ # *****************************************************************************
1052
+
1053
+ def multiplicative_sequence(q, n=None):
1054
+ r"""
1055
+ Turn the polynomial ``q`` into its multiplicative sequence.
1056
+
1057
+ Let `q` be a polynomial and `x_1, \ldots x_n` indeterminates. The
1058
+ *multiplicative sequence of* `q` is then given by the polynomials `K_j`
1059
+
1060
+ .. MATH::
1061
+
1062
+ \sum_{j=0}^n K_j(\sigma_1, \ldots, \sigma_j) z^j =
1063
+ \prod_{i=1}^{n} q(z \,x_i),
1064
+
1065
+ where `\sigma_i` is the `i`-th elementary symmetric polynomial in the
1066
+ indeterminates `x_i`.
1067
+
1068
+ INPUT:
1069
+
1070
+ - ``q`` -- polynomial to turn into its multiplicative sequence
1071
+ - ``n`` -- (default: ``None``) the highest order `n` of the sequence;
1072
+ if ``None``, the order of ``q`` is assumed
1073
+
1074
+ OUTPUT: a symmetric polynomial representing the multiplicative sequence
1075
+
1076
+ EXAMPLES::
1077
+
1078
+ sage: P.<x> = PolynomialRing(QQ)
1079
+ sage: from sage.manifolds.differentiable.characteristic_cohomology_class import multiplicative_sequence
1080
+ sage: f = 1 + x - x^2
1081
+ sage: sym = multiplicative_sequence(f); sym
1082
+ e[] + e[1] - e[1, 1] + 3*e[2]
1083
+
1084
+ The maximal order of the result can be stated with ``n``::
1085
+
1086
+ sage: sym_5 = multiplicative_sequence(f, n=5); sym_5
1087
+ e[] + e[1] - e[1, 1] + 3*e[2] - e[2, 1] + e[2, 2] + 4*e[3] - 3*e[3, 1]
1088
+ + e[3, 2] + 7*e[4] - 4*e[4, 1] + 11*e[5]
1089
+ """
1090
+ from sage.combinat.partition import Partitions
1091
+ from sage.combinat.sf.sf import SymmetricFunctions
1092
+ from sage.misc.misc_c import prod
1093
+
1094
+ if n is None:
1095
+ n = q.degree()
1096
+
1097
+ R = q.parent().base_ring()
1098
+ Sym = SymmetricFunctions(R)
1099
+ m = Sym.m()
1100
+
1101
+ # Get the multiplicative sequence in the monomial basis:
1102
+ mon_pol = m._from_dict({p: prod(q[i] for i in p)
1103
+ for k in range(n + 1)
1104
+ for p in Partitions(k)})
1105
+ return Sym.e()(mon_pol)
1106
+
1107
+
1108
+ def additive_sequence(q, k, n=None):
1109
+ r"""
1110
+ Turn the polynomial ``q`` into its additive sequence.
1111
+
1112
+ Let `q` be a polynomial and `x_1, \ldots x_n` indeterminates. The
1113
+ *additive sequence of* `q` is then given by the polynomials `Q_j`
1114
+
1115
+ .. MATH::
1116
+
1117
+ \sum_{j=0}^n Q_j(\sigma_1, \ldots, \sigma_j) z^j =
1118
+ \sum_{i=1}^{k} q(z \,x_i),
1119
+
1120
+ where `\sigma_i` is the `i`-th elementary symmetric polynomial in the
1121
+ indeterminates `x_i`.
1122
+
1123
+ INPUT:
1124
+
1125
+ - ``q`` -- polynomial to turn into its additive sequence
1126
+ - ``k`` -- maximal index `k` of the sum
1127
+ - ``n`` -- (default: ``None``) the highest order of the sequence `n`;
1128
+ if ``None``, the order of ``q`` is assumed
1129
+
1130
+ OUTPUT: a symmetric polynomial representing the additive sequence
1131
+
1132
+ EXAMPLES::
1133
+
1134
+ sage: P.<x> = PolynomialRing(QQ)
1135
+ sage: from sage.manifolds.differentiable.characteristic_cohomology_class import additive_sequence
1136
+ sage: f = 1 + x - x^2
1137
+ sage: sym = additive_sequence(f, 2); sym
1138
+ 2*e[] + e[1] - e[1, 1] + 2*e[2]
1139
+
1140
+ The maximal order of the result can be stated with ``n``::
1141
+
1142
+ sage: sym_1 = additive_sequence(f, 2, 1); sym_1
1143
+ 2*e[] + e[1]
1144
+ """
1145
+ from sage.combinat.partition import Partitions
1146
+ from sage.combinat.sf.sf import SymmetricFunctions
1147
+
1148
+ if n is None:
1149
+ n = q.degree()
1150
+
1151
+ R = q.parent().base_ring()
1152
+ Sym = SymmetricFunctions(R)
1153
+ m = Sym.m()
1154
+
1155
+ # Express the additive sequence in the monomial basis, the 0-th
1156
+ # order term must be treated separately; here comes ``rk`` into play:
1157
+ m_dict = {Partitions(0)([]): k * q[0]}
1158
+ m_dict.update({Partitions(k)([k]): q[k] for k in range(1, n + 1)})
1159
+ mon_pol = m._from_dict(m_dict)
1160
+ return Sym.e()(mon_pol)
1161
+
1162
+
1163
+ def fast_wedge_power(form, n):
1164
+ r"""
1165
+ Return the wedge product power of `form` using a square-and-wedge
1166
+ algorithm.
1167
+
1168
+ INPUT:
1169
+
1170
+ - ``form`` -- a differential form
1171
+ - ``n`` -- nonnegative integer
1172
+
1173
+ EXAMPLES::
1174
+
1175
+ sage: M = Manifold(4, 'M')
1176
+ sage: X.<x,y,z,t> = M.chart()
1177
+ sage: omega = M.diff_form(2, name='omega')
1178
+ sage: omega[0,1] = t*y^2 + 2*x
1179
+ sage: omega[0,3] = z - 2*y
1180
+ sage: from sage.manifolds.differentiable.characteristic_cohomology_class import fast_wedge_power
1181
+ sage: fast_wedge_power(omega, 0)
1182
+ Scalar field 1 on the 4-dimensional differentiable manifold M
1183
+ sage: fast_wedge_power(omega, 1)
1184
+ 2-form omega on the 4-dimensional differentiable manifold M
1185
+ sage: fast_wedge_power(omega, 2)
1186
+ 4-form omega∧omega on the 4-dimensional differentiable manifold M
1187
+ """
1188
+ if n == 0:
1189
+ return form._domain._one_scalar_field
1190
+ elif n < 0:
1191
+ raise ValueError("'n' must be nonnegative")
1192
+ val = form
1193
+ while not (n & 1):
1194
+ val = val.wedge(val)
1195
+ n >>= 1
1196
+
1197
+ # Now multiply together the correct factors form^(2^i)
1198
+ res = val
1199
+ n >>= 1
1200
+ while n:
1201
+ val = val.wedge(val)
1202
+ if n & 1:
1203
+ res = val.wedge(res)
1204
+ n >>= 1
1205
+
1206
+ return res
1207
+
1208
+
1209
+ class Algorithm_generic(SageObject):
1210
+ r"""
1211
+ Abstract algorithm class to compute the characteristic forms of the
1212
+ generators.
1213
+
1214
+ EXAMPLES::
1215
+
1216
+ sage: from sage.manifolds.differentiable.characteristic_cohomology_class import Algorithm_generic
1217
+ sage: algorithm = Algorithm_generic()
1218
+ sage: algorithm.get
1219
+ Cached version of <function Algorithm_generic.get at 0x...>
1220
+ sage: algorithm.get_local
1221
+ Traceback (most recent call last):
1222
+ ...
1223
+ NotImplementedError: <abstract method get_local at 0x...>
1224
+ sage: algorithm.get_gen_pow
1225
+ Cached version of <function Algorithm_generic.get_gen_pow at 0x...>
1226
+ """
1227
+ @cached_method
1228
+ def get(self, nab):
1229
+ r"""
1230
+ Return the global characteristic forms of the generators w.r.t. a given
1231
+ connection.
1232
+
1233
+ The result is cached.
1234
+
1235
+ OUTPUT:
1236
+
1237
+ - a list containing the generator's global characteristic forms as
1238
+ instances of
1239
+ :class:`sage.manifolds.differentiable.diff_form.DiffForm`
1240
+
1241
+ EXAMPLES::
1242
+
1243
+ sage: M = manifolds.EuclideanSpace(4)
1244
+ sage: TM = M.tangent_bundle()
1245
+ sage: g = M.metric()
1246
+ sage: nab = g.connection()
1247
+ sage: nab.set_immutable()
1248
+
1249
+ ::
1250
+
1251
+ sage: p = TM.characteristic_cohomology_class('Pontryagin')
1252
+ sage: p_form = p.get_form(nab); p_form # long time
1253
+ Mixed differential form p(TE^4, nabla_g) on the 4-dimensional
1254
+ Euclidean space E^4
1255
+ sage: p_form.display_expansion() # long time
1256
+ p(TE^4, nabla_g) = 1
1257
+ """
1258
+ if isinstance(nab, AffineConnection):
1259
+ vbundle = nab._domain.tangent_bundle()
1260
+ elif isinstance(nab, BundleConnection):
1261
+ vbundle = nab._vbundle
1262
+ else:
1263
+ raise TypeError(f'{nab} must be a connection')
1264
+ dom = nab._domain
1265
+ res = [] # will be specified within first iteration
1266
+ for frame in dom._get_min_covering(nab._coefficients):
1267
+ cmat = [[nab.curvature_form(i, j, frame) for j in vbundle.irange()]
1268
+ for i in vbundle.irange()]
1269
+ res_loc = self.get_local(cmat)
1270
+ if not res:
1271
+ # until now, degrees of generators were unknown
1272
+ res = [dom.diff_form(loc_form.degree())
1273
+ for loc_form in res_loc]
1274
+ for form, loc_form in zip(res, res_loc):
1275
+ form.set_restriction(loc_form)
1276
+ # TODO: make `res` immutable?
1277
+ return res
1278
+
1279
+ @abstract_method
1280
+ def get_local(self, cmat):
1281
+ r"""
1282
+ Abstract method to get the local forms of the generators w.r.t. a given
1283
+ curvature form matrix ``cmat``.
1284
+
1285
+ OUTPUT: list containing the generator's local characteristic forms
1286
+
1287
+ ALGORITHM:
1288
+
1289
+ The inherited class determines the algorithm.
1290
+
1291
+ EXAMPLES:
1292
+
1293
+ 4-dimensional Euclidean space::
1294
+
1295
+ sage: M = manifolds.EuclideanSpace(4)
1296
+ sage: TM = M.tangent_bundle()
1297
+ sage: g = M.metric()
1298
+ sage: nab = g.connection()
1299
+ sage: e = M.frames()[0] # select standard frame
1300
+ sage: cmat = [ [nab.curvature_form(i, j, e) # long time
1301
+ ....: for j in TM.irange()]
1302
+ ....: for i in TM.irange()]
1303
+
1304
+ Import the algorithm::
1305
+
1306
+ sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginAlgorithm
1307
+ sage: algorithm = PontryaginAlgorithm()
1308
+ sage: [p1] = algorithm.get_local(cmat) # long time
1309
+ sage: p1.display() # long time
1310
+ 0
1311
+
1312
+ A concrete implementation is given by a
1313
+ :class:`sage.misc.fast_methods.Singleton`::
1314
+
1315
+ sage: algorithm is PontryaginAlgorithm()
1316
+ True
1317
+ """
1318
+ pass
1319
+
1320
+ @cached_method
1321
+ def get_gen_pow(self, nab, i, n):
1322
+ r"""
1323
+ Return the `n`-th power of the `i`-th generator's characteristic form
1324
+ w.r.t ``nab``.
1325
+
1326
+ The result is cached.
1327
+
1328
+ EXAMPLES::
1329
+
1330
+ sage: M = manifolds.EuclideanSpace(8)
1331
+ sage: TM = M.tangent_bundle()
1332
+ sage: g = M.metric()
1333
+ sage: nab = g.connection()
1334
+ sage: nab.set_immutable()
1335
+
1336
+ ::
1337
+
1338
+ sage: A = TM.characteristic_cohomology_class('AHat')
1339
+ sage: A_form = A.get_form(nab); A_form # long time
1340
+ Mixed differential form A^(TE^8, nabla_g) on the 8-dimensional
1341
+ Euclidean space E^8
1342
+ sage: A_form.display_expansion() # long time
1343
+ A^(TE^8, nabla_g) = 1
1344
+ """
1345
+ if n == 0:
1346
+ return nab._domain._one_scalar_field # no computation necessary
1347
+ return fast_wedge_power(self.get(nab)[i], n)
1348
+
1349
+
1350
+ class ChernAlgorithm(Singleton, Algorithm_generic):
1351
+ r"""
1352
+ Algorithm class to generate Chern forms.
1353
+
1354
+ EXAMPLES:
1355
+
1356
+ Define a complex line bundle over a 2-dimensional manifold::
1357
+
1358
+ sage: M = Manifold(2, 'M', structure='Lorentzian')
1359
+ sage: X.<t,x> = M.chart()
1360
+ sage: E = M.vector_bundle(1, 'E', field='complex'); E
1361
+ Differentiable complex vector bundle E -> M of rank 1 over the base space
1362
+ 2-dimensional Lorentzian manifold M
1363
+ sage: e = E.local_frame('e')
1364
+ sage: nab = E.bundle_connection('nabla^E', latex_name=r'\nabla^E')
1365
+ sage: omega = M.one_form(name='omega')
1366
+ sage: A = function('A')
1367
+ sage: nab.set_connection_form(0, 0)[1] = I*A(t)
1368
+ sage: nab[0, 0].display()
1369
+ connection (0,0) of bundle connection nabla^E w.r.t. Local frame
1370
+ (E|_M, (e_0)) = I*A(t) dx
1371
+ sage: nab.set_immutable()
1372
+
1373
+ Import the algorithm and apply ``nab`` to it::
1374
+
1375
+ sage: from sage.manifolds.differentiable.characteristic_cohomology_class import ChernAlgorithm
1376
+ sage: algorithm = ChernAlgorithm()
1377
+ sage: algorithm.get(nab)
1378
+ [2-form on the 2-dimensional Lorentzian manifold M]
1379
+ sage: algorithm.get(nab)[0].display()
1380
+ 1/2*d(A)/dt/pi dt∧dx
1381
+
1382
+ Check some equalities::
1383
+
1384
+ sage: cmat = [[nab.curvature_form(0, 0, e)]]
1385
+ sage: algorithm.get(nab)[0] == algorithm.get_local(cmat)[0] # bundle trivial
1386
+ True
1387
+ sage: algorithm.get_gen_pow(nab, 0, 1) == algorithm.get(nab)[0]
1388
+ True
1389
+ """
1390
+ def get_local(self, cmat):
1391
+ r"""
1392
+ Return the local Chern forms w.r.t. a given curvature form matrix.
1393
+
1394
+ OUTPUT:
1395
+
1396
+ - a list containing the local characteristic Chern forms as
1397
+ instances of
1398
+ :class:`sage.manifolds.differentiable.diff_form.DiffForm`
1399
+
1400
+ ALGORITHM::
1401
+
1402
+ The algorithm is based on the Faddeev-LeVerrier algorithm for the
1403
+ characteristic polynomial.
1404
+
1405
+ EXAMPLES:
1406
+
1407
+ Define a complex line bundle over a 2-dimensional manifold::
1408
+
1409
+ sage: M = Manifold(2, 'M', structure='Lorentzian')
1410
+ sage: X.<t,x> = M.chart()
1411
+ sage: E = M.vector_bundle(1, 'E', field='complex'); E
1412
+ Differentiable complex vector bundle E -> M of rank 1 over the base
1413
+ space 2-dimensional Lorentzian manifold M
1414
+ sage: e = E.local_frame('e')
1415
+ sage: nab = E.bundle_connection('nabla^E', latex_name=r'\nabla^E')
1416
+ sage: omega = M.one_form(name='omega')
1417
+ sage: A = function('A')
1418
+ sage: nab.set_connection_form(0, 0)[1] = I*A(t)
1419
+ sage: nab[0, 0].display()
1420
+ connection (0,0) of bundle connection nabla^E w.r.t. Local frame
1421
+ (E|_M, (e_0)) = I*A(t) dx
1422
+ sage: cmat = [[nab.curvature_form(i, j, e) for j in E.irange()]
1423
+ ....: for i in E.irange()]
1424
+
1425
+ Import the algorithm and apply ``cmat`` to it::
1426
+
1427
+ sage: from sage.manifolds.differentiable.characteristic_cohomology_class import ChernAlgorithm
1428
+ sage: algorithm = ChernAlgorithm()
1429
+ sage: algorithm.get_local(cmat)
1430
+ [2-form on the 2-dimensional Lorentzian manifold M]
1431
+ """
1432
+ from sage.symbolic.constants import I, pi
1433
+
1434
+ dom = cmat[0][0]._domain
1435
+ rk = len(cmat)
1436
+ dim = dom._dim
1437
+ ran = min(rk, dim // 2)
1438
+ if ran < 1:
1439
+ return [] # nothing to compute
1440
+ fac = I / (2 * pi)
1441
+ res = []
1442
+ m = cmat
1443
+ for k in range(1, ran):
1444
+ c = -sum(m[i][i] for i in range(rk)) / k
1445
+ res.append(fac * c)
1446
+ for i in range(rk):
1447
+ m[i][i] += c
1448
+ fac *= I / (2 * pi)
1449
+ m = [[sum(cmat[i][l].wedge(m[l][j]) for l in range(rk))
1450
+ for j in range(rk)] for i in range(rk)]
1451
+ res.append(-fac * sum(m[i][i] for i in range(rk)) / ran)
1452
+ return res
1453
+
1454
+
1455
+ class PontryaginAlgorithm(Singleton, Algorithm_generic):
1456
+ r"""
1457
+ Algorithm class to generate Pontryagin forms.
1458
+
1459
+ EXAMPLES:
1460
+
1461
+ 5-dimensional Euclidean space::
1462
+
1463
+ sage: M = manifolds.EuclideanSpace(5)
1464
+ sage: g = M.metric()
1465
+ sage: nab = g.connection()
1466
+ sage: nab.set_immutable()
1467
+
1468
+ Import the algorithm::
1469
+
1470
+ sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginAlgorithm
1471
+ sage: algorithm = PontryaginAlgorithm()
1472
+ sage: [p1] = algorithm.get(nab) # long time
1473
+ sage: p1.display() # long time
1474
+ 0
1475
+ """
1476
+ def get_local(self, cmat):
1477
+ r"""
1478
+ Return the local Pontryagin forms w.r.t. a given curvature form matrix.
1479
+
1480
+ OUTPUT: list containing the local characteristic Pontryagin forms
1481
+
1482
+ ALGORITHM::
1483
+
1484
+ The algorithm is based on the Faddeev-LeVerrier algorithm for the
1485
+ characteristic polynomial.
1486
+
1487
+ EXAMPLES:
1488
+
1489
+ 5-dimensional Euclidean space::
1490
+
1491
+ sage: M = manifolds.EuclideanSpace(5)
1492
+ sage: TM = M.tangent_bundle()
1493
+ sage: g = M.metric()
1494
+ sage: nab = g.connection()
1495
+ sage: e = M.frames()[0] # select standard frame
1496
+ sage: cmat = [ [nab.curvature_form(i, j, e) # long time
1497
+ ....: for j in TM.irange()]
1498
+ ....: for i in TM.irange()]
1499
+
1500
+ Import the algorithm::
1501
+
1502
+ sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginAlgorithm
1503
+ sage: algorithm = PontryaginAlgorithm()
1504
+ sage: [p1] = algorithm.get_local(cmat) # long time
1505
+ sage: p1.display() # long time
1506
+ 0
1507
+ """
1508
+ from sage.symbolic.constants import pi
1509
+
1510
+ dom = cmat[0][0]._domain
1511
+ rk = len(cmat)
1512
+ dim = dom._dim
1513
+ ran = min(rk // 2, dim // 4)
1514
+ if ran < 1:
1515
+ return [] # nothing to compute
1516
+ fac = 1 / (2 * pi) ** 2
1517
+ res = []
1518
+ m = cmat2 = [[sum(cmat[i][l].wedge(cmat[l][j])
1519
+ for l in range(rk))
1520
+ for j in range(rk)] for i in range(rk)]
1521
+ for k in range(1, ran):
1522
+ c = -sum(m[i][i] for i in range(rk)) / (2 * k)
1523
+ res.append(fac * c)
1524
+ for i in range(rk):
1525
+ m[i][i] += c
1526
+ fac *= 1 / (2 * pi) ** 2
1527
+ m = [[sum(cmat2[i][l].wedge(m[l][j]) for l in range(rk))
1528
+ for j in range(rk)] for i in range(rk)]
1529
+ res.append(-fac * sum(m[i][i] for i in range(rk)) / (2 * ran))
1530
+ return res
1531
+
1532
+
1533
+ class EulerAlgorithm(Singleton, Algorithm_generic):
1534
+ r"""
1535
+ Algorithm class to generate Euler forms.
1536
+
1537
+ EXAMPLES:
1538
+
1539
+ Consider the 2-dimensional Euclidean space::
1540
+
1541
+ sage: M = manifolds.EuclideanSpace(2)
1542
+ sage: g = M.metric()
1543
+ sage: nab = g.connection()
1544
+ sage: nab.set_immutable()
1545
+
1546
+ Import the algorithm and apply ``nab`` to it::
1547
+
1548
+ sage: from sage.manifolds.differentiable.characteristic_cohomology_class import EulerAlgorithm
1549
+ sage: algorithm = EulerAlgorithm()
1550
+ sage: algorithm.get(nab)
1551
+ [2-form on the Euclidean plane E^2]
1552
+ sage: algorithm.get(nab)[0].display()
1553
+ 0
1554
+ """
1555
+ @cached_method
1556
+ def get(self, nab):
1557
+ r"""
1558
+ Return the global characteristic forms of the generators w.r.t. a given
1559
+ connection.
1560
+
1561
+ INPUT:
1562
+
1563
+ - ``nab`` -- a metric connection `\nabla`
1564
+
1565
+ OUTPUT: list containing the global characteristic Euler form
1566
+
1567
+ ALGORITHM:
1568
+
1569
+ Assume that `\nabla` is compatible with the metric `g`, and let
1570
+ `(s_1, \ldots, s_n)` be any oriented frame. Denote by
1571
+ `G_s = (g(s_i, s_j))_{ij}` the metric tensor and let
1572
+ `\Omega_s` be the curvature form matrix of `\nabla` w.r.t. `s`.
1573
+ Then, we get:
1574
+
1575
+ .. MATH::
1576
+
1577
+ \left(G_s \cdot \Omega_s \right)_{ij} = g\!\left(R(.,.)s_i, s_j\right),
1578
+
1579
+ where `R` is the Riemannian curvature tensor w.r.t. `\nabla`.
1580
+
1581
+ The characteristic Euler form is now obtained by the expression
1582
+
1583
+ .. MATH::
1584
+
1585
+ \frac{1}{\sqrt{\left|\det(G_s)\right|}} \
1586
+ \mathrm{Pf}\!\left(G_s \cdot \frac{\Omega_s}{2 \pi}\right).
1587
+
1588
+ EXAMPLES:
1589
+
1590
+ Consider the 2-sphere::
1591
+
1592
+ sage: M.<x,y> = manifolds.Sphere(2, coordinates='stereographic')
1593
+ sage: g = M.metric() # long time
1594
+ sage: nab = g.connection() # long time
1595
+ sage: nab.set_immutable() # long time
1596
+
1597
+ Import the algorithm and apply ``nab`` to it::
1598
+
1599
+ sage: from sage.manifolds.differentiable.characteristic_cohomology_class import EulerAlgorithm
1600
+ sage: algorithm = EulerAlgorithm()
1601
+ sage: algorithm.get(nab) # long time
1602
+ [2-form on the 2-sphere S^2 of radius 1 smoothly embedded in the
1603
+ Euclidean space E^3]
1604
+ sage: algorithm.get(nab)[0].display() # long time
1605
+ 2/(pi + pi*x^4 + pi*y^4 + 2*pi*x^2 + 2*(pi + pi*x^2)*y^2) dx∧dy
1606
+
1607
+ REFERENCES:
1608
+
1609
+ - [Che1944]_
1610
+ - [Baer2020]_
1611
+ """
1612
+ if not isinstance(nab, LeviCivitaConnection):
1613
+ raise TypeError('Euler forms are currently only supported for '
1614
+ 'Levi-Civita connections')
1615
+ dom = nab._domain
1616
+ vbundle = dom.tangent_bundle()
1617
+ rk = vbundle._rank
1618
+ if not vbundle.has_orientation():
1619
+ raise ValueError('Euler forms can only be defined for orientable '
1620
+ 'vector bundles')
1621
+ if rk % 2 != 0:
1622
+ raise ValueError('Euler forms are currently only supported for '
1623
+ 'vector bundles with even rank')
1624
+ res = dom.diff_form(rk)
1625
+ g = nab._metric
1626
+ for frame in dom._get_min_covering(vbundle.orientation()):
1627
+ # (G_s * Ω_s)_ij = g(R(.,.)s_i, s_j)
1628
+ gcmat = [[sum(g[[frame, i, j]] * nab.curvature_form(j, k, frame)
1629
+ for j in vbundle.irange())
1630
+ for k in vbundle.irange()] for i in vbundle.irange()]
1631
+ [res_loc] = self.get_local(gcmat) # Pf(G_s * Ω_s) mod const.
1632
+ # e = 1 / sqrt(|det(G_s)|) * Pf(G_s * Ω_s) mod const.
1633
+ det = g.det(frame)
1634
+ if det.is_trivial_zero():
1635
+ raise ValueError(f'metric {g} must be non-degenerate')
1636
+ sqrt_det = det.abs().sqrt()
1637
+ res.set_restriction(res_loc / sqrt_det) # local Euler form
1638
+ # TODO: make `res` immutable?
1639
+ return [res]
1640
+
1641
+ def get_local(self, cmat):
1642
+ r"""
1643
+ Return the normalized Pfaffian w.r.t. a given curvature form matrix.
1644
+
1645
+ The normalization is given by the factor
1646
+ `\left(\frac{1}{2 \pi}\right)^{\frac{k}{2}}`, where `k` is the
1647
+ dimension of the curvature matrix.
1648
+
1649
+ OUTPUT: list containing the normalized Pfaffian of a given curvature form
1650
+
1651
+ .. NOTE::
1652
+
1653
+ In general, the output does *not* represent the local
1654
+ characteristic Euler form. The result is only guaranteed to be the
1655
+ local Euler form if ``cmat`` is given w.r.t. an orthonormal
1656
+ oriented frame. See :meth:`get` for details.
1657
+
1658
+ ALGORITHM::
1659
+
1660
+ The algorithm is based on the Bär-Faddeev-LeVerrier algorithm for
1661
+ the Pfaffian.
1662
+
1663
+ EXAMPLES:
1664
+
1665
+ Consider the 2-sphere::
1666
+
1667
+ sage: M.<th,phi> = manifolds.Sphere(2) # use spherical coordinates
1668
+ sage: TM = M.tangent_bundle()
1669
+ sage: g = M.metric()
1670
+ sage: nab = g.connection()
1671
+ sage: e = M.frames()[0] # select frame (opposite orientation!)
1672
+ sage: cmat = [[nab.curvature_form(i, j, e) for j in TM.irange()]
1673
+ ....: for i in TM.irange()]
1674
+
1675
+ We need some preprocessing because the frame is not orthonormal::
1676
+
1677
+ sage: gcmat = [[sum(g[[e, i, j]] * nab.curvature_form(j, k, e)
1678
+ ....: for j in TM.irange())
1679
+ ....: for k in TM.irange()] for i in TM.irange()]
1680
+
1681
+ Now, ``gcmat`` is guaranteed to be skew-symmetric and can be applied
1682
+ to :meth:`get_local`. Then, the result must be normalized::
1683
+
1684
+ sage: from sage.manifolds.differentiable.characteristic_cohomology_class import EulerAlgorithm
1685
+ sage: algorithm = EulerAlgorithm()
1686
+ sage: euler = -algorithm.get_local(gcmat)[0] / sqrt(g.det(frame=e))
1687
+ sage: euler.display()
1688
+ 1/2*sin(th)/pi dth∧dphi
1689
+ """
1690
+ from sage.symbolic.constants import pi
1691
+
1692
+ rk = len(cmat)
1693
+ ran = rk // 2
1694
+ m = a = [cmat[i].copy() for i in range(rk)]
1695
+ for i in range(0, rk, 2):
1696
+ m[i], m[i + 1] = m[i + 1], m[i] # swap entries
1697
+ for k in range(rk):
1698
+ m[k][i + 1] = -m[k][i + 1]
1699
+ for k in range(1, ran):
1700
+ e = -sum(m[i][i] for i in range(rk)) / (2 * k)
1701
+ for i in range(rk):
1702
+ m[i][i] += e
1703
+ m = [[sum(a[i][l].wedge(m[l][j]) for l in range(rk))
1704
+ for j in range(rk)] for i in range(rk)]
1705
+ e = -sum(m[i][i] for i in range(rk)) / (2 * ran) # Pfaffian mod sign
1706
+ e *= (-1 / (2 * pi)) ** ran # normalize
1707
+ return [e]
1708
+
1709
+
1710
+ class PontryaginEulerAlgorithm(Singleton, Algorithm_generic):
1711
+ r"""
1712
+ Algorithm class to generate Euler and Pontryagin forms.
1713
+
1714
+ EXAMPLES:
1715
+
1716
+ 6-dimensional Euclidean space::
1717
+
1718
+ sage: M = manifolds.EuclideanSpace(6)
1719
+ sage: g = M.metric()
1720
+ sage: nab = g.connection()
1721
+ sage: nab.set_immutable()
1722
+
1723
+ Import the algorithm::
1724
+
1725
+ sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginEulerAlgorithm
1726
+ sage: algorithm = PontryaginEulerAlgorithm()
1727
+ sage: e_form, p1_form = algorithm.get(nab) # long time
1728
+ sage: e_form.display() # long time
1729
+ 0
1730
+ sage: p1_form.display() # long time
1731
+ 0
1732
+ """
1733
+
1734
+ @cached_method
1735
+ def get(self, nab):
1736
+ r"""
1737
+ Return the global characteristic forms of the generators w.r.t. a given
1738
+ connection.
1739
+
1740
+ OUTPUT:
1741
+
1742
+ - a list containing the global Euler form in the first entry, and the
1743
+ global Pontryagin forms in the remaining entries.
1744
+
1745
+ EXAMPLES:
1746
+
1747
+ 4-dimensional Euclidean space::
1748
+
1749
+ sage: M = manifolds.EuclideanSpace(4)
1750
+ sage: g = M.metric()
1751
+ sage: nab = g.connection()
1752
+ sage: nab.set_immutable()
1753
+
1754
+ Import the algorithm::
1755
+
1756
+ sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginEulerAlgorithm
1757
+ sage: algorithm = PontryaginEulerAlgorithm()
1758
+ sage: algorithm.get(nab) # long time
1759
+ [4-form on the 4-dimensional Euclidean space E^4,
1760
+ 4-form on the 4-dimensional Euclidean space E^4]
1761
+ """
1762
+ return EulerAlgorithm().get(nab) + PontryaginAlgorithm().get(nab)
1763
+
1764
+ def get_local(self, cmat):
1765
+ r"""
1766
+ Return the local Euler and Pontryagin forms w.r.t. a given curvature
1767
+ form matrix.
1768
+
1769
+ .. NOTE::
1770
+
1771
+ Similar as for :class:`EulerAlgorithm`, the first entry only
1772
+ represents the Euler form if the curvature form matrix is chosen
1773
+ w.r.t. an orthonormal oriented frame. See
1774
+ :meth:`EulerAlgorithm.get_local` for details.
1775
+
1776
+ OUTPUT:
1777
+
1778
+ - a list containing the local Euler form in the first entry, and the
1779
+ local Pontryagin forms in the remaining entries.
1780
+
1781
+ EXAMPLES:
1782
+
1783
+ 6-dimensional Euclidean space::
1784
+
1785
+ sage: M = manifolds.EuclideanSpace(6)
1786
+ sage: TM = M.tangent_bundle()
1787
+ sage: g = M.metric()
1788
+ sage: nab = g.connection()
1789
+ sage: e = M.frames()[0] # select the standard frame
1790
+ sage: cmat = [ [nab.curvature_form(i, j, e) # long time
1791
+ ....: for j in TM.irange()]
1792
+ ....: for i in TM.irange() ]
1793
+
1794
+ Import the algorithm::
1795
+
1796
+ sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginEulerAlgorithm
1797
+ sage: algorithm = PontryaginEulerAlgorithm()
1798
+ sage: e, p1 = algorithm.get_local(cmat) # long time
1799
+ sage: e.display() # long time
1800
+ 0
1801
+ sage: p1.display() # long time
1802
+ 0
1803
+ """
1804
+ res = EulerAlgorithm().get_local(cmat) # first entry is Euler class
1805
+ res += PontryaginAlgorithm().get_local(cmat) # rest Pontryagin
1806
+ return res
1807
+
1808
+ @cached_method
1809
+ def get_gen_pow(self, nab, i, n):
1810
+ r"""
1811
+ Return the `n`-th power of the `i`-th generator w.r.t ``nab``.
1812
+
1813
+ The result is cached.
1814
+
1815
+ EXAMPLES:
1816
+
1817
+ 4-dimensional Euclidean space::
1818
+
1819
+ sage: M = manifolds.EuclideanSpace(4)
1820
+ sage: TM = M.tangent_bundle()
1821
+ sage: g = M.metric()
1822
+ sage: nab = g.connection()
1823
+ sage: nab.set_immutable()
1824
+
1825
+ Import the algorithm::
1826
+
1827
+ sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginEulerAlgorithm
1828
+ sage: algorithm = PontryaginEulerAlgorithm()
1829
+ sage: e = algorithm.get_gen_pow(nab, 0, 1) # Euler, long time
1830
+ sage: e.display() # long time
1831
+ 0
1832
+ sage: p1_pow2 = algorithm.get_gen_pow(nab, 1, 2) # 1st Pontryagin squared, long time
1833
+ sage: p1_pow2 # long time
1834
+ 8-form zero on the 4-dimensional Euclidean space E^4
1835
+ """
1836
+ if n == 0:
1837
+ return nab._domain._one_scalar_field # no computation necessary
1838
+ if i == 0:
1839
+ return fast_wedge_power(EulerAlgorithm().get(nab)[0], n)
1840
+ return fast_wedge_power(PontryaginAlgorithm().get(nab)[i - 1], n)