summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRelease Manager <release@sagemath.org>2016-05-28 00:50:14 +0200
committerVolker Braun <vbraun.name@gmail.com>2016-05-28 01:01:25 +0200
commitd77e2e9840d187f01a8e7f29abe06dd5561f6f74 (patch)
tree348abe8c2ac1a974c3957bf2658513eba932b031
parentTrac #20691: Posets have elements, not vertices (diff)
parentBasics of differentiable manifolds with changes in morphisms of topological m... (diff)
Trac #18783: Differentiable manifolds: basics
This is the first ticket about the implementation of differentiable manifolds resulting from the [http://sagemanifolds.obspm.fr/ SageManifolds project]. See the metaticket #18528 for an overview. The base field K of the differentiable manifold is generic (only assumed to be some non-discrete topological field), so that the user may specify e.g. K='''R''' (real manifolds) or K='''C''' (complex manifolds). This ticket implements the following Python classes, all of them being subclasses of classes introduced for topological manifolds (tickets #18529, #18640, #18725): - `DifferentiableManifold` (subclass of `TopologicalManifold`, cf. #18529): differentiable manifold over a topological field K (Parent class) - `DiffChart` (subclass of `Chart`, cf. #18529): chart of a K-differentiable atlas - `RealDiffChart` (subclass of `RealChart`, cf. #18529): chart of a K-differentiable atlas for K='''R''' - `DiffCoordChange` (subclass of `CoordChange`, cf. #18529): differentiable transition map - `DiffScalarFieldAlgebra` (subclass of `ScalarFieldAlgebra`, cf. #18640): set C^k^(M) of k-times continuously K-differentiable functions M --> K, where M is a differentiable manifold over K, C^k^(M) being a commutative algebra over K (Parent class) - `DiffScalarField` (subclass of `ScalarField`, cf. #18640): k-times continuously K-differentiable function M --> K (Element class) - `DiffManifoldHomset` (subclass of `TopManifoldHomset`, cf. #18725): set Hom(M,N) of differentiable maps between the differentiable manifolds M and N over the same topological field K (Parent class) - `DiffMap` (subclass of `ContinuousMap`, cf. #18725): differentiable map M --> N (Element class) The follow-up ticket is #18843. '''Documentation''': The reference manual is produced by `sage -docbuild reference/manifolds html` It can also be accessed online at http://sagemanifolds.obspm.fr/doc/18783/reference/manifolds/ More documentation (e.g. example worksheets) can be found [http://sagemanifolds.obspm.fr/documentation.html here]. URL: http://trac.sagemath.org/18783 Reported by: egourgoulhon Ticket author(s): Eric Gourgoulhon, Michal Bejger Reviewer(s): Volker Braun
-rw-r--r--src/doc/en/reference/manifolds/diff_manifold.rst13
-rw-r--r--src/doc/en/reference/manifolds/diff_map.rst9
-rw-r--r--src/doc/en/reference/manifolds/diff_scalarfield.rst9
-rw-r--r--src/doc/en/reference/manifolds/index.rst2
-rw-r--r--src/sage/manifolds/all.py2
-rw-r--r--src/sage/manifolds/differentiable/__init__.py1
-rw-r--r--src/sage/manifolds/differentiable/chart.py701
-rw-r--r--src/sage/manifolds/differentiable/diff_map.py484
-rw-r--r--src/sage/manifolds/differentiable/manifold.py953
-rw-r--r--src/sage/manifolds/differentiable/manifold_homset.py200
-rw-r--r--src/sage/manifolds/differentiable/scalarfield.py677
-rw-r--r--src/sage/manifolds/differentiable/scalarfield_algebra.py467
-rw-r--r--src/sage/manifolds/manifold.py124
-rw-r--r--src/sage/manifolds/structure.py57
14 files changed, 3674 insertions, 25 deletions
diff --git a/src/doc/en/reference/manifolds/diff_manifold.rst b/src/doc/en/reference/manifolds/diff_manifold.rst
new file mode 100644
index 00000000..0cfc2d8
--- /dev/null
+++ b/src/doc/en/reference/manifolds/diff_manifold.rst
@@ -0,0 +1,13 @@
+Differentiable Manifolds
+========================
+
+.. toctree::
+ :maxdepth: 2
+
+ sage/manifolds/differentiable/manifold
+
+ sage/manifolds/differentiable/chart
+
+ diff_scalarfield
+
+ diff_map
diff --git a/src/doc/en/reference/manifolds/diff_map.rst b/src/doc/en/reference/manifolds/diff_map.rst
new file mode 100644
index 00000000..ee43456
--- /dev/null
+++ b/src/doc/en/reference/manifolds/diff_map.rst
@@ -0,0 +1,9 @@
+Differentiable Maps
+===================
+
+.. toctree::
+ :maxdepth: 2
+
+ sage/manifolds/differentiable/manifold_homset
+
+ sage/manifolds/differentiable/diff_map
diff --git a/src/doc/en/reference/manifolds/diff_scalarfield.rst b/src/doc/en/reference/manifolds/diff_scalarfield.rst
new file mode 100644
index 00000000..9eb217c
--- /dev/null
+++ b/src/doc/en/reference/manifolds/diff_scalarfield.rst
@@ -0,0 +1,9 @@
+Scalar Fields
+=============
+
+.. toctree::
+ :maxdepth: 2
+
+ sage/manifolds/differentiable/scalarfield_algebra
+
+ sage/manifolds/differentiable/scalarfield
diff --git a/src/doc/en/reference/manifolds/index.rst b/src/doc/en/reference/manifolds/index.rst
index 13995d6..dd546af 100644
--- a/src/doc/en/reference/manifolds/index.rst
+++ b/src/doc/en/reference/manifolds/index.rst
@@ -15,6 +15,8 @@ More documentation (in particular example worksheets) can be found
manifold
+ diff_manifold
+
sage/manifolds/utilities
.. include:: ../footer.txt
diff --git a/src/sage/manifolds/all.py b/src/sage/manifolds/all.py
index 990657e..ae5fc2c 100644
--- a/src/sage/manifolds/all.py
+++ b/src/sage/manifolds/all.py
@@ -1,3 +1,3 @@
from sage.misc.lazy_import import lazy_import
lazy_import('sage.manifolds.manifold', 'Manifold')
-
+lazy_import('sage.manifolds.utilities', 'set_axes_labels')
diff --git a/src/sage/manifolds/differentiable/__init__.py b/src/sage/manifolds/differentiable/__init__.py
new file mode 100644
index 00000000..932b798
--- /dev/null
+++ b/src/sage/manifolds/differentiable/__init__.py
@@ -0,0 +1 @@
+# Empty file
diff --git a/src/sage/manifolds/differentiable/chart.py b/src/sage/manifolds/differentiable/chart.py
new file mode 100644
index 00000000..cdba762
--- /dev/null
+++ b/src/sage/manifolds/differentiable/chart.py
@@ -0,0 +1,701 @@
+r"""
+Coordinate Charts on Differentiable Manifolds
+
+The class :class:`DiffChart` implements coordinate charts on a differentiable
+manifold over a topological field `K` (in most applications, `K = \RR` or
+`K = \CC`).
+
+The subclass :class:`RealDiffChart` is devoted
+to the case `K=\RR`, for which the concept of coordinate range is meaningful.
+Moreover, :class:`RealDiffChart` is endowed with some plotting
+capabilities (cf. method :meth:`~sage.manifolds.chart.RealChart.plot`).
+
+Transition maps between charts are implemented via the class
+:class:`DiffCoordChange`.
+
+AUTHORS:
+
+- Eric Gourgoulhon, Michal Bejger (2013-2015) : initial version
+
+REFERENCES:
+
+- 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>
+#
+# 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.manifolds.chart import Chart, RealChart, CoordChange
+
+class DiffChart(Chart):
+ r"""
+ Chart on a differentiable manifold.
+
+ Given a differentiable manifold `M` of dimension `n` over a topological
+ field `K`, a *chart* is a member `(U,\varphi)` of the manifold's
+ differentiable atlas; `U` is then 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
+ - ``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 differentiable manifold::
+
+ sage: M = Manifold(2, 'M', field='complex')
+ 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.differentiable.chart.DiffChart'>
+
+ 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')
+ 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
+
+ The trick is performed by Sage preparser::
+
+ sage: preparse("X.<x,y> = M.chart()")
+ "X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)"
+
+ 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')
+ 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')
+ sage: X.<x,y> = M.chart()
+
+ In the above example, the chart X covers entirely the manifold M::
+
+ sage: X.domain()
+ 2-dimensional complex 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 2-dimensional complex 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', 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 operator
+ ``[:]``::
+
+ sage: Y[:]
+ (z1, 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 action of the chart map `\varphi` on a point is obtained by means of
+ the call operator, i.e. the operator ``()``::
+
+ sage: p = M.point((1+i, 2), chart=X); p
+ Point on the 2-dimensional complex manifold M
+ sage: X(p)
+ (I + 1, 2)
+ sage: X(p) == p.coord(X)
+ True
+
+ .. SEEALSO::
+
+ :class:`~sage.manifolds.differentiable.chart.RealDiffChart` for charts
+ on differentiable manifolds over `\RR`.
+
+ """
+ def __init__(self, domain, coordinates='', names=None):
+ r"""
+ Construct a chart.
+
+ TESTS::
+
+ sage: M = Manifold(2, 'M', field='complex')
+ sage: X.<x,y> = M.chart()
+ sage: X
+ Chart (M, (x, y))
+ sage: type(X)
+ <class 'sage.manifolds.differentiable.chart.DiffChart'>
+ sage: assumptions() # no assumptions on x,y set by X._init_coordinates
+ []
+ sage: TestSuite(X).run()
+
+ """
+ Chart.__init__(self, domain, coordinates=coordinates, names=names)
+
+
+ def transition_map(self, other, transformations, intersection_name=None,
+ restrictions1=None, restrictions2=None):
+ r"""
+ Construct the transition map between the current chart,
+ `(U,\varphi)` say, and another one, `(V,\psi)` say.
+
+ If `n` is the manifold's dimension, the *transition map* is the
+ map
+
+ .. MATH::
+
+ \psi\circ\varphi^{-1}: \varphi(U\cap V) \subset K^n
+ \rightarrow \psi(U\cap V) \subset K^n,
+
+ where `K` is the manifold's base field. In other words, the
+ transition map expresses the coordinates `(y^1,\ldots,y^n)` of
+ `(V,\psi)` in terms of the coordinates `(x^1,\ldots,x^n)` of
+ `(U,\varphi)` on the open subset where the two charts intersect, i.e.
+ on `U\cap V`.
+
+ By definition, the transition map `\psi\circ\varphi^{-1}` must be
+ of classe `C^k`, where `k` is the degree of differentiability of the
+ manifold (cf.
+ :meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.diff_degree`).
+
+ INPUT:
+
+ - ``other`` -- the chart `(V,\psi)`
+ - ``transformations`` -- tuple (or list) `(Y_1,\ldots,Y_2)`, where
+ `Y_i` is the symbolic expression of the coordinate `y^i` in terms
+ of the coordinates `(x^1,\ldots,x^n)`
+ - ``intersection_name`` -- (default: ``None``) name to be given to the
+ subset `U\cap V` if the latter differs from `U` or `V`
+ - ``restrictions1`` -- (default: ``None``) list of conditions on the
+ coordinates of the current chart that define `U\cap V` if the
+ latter differs from `U`. ``restrictions1`` must be a list of
+ of symbolic equalities or inequalities involving the
+ coordinates, such as x>y or x^2+y^2 != 0. The items of the list
+ ``restrictions1`` 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
+ ``restrictions1``. For example, ``restrictions1`` = [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 ``restrictions1`` contains only one item, this item can
+ be passed as such, i.e. writing x>y instead of the single-element
+ list [x>y].
+ - ``restrictions2`` -- (default: ``None``) list of conditions on the
+ coordinates of the chart `(V,\psi)` that define `U\cap V` if the
+ latter differs from `V` (see ``restrictions1`` for the syntax)
+
+ OUTPUT:
+
+ - The transition map `\psi\circ\varphi^{-1}` defined on `U\cap V`, as an
+ instance of :class:`DiffCoordChange`.
+
+ EXAMPLES:
+
+ Transition map between two stereographic charts on the circle `S^1`::
+
+ sage: M = Manifold(1, 'S^1')
+ sage: U = M.open_subset('U') # Complement of the North pole
+ sage: cU.<x> = U.chart() # Stereographic chart from the North pole
+ sage: V = M.open_subset('V') # Complement of the South pole
+ sage: cV.<y> = V.chart() # Stereographic chart from the South pole
+ sage: M.declare_union(U,V) # S^1 is the union of U and V
+ sage: trans = cU.transition_map(cV, 1/x, intersection_name='W',
+ ....: restrictions1= x!=0, restrictions2 = y!=0)
+ sage: trans
+ Change of coordinates from Chart (W, (x,)) to Chart (W, (y,))
+ sage: trans.display()
+ y = 1/x
+
+ The subset `W`, intersection of `U` and `V`, has been created by
+ ``transition_map()``::
+
+ sage: M.list_of_subsets()
+ [1-dimensional differentiable manifold S^1,
+ Open subset U of the 1-dimensional differentiable manifold S^1,
+ Open subset V of the 1-dimensional differentiable manifold S^1,
+ Open subset W of the 1-dimensional differentiable manifold S^1]
+ sage: W = M.list_of_subsets()[3]
+ sage: W is U.intersection(V)
+ True
+ sage: M.atlas()
+ [Chart (U, (x,)), Chart (V, (y,)), Chart (W, (x,)), Chart (W, (y,))]
+
+ Transition map between the polar chart and the Cartesian one on
+ `\RR^2`::
+
+ sage: M = Manifold(2, 'R^2')
+ sage: c_cart.<x,y> = M.chart()
+ sage: U = M.open_subset('U') # the complement of the half line {y=0, x >= 0}
+ sage: c_spher.<r,phi> = U.chart(r'r:(0,+oo) phi:(0,2*pi):\phi')
+ sage: trans = c_spher.transition_map(c_cart, (r*cos(phi), r*sin(phi)),
+ ....: restrictions2=(y!=0, x<0))
+ sage: trans
+ Change of coordinates from Chart (U, (r, phi)) to Chart (U, (x, y))
+ sage: trans.display()
+ x = r*cos(phi)
+ y = r*sin(phi)
+
+ In this case, no new subset has been created since `U\cap M = U`::
+
+ sage: M.list_of_subsets()
+ [2-dimensional differentiable manifold R^2,
+ Open subset U of the 2-dimensional differentiable manifold R^2]
+
+ but a new chart has been created: `(U, (x, y))`::
+
+ sage: M.atlas()
+ [Chart (R^2, (x, y)), Chart (U, (r, phi)), Chart (U, (x, y))]
+
+ """
+ dom1 = self._domain
+ dom2 = other._domain
+ dom = dom1.intersection(dom2, name=intersection_name)
+ if dom is dom1:
+ chart1 = self
+ else:
+ chart1 = self.restrict(dom, restrictions1)
+ if dom is dom2:
+ chart2 = other
+ else:
+ chart2 = other.restrict(dom, restrictions2)
+ if not isinstance(transformations, (tuple, list)):
+ transformations = [transformations]
+ return DiffCoordChange(chart1, chart2, *transformations)
+
+
+#*****************************************************************************
+
+class RealDiffChart(DiffChart, RealChart):
+ r"""
+ Chart on a differentiable manifold over `\RR`.
+
+ Given a differentiable manifold `M` of dimension `n` over `\RR`,
+ a *chart* is a member `(U,\varphi)` of the manifold's
+ differentiable atlas; `U` is then an open subset of `M` and
+ `\varphi: U \rightarrow V \subset \RR^n` is a homeomorphism from
+ `U` to an open subset `V` of `\RR^n`.
+
+ The components `(x^1,\ldots,x^n)` of `\varphi`, defined by
+ `\varphi(p) = (x^1(p),\ldots,x^n(p))\in \RR^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
+ - ``coordinates`` -- (default: '' (empty string)) single string defining
+ the coordinate symbols and ranges, with ' ' (whitespace) as a separator;
+ each item has at most three fields, separated by ':':
+
+ 1. The coordinate symbol (a letter or a few letters)
+ 2. (optional) The interval `I` defining the coordinate range: if not
+ provided, the coordinate is assumed to span all `\RR`; otherwise
+ `I` must be provided in the form ``(a,b)`` (or equivalently
+ ``]a,b[``). The bounds ``a`` and ``b`` can be ``+/-Infinity``,
+ ``Inf``, ``infinity``, ``inf`` or ``oo``.
+ For *singular* coordinates, non-open intervals such as ``[a,b]`` and
+ ``(a,b]`` (or equivalently ``]a,b]``) are allowed.
+ Note that the interval declaration must not contain any whitespace.
+ 3. (optional) The LaTeX spelling of the coordinate; if not provided the
+ coordinate symbol given in the first field will be used.
+
+ The order of the fields 2 and 3 does not matter and each of them can be
+ omitted.
+ 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 backslash characters (see examples below).
+ If no interval range and 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:
+
+ Cartesian coordinates on `\RR^3`::
+
+ sage: M = Manifold(3, 'R^3', r'\RR^3', start_index=1)
+ sage: c_cart = M.chart('x y z'); c_cart
+ Chart (R^3, (x, y, z))
+ sage: type(c_cart)
+ <class 'sage.manifolds.differentiable.chart.RealDiffChart'>
+
+ To have the coordinates accessible as global variables, one has to set::
+
+ sage: (x,y,z) = c_cart[:]
+
+ However, a shortcut is to use the declarator ``<x,y,z>`` in the left-hand
+ side of the chart declaration (there is then no need to pass the string
+ ``'x y z'`` to ``chart()``)::
+
+ sage: M = Manifold(3, 'R^3', r'\RR^3', start_index=1)
+ sage: c_cart.<x,y,z> = M.chart(); c_cart
+ Chart (R^3, (x, y, z))
+
+ The coordinates are then immediately accessible::
+
+ sage: y
+ y
+ sage: y is c_cart[2]
+ True
+
+ The trick is performed by 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)"
+
+ Note that ``x, y, z`` declared in ``<x,y,z>`` are mere Python variable
+ names and do not have to coincide with the coordinate symbols; for instance,
+ one may write::
+
+ sage: M = Manifold(3, 'R^3', r'\RR^3', start_index=1)
+ sage: c_cart.<x1,y1,z1> = M.chart('x y z'); c_cart
+ Chart (R^3, (x, y, z))
+
+ Then ``y`` is not known as a global variable and the coordinate `y`
+ is accessible only through the global variable ``y1``::
+
+ sage: y1
+ y
+ sage: y1 is c_cart[2]
+ True
+
+ However, having the name of the Python variable coincide with the
+ coordinate symbol is quite convenient; so it is recommended to declare::
+
+ sage: forget() # for doctests only
+ sage: M = Manifold(3, 'R^3', r'\RR^3', start_index=1)
+ sage: c_cart.<x,y,z> = M.chart()
+
+ Spherical coordinates on the subset `U` of `\RR^3` that is the
+ complement of the half-plane `\{y=0, x\geq 0\}`::
+
+ sage: U = M.open_subset('U')
+ sage: c_spher.<r,th,ph> = U.chart(r'r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi')
+ sage: c_spher
+ Chart (U, (r, th, ph))
+
+ Note the prefix 'r' for the string defining the coordinates in the
+ arguments of ``chart``.
+
+ Coordinates are Sage symbolic variables (see
+ :mod:`sage.symbolic.expression`)::
+
+ sage: type(th)
+ <type 'sage.symbolic.expression.Expression'>
+ sage: latex(th)
+ {\theta}
+ sage: assumptions(th)
+ [th is real, th > 0, th < pi]
+
+ Coordinate are also accessible by their indices::
+
+ sage: x1 = c_spher[1]; x2 = c_spher[2]; x3 = c_spher[3]
+ sage: [x1, x2, x3]
+ [r, th, ph]
+ sage: (x1, x2, x3) == (r, th, ph)
+ True
+
+ The full set of coordinates is obtained by means of the operator [:]::
+
+ sage: c_cart[:]
+ (x, y, z)
+ sage: c_spher[:]
+ (r, th, ph)
+
+ Let us check that the declared coordinate ranges have been taken into
+ account::
+
+ sage: c_cart.coord_range()
+ x: (-oo, +oo); y: (-oo, +oo); z: (-oo, +oo)
+ sage: c_spher.coord_range()
+ r: (0, +oo); th: (0, pi); ph: (0, 2*pi)
+ sage: bool(th>0 and th<pi)
+ True
+ sage: assumptions() # list all current symbolic assumptions
+ [x is real, y is real, z is real, r is real, r > 0, th is real,
+ th > 0, th < pi, ph is real, ph > 0, ph < 2*pi]
+
+ The coordinate ranges are used for simplifications::
+
+ sage: simplify(abs(r)) # r has been declared to lie in the interval (0,+oo)
+ r
+ sage: simplify(abs(x)) # no positive range has been declared for x
+ abs(x)
+
+ Each constructed chart is automatically added to the manifold's user atlas::
+
+ sage: M.atlas()
+ [Chart (R^3, (x, y, z)), Chart (U, (r, th, ph))]
+
+ and to the atlas of its domain::
+
+ sage: U.atlas()
+ [Chart (U, (r, th, ph))]
+
+
+ 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 (R^3, (x, y, z))
+ sage: U.default_chart()
+ Chart (U, (r, th, ph))
+
+ 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 action of the chart map `\varphi` on a point is obtained by means of
+ the call operator, i.e. the operator ``()``::
+
+ sage: p = M.point((1,0,-2)); p
+ Point on the 3-dimensional differentiable manifold R^3
+ sage: c_cart(p)
+ (1, 0, -2)
+ sage: c_cart(p) == p.coord(c_cart)
+ True
+ sage: q = M.point((2,pi/2,pi/3), chart=c_spher) # point defined by its spherical coordinates
+ sage: c_spher(q)
+ (2, 1/2*pi, 1/3*pi)
+ sage: c_spher(q) == q.coord(c_spher)
+ True
+ sage: a = U.point((1,pi/2,pi)) # the default coordinates on U are the spherical ones
+ sage: c_spher(a)
+ (1, 1/2*pi, pi)
+ sage: c_spher(a) == a.coord(c_spher)
+ True
+
+ Cartesian coordinates on `U` as an example of chart construction with
+ coordinate restrictions: since `U` is the complement of the half-plane
+ `\{y=0, x\geq 0\}`, we must have `y\not=0` or `x<0` on U. Accordingly,
+ we set::
+
+ sage: c_cartU.<x,y,z> = U.chart()
+ sage: c_cartU.add_restrictions((y!=0, x<0)) # the tuple (y!=0, x<0) means y!=0 or x<0
+ sage: # c_cartU.add_restrictions([y!=0, x<0]) would have meant y!=0 AND x<0
+ sage: U.atlas()
+ [Chart (U, (r, th, ph)), Chart (U, (x, y, z))]
+ sage: M.atlas()
+ [Chart (R^3, (x, y, z)), Chart (U, (r, th, ph)), Chart (U, (x, y, z))]
+ sage: c_cartU.valid_coordinates(-1,0,2)
+ True
+ sage: c_cartU.valid_coordinates(1,0,2)
+ False
+ sage: c_cart.valid_coordinates(1,0,2)
+ True
+
+ Chart grids can be drawn in 2D or 3D graphics thanks to the method
+ :meth:`~sage.manifolds.chart.RealChart.plot`.
+
+ """
+ def __init__(self, domain, coordinates='', names=None):
+ r"""
+ Construct a chart on a real differentiable manifold.
+
+ TESTS::
+
+ sage: forget() # for doctests only
+ sage: M = Manifold(2, 'M')
+ sage: X.<x,y> = M.chart()
+ sage: X
+ Chart (M, (x, y))
+ sage: type(X)
+ <class 'sage.manifolds.differentiable.chart.RealDiffChart'>
+ sage: assumptions() # assumptions set in X._init_coordinates
+ [x is real, y is real]
+ sage: TestSuite(X).run()
+
+ """
+ RealChart.__init__(self, domain, coordinates=coordinates, names=names)
+ #!# vector frame shall be initialized here in ticket #18843
+
+#*****************************************************************************
+
+class DiffCoordChange(CoordChange):
+ r"""
+ Transition map between two charts of a differentiable manifold.
+
+ Giving two coordinate charts `(U,\varphi)` and `(V,\psi)` on a
+ differentiable manifold `M` of dimension `n` over a topological field `K`,
+ the *transition map from* `(U,\varphi)` *to* `(V,\psi)` is the map
+
+ .. MATH::
+
+ \psi\circ\varphi^{-1}: \varphi(U\cap V) \subset K^n
+ \rightarrow \psi(U\cap V) \subset K^n,
+
+ In other words, the transition map `\psi\circ\varphi^{-1}` expresses the
+ coordinates `(y^1,\ldots,y^n)` of `(V,\psi)` in terms of the coordinates
+ `(x^1,\ldots,x^n)` of `(U,\varphi)` on the open subset where the two
+ charts intersect, i.e. on `U\cap V`.
+
+ By definition, the transition map `\psi\circ\varphi^{-1}` must be
+ of classe `C^k`, where `k` is the degree of differentiability of the
+ manifold (cf.
+ :meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.diff_degree`).
+
+ INPUT:
+
+ - ``chart1`` -- chart `(U,\varphi)`
+ - ``chart2`` -- chart `(V,\psi)`
+ - ``transformations`` -- tuple (or list) `(Y_1,\ldots,Y_2)`, where
+ `Y_i` is the symbolic expression of the coordinate `y^i` in terms
+ of the coordinates `(x^1,\ldots,x^n)`
+
+ EXAMPLES:
+
+ Transition map on a 2-dimensional differentiable manifold::
+
+ sage: M = Manifold(2, 'M')
+ sage: X.<x,y> = M.chart()
+ sage: Y.<u,v> = M.chart()
+ sage: X_to_Y = X.transition_map(Y, [x+y, x-y])
+ sage: X_to_Y
+ Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v))
+ sage: type(X_to_Y)
+ <class 'sage.manifolds.differentiable.chart.DiffCoordChange'>
+ sage: X_to_Y.display()
+ u = x + y
+ v = x - y
+
+ """
+ def __init__(self, chart1, chart2, *transformations):
+ r"""
+ Construct a transition map.
+
+ TESTS::
+
+ sage: M = Manifold(2, 'M')
+ sage: X.<x,y> = M.chart()
+ sage: Y.<u,v> = M.chart()
+ sage: X_to_Y = X.transition_map(Y, [x+y, x-y])
+ sage: X_to_Y
+ Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v))
+ sage: type(X_to_Y)
+ <class 'sage.manifolds.differentiable.chart.DiffCoordChange'>
+ sage: TestSuite(X_to_Y).run(skip='_test_pickling')
+
+ .. TODO::
+
+ fix _test_pickling
+
+ """
+ CoordChange.__init__(self, chart1, chart2, *transformations)
+ # Jacobian matrix:
+ self._jacobian = self._transf.jacobian()
+ # Jacobian determinant:
+ if self._n1 == self._n2:
+ self._jacobian_det = self._transf.jacobian_det()
diff --git a/src/sage/manifolds/differentiable/diff_map.py b/src/sage/manifolds/differentiable/diff_map.py
new file mode 100644
index 00000000..7ab681e
--- /dev/null
+++ b/src/sage/manifolds/differentiable/diff_map.py
@@ -0,0 +1,484 @@
+r"""
+Differentiable Maps between Differentiable Manifolds
+
+The class :class:`DiffMap` implements differentiable maps from a differentiable
+manifold `M` to a differentiable manifold `N` over the same topological field
+`K` as `M` (in most applications, `K = \RR` or `K = \CC`):
+
+.. MATH::
+
+ \Phi: M \longrightarrow N
+
+
+AUTHORS:
+
+- Eric Gourgoulhon, Michal Bejger (2013-2015): initial version
+
+REFERENCES:
+
+- Chap. 1 of [KN63]_ \S. Kobayashi & K. Nomizu : *Foundations of Differential
+ Geometry*, vol. 1, Interscience Publishers (New York) (1963)
+- Chaps. 2 and 3 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>
+#
+# 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.manifolds.continuous_map import ContinuousMap
+
+class DiffMap(ContinuousMap):
+ r"""
+ Differentiable map between two differentiable manifolds.
+
+ This class implements differentiable maps of the type
+
+ .. MATH::
+
+ \Phi: M \longrightarrow N
+
+ where `M` and `N` are differentiable manifolds over the same topological
+ field `K` (in most applications, `K = \RR` or `K = \CC`).
+
+ Differentiable maps are the *morphisms* of the *category* of
+ differentiable manifolds. The set of all differentiable maps from `M` to
+ `N` is therefore the homset between `M` and `N`, which is denoted by
+ `\mathrm{Hom}(M,N)`.
+
+ The class :class:`DiffMap` is a Sage *element* class, whose *parent*
+ class is
+ :class:`~sage.manifolds.differentiable.manifold_homset.DifferentiableManifoldHomset`.
+ It inherits from the class
+ :class:`~sage.manifolds.continuous_map.ContinuousMap` since a
+ differentiable map is obviously a continuous one.
+
+ INPUT:
+
+ - ``parent`` -- homset `\mathrm{Hom}(M,N)` to which the differentiable
+ map belongs
+ - ``coord_functions`` -- (default: ``None``) if not ``None``, must be
+ a dictionary of the coordinate expressions (as lists (or tuples) of the
+ coordinates of the image expressed in terms of the coordinates of
+ the considered point) with the pairs of charts (chart1, chart2)
+ as keys (chart1 being a chart on `M` and chart2 a chart on `N`).
+ If the dimension of the map's codomain is 1, a single coordinate
+ expression can be passed instead of a tuple with a single element
+ - ``name`` -- (default: ``None``) name given to the differentiable map
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
+ differentiable map; if ``None``, the LaTeX symbol is set to ``name``
+ - ``is_isomorphism`` -- (default: ``False``) determines whether the
+ constructed object is a isomorphism (i.e. a diffeomorphism); if set to
+ ``True``, then the manifolds `M` and `N` must have the same dimension.
+ - ``is_identity`` -- (default: ``False``) determines whether the
+ constructed object is the identity map; if set to ``True``,
+ then `N` must be `M` and the entry ``coord_functions`` is not used.
+
+ .. NOTE::
+
+ If the information passed by means of the argument ``coord_functions``
+ is not sufficient to fully specify the differentiable map,
+ further coordinate expressions, in other charts, can be subsequently
+ added by means of the method
+ :meth:`~sage.manifolds.continuous_map.ContinuousMap.add_expr`
+
+ EXAMPLES:
+
+ The standard embedding of the sphere `S^2` into `\RR^3`::
+
+ sage: M = Manifold(2, 'S^2') # the 2-dimensional sphere S^2
+ sage: U = M.open_subset('U') # complement of the North pole
+ sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
+ sage: V = M.open_subset('V') # complement of the South pole
+ sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
+ sage: M.declare_union(U,V) # S^2 is the union of U and V
+ sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)),
+ ....: intersection_name='W', restrictions1= x^2+y^2!=0,
+ ....: restrictions2= u^2+v^2!=0)
+ sage: uv_to_xy = xy_to_uv.inverse()
+ sage: N = Manifold(3, 'R^3', r'\RR^3') # R^3
+ sage: c_cart.<X,Y,Z> = N.chart() # Cartesian coordinates on R^3
+ sage: Phi = M.diff_map(N,
+ ....: {(c_xy, c_cart): [2*x/(1+x^2+y^2), 2*y/(1+x^2+y^2), (x^2+y^2-1)/(1+x^2+y^2)],
+ ....: (c_uv, c_cart): [2*u/(1+u^2+v^2), 2*v/(1+u^2+v^2), (1-u^2-v^2)/(1+u^2+v^2)]},
+ ....: name='Phi', latex_name=r'\Phi')
+ sage: Phi
+ Differentiable map Phi from the 2-dimensional differentiable manifold
+ S^2 to the 3-dimensional differentiable manifold R^3
+ sage: Phi.parent()
+ Set of Morphisms from 2-dimensional differentiable manifold S^2 to
+ 3-dimensional differentiable manifold R^3 in Category of smooth
+ manifolds over Real Field with 53 bits of precision
+ sage: Phi.parent() is Hom(M, N)
+ True
+ sage: type(Phi)
+ <class 'sage.manifolds.differentiable.diff_map.DifferentiableManifoldHomset_with_category.element_class'>
+ sage: Phi.display()
+ Phi: S^2 --> R^3
+ on U: (x, y) |--> (X, Y, Z) = (2*x/(x^2 + y^2 + 1), 2*y/(x^2 + y^2 + 1),
+ (x^2 + y^2 - 1)/(x^2 + y^2 + 1))
+ on V: (u, v) |--> (X, Y, Z) = (2*u/(u^2 + v^2 + 1), 2*v/(u^2 + v^2 + 1),
+ -(u^2 + v^2 - 1)/(u^2 + v^2 + 1))
+
+ It is possible to create the map via the method
+ :meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.diff_map`
+ only in a single pair of charts: the argument ``coord_functions`` is then
+ a mere list of coordinate expressions (and not a dictionary) and the
+ arguments ``chart1`` and ``chart2`` have to be provided if the charts
+ differ from the default ones on the domain and/or the codomain::
+
+ sage: Phi1 = M.diff_map(N, [2*x/(1+x^2+y^2), 2*y/(1+x^2+y^2),
+ ....: (x^2+y^2-1)/(1+x^2+y^2)],
+ ....: chart1=c_xy, chart2=c_cart, name='Phi',
+ ....: latex_name=r'\Phi')
+
+ Since ``c_xy`` and ``c_cart`` are the default charts on respectively ``M``
+ and ``N``, they can be omitted, so that the above declaration is equivalent
+ to::
+
+ sage: Phi1 = M.diff_map(N, [2*x/(1+x^2+y^2), 2*y/(1+x^2+y^2),
+ ....: (x^2+y^2-1)/(1+x^2+y^2)],
+ ....: name='Phi', latex_name=r'\Phi')
+
+ With such a declaration, the differentiable map is only partially defined
+ on the manifold `S^2`, being known in only one chart::
+
+ sage: Phi1.display()
+ Phi: S^2 --> R^3
+ on U: (x, y) |--> (X, Y, Z) = (2*x/(x^2 + y^2 + 1), 2*y/(x^2 + y^2 + 1),
+ (x^2 + y^2 - 1)/(x^2 + y^2 + 1))
+
+ The definition can be completed by means of the method
+ :meth:`~sage.manifolds.continuous_map.ContinuousMap.add_expr`::
+
+ sage: Phi1.add_expr(c_uv, c_cart, [2*u/(1+u^2+v^2), 2*v/(1+u^2+v^2),
+ ....: (1-u^2-v^2)/(1+u^2+v^2)])
+ sage: Phi1.display()
+ Phi: S^2 --> R^3
+ on U: (x, y) |--> (X, Y, Z) = (2*x/(x^2 + y^2 + 1), 2*y/(x^2 + y^2 + 1),
+ (x^2 + y^2 - 1)/(x^2 + y^2 + 1))
+ on V: (u, v) |--> (X, Y, Z) = (2*u/(u^2 + v^2 + 1), 2*v/(u^2 + v^2 + 1),
+ -(u^2 + v^2 - 1)/(u^2 + v^2 + 1))
+
+ At this stage, ``Phi1`` and ``Phi`` are fully equivalent::
+
+ sage: Phi1 == Phi
+ True
+
+ The test suite is passed::
+
+ sage: TestSuite(Phi).run()
+ sage: TestSuite(Phi1).run()
+
+ The map acts on points::
+
+ sage: np = M.point((0,0), chart=c_uv, name='N') # the North pole
+ sage: Phi(np)
+ Point Phi(N) on the 3-dimensional differentiable manifold R^3
+ sage: Phi(np).coord() # Cartesian coordinates
+ (0, 0, 1)
+ sage: sp = M.point((0,0), chart=c_xy, name='S') # the South pole
+ sage: Phi(sp).coord() # Cartesian coordinates
+ (0, 0, -1)
+
+ Differentiable maps can be composed by means of the operator ``*``: let
+ us introduce the map `\RR^3\rightarrow \RR^2` corresponding to
+ the projection from the point `(X,Y,Z)=(0,0,1)` onto the equatorial plane
+ `Z=0`::
+
+ sage: P = Manifold(2, 'R^2', r'\RR^2') # R^2 (equatorial plane)
+ sage: cP.<xP, yP> = P.chart()
+ sage: Psi = N.diff_map(P, (X/(1-Z), Y/(1-Z)), name='Psi',
+ ....: latex_name=r'\Psi')
+ sage: Psi
+ Differentiable map Psi from the 3-dimensional differentiable manifold
+ R^3 to the 2-dimensional differentiable manifold R^2
+ sage: Psi.display()
+ Psi: R^3 --> R^2
+ (X, Y, Z) |--> (xP, yP) = (-X/(Z - 1), -Y/(Z - 1))
+
+ Then we compose ``Psi`` with ``Phi``, thereby getting a map
+ `S^2\rightarrow \RR^2`::
+
+ sage: ster = Psi*Phi ; ster
+ Differentiable map from the 2-dimensional differentiable manifold S^2
+ to the 2-dimensional differentiable manifold R^2
+
+ Let us test on the South pole (``sp``) that ``ster`` is indeed the
+ composite of ``Psi`` and ``Phi``::
+
+ sage: ster(sp) == Psi(Phi(sp))
+ True
+
+ Actually ``ster`` is the stereographic projection from the North pole, as
+ its coordinate expression reveals::
+
+ sage: ster.display()
+ S^2 --> R^2
+ on U: (x, y) |--> (xP, yP) = (x, y)
+ on V: (u, v) |--> (xP, yP) = (u/(u^2 + v^2), v/(u^2 + v^2))
+
+ If its codomain is 1-dimensional, a differentiable map must be
+ defined by a single symbolic expression for each pair of charts, and not
+ by a list/tuple with a single element::
+
+ sage: N = Manifold(1, 'N')
+ sage: c_N = N.chart('X')
+ sage: Phi = M.diff_map(N, {(c_xy, c_N): x^2+y^2,
+ ....: (c_uv, c_N): 1/(u^2+v^2)}) # not ...[1/(u^2+v^2)] or (1/(u^2+v^2),)
+
+ An example of differentiable map `\RR \rightarrow \RR^2`::
+
+ sage: R = Manifold(1, 'R') # field R
+ sage: T.<t> = R.chart() # canonical chart on R
+ sage: R2 = Manifold(2, 'R^2') # R^2
+ sage: c_xy.<x,y> = R2.chart() # Cartesian coordinates on R^2
+ sage: Phi = R.diff_map(R2, [cos(t), sin(t)], name='Phi') ; Phi
+ Differentiable map Phi from the 1-dimensional differentiable manifold R
+ to the 2-dimensional differentiable manifold R^2
+ sage: Phi.parent()
+ Set of Morphisms from 1-dimensional differentiable manifold R to
+ 2-dimensional differentiable manifold R^2 in Category of smooth
+ manifolds over Real Field with 53 bits of precision
+ sage: Phi.parent() is Hom(R, R2)
+ True
+ sage: Phi.display()
+ Phi: R --> R^2
+ t |--> (x, y) = (cos(t), sin(t))
+
+ An example of diffeomorphism between the unit open disk and the Euclidean
+ plane `\RR^2`::
+
+ sage: D = R2.open_subset('D', coord_def={c_xy: x^2+y^2<1}) # the open unit disk
+ sage: Phi = D.diffeomorphism(R2, [x/sqrt(1-x^2-y^2), y/sqrt(1-x^2-y^2)],
+ ....: name='Phi', latex_name=r'\Phi')
+ sage: Phi
+ Diffeomorphism Phi from the Open subset D of the 2-dimensional
+ differentiable manifold R^2 to the 2-dimensional differentiable
+ manifold R^2
+ sage: Phi.parent()
+ Set of Morphisms from Open subset D of the 2-dimensional differentiable
+ manifold R^2 to 2-dimensional differentiable manifold R^2 in Join of
+ Category of subobjects of sets and Category of smooth manifolds over
+ Real Field with 53 bits of precision
+ sage: Phi.parent() is Hom(D, R2)
+ True
+ sage: Phi.display()
+ Phi: D --> R^2
+ (x, y) |--> (x, y) = (x/sqrt(-x^2 - y^2 + 1), y/sqrt(-x^2 - y^2 + 1))
+
+ The image of a point::
+
+ sage: p = D.point((1/2,0))
+ sage: q = Phi(p) ; q
+ Point on the 2-dimensional differentiable manifold R^2
+ sage: q.coord()
+ (1/3*sqrt(3), 0)
+
+ The inverse diffeomorphism is computed by means of the method
+ :meth:`~sage.manifolds.continuous_map.ContinuousMap.inverse`::
+
+ sage: Phi.inverse()
+ Diffeomorphism Phi^(-1) from the 2-dimensional differentiable manifold R^2
+ to the Open subset D of the 2-dimensional differentiable manifold R^2
+ sage: Phi.inverse().display()
+ Phi^(-1): R^2 --> D
+ (x, y) |--> (x, y) = (x/sqrt(x^2 + y^2 + 1), y/sqrt(x^2 + y^2 + 1))
+
+ Equivalently, one may use the notations ``^(-1)`` or ``~`` to get the
+ inverse::
+
+ sage: Phi^(-1) is Phi.inverse()
+ True
+ sage: ~Phi is Phi.inverse()
+ True
+
+ Check that ``~Phi`` is indeed the inverse of ``Phi``::
+
+ sage: (~Phi)(q) == p
+ True
+ sage: Phi * ~Phi == R2.identity_map()
+ True
+ sage: ~Phi * Phi == D.identity_map()
+ True
+
+ The coordinate expression of the inverse diffeomorphism::
+
+ sage: (~Phi).display()
+ Phi^(-1): R^2 --> D
+ (x, y) |--> (x, y) = (x/sqrt(x^2 + y^2 + 1), y/sqrt(x^2 + y^2 + 1))
+
+ A special case of diffeomorphism: the identity map of the open unit disk::
+
+ sage: id = D.identity_map() ; id
+ Identity map Id_D of the Open subset D of the 2-dimensional
+ differentiable manifold R^2
+ sage: latex(id)
+ \mathrm{Id}_{D}
+ sage: id.parent()
+ Set of Morphisms from Open subset D of the 2-dimensional differentiable
+ manifold R^2 to Open subset D of the 2-dimensional differentiable
+ manifold R^2 in Join of Category of subobjects of sets and Category of
+ smooth manifolds over Real Field with 53 bits of precision
+ sage: id.parent() is Hom(D, D)
+ True
+ sage: id is Hom(D,D).one() # the identity element of the monoid Hom(D,D)
+ True
+
+ The identity map acting on a point::
+
+ sage: id(p)
+ Point on the 2-dimensional differentiable manifold R^2
+ sage: id(p) == p
+ True
+ sage: id(p) is p
+ True
+
+ The coordinate expression of the identity map::
+
+ sage: id.display()
+ Id_D: D --> D
+ (x, y) |--> (x, y)
+
+ The identity map is its own inverse::
+
+ sage: id^(-1) is id
+ True
+ sage: ~id is id
+ True
+
+ """
+ def __init__(self, parent, coord_functions=None, name=None,
+ latex_name=None, is_isomorphism=False, is_identity=False):
+ r"""
+ Construct a differentiable map.
+
+ TESTS::
+
+ sage: M = Manifold(2, 'M')
+ sage: X.<x,y> = M.chart()
+ sage: N = Manifold(3, 'N')
+ sage: Y.<u,v,w> = N.chart()
+ sage: f = Hom(M,N)({(X,Y): (x+y, x*y, x-y)}, name='f') ; f
+ Differentiable map f from the 2-dimensional differentiable manifold
+ M to the 3-dimensional differentiable manifold N
+ sage: f.display()
+ f: M --> N
+ (x, y) |--> (u, v, w) = (x + y, x*y, x - y)
+ sage: TestSuite(f).run()
+
+ The identity map::
+
+ sage: f = Hom(M,M)({}, is_identity=True) ; f
+ Identity map Id_M of the 2-dimensional differentiable manifold M
+ sage: f.display()
+ Id_M: M --> M
+ (x, y) |--> (x, y)
+ sage: TestSuite(f).run()
+
+ """
+ ContinuousMap.__init__(self, parent, coord_functions=coord_functions,
+ name=name, latex_name=latex_name,
+ is_isomorphism=is_isomorphism,
+ is_identity=is_identity)
+
+ #
+ # SageObject methods
+ #
+
+ def _repr_(self):
+ r"""
+ String representation of the object.
+
+ TESTS::
+
+ sage: M = Manifold(2, 'M')
+ sage: X.<x,y> = M.chart()
+ sage: N = Manifold(2, 'N')
+ sage: Y.<u,v> = N.chart()
+ sage: f = Hom(M,N)({(X,Y): (x+y,x*y)})
+ sage: f._repr_()
+ 'Differentiable map from the 2-dimensional differentiable manifold M to
+ the 2-dimensional differentiable manifold N'
+ sage: f = Hom(M,N)({(X,Y): (x+y,x*y)}, name='f')
+ sage: f._repr_()
+ 'Differentiable map f from the 2-dimensional differentiable manifold M to
+ the 2-dimensional differentiable manifold N'
+ sage: f = Hom(M,N)({(X,Y): (x+y,x-y)}, name='f', is_isomorphism=True)
+ sage: f._repr_()
+ 'Diffeomorphism f from the 2-dimensional differentiable manifold M to
+ the 2-dimensional differentiable manifold N'
+ sage: f = Hom(M,M)({(X,X): (x+y,x-y)}, name='f', is_isomorphism=True)
+ sage: f._repr_()
+ 'Diffeomorphism f of the 2-dimensional differentiable manifold M'
+ sage: f = Hom(M,M)({}, name='f', is_identity=True)
+ sage: f._repr_()
+ 'Identity map f of the 2-dimensional differentiable manifold M'
+
+ """
+ if self._is_identity:
+ return "Identity map " + self._name + \
+ " of the {}".format(self._domain)
+ if self._is_isomorphism:
+ description = "Diffeomorphism"
+ else:
+ description = "Differentiable map"
+ if self._name is not None:
+ description += " " + self._name
+ if self._domain == self._codomain:
+ if self._is_isomorphism:
+ description += " of the {}".format(self._domain)
+ else:
+ description += " from the {} to itself".format(self._domain)
+ else:
+ description += " from the {} to the {}".format(self._domain,
+ self._codomain)
+ return description
+
+ def _init_derived(self):
+ r"""
+ Initialize the derived quantities.
+
+ TEST::
+
+ sage: M = Manifold(2, 'M')
+ sage: X.<x,y> = M.chart()
+ sage: f = M.diffeomorphism(M, [x+y, x-y])
+ sage: f._init_derived()
+ sage: f._restrictions
+ {}
+ sage: f._inverse
+
+ """
+ ContinuousMap._init_derived(self) # derived quantities of the mother
+ # class
+ self._diff = {} # dict. of the coord. expressions of the differential
+ # keys: pair of charts
+
+ def _del_derived(self):
+ r"""
+ Delete the derived quantities.
+
+ TEST::
+
+ sage: M = Manifold(2, 'M')
+ sage: X.<x,y> = M.chart()
+ sage: f = M.diffeomorphism(M, [x+y, x-y])
+ sage: f^(-1)
+ Diffeomorphism of the 2-dimensional differentiable manifold M
+ sage: f._inverse # was set by f^(-1)
+ Diffeomorphism of the 2-dimensional differentiable manifold M
+ sage: f._del_derived()
+ sage: f._inverse # has been set to None by _del_derived()
+
+ """
+ ContinuousMap._del_derived(self) # derived quantities of the mother
+ # class
+ self._diff.clear()
diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py
new file mode 100644
index 00000000..a4d4a0b
--- /dev/null
+++ b/src/sage/manifolds/differentiable/manifold.py
@@ -0,0 +1,953 @@
+r"""
+Differentiable Manifolds
+
+Given a non-discrete topological field `K` (in most applications, `K = \RR` or
+`K = \CC`; see however [4]_ for `K = \QQ_p` and [5]_ for other fields),
+a *differentiable manifold over* `K` is a topological manifold `M` over `K`
+equipped with an atlas whose transitions maps are of class `C^k` (i.e.
+`k`-times continuously differentiable) for a fixed positive integer `k`
+(possibly `k=\infty`). `M` is then called a `C^k`-*manifold over* `K`.
+
+Note that
+
+- if the mention of `K` is omitted, then `K=\RR` is assumed;
+- if `K=\CC`, any `C^k`-manifold with `k\geq 1` is actually a
+ `C^\infty`-manifold (even an analytic manifold);
+- if `K=\RR`, any `C^k`-manifold with `k\geq 1` admits a compatible
+ `C^\infty`-structure (Whitney's smoothing theorem).
+
+Differentiable manifolds are implemented via the class
+:class:`DifferentiableManifold`.
+Open subsets of differentiable manifolds are also implemented via
+:class:`DifferentiableManifold`, since they are differentiable manifolds by
+themselves.
+
+The user interface is provided by the generic function
+:func:`~sage.manifolds.manifold.Manifold`, with
+the argument ``structure`` set to ``'differentiable'`` and the argument
+``diff_degree`` set to `k`, or the argument ``structure`` set to ``'smooth'``
+(the default value).
+
+.. RUBRIC:: Example 1: the 2-sphere as a differentiable manifold of dimension
+ 2 over `\RR`
+
+One starts by declaring `S^2` as a 2-dimensional differentiable manifold::
+
+ sage: M = Manifold(2, 'S^2')
+ sage: M
+ 2-dimensional differentiable manifold S^2
+
+Since the base topological field has not been specified in the argument list
+of ``Manifold``, `\RR` is assumed::
+
+ sage: M.base_field()
+ Real Field with 53 bits of precision
+ sage: dim(M)
+ 2
+
+By default, the created object is a smooth manifold::
+
+ sage: M.diff_degree()
+ +Infinity
+
+Let us consider the complement of a point, the "North pole" say; this is an
+open subset of `S^2`, which we call `U`::
+
+ sage: U = M.open_subset('U'); U
+ Open subset U of the 2-dimensional differentiable manifold S^2
+
+A standard chart on `U` is provided by the stereographic projection from the
+North pole to the equatorial plane::
+
+ sage: stereoN.<x,y> = U.chart(); stereoN
+ Chart (U, (x, y))
+
+Thanks to the operator ``<x,y>`` on the left-hand side, the coordinates
+declared in a chart (here `x` and `y`), are accessible by their names; they are
+Sage's symbolic variables::
+
+ sage: y
+ y
+ sage: type(y)
+ <type 'sage.symbolic.expression.Expression'>
+
+The South pole is the point of coordinates `(x,y)=(0,0)` in the above
+chart::
+
+ sage: S = U.point((0,0), chart=stereoN, name='S'); S
+ Point S on the 2-dimensional differentiable manifold S^2
+
+Let us call `V` the open subset that is the complement of the South pole and
+let us introduce on it the chart induced by the stereographic projection from
+the South pole to the equatorial plane::
+
+ sage: V = M.open_subset('V'); V
+ Open subset V of the 2-dimensional differentiable manifold S^2
+ sage: stereoS.<u,v> = V.chart(); stereoS
+ Chart (V, (u, v))
+
+The North pole is the point of coordinates `(u,v)=(0,0)` in this chart::
+
+ sage: N = V.point((0,0), chart=stereoS, name='N'); N
+ Point N on the 2-dimensional differentiable manifold S^2
+
+To fully construct the manifold, we declare that it is the union of `U`
+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`)::
+
+ 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, restrictions2= u^2+v^2!=0)
+ sage: stereoN_to_S
+ Change of coordinates from Chart (W, (x, y)) to Chart (W, (u, v))
+ sage: stereoN_to_S.display()
+ u = x/(x^2 + y^2)
+ v = y/(x^2 + y^2)
+
+We give the name ``W`` to the Python variable representing `W=U\cap V`::
+
+ sage: W = U.intersection(V)
+
+The inverse of the transition map is computed by the method ``inverse()``::
+
+ sage: stereoN_to_S.inverse()
+ Change of coordinates from Chart (W, (u, v)) to Chart (W, (x, y))
+ sage: stereoN_to_S.inverse().display()
+ x = u/(u^2 + v^2)
+ y = v/(u^2 + v^2)
+
+At this stage, we have four open subsets on `S^2`::
+
+ sage: M.list_of_subsets()
+ [2-dimensional differentiable manifold S^2,
+ Open subset U of the 2-dimensional differentiable manifold S^2,
+ Open subset V of the 2-dimensional differentiable manifold S^2,
+ Open subset W of the 2-dimensional differentiable manifold S^2]
+
+`W` is the open subset that is the complement of the two poles::
+
+ sage: N in W or S in W
+ False
+
+The North pole lies in `V` and the South pole in `U`::
+
+ sage: N in V, N in U
+ (True, False)
+ sage: S in U, S in V
+ (True, False)
+
+The manifold's (user) atlas contains four charts, two of them
+being restrictions of charts to a smaller domain::
+
+ sage: M.atlas()
+ [Chart (U, (x, y)), Chart (V, (u, v)), Chart (W, (x, y)), Chart (W, (u, v))]
+
+Let us consider the point of coordinates (1,2) in the chart ``stereoN``::
+
+ sage: p = M.point((1,2), chart=stereoN, name='p'); p
+ Point p on the 2-dimensional differentiable manifold S^2
+ sage: p.parent()
+ 2-dimensional differentiable manifold S^2
+ sage: p in W
+ True
+
+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)
+
+Given the definition of `p`, we have of course::
+
+ sage: stereoN(p)
+ (1, 2)
+
+Similarly::
+
+ sage: stereoS(N)
+ (0, 0)
+ sage: stereoN(S)
+ (0, 0)
+
+A differentiable scalar field on the sphere::
+
+ sage: f = M.scalar_field({stereoN: atan(x^2+y^2), stereoS: pi/2-atan(u^2+v^2)},
+ ....: name='f')
+ sage: f
+ Scalar field f on the 2-dimensional differentiable manifold S^2
+ sage: f.display()
+ f: S^2 --> R
+ on U: (x, y) |--> arctan(x^2 + y^2)
+ on V: (u, v) |--> 1/2*pi - arctan(u^2 + v^2)
+ sage: f(p)
+ arctan(5)
+ sage: f(N)
+ 1/2*pi
+ sage: f(S)
+ 0
+ sage: f.parent()
+ Algebra of differentiable scalar fields on the 2-dimensional differentiable
+ manifold S^2
+ sage: f.parent().category()
+ Category of commutative algebras over Symbolic Ring
+
+
+.. RUBRIC:: Example 2: the Riemann sphere as a differentiable manifold of
+ dimension 1 over `\CC`
+
+We declare the Riemann sphere `\CC^*` as a 1-dimensional differentiable
+manifold over `\CC`::
+
+ sage: M = Manifold(1, 'C*', field='complex'); M
+ 1-dimensional complex manifold C*
+
+We introduce a first open subset, which is actually
+`\CC = \CC^*\setminus\{\infty\}` if we interpret `\CC^*` as the Alexandroff
+one-point compactification of `\CC`::
+
+ sage: U = M.open_subset('U')
+
+A natural chart on `U` is then nothing but the identity map of `\CC`, hence
+we denote the associated coordinate by `z`::
+
+ sage: Z.<z> = U.chart()
+
+The origin of the complex plane is the point of coordinate `z=0`::
+
+ sage: O = U.point((0,), chart=Z, name='O'); O
+ Point O on the 1-dimensional complex manifold C*
+
+Another open subset of `\CC^*` is `V = \CC^*\setminus\{O\}`::
+
+ sage: V = M.open_subset('V')
+
+We define a chart on `V` such that the point at infinity is the point of
+coordinate 0 in this chart::
+
+ sage: W.<w> = V.chart(); W
+ Chart (V, (w,))
+ sage: inf = M.point((0,), chart=W, name='inf', latex_name=r'\infty')
+ sage: inf
+ Point inf on the 1-dimensional complex manifold C*
+
+To fully construct the Riemann sphere, we declare that it is the union of `U`
+and `V`::
+
+ sage: M.declare_union(U,V)
+
+and we provide the transition map between the two charts as `w=1/z` on
+on `A = U\cap V`::
+
+ sage: Z_to_W = Z.transition_map(W, 1/z, intersection_name='A',
+ ....: restrictions1= z!=0, restrictions2= w!=0)
+ sage: Z_to_W
+ Change of coordinates from Chart (A, (z,)) to Chart (A, (w,))
+ sage: Z_to_W.display()
+ w = 1/z
+ sage: Z_to_W.inverse()
+ Change of coordinates from Chart (A, (w,)) to Chart (A, (z,))
+ sage: Z_to_W.inverse().display()
+ z = 1/w
+
+Let consider the complex number `i` as a point of the Riemann sphere::
+
+ sage: i = M((I,), chart=Z, name='i'); i
+ Point i on the 1-dimensional complex manifold C*
+
+Its coordinates w.r.t. the charts ``Z`` and ``W`` are::
+
+ sage: Z(i)
+ (I,)
+ sage: W(i)
+ (-I,)
+
+and we have::
+
+ sage: i in U
+ True
+ sage: i in V
+ True
+
+The following subsets and charts have been defined::
+
+ sage: M.list_of_subsets()
+ [Open subset A of the 1-dimensional complex manifold C*,
+ 1-dimensional complex manifold C*,
+ Open subset U of the 1-dimensional complex manifold C*,
+ Open subset V of the 1-dimensional complex manifold C*]
+ sage: M.atlas()
+ [Chart (U, (z,)), Chart (V, (w,)), Chart (A, (z,)), Chart (A, (w,))]
+
+A constant map `\CC^* \rightarrow \CC`::
+
+ sage: f = M.constant_scalar_field(3+2*I, name='f'); f
+ Scalar field f on the 1-dimensional complex manifold C*
+ sage: f.display()
+ f: C* --> C
+ on U: z |--> 2*I + 3
+ on V: w |--> 2*I + 3
+ sage: f(O)
+ 2*I + 3
+ sage: f(i)
+ 2*I + 3
+ sage: f(inf)
+ 2*I + 3
+ sage: f.parent()
+ Algebra of differentiable scalar fields on the 1-dimensional complex
+ manifold C*
+ sage: f.parent().category()
+ Category of commutative algebras over Symbolic Ring
+
+AUTHORS:
+
+- Eric Gourgoulhon (2015): initial version
+
+REFERENCES:
+
+.. [1] \J.M. Lee : *Introduction to Smooth Manifolds*, 2nd ed., Springer
+ (New York) (2012); :doi:`10.1007/978-1-4419-9982-5`
+.. [2] \S. Kobayashi & K. Nomizu : *Foundations of Differential Geometry*,
+ vol. 1, Interscience Publishers (New York) (1963)
+.. [3] \D. Huybrechts : *Complex Geometry*, Springer (Berlin) (2005);
+ :doi:`10.1007/b137952`
+.. [4] \J.-P. Serre : *Lie Algebras and Lie Groups*, 2nd ed., Springer
+ (Berlin) (1992); :doi:`10.1007/978-3-540-70634-2`
+.. [5] \W. Bertram : *Differential Geometry, Lie Groups and Symmetric Spaces
+ over General Base Fields and Rings*, Memoirs of the American Mathematical
+ Society, vol. 192 (2008); :doi:`10.1090/memo/0900`; :arxiv:`math/0502168`
+.. [6] \M. Berger & B. Gostiaux : *Differential Geometry: Manifolds, Curves and
+ Surfaces*, Springer (New York) (1988); :doi:`10.1007/978-1-4612-1033-7`
+
+"""
+
+#*****************************************************************************
+# Copyright (C) 2015 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
+# Copyright (C) 2015 Michal Bejger <bejger@camk.edu.pl>
+#
+# 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.categories.manifolds import Manifolds
+from sage.categories.homset import Hom
+from sage.rings.all import CC
+from sage.rings.real_mpfr import RR
+from sage.rings.infinity import infinity
+from sage.rings.integer import Integer
+from sage.misc.latex import latex
+from sage.manifolds.manifold import TopologicalManifold
+
+###############################################################################
+
+class DifferentiableManifold(TopologicalManifold):
+ r"""
+ Differentiable manifold over a topological field `K`.
+
+ Given a non-discrete topological field `K` (in most applications,
+ `K = \RR` or `K = \CC`; see however [4]_ for `K = \QQ_p` and [5]_ for
+ other fields), a *differentiable manifold over* `K` is a topological
+ manifold `M` over `K` equipped with an atlas whose transitions maps are of
+ class `C^k` (i.e. `k`-times continuously differentiable) for a fixed
+ positive integer `k` (possibly `k=\infty`). `M` is then called a
+ `C^k`-*manifold over* `K`.
+
+ Note that
+
+ - if the mention of `K` is omitted, then `K=\RR` is assumed;
+ - if `K=\CC`, any `C^k`-manifold with `k\geq 1` is actually a
+ `C^\infty`-manifold (even an analytic manifold);
+ - if `K=\RR`, any `C^k`-manifold with `k\geq 1` admits a compatible
+ `C^\infty`-structure (Whitney's smoothing theorem).
+
+ INPUT:
+
+ - ``n`` -- positive integer; dimension of the manifold
+ - ``name`` -- string; name (symbol) given to the manifold
+ - ``field`` -- field `K` on which the manifold is
+ defined; allowed values are
+
+ - ``'real'`` or an object of type ``RealField`` (e.g., ``RR``) for
+ a manifold over `\RR`
+ - ``'complex'`` or an object of type ``ComplexField`` (e.g., ``CC``)
+ for a manifold over `\CC`
+ - an object in the category of topological fields (see
+ :class:`~sage.categories.fields.Fields` and
+ :class:`~sage.categories.topological_spaces.TopologicalSpaces`)
+ for other types of manifolds
+
+ - ``structure`` -- manifold structure (see
+ :class:`~sage.manifolds.structure.DifferentialStructure` or
+ :class:`~sage.manifolds.structure.RealDifferentialStructure`)
+ - ``ambient`` -- (default: ``None``) if not ``None``, must be a
+ differentiable manifold; the created object is then an open subset of
+ ``ambient``
+ - ``diff_degree`` -- (default: ``infinity``) degree `k` of
+ differentiability
+ - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to
+ denote the manifold; if none is provided, it is set to ``name``
+ - ``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
+ - ``category`` -- (default: ``None``) to specify the category; if ``None``,
+ ``Manifolds(field).Differentiable()`` (or ``Manifolds(field).Smooth()``
+ if ``diff_degree`` = ``infinity``) is assumed (see the category
+ :class:`~sage.categories.manifolds.Manifolds`)
+ - ``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.ManifoldSubset`,
+ via :class:`~sage.manifolds.manifold.TopologicalManifold`,
+ would return the previously constructed object corresponding to these
+ arguments).
+
+ EXAMPLES:
+
+ A 4-dimensional differentiable manifold (over `\RR`)::
+
+ sage: M = Manifold(4, 'M', latex_name=r'\mathcal{M}'); M
+ 4-dimensional differentiable manifold M
+ sage: type(M)
+ <class 'sage.manifolds.differentiable.manifold.DifferentiableManifold_with_category'>
+ sage: latex(M)
+ \mathcal{M}
+ sage: dim(M)
+ 4
+
+ Since the base field has not been specified, `\RR` has been assumed::
+
+ sage: M.base_field()
+ Real Field with 53 bits of precision
+
+ Since the degree of differentiability has not been specified, the default
+ value, `C^\infty`, has been assumed::
+
+ sage: M.diff_degree()
+ +Infinity
+
+ The input parameter ``start_index`` defines the range of indices on the
+ manifold::
+
+ sage: M = Manifold(4, 'M')
+ sage: list(M.irange())
+ [0, 1, 2, 3]
+ sage: M = Manifold(4, 'M', start_index=1)
+ sage: list(M.irange())
+ [1, 2, 3, 4]
+ sage: list(Manifold(4, 'M', start_index=-2).irange())
+ [-2, -1, 0, 1]
+
+ A complex manifold::
+
+ sage: N = Manifold(3, 'N', field='complex'); N
+ 3-dimensional complex manifold N
+
+ A differentiable manifold over `\QQ_5`, the field of 5-adic numbers::
+
+ sage: N = Manifold(2, 'N', field=Qp(5)); N
+ 2-dimensional differentiable manifold N over the 5-adic Field with
+ capped relative precision 20
+
+ A differentiable manifold is of course a topological manifold::
+
+ sage: isinstance(M, sage.manifolds.manifold.TopologicalManifold)
+ True
+ sage: isinstance(N, sage.manifolds.manifold.TopologicalManifold)
+ True
+
+ A differentiable manifold is a Sage *parent* object, in the category of
+ differentiable (here smooth) manifolds over a given topological field (see
+ :class:`~sage.categories.manifolds.Manifolds`)::
+
+ sage: isinstance(M, Parent)
+ True
+ sage: M.category()
+ Category of smooth manifolds over Real Field with 53 bits of precision
+ sage: from sage.categories.manifolds import Manifolds
+ sage: M.category() is Manifolds(RR).Smooth()
+ True
+ sage: M.category() is Manifolds(M.base_field()).Smooth()
+ True
+ sage: M in Manifolds(RR).Smooth()
+ True
+ sage: N in Manifolds(Qp(5)).Smooth()
+ True
+
+ The corresponding Sage *elements* are points::
+
+ sage: X.<t, x, y, z> = M.chart()
+ sage: p = M.an_element(); p
+ Point on the 4-dimensional differentiable manifold M
+ sage: p.parent()
+ 4-dimensional differentiable manifold M
+ sage: M.is_parent_of(p)
+ True
+ sage: p in M
+ True
+
+ The manifold's points are instances of class
+ :class:`~sage.manifolds.point.ManifoldPoint`::
+
+ sage: isinstance(p, sage.manifolds.point.ManifoldPoint)
+ True
+
+ Since an open subset of a differentiable manifold `M` is itself a
+ differentiable manifold, open subsets of `M` have all attributes of
+ manifolds::
+
+ sage: U = M.open_subset('U', coord_def={X: t>0}); U
+ Open subset U of the 4-dimensional differentiable manifold M
+ sage: U.category()
+ Join of Category of subobjects of sets and Category of smooth manifolds
+ over Real Field with 53 bits of precision
+ sage: U.base_field() == M.base_field()
+ True
+ sage: dim(U) == dim(M)
+ True
+
+ The manifold passes all the tests of the test suite relative to its
+ category::
+
+ sage: TestSuite(M).run()
+
+ """
+ def __init__(self, n, name, field, structure, ambient=None,
+ diff_degree=infinity, latex_name=None, start_index=0,
+ category=None, unique_tag=None):
+ r"""
+ Construct a differentiable manifold.
+
+ TESTS::
+
+ sage: M = Manifold(3, 'M', latex_name=r'\mathbb{M}',
+ ....: start_index=1)
+ sage: M
+ 3-dimensional differentiable manifold M
+ sage: latex(M)
+ \mathbb{M}
+ sage: dim(M)
+ 3
+ sage: X.<x,y,z> = M.chart()
+ sage: TestSuite(M).run()
+
+ Tests for open subsets, which are constructed as differentiable
+ manifolds::
+
+ sage: U = M.open_subset('U', coord_def={X: x>0})
+ sage: type(U)
+ <class 'sage.manifolds.differentiable.manifold.DifferentiableManifold_with_category'>
+ sage: U.category() is M.category().Subobjects()
+ True
+ sage: TestSuite(U).run()
+
+ """
+ if ambient is None:
+ if category is None:
+ if field == 'real':
+ field_c = RR
+ elif field == 'complex':
+ field_c = CC
+ else:
+ field_c = field
+ if diff_degree == infinity:
+ category = Manifolds(field_c).Smooth()
+ else:
+ category = Manifolds(field_c).Differentiable()
+ elif not isinstance(ambient, DifferentiableManifold):
+ raise TypeError("the argument 'ambient' must be a " +
+ "differentiable manifold")
+ TopologicalManifold.__init__(self, n, name, field, structure,
+ ambient=ambient,
+ latex_name=latex_name,
+ start_index=start_index,
+ category=category)
+ # The degree of differentiability:
+ if diff_degree == infinity:
+ self._diff_degree = infinity
+ elif not isinstance(diff_degree, (int, Integer)):
+ raise TypeError("the argument 'diff_degree' must be an integer")
+ elif diff_degree < 1:
+ raise ValueError("the argument 'diff_degree' must be a positive " +
+ "integer")
+ else:
+ self._diff_degree = diff_degree
+
+ def diff_degree(self):
+ r"""
+ Return the manifold's degree of differentiability.
+
+ The degree of differentiability is the integer `k` (possibly
+ `k=\infty`) such that the manifold is a `C^k`-manifold over its base
+ field.
+
+ EXAMPLES::
+
+ sage: M = Manifold(2, 'M')
+ sage: M.diff_degree()
+ +Infinity
+ sage: M = Manifold(2, 'M', structure='differentiable', diff_degree=3)
+ sage: M.diff_degree()
+ 3
+
+ """
+ return self._diff_degree
+
+ def open_subset(self, name, latex_name=None, coord_def={}):
+ r"""
+ Create an open subset of the manifold.
+
+ An open subset is a set that is (i) included in the manifold and (ii)
+ open with respect to the manifold's topology. It is a differentiable
+ manifold by itself. Hence the returned object is an instance of
+ :class:`DifferentiableManifold`.
+
+ INPUT:
+
+ - ``name`` -- name given to the open subset
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
+ subset; if none is provided, it is set to ``name``
+ - ``coord_def`` -- (default: {}) definition of the subset in
+ terms of coordinates; ``coord_def`` must a be dictionary with keys
+ charts in the manifold's atlas and values the symbolic expressions
+ formed by the coordinates to define the subset.
+
+ OUTPUT:
+
+ - the open subset, as an instance of :class:`DifferentiableManifold`
+
+ EXAMPLES:
+
+ Creating an open subset of a differentiable manifold::
+
+ sage: M = Manifold(2, 'M')
+ sage: A = M.open_subset('A'); A
+ Open subset A of the 2-dimensional differentiable manifold M
+
+ As an open subset of a differentiable manifold, ``A`` is itself a
+ differentiable manifold, on the same topological field and of the same
+ dimension as ``M``::
+
+ sage: A.category()
+ Join of Category of subobjects of sets and Category of smooth
+ manifolds over Real Field with 53 bits of precision
+ sage: A.base_field() == M.base_field()
+ True
+ sage: dim(A) == dim(M)
+ True
+
+ Creating an open subset of ``A``::
+
+ sage: B = A.open_subset('B'); B
+ Open subset B of the 2-dimensional differentiable manifold M
+
+ We have then::
+
+ sage: A.list_of_subsets()
+ [Open subset A of the 2-dimensional differentiable manifold M,
+ Open subset B of the 2-dimensional differentiable manifold M]
+ sage: B.is_subset(A)
+ True
+ sage: B.is_subset(M)
+ True
+
+ Defining an open subset by some coordinate restrictions: the open
+ unit disk in of the Euclidean plane::
+
+ sage: X.<x,y> = M.chart() # Cartesian coordinates on M
+ sage: U = M.open_subset('U', coord_def={X: x^2+y^2<1}); U
+ Open subset U of the 2-dimensional differentiable manifold M
+
+ Since the argument ``coord_def`` has been set, ``U`` is automatically
+ endowed with a chart, which is the restriction of ``X``
+ to ``U``::
+
+ sage: U.atlas()
+ [Chart (U, (x, y))]
+ sage: U.default_chart()
+ Chart (U, (x, y))
+ sage: U.default_chart() is X.restrict(U)
+ True
+
+ An point in ``U``::
+
+ sage: p = U.an_element(); p
+ Point on the 2-dimensional differentiable manifold M
+ sage: X(p) # the coordinates (x,y) of p
+ (0, 0)
+ sage: p in U
+ True
+
+ Checking whether various points, defined by their coordinates w.r.t.
+ chart ``X``, are in ``U``::
+
+ sage: M((0,1/2)) in U
+ True
+ sage: M((0,1)) in U
+ False
+ sage: M((1/2,1)) in U
+ False
+ sage: M((-1/2,1/3)) in U
+ True
+
+ """
+ resu = DifferentiableManifold(self._dim, name, self._field,
+ self._structure, ambient=self._manifold,
+ diff_degree=self._diff_degree,
+ latex_name=latex_name,
+ start_index=self._sindex)
+ resu._supersets.update(self._supersets)
+ for sd in self._supersets:
+ sd._subsets.add(resu)
+ self._top_subsets.add(resu)
+ # Charts on the result from the coordinate definition:
+ for chart, restrictions in coord_def.iteritems():
+ if chart not in self._atlas:
+ raise ValueError("the {} does not belong to ".format(chart) +
+ "the atlas of {}".format(self))
+ chart.restrict(resu, restrictions)
+ # Transition maps on the result inferred from those of self:
+ for chart1 in coord_def:
+ for chart2 in coord_def:
+ if chart2 != chart1 and (chart1, chart2) in self._coord_changes:
+ self._coord_changes[(chart1, chart2)].restrict(resu)
+ #!# update vector frames and change of frames
+ return resu
+
+ def diff_map(self, codomain, coord_functions=None, chart1=None,
+ chart2=None, name=None, latex_name=None):
+ r"""
+ Define a differentiable map between the current differentiable manifold
+ and a differentiable manifold over the same topological field.
+
+ See :class:`~sage.manifolds.differentiable.diff_map.DiffMap` for a
+ complete documentation.
+
+ INPUT:
+
+ - ``codomain`` -- the map codomain (a differentiable manifold over the
+ same topological field as the current differentiable manifold)
+ - ``coord_functions`` -- (default: ``None``) if not ``None``, must be
+ either
+
+ - (i) a dictionary of
+ the coordinate expressions (as lists (or tuples) of the
+ coordinates of the image expressed in terms of the coordinates of
+ the considered point) with the pairs of charts (chart1, chart2)
+ as keys (chart1 being a chart on the current manifold and chart2 a
+ chart on ``codomain``)
+ - (ii) a single coordinate expression in a given pair of charts, the
+ latter being provided by the arguments ``chart1`` and ``chart2``
+
+ In both cases, if the dimension of the arrival manifold is 1,
+ a single coordinate expression can be passed instead of a tuple with
+ a single element
+ - ``chart1`` -- (default: ``None``; used only in case (ii) above) chart
+ on the current manifold defining the start coordinates involved in
+ ``coord_functions`` for case (ii); if none is provided, the
+ coordinates are assumed to refer to the manifold's default chart
+ - ``chart2`` -- (default: ``None``; used only in case (ii) above) chart
+ on ``codomain`` defining the arrival coordinates involved in
+ ``coord_functions`` for case (ii); if none is provided, the
+ coordinates are assumed to refer to the default chart of ``codomain``
+ - ``name`` -- (default: ``None``) name given to the differentiable
+ map
+ - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
+ differentiable map; if none is provided, the LaTeX symbol is set to
+ ``name``
+
+ OUTPUT:
+
+ - the differentiable map, as an instance of
+ :class:`~sage.manifolds.differentiable.diff_map.DiffMap`
+
+ EXAMPLES:
+
+ A differentiable map between an open subset of `S^2` covered by regular
+ spherical coordinates and `\RR^3`::
+
+ sage: M = Manifold(2, 'S^2')
+ sage: U = M.open_subset('U')
+ sage: c_spher.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
+ sage: N = Manifold(3, 'R^3', r'\RR^3')
+ sage: c_cart.<x,y,z> = N.chart() # Cartesian coord. on R^3
+ sage: Phi = U.diff_map(N, (sin(th)*cos(ph), sin(th)*sin(ph), cos(th)),
+ ....: name='Phi', latex_name=r'\Phi')
+ sage: Phi
+ Differentiable map Phi from the Open subset U of the 2-dimensional
+ differentiable manifold S^2 to the 3-dimensional differentiable
+ manifold R^3
+
+ The same definition, but with a dictionary with pairs of charts as
+ keys (case (i) above)::
+
+ sage: Phi1 = U.diff_map(N,
+ ....: {(c_spher, c_cart): (sin(th)*cos(ph), sin(th)*sin(ph),
+ ....: cos(th))}, name='Phi', latex_name=r'\Phi')
+ sage: Phi1 == Phi
+ True
+
+ The differentiable map acting on a point::
+
+ sage: p = U.point((pi/2, pi)) ; p
+ Point on the 2-dimensional differentiable manifold S^2
+ sage: Phi(p)
+ Point on the 3-dimensional differentiable manifold R^3
+ sage: Phi(p).coord(c_cart)
+ (-1, 0, 0)
+ sage: Phi1(p) == Phi(p)
+ True
+
+ See the documentation of class
+ :class:`~sage.manifolds.differentiable.diff_map.DiffMap` for more
+ examples.
+
+ """
+ homset = Hom(self, codomain)
+ if coord_functions is None:
+ coord_functions = {}
+ if not isinstance(coord_functions, dict):
+ # Turn coord_functions into a dictionary:
+ if chart1 is None:
+ chart1 = self._def_chart
+ elif chart1 not in self._atlas:
+ raise ValueError("{} is not a chart ".format(chart1) +
+ "defined on the {}".format(self))
+ if chart2 is None:
+ chart2 = codomain._def_chart
+ elif chart2 not in codomain._atlas:
+ raise ValueError("{} is not a chart ".format(chart2) +
+ " defined on the {}".format(codomain))
+ coord_functions = {(chart1, chart2): coord_functions}
+ return homset(coord_functions, name=name, latex_name=latex_name)
+
+ def diff_mapping(self, codomain, coord_functions=None, chart1=None,
+ chart2=None, name=None, latex_name=None):
+ r"""
+ Deprecated.
+
+ Use :meth:`diff_map` instead.
+
+ EXAMPLE::
+
+ sage: M = Manifold(2, 'M'); X.<x,y> = M.chart()
+ sage: N = Manifold(2, 'N'); Y.<u,v> = N.chart()
+ sage: Phi = M.diff