summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Gourgoulhon <eric.gourgoulhon@obspm.fr>2015-12-02 15:26:01 +0100
committerEric Gourgoulhon <eric.gourgoulhon@obspm.fr>2015-12-02 15:26:01 +0100
commitd3e5d4d31b0048ee51674ff28d4f5e26e85d2a8f (patch)
tree1bba97d32c2b4c1c8b5d14ad05becde4fc1a4907
parentUpdated Sage version to 6.10.beta6 (diff)
parentSome small tweaks as part of the review. (diff)
Revert to UniqueRepresentation for topological manifolds
-rw-r--r--src/doc/en/reference/index.rst1
l---------src/doc/en/reference/manifolds/conf.py1
-rw-r--r--src/doc/en/reference/manifolds/index.rst18
-rw-r--r--src/doc/en/reference/manifolds/manifold.rst13
-rw-r--r--src/sage/all.py2
-rw-r--r--src/sage/manifolds/__init__.py1
-rw-r--r--src/sage/manifolds/all.py2
-rw-r--r--src/sage/manifolds/chart.py2036
-rw-r--r--src/sage/manifolds/manifold.py1618
-rw-r--r--src/sage/manifolds/point.py726
-rw-r--r--src/sage/manifolds/subset.py1029
11 files changed, 5447 insertions, 0 deletions
diff --git a/src/doc/en/reference/index.rst b/src/doc/en/reference/index.rst
index ed28a7a..104cf4e 100644
--- a/src/doc/en/reference/index.rst
+++ b/src/doc/en/reference/index.rst
@@ -86,6 +86,7 @@ Geometry and Topology
* :doc:`Combinatorial Geometry <geometry/index>`
* :doc:`Cell Complexes and their Homology <homology/index>`
* :doc:`Differential Forms <tensor/index>`
+* :doc:`Manifolds <manifolds/index>`
* :doc:`Parametrized Surfaces <riemannian_geometry/index>`
Number Theory, Algebraic Geometry
diff --git a/src/doc/en/reference/manifolds/conf.py b/src/doc/en/reference/manifolds/conf.py
new file mode 120000
index 00000000..2bdf7e6
--- /dev/null
+++ b/src/doc/en/reference/manifolds/conf.py
@@ -0,0 +1 @@
+../conf_sub.py \ No newline at end of file
diff --git a/src/doc/en/reference/manifolds/index.rst b/src/doc/en/reference/manifolds/index.rst
new file mode 100644
index 00000000..f0d5932
--- /dev/null
+++ b/src/doc/en/reference/manifolds/index.rst
@@ -0,0 +1,18 @@
+Manifolds
+=========
+
+This is the Sage implementation of manifolds resulting from the
+`SageManifolds project <http://sagemanifolds.obspm.fr/>`_.
+This section describes only the "manifold" part of SageManifolds;
+the pure algebraic part is described in the section
+:ref:`tensors-on-free-modules`.
+
+More documentation (in particular example worksheets) can be found
+`here <http://sagemanifolds.obspm.fr/documentation.html>`_.
+
+.. toctree::
+ :maxdepth: 2
+
+ manifold
+
+.. include:: ../footer.txt
diff --git a/src/doc/en/reference/manifolds/manifold.rst b/src/doc/en/reference/manifolds/manifold.rst
new file mode 100644
index 00000000..4180570
--- /dev/null
+++ b/src/doc/en/reference/manifolds/manifold.rst
@@ -0,0 +1,13 @@
+Topological manifolds
+=====================
+
+.. toctree::
+ :maxdepth: 2
+
+ sage/manifolds/manifold
+
+ sage/manifolds/point
+
+ sage/manifolds/subset
+
+ sage/manifolds/chart
diff --git a/src/sage/all.py b/src/sage/all.py
index 3ddfe08..664bc0b 100644
--- a/src/sage/all.py
+++ b/src/sage/all.py
@@ -173,6 +173,8 @@ from sage.matroids.all import *
from sage.game_theory.all import *
+from sage.manifolds.all import *
+
# Lazily import notebook functions and interacts (#15335)
lazy_import('sagenb.notebook.notebook_object', 'notebook')
lazy_import('sagenb.notebook.notebook_object', 'inotebook')
diff --git a/src/sage/manifolds/__init__.py b/src/sage/manifolds/__init__.py
new file mode 100644
index 00000000..932b798
--- /dev/null
+++ b/src/sage/manifolds/__init__.py
@@ -0,0 +1 @@
+# Empty file
diff --git a/src/sage/manifolds/all.py b/src/sage/manifolds/all.py
new file mode 100644
index 00000000..c7defde
--- /dev/null
+++ b/src/sage/manifolds/all.py
@@ -0,0 +1,2 @@
+from sage.misc.lazy_import import lazy_import
+lazy_import('sage.manifolds.manifold', 'Manifold')
diff --git a/src/sage/manifolds/chart.py b/src/sage/manifolds/chart.py
new file mode 100644
index 00000000..a86c75e
--- /dev/null
+++ b/src/sage/manifolds/chart.py
@@ -0,0 +1,2036 @@
+r"""
+Coordinate charts
+
+The class :class:`Chart` implements coordinate charts on a topological manifold
+over a topological field `K`. The subclass :class:`RealChart` is devoted
+to the case `K=\RR`, for which the concept of coordinate range is meaningful.
+
+Transition maps between charts are implemented via the class
+:class:`CoordChange`.
+
+AUTHORS:
+
+- Eric Gourgoulhon, Michal Bejger (2013-2015) : initial version
+- Travis Scrimshaw (2015): review tweaks
+
+REFERENCES:
+
+- Chap. 2 of [Lee11]_ J.M. Lee: *Introduction to Topological Manifolds*,
+ 2nd ed., Springer (New York) (2011)
+
+- Chap. 1 of [Lee13]_ J.M. Lee : *Introduction to Smooth Manifolds*,
+ 2nd ed., Springer (New York) (2013)
+"""
+
+#*****************************************************************************
+# Copyright (C) 2015 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
+# Copyright (C) 2015 Michal Bejger <bejger@camk.edu.pl>
+# Copyright (C) 2015 Travis Scrimshaw <tscrimsh@umn.edu>
+#
+# Distributed under the terms of the GNU General Public License (GPL)
+# as published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+# http://www.gnu.org/licenses/
+#*****************************************************************************
+
+from sage.structure.sage_object import SageObject
+from sage.structure.unique_representation import UniqueRepresentation
+from sage.symbolic.ring import SR
+from sage.rings.infinity import Infinity
+from sage.misc.latex import latex
+from sage.manifolds.manifold import TopologicalManifold
+
+class Chart(UniqueRepresentation, SageObject):
+ r"""
+ Chart on a topological manifold.
+
+ Given a topological manifold `M` of dimension `n` over a topological field
+ `K`, a *chart* on `M` is a pair `(U,\varphi)`, where `U` is an open subset
+ of `M` and `\varphi: U \rightarrow V \subset K^n` is a homeomorphism from
+ `U` to an open subset `V` of `K^n`.
+
+ The components `(x^1, \ldots, x^n)` of `\varphi`, defined by
+ `\varphi(p) = (x^1(p), \ldots, x^n(p)) \in K^n` for any point
+ `p \in U`, are called the *coordinates* of the chart `(U, \varphi)`.
+
+ INPUT:
+
+ - ``domain`` -- open subset `U` on which the chart is defined (must be
+ an instance of :class:`~sage.manifolds.manifold.TopologicalManifold`)
+ - ``coordinates`` -- (default: ``''`` (empty string)) single string
+ defining the coordinate symbols, with ``' '`` (whitespace) as a
+ separator; each item has at most two fields, separated by ``:``:
+
+ 1. The coordinate symbol (a letter or a few letters)
+ 2. (optional) The LaTeX spelling of the coordinate; if not provided the
+ coordinate symbol given in the first field will be used.
+
+ If it contains any LaTeX expression, the string ``coordinates`` must be
+ declared with the prefix 'r' (for "raw") to allow for a proper treatment
+ of LaTeX's backslash character (see examples below).
+ If no LaTeX spelling is to be set for any coordinate, the argument
+ ``coordinates`` can be omitted when the shortcut operator ``<,>`` is
+ used via Sage preparser (see examples below).
+ - ``names`` -- (default: ``None``) unused argument, except if
+ ``coordinates`` is not provided; it must then be a tuple containing
+ the coordinate symbols (this is guaranteed if the shortcut operator
+ ``<,>`` is used)
+
+ EXAMPLES:
+
+ A chart on a complex 2-dimensional topological manifold::
+
+ sage: M = Manifold(2, 'M', field='complex', type='topological')
+ sage: X = M.chart('x y'); X
+ Chart (M, (x, y))
+ sage: latex(X)
+ \left(M,(x, y)\right)
+ sage: type(X)
+ <class 'sage.manifolds.chart.Chart'>
+
+ To manipulate the coordinates `(x,y)` as global variables,
+ one has to set::
+
+ sage: x,y = X[:]
+
+ However, a shortcut is to use the declarator ``<x,y>`` in the left-hand
+ side of the chart declaration (there is then no need to pass the string
+ ``'x y'`` to ``chart()``)::
+
+ sage: M = Manifold(2, 'M', field='complex', type='topological')
+ sage: X.<x,y> = M.chart(); X
+ Chart (M, (x, y))
+
+ The coordinates are then immediately accessible::
+
+ sage: y
+ y
+ sage: x is X[0] and y is X[1]
+ True
+
+ Note that ``x`` and ``y`` declared in ``<x,y>`` are mere Python variable
+ names and do not have to coincide with the coordinate symbols;
+ for instance, one may write::
+
+ sage: M = Manifold(2, 'M', field='complex', type='topological')
+ sage: X.<x1,y1> = M.chart('x y'); X
+ Chart (M, (x, y))
+
+ Then ``y`` is not known as a global Python variable and the
+ coordinate `y` is accessible only through the global variable ``y1``::
+
+ sage: y1
+ y
+ sage: latex(y1)
+ y
+ sage: y1 is X[1]
+ True
+
+ However, having the name of the Python variable coincide with the
+ coordinate symbol is quite convenient; so it is recommended to declare::
+
+ sage: M = Manifold(2, 'M', field='complex', type='topological')
+ sage: X.<x,y> = M.chart()
+
+ In the above example, the chart X covers entirely the manifold ``M``::
+
+ sage: X.domain()
+ Complex 2-dimensional topological manifold M
+
+ Of course, one may declare a chart only on an open subset of ``M``::
+
+ sage: U = M.open_subset('U')
+ sage: Y.<z1, z2> = U.chart(r'z1:\zeta_1 z2:\zeta_2'); Y
+ Chart (U, (z1, z2))
+ sage: Y.domain()
+ Open subset U of the Complex 2-dimensional topological manifold M
+
+ In the above declaration, we have also specified some LaTeX writing
+ of the coordinates different from the text one::
+
+ sage: latex(z1)
+ {\zeta_1}
+
+ Note the prefix ``r`` in front of the string ``r'z1:\zeta_1 z2:\zeta_2'``;
+ it makes sure that the backslash character is treated as an ordinary
+ character, to be passed to the LaTeX interpreter.
+
+ Coordinates are Sage symbolic variables (see
+ :mod:`sage.symbolic.expression`)::
+
+ sage: type(z1)
+ <type 'sage.symbolic.expression.Expression'>
+
+ In addition to the Python variable name provided in the operator ``<.,.>``,
+ the coordinates are accessible by their indices::
+
+ sage: Y[0], Y[1]
+ (z1, z2)
+
+ The index range is that declared during the creation of the manifold. By
+ default, it starts at 0, but this can be changed via the parameter
+ ``start_index``::
+
+ sage: M1 = Manifold(2, 'M_1', field='complex', type='topological',
+ ....: start_index=1)
+ sage: Z.<u,v> = M1.chart()
+ sage: Z[1], Z[2]
+ (u, v)
+
+ The full set of coordinates is obtained by means of the slice
+ operator ``[:]``::
+
+ sage: Y[:]
+ (z1, z2)
+
+ Some partial sets of coordinates::
+
+ sage: Y[:1]
+ (z1,)
+ sage: Y[1:]
+ (z2,)
+
+ Each constructed chart is automatically added to the manifold's user
+ atlas::
+
+ sage: M.atlas()
+ [Chart (M, (x, y)), Chart (U, (z1, z2))]
+
+ and to the atlas of the chart's domain::
+
+ sage: U.atlas()
+ [Chart (U, (z1, z2))]
+
+ Manifold subsets have a *default chart*, which, unless changed via the
+ method
+ :meth:`~sage.manifolds.manifold.TopologicalManifold.set_default_chart`,
+ is the first defined chart on the subset (or on a open subset of it)::
+
+ sage: M.default_chart()
+ Chart (M, (x, y))
+ sage: U.default_chart()
+ Chart (U, (z1, z2))
+
+ The default charts are not privileged charts on the manifold, but rather
+ charts whose name can be skipped in the argument list of functions having
+ an optional ``chart=`` argument.
+
+ The chart map `\varphi` acting on a point is obtained by passing
+ it as an input to the map::
+
+ sage: p = M.point((1+i, 2), chart=X); p
+ Point on the Complex 2-dimensional topological manifold M
+ sage: X(p)
+ (I + 1, 2)
+ sage: X(p) == p.coord(X)
+ True
+
+ .. SEEALSO::
+
+ :class:`sage.manifolds.chart.RealChart` for charts on topological
+ manifolds over `\RR`.
+
+ """
+ def __init__(self, domain, coordinates='', names=None):
+ r"""
+ Construct a chart.
+
+ TESTS::
+
+ sage: M = Manifold(2, 'M', field='complex', type='topological')
+ sage: X.<x,y> = M.chart()
+ sage: X
+ Chart (M, (x, y))
+ sage: type(X)
+ <class 'sage.manifolds.chart.Chart'>
+ sage: assumptions() # no assumptions on x,y set by X._init_coordinates
+ []
+ sage: TestSuite(X).run()
+
+ """
+ if not isinstance(domain, TopologicalManifold):
+ raise TypeError("the first argument must be an open subset of " +
+ "a topological manifold")
+ if coordinates == '':
+ for x in names:
+ coordinates += x + ' '
+ coordinates = coordinates[:-1]
+ self._manifold = domain.manifold()
+ self._domain = domain
+ # Treatment of the coordinates:
+ if ' ' in coordinates:
+ coord_list = coordinates.split()
+ else:
+ coord_list = [coordinates]
+ if len(coord_list) != self._manifold.dim():
+ raise ValueError("the list of coordinates must contain " +
+ "{} elements".format(self._manifold.dim()))
+ # The treatment of coordinates is performed by a seperate method,
+ # _init_coordinates, which sets self._xx and
+ # which may be redefined for subclasses (for instance RealChart).
+ self._init_coordinates(coord_list)
+ coord_string = ' '.join(str(x) for x in self._xx)
+ if coord_string in self._domain._charts_by_coord:
+ raise ValueError("the chart with coordinates " + coord_string +
+ " has already been declared on " +
+ "the {}".format(self._domain))
+ self._domain._charts_by_coord[coord_string] = self
+ #
+ # Additional restrictions on the coordinates
+ self._restrictions = [] # to be set with method add_restrictions()
+ #
+ # The chart is added to the domain's atlas, as well as to all the
+ # atlases of the domain's supersets; moreover the fist defined chart
+ # is considered as the default chart
+ for sd in self._domain._supersets:
+ # the chart is added in the top charts only if its coordinates have
+ # not been used:
+ for chart in sd._atlas:
+ if self._xx == chart._xx:
+ break
+ else:
+ sd._top_charts.append(self)
+ sd._atlas.append(self)
+ if sd._def_chart is None:
+ sd._def_chart = self
+ # The chart is added to the list of the domain's covering charts:
+ self._domain._covering_charts.append(self)
+ # Initialization of the set of charts that are restrictions of the
+ # current chart to subsets of the chart domain:
+ self._subcharts = set([self])
+ # Initialization of the set of charts which the current chart is a
+ # restriction of:
+ self._supercharts = set([self])
+ #
+ self._dom_restrict = {} # dict. of the restrictions of self to
+ # subsets of self._domain, with the
+ # subsets as keys
+
+ def _init_coordinates(self, coord_list):
+ r"""
+ Initialization of the coordinates as symbolic variables.
+
+ This method must be redefined by derived classes in order to take
+ into account specificities (e.g. enforcing real coordinates).
+
+ INPUT:
+
+ - ``coord_list`` -- list of coordinate fields, which items in each
+ field separated by ":"; there are at most 2 items per field:
+ the coordinate name and the coordinate LaTeX symbol
+
+ TESTS::
+
+ sage: M = Manifold(2, 'M', field='complex', type='topological')
+ sage: X.<z1, z2> = M.chart()
+ sage: X._init_coordinates(['z1', 'z2'])
+ sage: X
+ Chart (M, (z1, z2))
+ sage: X._init_coordinates([r'z1:\zeta_1', r'z2:\zeta_2'])
+ sage: X
+ Chart (M, (z1, z2))
+ sage: latex(X)
+ \left(M,({\zeta_1}, {\zeta_2})\right)
+
+ """
+ xx_list = [] # will contain the coordinates as Sage symbolic variables
+ for coord_field in coord_list:
+ coord_properties = coord_field.split(':')
+ coord_symb = coord_properties[0].strip() # the coordinate symbol
+ # LaTeX symbol:
+ coord_latex = None
+ for prop in coord_properties[1:]:
+ coord_latex = prop.strip()
+ # Construction of the coordinate as some Sage's symbolic variable:
+ coord_var = SR.var(coord_symb, latex_name=coord_latex)
+ xx_list.append(coord_var)
+ self._xx = tuple(xx_list)
+
+ def _repr_(self):
+ r"""
+ String representation of the object.
+
+ TESTS::
+
+ sage: M = Manifold(2, 'M', field='complex', type='topological')
+ sage: X.<x,y> = M.chart()
+ sage: X
+ Chart (M, (x, y))
+
+ """
+ return 'Chart ({}, {})'.format(self._domain._name, self._xx)
+
+ def _latex_(self):
+ r"""
+ LaTeX representation of the object.
+
+ TESTS::
+
+ sage: M = Manifold(2, 'M', field='complex', type='topological')
+ sage: X.<x,y> = M.chart()
+ sage: X._latex_()
+ '\\left(M,(x, y)\\right)'
+ sage: Y.<z1, z2> = M.chart(r'z1:\zeta_1 z2:\zeta2')
+ sage: Y._latex_()
+ '\\left(M,({\\zeta_1}, {\\zeta2})\\right)'
+ sage: latex(Y)
+ \left(M,({\zeta_1}, {\zeta2})\right)
+
+ """
+ description = r'\left(' + latex(self._domain).strip() + ',('
+ n = len(self._xx)
+ for i in range(n-1):
+ description += latex(self._xx[i]).strip() + ', '
+ description += latex(self._xx[n-1]).strip() + r')\right)'
+ return description
+
+ def _first_ngens(self, n):
+ r"""
+ Return the list of coordinates.
+
+ This is useful only for the use of Sage preparser::
+
+ sage: preparse("c_cart.<x,y,z> = M.chart()")
+ "c_cart = M.chart(names=('x', 'y', 'z',)); (x, y, z,) = c_cart._first_ngens(3)"
+
+ """
+ return self[:]
+
+ def __getitem__(self, i):
+ r"""
+ Access to the coordinates.
+
+ INPUT:
+
+ - ``i`` -- index of the coordinate; if the slice ``[:]``, then all
+ the coordinates are returned
+
+ OUTPUT:
+
+ - the coordinate of index ``i`` or all the coordinates (as a tuple) if
+ ``i`` is the slice ``[:]``
+
+ EXAMPLES::
+
+ sage: M = Manifold(2, 'M', field='complex', type='topological')
+ sage: X.<x,y> = M.chart()
+ sage: X[0]
+ x
+ sage: X[1]
+ y
+ sage: X[:]
+ (x, y)
+
+ The index range is controlled by the parameter ``start_index``::
+
+ sage: M = Manifold(2, 'M', field='complex', type='topological',
+ ....: start_index=1)
+ sage: X.<x,y> = M.chart()
+ sage: X[1]
+ x
+ sage: X[2]
+ y
+ sage: X[:]
+ (x, y)
+
+ We check that slices are properly shifted as well::
+
+ sage: X[2:]
+ (y,)
+ sage: X[:2]
+ (x,)
+ """
+ if isinstance(i, slice):
+ start,stop = i.start,i.stop
+ if start is not None:
+ start -= self._manifold._sindex
+ if stop is not None:
+ stop -= self._manifold._sindex
+ return self._xx[start:stop:i.step]
+ else:
+ return self._xx[i-self._manifold._sindex]
+
+ def __call__(self, point):
+ r"""
+ Return the coordinates of a given point.
+
+ INPUT:
+
+ - ``point`` -- point in the domain of the chart
+
+ OUTPUT:
+
+ - tuple of the coordinates of the point
+
+ EXAMPLES::
+
+ sage: M = Manifold(2, 'M', field='complex', type='topological')
+ sage: X.<x,y> = M.chart()
+ sage: p = M.point((1+i, 2-i), chart=X)
+ sage: X(p)
+ (I + 1, -I + 2)
+ sage: X(M.an_element())
+ (0, 0)
+
+ """
+ return point.coord(self)
+
+ def domain(self):
+ r"""
+ Return the open subset on which the chart is defined.
+
+ EXAMPLES::
+
+ sage: M = Manifold(2, 'M', type='topological')
+ sage: X.<x,y> = M.chart()
+ sage: X.domain()
+ 2-dimensional topological manifold M
+ sage: U = M.open_subset('U')
+ sage: Y.<u,v> = U.chart()
+ sage: Y.domain()
+ Open subset U of the 2-dimensional topological manifold M
+
+ """
+ return self._domain
+
+ def manifold(self):
+ r"""
+ Return the manifold on which the chart is defined.
+
+ EXAMPLES::
+
+ sage: M = Manifold(2, 'M', type='topological')
+ sage: U = M.open_subset('U')
+ sage: X.<x,y> = U.chart()
+ sage: X.manifold()
+ 2-dimensional topological manifold M
+ sage: X.domain()
+ Open subset U of the 2-dimensional topological manifold M
+
+ """
+ return self._manifold
+
+ def add_restrictions(self, restrictions):
+ r"""
+ Add some restrictions on the coordinates.
+
+ INPUT:
+
+ - ``restrictions`` -- list of restrictions on the
+ coordinates, in addition to the ranges declared by the intervals
+ specified in the chart constructor.
+ A restriction can be any symbolic equality or inequality involving the
+ coordinates, such as x>y or x^2+y^2 != 0. The items of the list
+ ``restrictions`` are combined with the ``and`` operator; if some
+ restrictions are to be combined with the ``or`` operator instead, they
+ have to be passed as a tuple in some single item of the list
+ ``restrictions``. For example, ``restrictions`` = [x>y, (x!=0, y!=0),
+ z^2<x] means (x>y) and ((x!=0) or (y!=0)) and (z^2<x). If the list
+ ``restrictions`` contains only one item, this item can be passed as
+ such, i.e. writing x>y instead of the single element list [x>y].
+
+ EXAMPLES::
+
+ sage: M = Manifold(2, 'M', field='complex', type='topological')
+ sage: X.<x,y> = M.chart()
+ sage: X.add_restrictions(abs(x) > 1)
+ sage: X.valid_coordinates(2+i, 1)
+ True
+ sage: X.valid_coordinates(i, 1)
+ False
+
+ """
+ if not isinstance(restrictions, list):
+ # case of a single condition or conditions to be combined by "or"
+ restrictions = [restrictions]
+ self._restrictions.extend(restrictions)
+
+ def restrict(self, subset, restrictions=None):
+ r"""
+ Return the restriction of the chart to some open subset of its domain.
+
+ If the current chart is `(U,\varphi)`, a *restriction* (or *subchart*)
+ is a chart `(V,\psi)` such that `V\subset U` and `\psi = \varphi |_V`.
+
+ If such subchart has not been defined yet, it is constructed here.
+
+ The coordinates of the subchart bare the same names as the coordinates
+ of the current chart.
+
+ INPUT:
+
+ - ``subset`` -- open subset `V` of the chart domain `U` (must be an
+ instance of :class:`~sage.manifolds.manifold.TopologicalManifold`)
+ - ``restrictions`` -- (default: ``None``) list of coordinate
+ restrictions defining the subset `V`.
+ A restriction can be any symbolic equality or
+ inequality involving the coordinates, such as x>y or x^2+y^2 !=