Skip to content
This repository was archived by the owner on Feb 1, 2023. It is now read-only.

Commit 4e12d99

Browse files
author
Release Manager
committed
Trac #28562: Tensor Fields: Better Zero Treatment
The zero element is always a special element. Therefore it should be treated as such. It should shorten computations and certainly be immutable. This ticket is devoted to that topic. (Similarly for the one element in the scalar field and mixed form algebra). This ticket is part of the metaticket #28519. **Features** - an assertion error arises when altering the fixed elements zero or one - a new attribute `_is_zero` is added to tensor fields and mixed form (similar to scalar fields) - computations with involved zero or one are shortened by using a simple check - due to immutability of algebra elements, no copies are returned anymore for scalar field operations with zero or one - `_is_zero` attribute is applied for copies URL: https://trac.sagemath.org/28562 Reported by: gh-DeRhamSource Ticket author(s): Michael Jung Reviewer(s): Eric Gourgoulhon, Travis Scrimshaw
2 parents 78d7905 + f2928f8 commit 4e12d99

22 files changed

+985
-320
lines changed

src/sage/manifolds/differentiable/automorphismfield.py

Lines changed: 152 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,7 @@ class AutomorphismField(TensorField):
139139
True
140140
141141
"""
142-
def __init__(self, vector_field_module, name=None, latex_name=None,
143-
is_identity=False):
142+
def __init__(self, vector_field_module, name=None, latex_name=None):
144143
r"""
145144
Construct a field of tangent-space automorphisms on a
146145
non-parallelizable manifold.
@@ -168,7 +167,7 @@ def __init__(self, vector_field_module, name=None, latex_name=None,
168167
169168
Construction of the identity field::
170169
171-
sage: b = GL.element_class(XM, is_identity=True); b
170+
sage: b = GL.one(); b
172171
Field of tangent-space identity maps on the 2-dimensional
173172
differentiable manifold M
174173
sage: TestSuite(b).run(skip='_test_pickling')
@@ -186,24 +185,11 @@ def __init__(self, vector_field_module, name=None, latex_name=None,
186185
Fix ``_test_pickling`` (in the superclass :class:`TensorField`).
187186
188187
"""
189-
if is_identity:
190-
if name is None:
191-
name = 'Id'
192-
if latex_name is None and name == 'Id':
193-
latex_name = r'\mathrm{Id}'
194188
TensorField.__init__(self, vector_field_module, (1,1), name=name,
195189
latex_name=latex_name,
196190
parent=vector_field_module.general_linear_group())
197-
self._is_identity = is_identity
191+
self._is_identity = False # a priori
198192
self._init_derived() # initialization of derived quantities
199-
# Specific initializations for the field of identity maps:
200-
if self._is_identity:
201-
self._inverse = self
202-
for dom in self._domain._subsets:
203-
if dom.is_manifestly_parallelizable():
204-
fmodule = dom.vector_field_module()
205-
self._restrictions[dom] = fmodule.identity_map(name=name,
206-
latex_name=latex_name)
207193

208194
def _repr_(self):
209195
r"""
@@ -261,6 +247,151 @@ def _del_derived(self):
261247
# then deletes the inverse automorphism:
262248
self._inverse = None
263249

250+
def set_comp(self, basis=None):
251+
r"""
252+
Return the components of ``self`` w.r.t. a given module basis for
253+
assignment.
254+
255+
The components with respect to other bases are deleted, in order to
256+
avoid any inconsistency. To keep them, use the method :meth:`add_comp`
257+
instead.
258+
259+
INPUT:
260+
261+
- ``basis`` -- (default: ``None``) basis in which the components are
262+
defined; if none is provided, the components are assumed to refer to
263+
the module's default basis
264+
265+
OUTPUT:
266+
267+
- components in the given basis, as an instance of the
268+
class :class:`~sage.tensor.modules.comp.Components`; if such
269+
components did not exist previously, they are created.
270+
271+
EXAMPLES::
272+
273+
sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2
274+
sage: U = M.open_subset('U') # complement of the North pole
275+
sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
276+
sage: V = M.open_subset('V') # complement of the South pole
277+
sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
278+
sage: M.declare_union(U,V) # S^2 is the union of U and V
279+
sage: e_uv = c_uv.frame()
280+
sage: a= M.automorphism_field(name='a')
281+
sage: a.set_comp(e_uv)
282+
2-indices components w.r.t. Coordinate frame (V, (d/du,d/dv))
283+
sage: a.set_comp(e_uv)[0,0] = u+v
284+
sage: a.set_comp(e_uv)[1,1] = u+v
285+
sage: a.display(e_uv)
286+
a = (u + v) d/du*du + (u + v) d/dv*dv
287+
288+
Setting the components in a new frame::
289+
290+
sage: e = V.vector_frame('e')
291+
sage: a.set_comp(e)
292+
2-indices components w.r.t. Vector frame (V, (e_0,e_1))
293+
sage: a.set_comp(e)[0,1] = u*v
294+
sage: a.set_comp(e)[1,0] = u*v
295+
sage: a.display(e)
296+
a = u*v e_0*e^1 + u*v e_1*e^0
297+
298+
Since the frames ``e`` and ``e_uv`` are defined on the same domain, the
299+
components w.r.t. ``e_uv`` have been erased::
300+
301+
sage: a.display(c_uv.frame())
302+
Traceback (most recent call last):
303+
...
304+
ValueError: no basis could be found for computing the components
305+
in the Coordinate frame (V, (d/du,d/dv))
306+
307+
Since the identity map is a special element, its components cannot be
308+
changed::
309+
310+
sage: id = M.tangent_identity_field()
311+
sage: id.add_comp(e)[0,1] = u*v
312+
Traceback (most recent call last):
313+
...
314+
AssertionError: the components of the identity map cannot be changed
315+
316+
"""
317+
if self._is_identity:
318+
raise AssertionError("the components of the identity map cannot be "
319+
"changed")
320+
return TensorField._set_comp_unsafe(self, basis=basis)
321+
322+
def add_comp(self, basis=None):
323+
r"""
324+
Return the components of ``self`` w.r.t. a given module basis for
325+
assignment, keeping the components w.r.t. other bases.
326+
327+
To delete the components w.r.t. other bases, use the method
328+
:meth:`set_comp` instead.
329+
330+
INPUT:
331+
332+
- ``basis`` -- (default: ``None``) basis in which the components are
333+
defined; if none is provided, the components are assumed to refer to
334+
the module's default basis
335+
336+
.. WARNING::
337+
338+
If the automorphism field has already components in other bases, it
339+
is the user's responsibility to make sure that the components
340+
to be added are consistent with them.
341+
342+
OUTPUT:
343+
344+
- components in the given basis, as an instance of the
345+
class :class:`~sage.tensor.modules.comp.Components`;
346+
if such components did not exist previously, they are created
347+
348+
EXAMPLES::
349+
350+
sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2
351+
sage: U = M.open_subset('U') # complement of the North pole
352+
sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
353+
sage: V = M.open_subset('V') # complement of the South pole
354+
sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
355+
sage: M.declare_union(U,V) # S^2 is the union of U and V
356+
sage: e_uv = c_uv.frame()
357+
sage: a= M.automorphism_field(name='a')
358+
sage: a.add_comp(e_uv)
359+
2-indices components w.r.t. Coordinate frame (V, (d/du,d/dv))
360+
sage: a.add_comp(e_uv)[0,0] = u+v
361+
sage: a.add_comp(e_uv)[1,1] = u+v
362+
sage: a.display(e_uv)
363+
a = (u + v) d/du*du + (u + v) d/dv*dv
364+
365+
Setting the components in a new frame::
366+
367+
sage: e = V.vector_frame('e')
368+
sage: a.add_comp(e)
369+
2-indices components w.r.t. Vector frame (V, (e_0,e_1))
370+
sage: a.add_comp(e)[0,1] = u*v
371+
sage: a.add_comp(e)[1,0] = u*v
372+
sage: a.display(e)
373+
a = u*v e_0*e^1 + u*v e_1*e^0
374+
375+
The components with respect to ``e_uv`` are kept::
376+
377+
sage: a.display(e_uv)
378+
a = (u + v) d/du*du + (u + v) d/dv*dv
379+
380+
Since the identity map is a special element, its components cannot be
381+
changed::
382+
383+
sage: id = M.tangent_identity_field()
384+
sage: id.add_comp(e)[0,1] = u*v
385+
Traceback (most recent call last):
386+
...
387+
AssertionError: the components of the identity map cannot be changed
388+
389+
"""
390+
if self._is_identity:
391+
raise AssertionError("the components of the identity map cannot be "
392+
"changed")
393+
return TensorField._add_comp_unsafe(self, basis=basis)
394+
264395
def _new_instance(self):
265396
r"""
266397
Create an instance of the same class as ``self`` on the same
@@ -789,8 +920,6 @@ class AutomorphismFieldParal(FreeModuleAutomorphism, TensorFieldParal):
789920
- ``name`` -- (default: ``None``) name given to the field
790921
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the field;
791922
if none is provided, the LaTeX symbol is set to ``name``
792-
- ``is_identity`` -- (default: ``False``) determines whether the
793-
constructed object is a field of identity automorphisms
794923
795924
EXAMPLES:
796925
@@ -834,8 +963,7 @@ class AutomorphismFieldParal(FreeModuleAutomorphism, TensorFieldParal):
834963
True
835964
836965
"""
837-
def __init__(self, vector_field_module, name=None, latex_name=None,
838-
is_identity=False):
966+
def __init__(self, vector_field_module, name=None, latex_name=None):
839967
r"""
840968
Construct a field of tangent-space automorphisms.
841969
@@ -861,7 +989,7 @@ def __init__(self, vector_field_module, name=None, latex_name=None,
861989
862990
Construction of the field of identity maps::
863991
864-
sage: b = GL.element_class(XM, is_identity=True); b
992+
sage: b = GL.one(); b
865993
Field of tangent-space identity maps on the 2-dimensional
866994
differentiable manifold M
867995
sage: b[:]
@@ -871,12 +999,12 @@ def __init__(self, vector_field_module, name=None, latex_name=None,
871999
8721000
"""
8731001
FreeModuleAutomorphism.__init__(self, vector_field_module,
874-
name=name, latex_name=latex_name,
875-
is_identity=is_identity)
1002+
name=name, latex_name=latex_name)
8761003
# TensorFieldParal attributes:
8771004
self._vmodule = vector_field_module
8781005
self._domain = vector_field_module._domain
8791006
self._ambient_domain = vector_field_module._ambient_domain
1007+
self._is_identity = False # a priori
8801008
# Initialization of derived quantities:
8811009
TensorFieldParal._init_derived(self)
8821010

src/sage/manifolds/differentiable/automorphismfield_group.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,16 @@ def one(self):
300300
[0 1]
301301
302302
"""
303-
return self.element_class(self._vmodule, is_identity=True)
303+
# Specific initializations for the field of identity maps:
304+
resu = self._element_constructor_(name='Id', latex_name=r'\mathrm{Id}')
305+
resu._inverse = resu
306+
for dom in resu._domain._subsets:
307+
if dom.is_manifestly_parallelizable():
308+
fmodule = dom.vector_field_module()
309+
resu._restrictions[dom] = fmodule.identity_map(name='Id',
310+
latex_name=r'\mathrm{Id}')
311+
resu._is_identity = True
312+
return resu
304313

305314
#### End of monoid methods ####
306315

src/sage/manifolds/differentiable/diff_form.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,21 @@ def wedge(self, other):
525525
raise ValueError("incompatible ambient domains for exterior product")
526526
dom_resu = self._domain.intersection(other._domain)
527527
ambient_dom_resu = self._ambient_domain.intersection(other._ambient_domain)
528+
resu_degree = self._tensor_rank + other._tensor_rank
529+
dest_map = self._vmodule._dest_map
530+
dest_map_resu = dest_map.restrict(dom_resu,
531+
subcodomain=ambient_dom_resu)
532+
# Facilitate computations involving zero:
533+
if resu_degree > ambient_dom_resu._dim:
534+
return dom_resu.diff_form_module(resu_degree,
535+
dest_map=dest_map_resu).zero()
536+
if self._is_zero or other._is_zero:
537+
return dom_resu.diff_form_module(resu_degree,
538+
dest_map=dest_map_resu).zero()
539+
if self is other and (self._tensor_rank % 2) == 1:
540+
return dom_resu.diff_form_module(resu_degree,
541+
dest_map=dest_map_resu).zero()
542+
# Generic case:
528543
self_r = self.restrict(dom_resu)
529544
other_r = other.restrict(dom_resu)
530545
if ambient_dom_resu.is_manifestly_parallelizable():
@@ -549,11 +564,7 @@ def wedge(self, other):
549564
if not is_atomic(olname):
550565
olname = '(' + olname + ')'
551566
resu_latex_name = slname + r'\wedge ' + olname
552-
dest_map = self._vmodule._dest_map
553-
dest_map_resu = dest_map.restrict(dom_resu,
554-
subcodomain=ambient_dom_resu)
555567
vmodule = dom_resu.vector_field_module(dest_map=dest_map_resu)
556-
resu_degree = self._tensor_rank + other._tensor_rank
557568
resu = vmodule.alternating_form(resu_degree, name=resu_name,
558569
latex_name=resu_latex_name)
559570
for dom in self_r._restrictions:

src/sage/manifolds/differentiable/diff_form_module.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -443,13 +443,12 @@ def zero(self):
443443
2-form zero on the 3-dimensional differentiable manifold M
444444
445445
"""
446-
zero = self.element_class(self._vmodule, self._degree, name='zero',
447-
latex_name='0')
448446
zero = self._element_constructor_(name='zero', latex_name='0')
449447
for frame in self._domain._frames:
450448
if self._dest_map.restrict(frame._domain) == frame._dest_map:
451-
zero.add_comp(frame)
449+
zero._add_comp_unsafe(frame)
452450
# (since new components are initialized to zero)
451+
zero._is_zero = True # This element is certainly zero
453452
return zero
454453

455454
#### End of Parent methods

0 commit comments

Comments
 (0)