summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Gourgoulhon <eric.gourgoulhon@obspm.fr>2015-11-01 21:23:11 +0100
committerEric Gourgoulhon <eric.gourgoulhon@obspm.fr>2015-11-01 21:23:11 +0100
commitf342e03e7008831c4789b94b03674c1a0cbbf3a6 (patch)
treed76afb946de2badfa630dcf9111d6f78366b0f92
parentIntroduce function Manifold() as the global entry point to construct any type... (diff)
Remove UniqueRepresentation from topological manifolds, subsets and charts.
Add methods __hash__, __eq__, __reduce__
-rw-r--r--src/sage/manifolds/chart.py138
-rw-r--r--src/sage/manifolds/manifold.py178
-rw-r--r--src/sage/manifolds/point.py11
-rw-r--r--src/sage/manifolds/subset.py163
4 files changed, 388 insertions, 102 deletions
diff --git a/src/sage/manifolds/chart.py b/src/sage/manifolds/chart.py
index fe705df..fd8556e 100644
--- a/src/sage/manifolds/chart.py
+++ b/src/sage/manifolds/chart.py
@@ -33,7 +33,6 @@ REFERENCES:
#*****************************************************************************
from sage.structure.sage_object import SageObject
-from sage.structure.unique_representation import UniqueRepresentation
from sage.symbolic.ring import SR
from sage.rings.all import CC
from sage.rings.real_mpfr import RR
@@ -41,7 +40,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(SageObject):
r"""
Chart on a topological manifold.
@@ -97,7 +96,6 @@ class Chart(UniqueRepresentation, SageObject):
side of the chart declaration (there is then no need to pass the string
``'x y'`` to ``chart()``)::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', field='complex', type='topological')
sage: X.<x,y> = M.chart(); X
Chart (M, (x, y))
@@ -118,7 +116,6 @@ class Chart(UniqueRepresentation, SageObject):
names and do not have to coincide with the coordinate symbols;
for instance, one may write::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', field='complex', type='topological')
sage: X.<x1,y1> = M.chart('x y'); X
Chart (M, (x, y))
@@ -136,7 +133,6 @@ class Chart(UniqueRepresentation, SageObject):
However, having the name of the Python variable coincide with the
coordinate symbol is quite convenient; so it is recommended to declare::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', field='complex', type='topological')
sage: X.<x,y> = M.chart()
@@ -255,6 +251,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:
@@ -394,6 +391,131 @@ class Chart(UniqueRepresentation, SageObject):
"""
return self[:]
+ def __hash__(self):
+ r"""
+ Hash function.
+
+ TEST::
+
+ sage: M = Manifold(2, 'M', type='topological')
+ sage: X.<x,y> = M.chart()
+ sage: X.__hash__() # random
+ -4817665684801967664
+
+ """
+ return hash((self._domain,) + self._xx)
+
+ def __eq__(self, other):
+ r"""
+ Compare ``self`` with ``other``.
+
+ TESTS::
+
+ sage: M = Manifold(2, 'M', type='topological')
+ sage: X.<x,y> = M.chart()
+ sage: Y.<u,v> = M.chart()
+ sage: X.__eq__(Y)
+ False
+ sage: X.__eq__(X)
+ True
+ sage: U = M.open_subset('U', coord_def={X: x>0})
+ sage: XU = X.restrict(U)
+ sage: XU.__eq__(X)
+ False
+
+ """
+ if not isinstance(other, Chart):
+ return False
+ return (self._domain == other._domain) and (self._xx == other._xx)
+
+ def __ne__(self, other):
+ r"""
+ Non-equality operator.
+
+ TESTS::
+
+ sage: M = Manifold(2, 'M', type='topological')
+ sage: X.<x,y> = M.chart()
+ sage: Y.<u,v> = M.chart()
+ sage: X.__ne__(Y)
+ True
+ sage: X.__ne__(X)
+ False
+
+ """
+ return not self.__eq__(other)
+
+ 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)) == X
+ True
+
+ """
+ return (self.__class__, (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 __getitem__(self, i):
r"""
Access to the coordinates.
@@ -623,7 +745,6 @@ class Chart(UniqueRepresentation, SageObject):
EXAMPLE::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', field='complex', type='topological')
sage: X.<x,y> = M.chart()
sage: X.add_restrictions([abs(x)<1, y!=0])
@@ -759,7 +880,6 @@ class Chart(UniqueRepresentation, SageObject):
Transition map between the spherical chart and the Cartesian one on
`\RR^2`::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'R^2', type='topological')
sage: c_cart.<x,y> = M.chart()
sage: U = M.open_subset('U') # the complement of the half line {y=0, x >= 0}
@@ -865,7 +985,6 @@ class RealChart(Chart):
side of the chart declaration (there is then no need to pass the string
``'x y z'`` to ``chart()``)::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(3, 'R^3', r'\RR^3', type='topological',
....: start_index=1)
sage: c_cart.<x,y,z> = M.chart(); c_cart
@@ -902,7 +1021,6 @@ class RealChart(Chart):
However, having the name of the Python variable coincide with the
coordinate symbol is quite convenient; so it is recommended to declare::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: forget() # for doctests only
sage: M = Manifold(3, 'R^3', r'\RR^3', type='topological', start_index=1)
sage: c_cart.<x,y,z> = M.chart()
@@ -1161,7 +1279,6 @@ class RealChart(Chart):
Some coordinate bounds on a 2-dimensional manifold::
sage: forget() # for doctests only
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: c_xy.<x,y> = M.chart('x y:[0,1)')
sage: c_xy.coord_bounds(0) # x in (-oo,+oo) (the default)
@@ -1302,7 +1419,6 @@ class RealChart(Chart):
Cartesian coordinates on the open unit disc in $\RR^2$::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological') # the open unit disc
sage: X.<x,y> = M.chart()
sage: X.add_restrictions(x^2+y^2<1)
diff --git a/src/sage/manifolds/manifold.py b/src/sage/manifolds/manifold.py
index c67d6ba..097bc64 100644
--- a/src/sage/manifolds/manifold.py
+++ b/src/sage/manifolds/manifold.py
@@ -19,6 +19,9 @@ charts (see :class:`~sage.manifolds.chart.Chart`).
:class:`TopologicalManifold` serves as a base class for more specific manifold
classes.
+The user interface is provided by the generic function :func:`Manifold`, with
+the argument ``type`` set to ``'topological'``.
+
.. RUBRIC:: Example 1: the 2-sphere as a topological manifold of dimension
2 over `\RR`
@@ -400,16 +403,6 @@ class TopologicalManifold(TopologicalManifoldSubset):
sage: isinstance(p, sage.manifolds.point.TopologicalManifoldPoint)
True
- Manifolds are unique, as long as they are created with the same arguments::
-
- sage: M is Manifold(4, 'M', type='topological', start_index=1)
- True
- sage: M is Manifold(4, 'M', type='topological')
- False
- sage: M is Manifold(4, 'M', latex_name='M', type='topological',
- ....: start_index=1)
- False
-
Since an open subset of a topological manifold `M` is itself a topological
manifold, open subsets of `M` are instances of the class
:class:`TopologicalManifold`::
@@ -476,7 +469,7 @@ class TopologicalManifold(TopologicalManifoldSubset):
"a topological manifold")
# Initialization as a subset of the ambient manifold (possibly itself):
TopologicalManifoldSubset.__init__(self, ambient_manifold, name,
- latex_name=latex_name, category=category)
+ latex_name=latex_name, category=category)
self._is_open = True
self._open_covers = [[self]] # list of open covers of self
self._atlas = [] # list of charts defined on subsets of self
@@ -550,6 +543,106 @@ class TopologicalManifold(TopologicalManifoldSubset):
"""
return self._latex_name
+ def __hash__(self):
+ r"""
+ Hash function.
+
+ TESTS::
+
+ sage: M = Manifold(3, 'M', type='topological')
+ sage: M.__hash__() # random
+ 9122374470132259666
+
+ """
+ return hash((self._dim, self._field, self._name))
+
+ def __eq__(self, other):
+ r"""
+ Compare ``self`` with ``other``.
+
+ TESTS::
+
+ sage: M = Manifold(3, 'M', type='topological')
+ sage: N = Manifold(3, 'M', type='topological')
+ sage: M.__eq__(N)
+ True
+ sage: N = Manifold(3, 'N', type='topological') # change the name
+ sage: M.__eq__(N)
+ False
+ sage: N = Manifold(2, 'M', type='topological') # change the dimension
+ sage: M.__eq__(N)
+ False
+ sage: N = Manifold(3, 'M', type='topological', field='complex') # change the base field
+ sage: M.__eq__(N)
+ False
+
+ """
+ if not isinstance(other, TopologicalManifold):
+ return False
+ return (self._dim == other._dim) and (self._field == other._field) \
+ and (self._name == other._name)
+ #!# this is rather primitive: the atlases should be compared as well...
+
+ def __ne__(self, other):
+ r"""
+ Non-equality operator.
+
+ TESTS::
+
+ sage: M = Manifold(3, 'M', type='topological')
+ sage: N = Manifold(3, 'M', type='topological')
+ sage: M.__ne__(N)
+ False
+ sage: N = Manifold(3, 'N', type='topological') # change the name
+ sage: M.__ne__(N)
+ True
+
+ """
+ return not self.__eq__(other)
+
+ 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)) == M
+ True
+ sage: loads(dumps(U)) == U
+ True
+
+ """
+ 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 _an_element_(self):
r"""
Construct some point on the manifold.
@@ -885,23 +978,42 @@ class TopologicalManifold(TopologicalManifoldSubset):
EXAMPLES:
- Charts on subsets of `\RR^2`::
+ Let us consider `\RR^2` as a 2-dimensional manifold::
sage: M = Manifold(2, 'R^2', type='topological')
- sage: c_cart.<x,y> = M.chart() # Cartesian coordinates on R^2
+
+ Immediately after the manifold creation, the atlas is empty, since no
+ chart has been defined yet::
+
+ sage: M.atlas()
+ []
+
+ Let us introduce the chart of Cartesian coordinates::
+
+ sage: c_cart.<x,y> = M.chart()
sage: M.atlas()
[Chart (R^2, (x, y))]
- sage: U = M.open_subset('U', coord_def={c_cart: (y!=0,x<0)}) # U = R^2 \ half line {y=0,x>=0}
+
+ The complement of the half line `\{y=0,\; x\geq 0\}`::
+
+ sage: U = M.open_subset('U', coord_def={c_cart: (y!=0,x<0)})
sage: U.atlas()
[Chart (U, (x, y))]
sage: M.atlas()
[Chart (R^2, (x, y)), Chart (U, (x, y))]
- sage: c_spher.<r, ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi') # spherical (polar) coordinates on U
+
+ Spherical (polar) coordinates on `U`::
+
+ sage: c_spher.<r, ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi')
sage: U.atlas()
[Chart (U, (x, y)), Chart (U, (r, ph))]
sage: M.atlas()
[Chart (R^2, (x, y)), Chart (U, (x, y)), Chart (U, (r, ph))]
+ .. SEEALSO::
+
+ :meth:`top_charts`
+
"""
return self._atlas
@@ -919,7 +1031,6 @@ class TopologicalManifold(TopologicalManifoldSubset):
Charts on a 2-dimensional manifold::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: X.<x,y> = M.chart()
sage: U = M.open_subset('U', coord_def={X: x>0})
@@ -927,12 +1038,17 @@ class TopologicalManifold(TopologicalManifoldSubset):
sage: M.top_charts()
[Chart (M, (x, y)), Chart (U, (u, v))]
- Note that the (user) atlas contains one more chart: (U, (x,y)), which
- is not a "top" chart::
+ Note that the (user) atlas contains one more chart: ``(U, (x,y))``,
+ which is not a "top" chart::
sage: M.atlas()
[Chart (M, (x, y)), Chart (U, (x, y)), Chart (U, (u, v))]
+ .. SEEALSO::
+
+ :meth:`atlas` for the complete list of charts defined on the
+ manifold.
+
"""
return self._top_charts
@@ -952,7 +1068,6 @@ class TopologicalManifold(TopologicalManifoldSubset):
Default chart on a 2-dimensional manifold and on some subsets::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: M.chart('x y')
Chart (M, (x, y))
@@ -981,7 +1096,6 @@ class TopologicalManifold(TopologicalManifoldSubset):
Charts on a 2-dimensional manifold::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: c_xy.<x,y> = M.chart()
sage: c_uv.<u,v> = M.chart()
@@ -1027,13 +1141,12 @@ class TopologicalManifold(TopologicalManifoldSubset):
Change of coordinates on a 2-dimensional manifold::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: c_xy.<x,y> = M.chart()
sage: c_uv.<u,v> = M.chart()
- sage: c_xy.transition_map(c_uv, (x+y, x-y)) # defines the coordinate change
+ sage: c_xy.transition_map(c_uv, (x+y, x-y)) # defines the coord. change
Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v))
- sage: M.coord_change(c_xy, c_uv) # returns the coordinate change defined above
+ sage: M.coord_change(c_xy, c_uv) # returns the coord. change defined above
Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v))
"""
@@ -1056,7 +1169,6 @@ class TopologicalManifold(TopologicalManifoldSubset):
Various changes of coordinates on a 2-dimensional manifold::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: c_xy.<x,y> = M.chart()
sage: c_uv.<u,v> = M.chart()
@@ -1103,7 +1215,6 @@ class TopologicalManifold(TopologicalManifoldSubset):
EXAMPLES::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: U = M.open_subset('U')
sage: X.<x,y> = U.chart()
@@ -1145,7 +1256,6 @@ class TopologicalManifold(TopologicalManifoldSubset):
Creating an open subset of a 2-dimensional manifold::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: A = M.open_subset('A'); A
Open subset A of the 2-dimensional topological manifold M
@@ -1206,7 +1316,8 @@ class TopologicalManifold(TopologicalManifoldSubset):
category=self.category(),
ambient_manifold=self._manifold)
#!# NB: the above could have been
- # resu = type(self).__base__(...) instead of resu = TopologicalManifold(...)
+ # resu = type(self).__base__(...)
+ # instead of resu = TopologicalManifold(...)
# to allow for open_subset() of derived classes to call first this
# version,
# but, because of the category framework, it could NOT have been
@@ -1291,7 +1402,6 @@ class TopologicalManifold(TopologicalManifoldSubset):
Chart on a 2-dimensional manifold::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: U = M.open_subset('U')
sage: X = U.chart('x y'); X
@@ -1322,7 +1432,6 @@ class TopologicalManifold(TopologicalManifoldSubset):
left-hand side of the chart declaration (there is then no need to
pass the string 'x y' to chart())::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: U = M.open_subset('U')
sage: X.<x,y> = U.chart(); X
@@ -1382,7 +1491,8 @@ def Manifold(dim, name, latex_name=None, field='real', type='smooth',
- ``start_index`` -- (default: 0) integer; lower value of the range of
indices used for "indexed objects" on the manifold, e.g. coordinates
in a chart
- - ``extra_kwds`` -- keywords for specific types of manifolds
+ - ``extra_kwds`` -- keywords meaningful only for specific types of
+ manifolds
OUTPUT:
@@ -1413,13 +1523,9 @@ def Manifold(dim, name, latex_name=None, field='real', type='smooth',
sage: M = Manifold(3, 'M', type='topological', field=QQ); M
3-dimensional topological manifold M over the Rational Field
- A manifold has a unique representation::
-
- sage: M is Manifold(3, 'M', type='topological', field=QQ)
- True
-
See the documentation of class
- :class:`~sage.manifolds.manifold.TopologicalManifold` for more examples.
+ :class:`~sage.manifolds.manifold.TopologicalManifold` for more
+ detailed examples.
"""
type_ = type # in case the built-in function type is to be restored...
diff --git a/src/sage/manifolds/point.py b/src/sage/manifolds/point.py
index 078c737..6e43ebe 100644
--- a/src/sage/manifolds/point.py
+++ b/src/sage/manifolds/point.py
@@ -154,7 +154,6 @@ class TopologicalManifoldPoint(Element):
TESTS::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: X.<x,y> = M.chart()
sage: p = M((2,3), name='p'); p
@@ -263,7 +262,6 @@ class TopologicalManifoldPoint(Element):
Points on a 2-dimensional manifold::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: X.<x,y> = M.chart()
sage: p = M.point((1,3), name='p'); p
@@ -314,7 +312,6 @@ class TopologicalManifoldPoint(Element):
Spherical coordinates of a point on `\RR^3`::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(3, 'M', type='topological') # the part of R^3 covered by spherical coordinates
sage: c_spher.<r,th,ph> = M.chart(r'r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi') # spherical coordinates
sage: p = M.point((1, pi/2, pi))
@@ -342,7 +339,6 @@ class TopologicalManifoldPoint(Element):
Coordinates of a point on a 2-dimensional manifold::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: c_xy.<x,y> = M.chart()
sage: (a, b) = var('a b') # generic coordinates for the point
@@ -596,6 +592,8 @@ class TopologicalManifoldPoint(Element):
False
"""
+ if other is self:
+ return True
if not isinstance(other, TopologicalManifoldPoint):
return False
if other._manifold != self._manifold:
@@ -603,7 +601,10 @@ class TopologicalManifoldPoint(Element):
# Search for a common chart to compare the coordinates
common_chart = None
# the subset's default chart is privileged:
- def_chart = self._subset._def_chart
+ if hasattr(self._subset, '_def_chart'): # self._subset is open
+ def_chart = self._subset._def_chart
+ else:
+ def_chart = self._manifold._def_chart
if def_chart in self._coordinates and def_chart in other._coordinates:
common_chart = def_chart
else:
diff --git a/src/sage/manifolds/subset.py b/src/sage/manifolds/subset.py
index 98b83a1..4962170 100644
--- a/src/sage/manifolds/subset.py
+++ b/src/sage/manifolds/subset.py
@@ -3,8 +3,8 @@ Subsets of topological manifolds
The class :class:`TopologicalManifoldSubset` implements generic subsets of a
topological manifold. Open subsets are implemented by the class
-:class:`~sage.manifolds.manifold.TopologicalManifold` (since an open subset of a
-manifold is a manifold by itself), which inherits from
+:class:`~sage.manifolds.manifold.TopologicalManifold` (since an open subset of
+a manifold is a manifold by itself), which inherits from
:class:`TopologicalManifoldSubset`.
AUTHORS:
@@ -71,19 +71,15 @@ Lists of subsets after the above operations::
#*****************************************************************************
from sage.structure.parent import Parent
-from sage.misc.fast_methods import WithEqualityById
-from sage.structure.unique_representation import UniqueRepresentation
from sage.categories.sets_cat import Sets
-from sage.categories.homset import Hom
-from sage.rings.infinity import Infinity
from sage.manifolds.point import TopologicalManifoldPoint
-class TopologicalManifoldSubset(UniqueRepresentation, Parent):
+class TopologicalManifoldSubset(Parent):
r"""
Subset of a topological manifold.
- The class :class:`TopologicalManifoldSubset` inherits from the generic Sage class
- :class:`~sage.structure.parent.Parent` and is declared to belong to
+ The class :class:`TopologicalManifoldSubset` inherits from the generic Sage
+ class :class:`~sage.structure.parent.Parent` and is declared to belong to
the category of facade sets
(see :meth:`~sage.categories.sets_cat.Sets.SubcategoryMethods.Facade`).
The corresponding element class is
@@ -92,8 +88,9 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
(see example below).
Note that open subsets are not implemented directly by this class, but
- by the derived class :class:`~sage.manifolds.manifold.TopologicalManifold` (an
- open subset of a topological manifold being itself a topological manifold).
+ by the derived class :class:`~sage.manifolds.manifold.TopologicalManifold`
+ (an open subset of a topological manifold being itself a topological
+ manifold).
INPUT:
@@ -108,18 +105,19 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
A subset of a manifold::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: from sage.manifolds.subset import TopologicalManifoldSubset
- sage: A = TopologicalManifoldSubset(M, 'A', latex_name=r'\mathcal{A}'); A
+ sage: A = TopologicalManifoldSubset(M, 'A', latex_name=r'\mathcal{A}')
+ sage: A
Subset A of the 2-dimensional topological manifold M
sage: latex(A)
\mathcal{A}
sage: A.is_subset(M)
True
- Instead of importing :class:`TopologicalManifoldSubset` in the global namespace,
- it is recommended to use the method :meth:`subset` to create a new subset::
+ Instead of importing :class:`TopologicalManifoldSubset` in the global
+ namespace, it is recommended to use the method :meth:`subset` to create a
+ new subset::
sage: B = M.subset('B', latex_name=r'\mathcal{B}'); B
Subset B of the 2-dimensional topological manifold M
@@ -164,15 +162,12 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
TESTS::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: X.<x,y> = M.chart()
sage: A = M.subset('A'); A
Subset A of the 2-dimensional topological manifold M
"""
- if not isinstance(name, str):
- raise TypeError("{} is not a string".format(name))
if category is None:
base = None
category = Sets()
@@ -184,13 +179,9 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
else:
Parent.__init__(self, base=base, category=category,
facade=manifold)
- for dom in manifold._subsets:
- if name == dom._name:
- raise ValueError("the name '" + name +
- "' is already used for another " +
- "subset of the {}".format(manifold))
- manifold._subsets.add(self)
self._manifold = manifold
+ if not isinstance(name, str):
+ raise TypeError("{} is not a string".format(name))
self._name = name
if latex_name is None:
self._latex_name = self._name
@@ -198,6 +189,13 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
if not isinstance(latex_name, str):
raise TypeError("{} is not a string".format(latex_name))
self._latex_name = latex_name
+ if self is not self._manifold:
+ for dom in manifold._subsets:
+ if name == dom._name:
+ raise ValueError("the name '" + name +
+ "' is already used for another " +
+ "subset of the {}".format(manifold))
+ manifold._subsets.add(self)
self._supersets = set([manifold, self]) # subsets containing self
self._subsets = set([self]) # subsets of self
self._top_subsets = set([self]) # subsets contained in self but not
@@ -240,9 +238,7 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
sage: M = Manifold(2, 'M', type='topological')
sage: X.<x,y> = M.chart()
- sage: p = M._element_constructor_(); p
- Point on the 2-dimensional topological manifold M
- sage: p = M._element_constructor_((-2,3)); p # coord in the default chart
+ sage: p = M((-2,3)); p # coord in the default chart
Point on the 2-dimensional topological manifold M
sage: X(p)
(-2, 3)
@@ -250,7 +246,7 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
A generic subset has no default chart, so the chart must be explicited::
sage: A = M.subset('A')
- sage: p = A._element_constructor_((-2,3), chart=X); p
+ sage: p = A((-2,3), chart=X); p
Point on the 2-dimensional topological manifold M
sage: X(p)
(-2, 3)
@@ -262,28 +258,27 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
Coordinates in a chart with some coordinate restrictions::
sage: Y.<u,v> = M.chart('u:(-1,1) v:(-1,1)')
- sage: p = A._element_constructor_((0,1/2), chart=Y); p
+ sage: p = A((0,1/2), chart=Y); p
Point on the 2-dimensional topological manifold M
sage: Y(p)
(0, 1/2)
- sage: p = A._element_constructor_((0,1/2), chart=Y,
- ....: check_coords=False); p
+ sage: p = A((0,1/2), chart=Y, check_coords=False); p
Point on the 2-dimensional topological manifold M
sage: Y(p)
(0, 1/2)
- sage: p = A._element_constructor_((3,1/2), chart=Y)
+ sage: p = A((3,1/2), chart=Y)
Traceback (most recent call last):
...
ValueError: the coordinates (3, 1/2) are not valid on the Chart (M, (u, v))
Specifying the name of the point::
- sage: p = A._element_constructor_((-2,3), chart=X, name='p'); p
+ sage: p = A((-2,3), chart=X, name='p'); p
Point p on the 2-dimensional topological manifold M
A point as entry::
- sage: q = A._element_constructor_(p); q
+ sage: q = A(p); q
Point p on the 2-dimensional topological manifold M
sage: X(q)
(-2, 3)
@@ -360,13 +355,86 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
"""
return self._latex_name
+ def __hash__(self):
+ r"""
+ Hash function.
+
+ TEST::
+
+ sage: M = Manifold(3, 'M', type='topological')
+ sage: A = M.subset('A')
+ sage: A.__hash__() # random
+ 1649998564335275777
+
+ """
+ return hash((self._manifold, self._name))
+
+
+ def __eq__(self, other):
+ r"""
+ Compare ``self`` with ``other``.
+
+ TESTS::
+
+ sage: M = Manifold(3, 'M', type='topological')
+ sage: A = M.subset('A')
+ sage: B = M.subset('B')
+ sage: A.__eq__(A)
+ True
+ sage: A.__eq__(B)
+ False
+
+ """
+ if not isinstance(other, TopologicalManifoldSubset):
+ return False
+ return (self._manifold == other._manifold) and \
+ (self._name == other._name)
+
+ def __ne__(self, other):
+ r"""
+ Non-equality operator.
+
+ TESTS::
+
+ sage: M = Manifold(3, 'M', type='topological')
+ sage: A = M.subset('A')
+ sage: B = M.subset('B')
+ sage: A.__ne__(A)
+ False
+ sage: A.__ne__(B)
+ True
+
+ """
+ return not self.__eq__(other)
+
+ 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)) == A
+ True
+
+ """
+ return (TopologicalManifoldSubset, (self._manifold, self._name,
+ self._latex_name, self.category()))
+
def manifold(self):
r"""
Return the manifold of which the current object is a subset.
EXAMPLES::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: A = M.subset('A')
sage: A.manifold()
@@ -401,7 +469,6 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
EXAMPLES::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: M.open_covers()
[[2-dimensional topological manifold M]]
@@ -446,7 +513,6 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
Subsets of a 2-dimensional manifold::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: U = M.open_subset('U')
sage: V = M.subset('V')
@@ -491,7 +557,6 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
Subsets of a 2-dimensional manifold::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: U = M.open_subset('U')
sage: V = M.subset('V')
@@ -524,14 +589,14 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
OUTPUT:
- - the subset, as an instance of :class:`TopologicalManifoldSubset`, or of
- the derived class :class:`TopologicalManifold` if ``is_open`` is ``True``.
+ - the subset, as an instance of :class:`TopologicalManifoldSubset`, or
+ of the derived class :class:`TopologicalManifold` if ``is_open`` is
+ ``True``.
EXAMPLES:
Creating a subset of a manifold::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: a = M.subset('A'); a
Subset A of the 2-dimensional topological manifold M
@@ -578,14 +643,14 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
OUTPUT:
- - the superset, as an instance of :class:`TopologicalManifoldSubset` or of
- the derived class :class:`TopologicalManifold` if ``is_open`` is ``True``.
+ - the superset, as an instance of :class:`TopologicalManifoldSubset` or
+ of the derived class :class:`TopologicalManifold` if ``is_open`` is
+ ``True``.
EXAMPLES:
Creating some superset of a given subset::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: a = M.subset('A')
sage: b = a.superset('B'); b
@@ -643,14 +708,13 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
OUTPUT:
- - instance of :class:`TopologicalManifoldSubset` representing the subset that
- is the intersection of the current subset with ``other``
+ - instance of :class:`TopologicalManifoldSubset` representing the
+ subset that is the intersection of the current subset with ``other``
EXAMPLES:
Intersection of two subsets::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: a = M.subset('A')
sage: b = M.subset('B')
@@ -739,8 +803,8 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
OUTPUT:
- - instance of :class:`TopologicalManifoldSubset` representing the subset that
- is the union of the current subset with ``other``
+ - instance of :class:`TopologicalManifoldSubset` representing the
+ subset that is the union of the current subset with ``other``
EXAMPLES:
@@ -964,7 +1028,6 @@ class TopologicalManifoldSubset(UniqueRepresentation, Parent):
Points on a 2-dimensional manifold::
- sage: sage.manifolds.manifold.TopologicalManifold._clear_cache_() # for doctests only
sage: M = Manifold(2, 'M', type='topological')
sage: c_xy.<x,y> = M.chart()
sage: p = M.point((1,2), name='p'); p