summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Gourgoulhon <eric.gourgoulhon@obspm.fr>2015-11-08 17:49:04 +0100
committerEric Gourgoulhon <eric.gourgoulhon@obspm.fr>2015-11-08 17:49:04 +0100
commit252e616cc053a3b76ee563282222507cd78c9fb8 (patch)
treeff51eec2314f5bc5a2d038b5ab5310f11ba8b039
parentRevert to UniqueRepresentation for topological manifolds and charts, with the... (diff)
Remove UniqueRepresentation, leaving only WithEqualityById, for topological manifolds and charts.
-rw-r--r--src/sage/manifolds/chart.py117
-rw-r--r--src/sage/manifolds/manifold.py110
-rw-r--r--src/sage/manifolds/point.py35
-rw-r--r--src/sage/manifolds/subset.py53
4 files changed, 277 insertions, 38 deletions
diff --git a/src/sage/manifolds/chart.py b/src/sage/manifolds/chart.py
index 77cce77..a7d967b 100644
--- a/src/sage/manifolds/chart.py
+++ b/src/sage/manifolds/chart.py
@@ -33,7 +33,7 @@ REFERENCES:
#*****************************************************************************
from sage.structure.sage_object import SageObject
-from sage.structure.unique_representation import UniqueRepresentation
+from sage.misc.fast_methods import WithEqualityById
from sage.symbolic.ring import SR
from sage.rings.all import CC
from sage.rings.real_mpfr import RR
@@ -41,7 +41,7 @@ from sage.rings.infinity import Infinity
from sage.misc.latex import latex
from sage.manifolds.manifold import TopologicalManifold
-class Chart(UniqueRepresentation, SageObject):
+class Chart(WithEqualityById, SageObject):
r"""
Chart on a topological manifold.
@@ -252,6 +252,7 @@ class Chart(UniqueRepresentation, SageObject):
if coordinates == '':
for x in names:
coordinates += x + ' '
+ self._coordinate_string = coordinates[:-1] # for pickling (cf. __reduce__)
self._manifold = domain.manifold()
self._domain = domain
# Treatment of the coordinates:
@@ -391,6 +392,104 @@ class Chart(UniqueRepresentation, SageObject):
"""
return self[:]
+ def __reduce__(self):
+ r"""
+ Reduction function for the pickle protocole.
+
+ TESTS::
+
+ sage: M = Manifold(2, 'M', type='topological')
+ sage: X.<x,y> = M.chart()
+ sage: X.__reduce__()
+ (<class 'sage.manifolds.chart.RealChart'>,
+ (2-dimensional topological manifold M, 'x y'),
+ [])
+ sage: X.add_restrictions(x^2 + y^2 < 1)
+ sage: X.__reduce__()
+ (<class 'sage.manifolds.chart.RealChart'>,
+ (2-dimensional topological manifold M, 'x y'),
+ [x^2 + y^2 < 1])
+
+ Test of pickling::
+
+ sage: loads(dumps(X))
+ Chart (M, (x, y))
+
+ """
+ return (type(self), (self._domain, self._coordinate_string),
+ self.__getstate__())
+
+ def __getstate__(self):
+ r"""
+ Return the attributes of ``self`` that have been set after
+ the construction of the object.
+
+ This is used in pickling, to handle the coordinate restrictions,
+ since the latter have been defined by calls to
+ ``self.add_restrictions()`` and not at the object construction.
+
+ TESTS::
+
+ sage: M = Manifold(2, 'M', type='topological')
+ sage: X.<x,y> = M.chart()
+ sage: X.__getstate__()
+ []
+ sage: X.add_restrictions(x^2 + y^2 < 1)
+ sage: X.__getstate__()
+ [x^2 + y^2 < 1]
+
+ """
+ return self._restrictions
+
+ def __setstate__(self, coord_restrictions):
+ r"""
+ Set the attributes of ``self`` that are not initialized at the object
+ construction.
+
+ This is used in unpickling, to handle the coordinate restrictions,
+ since the latter have been defined by calls to
+ ``self.add_restrictions()`` and not at the object construction.
+
+ TESTS::
+
+ sage: M = Manifold(2, 'M', type='topological')
+ sage: X.<x,y> = M.chart()
+ sage: X._restrictions
+ []
+ sage: X.__setstate__([x^2+y^2<1])
+ sage: X._restrictions
+ [x^2 + y^2 < 1]
+
+ """
+ self._restrictions = coord_restrictions
+
+ def _test_pickling(self, **options):
+ r"""
+ Test pickling.
+
+ This test is weaker than
+ :meth:`sage.structure.sage_object.SageObject._test_pickling` in that
+ it does not require ``loads(dumps(self)) == self``.
+ It however checks that ``loads(dumps(self))`` proceeds without any
+ error and results in an object that is a chart with the same
+ coordinates as self.
+
+ TESTS::
+
+ sage: M = Manifold(2, 'M', type='topological')
+ sage: X.<x,y> = M.chart()
+ sage: X._test_pickling()
+ sage: X.add_restrictions(x < 0)
+ sage: X._test_pickling()
+
+ """
+ tester = self._tester(**options)
+ from sage.misc.all import loads, dumps
+ bckp = loads(dumps(self))
+ tester.assertEqual(type(bckp), type(self))
+ tester.assertEqual(bckp._xx, self._xx)
+ tester.assertEqual(bckp._restrictions, self._restrictions)
+
def __getitem__(self, i):
r"""
Access to the coordinates.
@@ -585,7 +684,7 @@ class Chart(UniqueRepresentation, SageObject):
coordinates = ""
for coord in self._xx:
coordinates += repr(coord) + ' '
- res = self.__class__(subset, coordinates)
+ res = type(self)(subset, coordinates)
res._restrictions.extend(self._restrictions)
# The coordinate restrictions are added to the result chart and
# possibly transformed into coordinate bounds:
@@ -1449,7 +1548,7 @@ class RealChart(Chart):
coordinates = ""
for coord in self._xx:
coordinates += repr(coord) + ' '
- res = self.__class__(subset, coordinates)
+ res = type(self)(subset, coordinates)
res._bounds = self._bounds
res._restrictions.extend(self._restrictions)
# The coordinate restrictions are added to the result chart and
@@ -1810,7 +1909,7 @@ class CoordChange(SageObject):
"transformation; use set_inverse() to set the inverse " +
"manually")
x2_to_x1 = list_x2_to_x1[0]
- self._inverse = self.__class__(self._chart2, self._chart1, *x2_to_x1)
+ self._inverse = type(self)(self._chart2, self._chart1, *x2_to_x1)
return self._inverse
@@ -1868,7 +1967,7 @@ class CoordChange(SageObject):
check = kwds['check']
else:
check = True
- self._inverse = self.__class__(self._chart2, self._chart1,
+ self._inverse = type(self)(self._chart2, self._chart1,
*transformations)
if check:
print "Check of the inverse coordinate transformation:"
@@ -1919,7 +2018,7 @@ class CoordChange(SageObject):
# transf = self._transf(*(other._transf.expr()))
#*# for now:
transf = self(*(other._transf))
- return self.__class__(other._chart1, self._chart2, *transf)
+ return type(self)(other._chart1, self._chart2, *transf)
def restrict(self, dom1, dom2=None):
r"""
@@ -1962,10 +2061,10 @@ class CoordChange(SageObject):
if (ch1, ch2) in dom1.coord_changes():
return dom1.coord_changes()[(ch1,ch2)]
#*# when MultiCoordFunction will be implemented (trac #18640):
- # return self.__class__(self._chart1.restrict(dom1),
+ # return type(self)(self._chart1.restrict(dom1),
# self._chart2.restrict(dom2), *(self._transf.expr()))
#*# for now:
- return self.__class__(self._chart1.restrict(dom1),
+ return type(self)(self._chart1.restrict(dom1),
self._chart2.restrict(dom2), *(self._transf))
def display(self):
diff --git a/src/sage/manifolds/manifold.py b/src/sage/manifolds/manifold.py
index f2fcedb..ab5a8ab 100644
--- a/src/sage/manifolds/manifold.py
+++ b/src/sage/manifolds/manifold.py
@@ -86,9 +86,9 @@ and `V`::
sage: M.declare_union(U,V)
and we provide the transition map between the charts ``stereoN`` = `(U, (x, y))`
-and ``stereoS`` = `(V, (u, v))`, denoting by W the intersection of U and V
-(W is the subset of U defined by `x^2+y^2\not=0`, as well as the subset of V
-defined by`u^2+v^2\not=0`)::
+and ``stereoS`` = `(V, (u, v))`, denoting by `W` the intersection of `U` and `V`
+(`W` is the subset of `U` defined by `x^2+y^2\not=0`, as well as the subset of
+`V` defined by `u^2+v^2\not=0`)::
sage: stereoN_to_S = stereoN.transition_map(stereoS, [x/(x^2+y^2), y/(x^2+y^2)],
....: intersection_name='W', restrictions1= x^2+y^2!=0,
@@ -147,7 +147,8 @@ Let us consider the point of coordinates (1,2) in the chart ``stereoN``::
sage: p in W
True
-The coordinates of `p` in the chart ``stereoS`` are::
+The coordinates of `p` in the chart ``stereoS`` are computed by letting
+the chart act on the point::
sage: stereoS(p)
(1/5, 2/5)
@@ -322,14 +323,6 @@ class TopologicalManifold(TopologicalManifoldSubset):
- ``ambient_manifold`` -- (default: ``None``) if not ``None``, the created
object is considered as an open subset of the topological manifold
``ambient_manifold``
- - ``unique_tag`` -- (default: ``None``) tag used to force the construction
- of a new object when all the other arguments have been used previously
- (without ``unique_tag``, the
- :class:`~sage.structure.unique_representation.UniqueRepresentation`
- behavior inherited from
- :class:`~sage.manifolds.subset.TopologicalManifoldSubset`
- would return the previously constructed object corresponding to these
- arguments).
EXAMPLES:
@@ -431,7 +424,7 @@ class TopologicalManifold(TopologicalManifoldSubset):
"""
def __init__(self, n, name, latex_name=None, field='real', start_index=0,
- category=None, ambient_manifold=None, unique_tag=None):
+ category=None, ambient_manifold=None):
r"""
Construct a topological manifold.
@@ -551,6 +544,76 @@ class TopologicalManifold(TopologicalManifoldSubset):
"""
return self._latex_name
+ def __reduce__(self):
+ r"""
+ Reduction function for the pickle protocole.
+
+ TESTS::
+
+ sage: M = Manifold(3, 'M', type='topological')
+ sage: M.__reduce__()
+ (<class 'sage.manifolds.manifold.TopologicalManifold'>,
+ (3,
+ 'M',
+ 'M',
+ Real Field with 53 bits of precision,
+ 0,
+ Category of manifolds over Real Field with 53 bits of precision,
+ None))
+ sage: U = M.open_subset('U')
+ sage: U.__reduce__()
+ (<class 'sage.manifolds.manifold.TopologicalManifold'>,
+ (3,
+ 'U',
+ 'U',
+ Real Field with 53 bits of precision,
+ 0,
+ Category of facade manifolds over Real Field with 53 bits of precision,
+ 3-dimensional topological manifold M))
+
+ Tests of pickling::
+
+ sage: loads(dumps(M))
+ 3-dimensional topological manifold M
+ sage: loads(dumps(U))
+ Open subset U of the 3-dimensional topological manifold M
+
+ """
+ if self._manifold is self:
+ ambient_manifold = None
+ else:
+ ambient_manifold = self._manifold
+ return (TopologicalManifold, (self._dim, self._name, self._latex_name,
+ self._field, self._sindex,
+ self.category(), ambient_manifold))
+
+ def _test_pickling(self, **options):
+ r"""
+ Test pickling.
+
+ This test is weaker than
+ :meth:`sage.structure.sage_object.SageObject._test_pickling` in that
+ it does not require ``loads(dumps(self)) == self``.
+ It however checks that ``loads(dumps(self))`` proceeds without any
+ error and results in an object that is a manifold of the same type as
+ ``self``, with some identical characteristics (dimension, name).
+
+ TESTS::
+
+ sage: M = Manifold(3, 'M', type='topological')
+ sage: M._test_pickling()
+ sage: M = Manifold(3, 'M', type='topological', field='complex')
+ sage: M._test_pickling()
+
+ """
+ tester = self._tester(**options)
+ from sage.misc.all import loads, dumps
+ bckp = loads(dumps(self))
+ tester.assertEqual(type(bckp), type(self))
+ tester.assertEqual(bckp.category(), self.category())
+ tester.assertEqual(bckp._dim, self._dim)
+ tester.assertEqual(bckp._name, self._name)
+
def _an_element_(self):
r"""
Construct some point on the manifold.
@@ -1229,7 +1292,7 @@ class TopologicalManifold(TopologicalManifoldSubset):
# to allow for open_subset() of derived classes to call first this
# version,
# but, because of the category framework, it could NOT have been
- # resu = self.__class__(...)
+ # resu = type(self)(...)
# cf. the discussion in
# https://groups.google.com/forum/#!topic/sage-devel/jHlFxhMDf3Y
resu._supersets.update(self._supersets)
@@ -1435,7 +1498,7 @@ def Manifold(dim, name, latex_name=None, field='real', type='smooth',
:class:`~sage.manifolds.manifold.TopologicalManifold` for more
detailed examples.
- .. RUBRIC:: Reusability of the manifold name
+ .. RUBRIC:: Uniqueness of manifold objects
Suppose we construct a manifold named `M`::
@@ -1488,19 +1551,24 @@ def Manifold(dim, name, latex_name=None, field='real', type='smooth',
sage: M.atlas()[0] != M_old.atlas()[0]
True
- The pickling works for both objects::
+ Moreover, the two manifolds ``M`` and ``M_old`` are still considered
+ distinct::
- sage: loads(dumps(M)) == M
+ sage: M != M_old
True
- sage: loads(dumps(M_old)) == M_old
+
+ This reflects the fact that the equality of manifold objects holds only
+ for identical objects, i.e. one has ``M1 == M2`` if, and only if,
+ ``M1 is M2``. Actually, the manifold classes inherit from
+ :class:`~sage.misc.fast_methods.WithEqualityById`::
+
+ sage: isinstance(M, sage.misc.fast_methods.WithEqualityById)
True
"""
- from time import time
type_ = type # in case the built-in function type is to be restored...
if type_ in ['topological', 'top']:
return TopologicalManifold(dim, name, latex_name=latex_name,
- field=field, start_index=start_index,
- unique_tag=time())
+ field=field, start_index=start_index)
raise NotImplementedError("manifolds of type {} are not ".format(type_) +
"implemented")
diff --git a/src/sage/manifolds/point.py b/src/sage/manifolds/point.py
index 6e43ebe..25c8adc 100644
--- a/src/sage/manifolds/point.py
+++ b/src/sage/manifolds/point.py
@@ -637,7 +637,7 @@ class TopologicalManifoldPoint(Element):
# raise ValueError("no common chart has been found to compare " +
# "{} and {}".format(self, other))
return self._coordinates[common_chart] == \
- other._coordinates[common_chart]
+ other._coordinates[common_chart]
def __ne__(self, other):
r"""
@@ -655,7 +655,7 @@ class TopologicalManifoldPoint(Element):
False
"""
- return not self.__eq__(other)
+ return not (self == other)
def __cmp__(self, other):
r"""
@@ -676,7 +676,7 @@ class TopologicalManifoldPoint(Element):
-1
"""
- if self.__eq__(other):
+ if self == other:
return 0
else:
return -1
@@ -694,10 +694,33 @@ class TopologicalManifoldPoint(Element):
sage: M = Manifold(2, 'M', type='topological')
sage: X.<x,y> = M.chart()
sage: p = M((2,-3), chart=X)
- sage: p.__hash__() # random
+ sage: hash(p) # random
8791657334475
- sage: p.__hash__() == hash(M)
+ sage: hash(p) == hash(M)
True
"""
- return self._manifold.__hash__()
+ return hash(self._manifold)
+
+ def _test_pickling(self, **options):
+ r"""
+ Test pickling.
+
+ This test is weaker than
+ :meth:`sage.structure.sage_object.SageObject._test_pickling` in that
+ it does not require ``loads(dumps(self)) == self``.
+ It however checks that ``loads(dumps(self))`` proceeds without any
+ error and results in an object that is a manifold point.
+
+ TESTS::
+
+ sage: M = Manifold(2, 'M', type='topological')
+ sage: X.<x,y> = M.chart()
+ sage: p = M((1,2), chart=X)
+ sage: p._test_pickling()
+
+ """
+ tester = self._tester(**options)
+ from sage.misc.all import loads, dumps
+ bckp = loads(dumps(self))
+ tester.assertEqual(type(bckp), type(self))
diff --git a/src/sage/manifolds/subset.py b/src/sage/manifolds/subset.py
index 36c28ce..8df3d34 100644
--- a/src/sage/manifolds/subset.py
+++ b/src/sage/manifolds/subset.py
@@ -71,11 +71,11 @@ Lists of subsets after the above operations::
#*****************************************************************************
from sage.structure.parent import Parent
-from sage.structure.unique_representation import UniqueRepresentation
+from sage.misc.fast_methods import WithEqualityById
from sage.categories.sets_cat import Sets
from sage.manifolds.point import TopologicalManifoldPoint
-class TopologicalManifoldSubset(UniqueRepresentation, Parent):
+class TopologicalManifoldSubset(WithEqualityById, Parent):
r"""
Subset of a topological manifold.
@@ -356,6 +356,55 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
"""
return self._latex_name
+ def __reduce__(self):
+ r"""
+ Reduction function for the pickle protocole.
+
+ TEST::
+
+ sage: M = Manifold(3, 'M', type='topological')
+ sage: A = M.subset('A')
+ sage: A.__reduce__()
+ (<class 'sage.manifolds.subset.TopologicalManifoldSubset'>,
+ (3-dimensional topological manifold M, 'A', 'A',
+ Category of facade sets))
+
+ Test of pickling::
+
+ sage: loads(dumps(A))
+ Subset A of the 3-dimensional topological manifold M
+
+ """
+ return (TopologicalManifoldSubset, (self._manifold, self._name,
+ self._latex_name, self.category()))
+
+ def _test_pickling(self, **options):
+ r"""
+ Test pickling.
+
+ This test is weaker than
+ :meth:`sage.structure.sage_object.SageObject._test_pickling` in that
+ it does not require ``loads(dumps(self)) == self``.
+ It however checks that ``loads(dumps(self))`` proceeds without any
+ error and results in an object that is a manifold subset of the same
+ type as ``self``, with the same name.
+
+ TESTS::
+
+ sage: M = Manifold(3, 'M', type='topological')
+ sage: A = M.subset('A')
+ sage: A._test_pickling()
+ sage: B = A.subset('B')
+ sage: B._test_pickling()
+
+ """
+ tester = self._tester(**options)
+ from sage.misc.all import loads, dumps
+ bckp = loads(dumps(self))
+ tester.assertEqual(type(bckp), type(self))
+ tester.assertEqual(bckp.category(), self.category())
+ tester.assertEqual(bckp._name, self._name)
+
def manifold(self):
r"""
Return the manifold of which the current object is a subset.