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

Commit

Permalink
Trac #30209: Merge branch 't/30239/tensorfield___call___alters_zero' …
Browse files Browse the repository at this point in the history
…into bundle_connection_change_of_frame
  • Loading branch information
Michael Jung committed Aug 1, 2020
2 parents e5a3ac4 + 43ec497 commit 135ffd5
Show file tree
Hide file tree
Showing 11 changed files with 266 additions and 124 deletions.
138 changes: 124 additions & 14 deletions src/sage/manifolds/scalarfield.py
Original file line number Diff line number Diff line change
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 @@ -1437,6 +1480,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 @@ -1718,17 +1764,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 @@ -1780,17 +1828,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 @@ -1858,6 +1908,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 @@ -1893,6 +1946,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 @@ -2119,6 +2175,8 @@ def restrict(self, subdomain):
resu = type(self)(subdomain.scalar_field_algebra(),
coord_expression=sexpress, name=self._name,
latex_name=self._latex_name)
if self.is_immutable():
resu.set_immutable() # restriction must be immutable, too
self._restrictions[subdomain] = resu
return self._restrictions[subdomain]

Expand Down Expand Up @@ -3454,3 +3512,55 @@ def set_calc_order(self, symbol, order, truncate=False):
if truncate:
expr.simplify()
self._del_derived()

def set_immutable(self):
r"""
Set ``self`` and all restrictions of ``self`` immutable.
EXAMPLES::
sage: M = Manifold(2, 'M')
sage: X.<x,y> = M.chart()
sage: U = M.open_subset('U', coord_def={X: x^2+y^2<1})
sage: f = M.scalar_field(x^2, name='f')
sage: fU = f.restrict(U)
sage: f.set_immutable()
sage: fU.is_immutable()
True
"""
for rst in self._restrictions.values():
rst.set_immutable()
super().set_immutable()

@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: g = M.scalar_field(x^2, name='g')
sage: g.set_immutable()
Check whether equality implies equality of hash::
sage: f == g
True
sage: hash(f) == hash(g)
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._manifold)
8 changes: 5 additions & 3 deletions src/sage/manifolds/scalarfield_algebra.py
Original file line number Diff line number Diff line change
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
1 change: 0 additions & 1 deletion src/sage/modules/free_module_element.pxd
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from sage.structure.element cimport Vector

cdef class FreeModuleElement(Vector):
cdef bint _is_mutable
cdef int set_unsafe(self, Py_ssize_t i, value) except -1
cdef get_unsafe(self, Py_ssize_t i)
cpdef int hamming_weight(self)
Expand Down
47 changes: 0 additions & 47 deletions src/sage/modules/free_module_element.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1485,53 +1485,6 @@ cdef class FreeModuleElement(Vector): # abstract base class
"""
return self.parent()([ a.subs(in_dict, **kwds) for a in self.list() ])

def set_immutable(self):
"""
Make this vector immutable. This operation can't be undone.
EXAMPLES::
sage: v = vector([1..5]); v
(1, 2, 3, 4, 5)
sage: v[1] = 10
sage: v.set_immutable()
sage: v[1] = 10
Traceback (most recent call last):
...
ValueError: vector is immutable; please change a copy instead (use copy())
"""
self._is_mutable = 0

def is_mutable(self):
"""
Return True if this vector is mutable, i.e., the entries can be
changed.
EXAMPLES::
sage: v = vector(QQ['x,y'], [1..5]); v.is_mutable()
True
sage: v.set_immutable()
sage: v.is_mutable()
False
"""
return self._is_mutable

def is_immutable(self):
"""
Return True if this vector is immutable, i.e., the entries cannot
be changed.
EXAMPLES::
sage: v = vector(QQ['x,y'], [1..5]); v.is_immutable()
False
sage: v.set_immutable()
sage: v.is_immutable()
True
"""
return not self._is_mutable

def change_ring(self, R):
"""
Change the base ring of this vector.
Expand Down
7 changes: 6 additions & 1 deletion src/sage/structure/element.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ cdef class ModuleElement(Element):
# self._lmul_(x) is self * x
cpdef _rmul_(self, Element left)

cdef class ModuleElementWithMutability(ModuleElement):
cdef bint _is_mutable
cpdef bint is_immutable(self)
cpdef bint is_mutable(self)

cdef class MonoidElement(Element):
cpdef _pow_int(self, n)

Expand Down Expand Up @@ -234,7 +239,7 @@ cdef class InfinityElement(RingElement):
pass


cdef class Vector(ModuleElement):
cdef class Vector(ModuleElementWithMutability):
cdef Py_ssize_t _degree

# Return the dot product using the simple metric
Expand Down
Loading

0 comments on commit 135ffd5

Please sign in to comment.