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

Commit

Permalink
Trac #30266: make scalarfields immutable
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Jung committed Aug 5, 2020
1 parent 2416d87 commit 4f07938
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 17 deletions.
109 changes: 95 additions & 14 deletions src/sage/manifolds/scalarfield.py
Expand Up @@ -40,12 +40,13 @@
# https://www.gnu.org/licenses/
# *****************************************************************************

from sage.structure.element import CommutativeAlgebraElement
from sage.structure.element import (CommutativeAlgebraElement,
ModuleElementWithMutability)
from sage.symbolic.expression import Expression
from sage.manifolds.chart_func import ChartFunction
from sage.misc.cachefunc import cached_method


class ScalarField(CommutativeAlgebraElement):
class ScalarField(CommutativeAlgebraElement, ModuleElementWithMutability):
r"""
Scalar field on a topological manifold.
Expand Down Expand Up @@ -277,6 +278,48 @@ class ScalarField(CommutativeAlgebraElement):
sage: zer is M.scalar_field_algebra().zero()
True
The constant scalar fields zero and one are immutable, and therefore
their expressions cannot be changed::
sage: zer.is_immutable()
True
sage: zer.set_expr(x)
Traceback (most recent call last):
...
AssertionError: the expressions of an immutable element cannot be
changed
sage: one = M.one_scalar_field()
sage: one.is_immutable()
True
sage: one.set_expr(x)
Traceback (most recent call last):
...
AssertionError: the expressions of an immutable element cannot be
changed
Other scalar fields can be declared immutable, too::
sage: c.is_immutable()
False
sage: c.set_immutable()
sage: c.is_immutable()
True
sage: c.set_expr(y^2)
Traceback (most recent call last):
...
AssertionError: the expressions of an immutable element cannot be
changed
sage: c.set_name('b')
Traceback (most recent call last):
...
AssertionError: the name of an immutable element cannot be changed
Immutable elements are hashable and can therefore be used as keys for
dictionaries::
sage: {c: 1}[c]
1
By definition, a scalar field acts on the manifold's points, sending
them to elements of the manifold's base field (real numbers in the
present case)::
Expand Down Expand Up @@ -1077,7 +1120,7 @@ def __init__(self, parent, coord_expression=None, chart=None, name=None,
sage: TestSuite(f).run()
"""
CommutativeAlgebraElement.__init__(self, parent)
super().__init__(parent) # both super classes have same signature
domain = parent._domain
self._domain = domain
self._manifold = domain.manifold()
Expand Down Expand Up @@ -1442,6 +1485,9 @@ def set_name(self, name=None, latex_name=None):
\Phi
"""
if self.is_immutable():
raise AssertionError("the name of an immutable element "
"cannot be changed")
if name is not None:
self._name = name
if latex_name is None:
Expand Down Expand Up @@ -1723,17 +1769,19 @@ def set_expr(self, coord_expression, chart=None):
sage: z.set_expr(3*y)
Traceback (most recent call last):
...
AssertionError: the expressions of the element zero cannot be changed
AssertionError: the expressions of an immutable element cannot be
changed
sage: one = M.one_scalar_field()
sage: one.set_expr(3*y)
Traceback (most recent call last):
...
AssertionError: the expressions of the element 1 cannot be changed
AssertionError: the expressions of an immutable element cannot be
changed
"""
if self is self.parent().one() or self is self.parent().zero():
raise AssertionError("the expressions of the element "
"{} cannot be changed".format(self._name))
if self.is_immutable():
raise AssertionError("the expressions of an immutable element "
"cannot be changed")
if chart is None:
chart = self._domain._def_chart
self._express.clear()
Expand Down Expand Up @@ -1785,17 +1833,19 @@ def add_expr(self, coord_expression, chart=None):
sage: z.add_expr(cos(u)-sin(v), c_uv)
Traceback (most recent call last):
...
AssertionError: the expressions of the element zero cannot be changed
AssertionError: the expressions of an immutable element cannot be
changed
sage: one = M.one_scalar_field()
sage: one.add_expr(cos(u)-sin(v), c_uv)
Traceback (most recent call last):
...
AssertionError: the expressions of the element 1 cannot be changed
AssertionError: the expressions of an immutable element cannot be
changed
"""
if self is self.parent().one() or self is self.parent().zero():
raise AssertionError("the expressions of the element "
"{} cannot be changed".format(self._name))
if self.is_immutable():
raise AssertionError("the expressions of an immutable element "
"cannot be changed")
if chart is None:
chart = self._domain._def_chart
self._express[chart] = chart.function(coord_expression)
Expand Down Expand Up @@ -1863,6 +1913,9 @@ def add_expr_by_continuation(self, chart, subdomain):
on V: (u, v) |--> arctan(1/(u^2 + v^2))
"""
if self.is_immutable():
raise AssertionError("the expressions of an immutable element "
"cannot be changed")
if not chart._domain.is_subset(self._domain):
raise ValueError("the chart is not defined on a subset of " +
"the scalar field domain")
Expand Down Expand Up @@ -1898,6 +1951,9 @@ def set_restriction(self, rst):
True
"""
if self.is_immutable():
raise AssertionError("the expressions of an immutable element "
"cannot be changed")
if not isinstance(rst, ScalarField):
raise TypeError("the argument must be a scalar field")
if not rst._domain.is_subset(self._domain):
Expand Down Expand Up @@ -3459,3 +3515,28 @@ def set_calc_order(self, symbol, order, truncate=False):
if truncate:
expr.simplify()
self._del_derived()

@cached_method
def __hash__(self):
r"""
Hash function.
TESTS::
sage: M = Manifold(2, 'M')
sage: X.<x,y> = M.chart()
sage: f = M.scalar_field(x^2, name='f')
sage: f.set_immutable()
sage: hash(f) == f.__hash__()
True
Let us check that ``f`` can be used as a dictionary key::
sage: {f: 1}[f]
1
"""
if self.is_mutable():
raise ValueError('element must be immutable in order to be '
'hashable')
return hash((self._domain, repr(self)))
8 changes: 5 additions & 3 deletions src/sage/manifolds/scalarfield_algebra.py
Expand Up @@ -596,6 +596,7 @@ def zero(self):
coord_expression=coord_express,
name='zero', latex_name='0')
zero._is_zero = True
zero.set_immutable()
return zero

@cached_method
Expand Down Expand Up @@ -625,6 +626,7 @@ def one(self):
"""
coord_express = {chart: chart.one_function()
for chart in self._domain.atlas()}
return self.element_class(self,
coord_expression=coord_express,
name='1', latex_name='1')
one = self.element_class(self, coord_expression=coord_express,
name='1', latex_name='1')
one.set_immutable()
return one

0 comments on commit 4f07938

Please sign in to comment.