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

Commit 0ba933a

Browse files
author
Michael Jung
committed
Trac #30274: first trial of immutability
1 parent fa6bd69 commit 0ba933a

File tree

9 files changed

+168
-57
lines changed

9 files changed

+168
-57
lines changed

src/sage/manifolds/differentiable/automorphismfield.py

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ def _repr_(self):
209209
210210
"""
211211
description = "Field of tangent-space "
212-
if self._is_identity:
212+
if self is self.parent().one():
213213
description += "identity maps "
214214
else:
215215
description += "automorphisms "
@@ -304,20 +304,20 @@ class :class:`~sage.tensor.modules.comp.Components`; if such
304304
ValueError: no basis could be found for computing the components
305305
in the Coordinate frame (V, (d/du,d/dv))
306306
307-
Since the identity map is a special element, its components cannot be
308-
changed::
307+
Since the identity map is an immutable element, its components
308+
cannot be changed::
309309
310310
sage: id = M.tangent_identity_field()
311311
sage: id.add_comp(e)[0,1] = u*v
312312
Traceback (most recent call last):
313313
...
314-
AssertionError: the components of the identity map cannot be changed
314+
AssertionError: the components of an immutable element cannot be
315+
changed
315316
316317
"""
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)
318+
comp = super().set_comp(basis=basis)
319+
self._is_identity = False # a priori
320+
return comp
321321

322322
def add_comp(self, basis=None):
323323
r"""
@@ -384,13 +384,13 @@ class :class:`~sage.tensor.modules.comp.Components`;
384384
sage: id.add_comp(e)[0,1] = u*v
385385
Traceback (most recent call last):
386386
...
387-
AssertionError: the components of the identity map cannot be changed
387+
AssertionError: the components of an immutable element cannot be
388+
changed
388389
389390
"""
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)
391+
comp = super().add_comp(basis=basis)
392+
self._is_identity = False # a priori
393+
return comp
394394

395395
def _new_instance(self):
396396
r"""
@@ -526,6 +526,41 @@ def __call__(self, *arg):
526526
# Case of 2 arguments:
527527
return TensorField.__call__(self, *arg)
528528

529+
def copy(self, name=None, latex_name=None):
530+
r"""
531+
Return an exact copy of the automorphism field ``self``.
532+
533+
INPUT:
534+
535+
- ``name`` -- (default: ``None``) name given to the copy
536+
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
537+
copy; if none is provided, the LaTeX symbol is set to ``name``
538+
539+
.. NOTE::
540+
541+
The name and the derived quantities are not copied.
542+
543+
EXAMPLES::
544+
545+
sage: M = Manifold(2, 'M')
546+
sage: U = M.open_subset('U') ; V = M.open_subset('V')
547+
sage: M.declare_union(U,V) # M is the union of U and V
548+
sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
549+
sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y),
550+
....: intersection_name='W', restrictions1= x>0,
551+
....: restrictions2= u+v>0)
552+
sage: uv_to_xy = xy_to_uv.inverse()
553+
sage: Id = M.tangent_identity_field(); Id
554+
Field of tangent-space identity maps on the 2-dimensional
555+
differentiable manifold M
556+
sage: one = Id.copy('1'); one
557+
Field of tangent-space automorphisms 1 on the 2-dimensional
558+
differentiable manifold M
559+
560+
"""
561+
copy = super().copy(name=name, latex_name=latex_name)
562+
copy._is_identity = self._is_identity
563+
return copy
529564

530565
#### MultiplicativeGroupElement methods ####
531566

@@ -868,9 +903,9 @@ def restrict(self, subdomain, dest_map=None):
868903
if subdomain == self._domain:
869904
return self
870905
if subdomain not in self._restrictions:
871-
if not self._is_identity:
906+
if self is not self.parent().one():
872907
return TensorField.restrict(self, subdomain, dest_map=dest_map)
873-
# Special case of the identity map:
908+
# Special case of the immutable identity map:
874909
if not subdomain.is_subset(self._domain):
875910
raise ValueError("the provided domain is not a subset of " +
876911
"the field's domain")
@@ -1035,7 +1070,7 @@ def _repr_(self):
10351070
10361071
"""
10371072
description = "Field of tangent-space "
1038-
if self._is_identity:
1073+
if self is self.parent().one():
10391074
description += "identity maps "
10401075
else:
10411076
description += "automorphisms "

src/sage/manifolds/differentiable/automorphismfield_group.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,9 @@ def one(self):
314314
if dom.is_manifestly_parallelizable():
315315
fmodule = dom.vector_field_module()
316316
resu._restrictions[dom] = fmodule.identity_map(name='Id',
317-
latex_name=r'\mathrm{Id}')
317+
latex_name=r'\mathrm{Id}')
318318
resu._is_identity = True
319+
resu.set_immutable()
319320
return resu
320321

321322
#### End of monoid methods ####

src/sage/manifolds/differentiable/diff_form_module.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,9 +447,10 @@ def zero(self):
447447
zero = self._element_constructor_(name='zero', latex_name='0')
448448
for frame in self._domain._frames:
449449
if self._dest_map.restrict(frame._domain) == frame._dest_map:
450-
zero._add_comp_unsafe(frame)
450+
zero.add_comp(frame)
451451
# (since new components are initialized to zero)
452452
zero._is_zero = True # This element is certainly zero
453+
zero.set_immutable()
453454
return zero
454455

455456
#### End of Parent methods

src/sage/manifolds/differentiable/manifold.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2520,8 +2520,7 @@ def automorphism_field(self, *comp, **kwargs):
25202520
resu._init_components(*comp, **kwargs)
25212521
return resu
25222522

2523-
def tangent_identity_field(self, name='Id', latex_name=None,
2524-
dest_map=None):
2523+
def tangent_identity_field(self, dest_map=None):
25252524
r"""
25262525
Return the field of identity maps in the tangent spaces on ``self``.
25272526
@@ -2589,7 +2588,7 @@ def tangent_identity_field(self, name='Id', latex_name=None,
25892588
25902589
"""
25912590
vmodule = self.vector_field_module(dest_map)
2592-
return vmodule.identity_map(name=name, latex_name=latex_name)
2591+
return vmodule.identity_map()
25932592

25942593
def default_frame(self):
25952594
r"""

src/sage/manifolds/differentiable/multivector_module.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,8 +399,10 @@ def zero(self):
399399
zero = self._element_constructor_(name='zero', latex_name='0')
400400
for frame in self._domain._frames:
401401
if self._dest_map.restrict(frame._domain) == frame._dest_map:
402-
zero._add_comp_unsafe(frame)
402+
zero.add_comp(frame)
403403
# (since new components are initialized to zero)
404+
zero._is_zero = True # This element is certainly zero
405+
zero.set_immutable()
404406
return zero
405407

406408
#### End of Parent methods

src/sage/manifolds/differentiable/tensorfield.py

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,12 @@
5555

5656
from sage.rings.integer import Integer
5757
from sage.rings.integer_ring import ZZ
58-
from sage.structure.element import ModuleElement
58+
from sage.structure.element import ModuleElementWithMutability
59+
from sage.misc.cachefunc import cached_method
5960
from sage.tensor.modules.free_module_tensor import FreeModuleTensor
6061
from sage.tensor.modules.tensor_with_indices import TensorWithIndices
6162

62-
class TensorField(ModuleElement):
63+
class TensorField(ModuleElementWithMutability):
6364
r"""
6465
Tensor field along a differentiable manifold.
6566
@@ -361,6 +362,35 @@ class TensorField(ModuleElement):
361362
sage: s.restrict(U) == f.restrict(U) * t.restrict(U)
362363
True
363364
365+
Notice that the zero tensor field is immutable, and therefore its
366+
components cannot be changed::
367+
368+
sage: zer = M.tensor_field_module((1, 1)).zero()
369+
sage: zer.is_immutable()
370+
True
371+
sage: zer.set_comp()
372+
Traceback (most recent call last):
373+
...
374+
AssertionError: the components of an immutable element cannot be
375+
changed
376+
377+
Other tensor fields can be declared immutable, too::
378+
379+
sage: t.is_immutable()
380+
False
381+
sage: t.set_immutable()
382+
sage: t.is_immutable()
383+
True
384+
sage: t.set_comp()
385+
Traceback (most recent call last):
386+
...
387+
AssertionError: the components of an immutable element cannot be
388+
changed
389+
sage: t.set_name('b')
390+
Traceback (most recent call last):
391+
...
392+
AssertionError: the name of an immutable element cannot be changed
393+
364394
"""
365395
def __init__(self, vector_field_module, tensor_type, name=None,
366396
latex_name=None, sym=None, antisym=None, parent=None):
@@ -409,7 +439,7 @@ def __init__(self, vector_field_module, tensor_type, name=None,
409439
"""
410440
if parent is None:
411441
parent = vector_field_module.tensor_module(*tensor_type)
412-
ModuleElement.__init__(self, parent)
442+
ModuleElementWithMutability.__init__(self, parent)
413443
self._vmodule = vector_field_module
414444
self._tensor_type = tuple(tensor_type)
415445
self._tensor_rank = self._tensor_type[0] + self._tensor_type[1]
@@ -601,6 +631,9 @@ def set_name(self, name=None, latex_name=None):
601631
a
602632
603633
"""
634+
if self.is_immutable():
635+
raise AssertionError("the name of an immutable element "
636+
"cannot be changed")
604637
if name is not None:
605638
self._name = name
606639
if latex_name is None:
@@ -907,6 +940,26 @@ def symmetries(self):
907940

908941
#### End of simple accessors #####
909942

943+
def set_immutable(self):
944+
r"""
945+
Set ``self`` and all restrictions of ``self`` immutable.
946+
947+
EXAMPLES::
948+
949+
sage: M = Manifold(2, 'M')
950+
sage: X.<x,y> = M.chart()
951+
sage: U = M.open_subset('U', coord_def={X: x^2+y^2<1})
952+
sage: a = M.tensor_field(1, 1, [[1+y,x], [0,x+y]], name='a')
953+
sage: aU = a.restrict(U)
954+
sage: a.set_immutable()
955+
sage: aU.is_immutable()
956+
True
957+
958+
"""
959+
for rst in self._restrictions.values():
960+
rst.set_immutable()
961+
super().set_immutable()
962+
910963
def set_restriction(self, rst):
911964
r"""
912965
Define a restriction of ``self`` to some subdomain.
@@ -943,6 +996,9 @@ def set_restriction(self, rst):
943996
True
944997
945998
"""
999+
if self.is_immutable():
1000+
raise AssertionError("the restrictions of an immutable element "
1001+
"cannot be changed")
9461002
if not isinstance(rst, TensorField):
9471003
raise TypeError("the argument must be a tensor field")
9481004
if not rst._domain.is_subset(self._domain):
@@ -1116,7 +1172,8 @@ def restrict(self, subdomain, dest_map=None):
11161172
res._restrictions.update(rst._restrictions)
11171173
res._restrictions_graph.update(rst._restrictions_graph)
11181174
rst._extensions_graph.update(res._extensions_graph)
1119-
1175+
if self.is_immutable():
1176+
res.set_immutable() # restrictions must be immutable, too
11201177
self._restrictions[subdomain] = res
11211178
self._restrictions_graph[subdomain] = res
11221179
res._extensions_graph.update(self._extensions_graph)
@@ -1242,17 +1299,18 @@ def set_comp(self, basis=None):
12421299
ValueError: no basis could be found for computing the components
12431300
in the Coordinate frame (V, (d/du,d/dv))
12441301
1245-
Since zero is a special element, its components cannot be changed::
1302+
Since zero is an immutable, its components cannot be changed::
12461303
12471304
sage: z = M.tensor_field_module((1, 1)).zero()
12481305
sage: z.set_comp(e)[0,1] = u*v
12491306
Traceback (most recent call last):
12501307
...
1251-
AssertionError: the components of the zero element cannot be changed
1308+
AssertionError: the components of an immutable element cannot be
1309+
changed
12521310
12531311
"""
1254-
if self is self.parent().zero():
1255-
raise AssertionError("the components of the zero element "
1312+
if self.is_immutable():
1313+
raise AssertionError("the components of an immutable element "
12561314
"cannot be changed")
12571315
self._is_zero = False # a priori
12581316
if basis is None:
@@ -1374,14 +1432,15 @@ def add_comp(self, basis=None):
13741432
Since zero is a special element, its components cannot be changed::
13751433
13761434
sage: z = M.tensor_field_module((1, 1)).zero()
1377-
sage: z.add_comp(e)[0,1] = u*v
1435+
sage: z.add_comp(e_uv)[1, 1] = u^2
13781436
Traceback (most recent call last):
13791437
...
1380-
AssertionError: the components of the zero element cannot be changed
1438+
AssertionError: the components of an immutable element cannot be
1439+
changed
13811440
13821441
"""
1383-
if self is self.parent().zero():
1384-
raise AssertionError("the components of the zero element "
1442+
if self.is_immutable():
1443+
raise AssertionError("the components of an immutable element "
13851444
"cannot be changed")
13861445
self._is_zero = False # a priori
13871446
if basis is None:
@@ -1455,6 +1514,9 @@ def add_comp_by_continuation(self, frame, subdomain, chart=None):
14551514
and `a` is defined on the entire manifold `S^2`.
14561515
14571516
"""
1517+
if self.is_immutable():
1518+
raise AssertionError("the components of an immutable element "
1519+
"cannot be changed")
14581520
dom = frame._domain
14591521
if not dom.is_subset(self._domain):
14601522
raise ValueError("the vector frame is not defined on a subset " +
@@ -1552,14 +1614,17 @@ def add_expr_from_subdomain(self, frame, subdomain):
15521614
on V: (xp, yp) |--> 1/(xp^2 + yp^2)
15531615
15541616
"""
1617+
if self.is_immutable():
1618+
raise AssertionError("the expressions of an immutable element "
1619+
"cannot be changed")
15551620
dom = frame._domain
15561621
if not dom.is_subset(self._domain):
15571622
raise ValueError("the vector frame is not defined on a subset " +
15581623
"of the tensor field domain")
15591624
if frame not in self.restrict(frame.domain())._components:
15601625
raise ValueError("the tensor doesn't have an expression in "
15611626
"the frame"+frame._repr_())
1562-
comp = self._add_comp_unsafe(frame)
1627+
comp = self._add_comp_unsafe(frame) # the components stay the same
15631628
scomp = self.restrict(subdomain).comp(frame.restrict(subdomain))
15641629
for ind in comp.non_redundant_index_generator():
15651630
comp[[ind]]._express.update(scomp[[ind]]._express)
@@ -1879,7 +1944,6 @@ def display_comp(self, frame=None, chart=None, coordinate_labels=True,
18791944
only_nonzero=only_nonzero,
18801945
only_nonredundant=only_nonredundant)
18811946

1882-
18831947
def __getitem__(self, args):
18841948
r"""
18851949
Return a component with respect to some frame.
@@ -2041,6 +2105,9 @@ def copy_from(self, other):
20412105
False
20422106
20432107
"""
2108+
if self.is_immutable():
2109+
raise AssertionError("the components of an immutable element "
2110+
"cannot be changed")
20442111
if other not in self.parent():
20452112
raise TypeError("the original must be an element "
20462113
+ "of {}".format(self.parent()))

src/sage/manifolds/differentiable/tensorfield_module.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,9 +580,10 @@ def zero(self):
580580
resu = self._element_constructor_(name='zero', latex_name='0')
581581
for frame in self._domain._frames:
582582
if self._dest_map.restrict(frame._domain) == frame._dest_map:
583-
resu._add_comp_unsafe(frame)
583+
resu.add_comp(frame)
584584
# (since new components are initialized to zero)
585585
resu._is_zero = True # This element is certainly zero
586+
resu.set_immutable()
586587
return resu
587588

588589
#***********************************************************************

0 commit comments

Comments
 (0)