Continuous Maps Between Topological Manifolds - Manifolds

Skip to content
Back to top
View this page
Edit this page

# Continuous Maps Between Topological Manifolds

`ContinuousMap` implements continuous maps from a topological manifold \(M\) to some topological manifold \(N\) over the same topological field \(K\) as \(M\).

AUTHORS:

- Eric Gourgoulhon, Michal Bejger (2013-2015): initial version

- Travis Scrimshaw (2016): review tweaks

REFERENCES:

- Chap. 1 of [KN1963]

- [Lee2011]

class sage.manifolds.continuous_map.ContinuousMap(parent, coord_functions=None, name=None, latex_name=None, is_isomorphism=False, is_identity=False)

  Bases: `Morphism`

  Continuous map between two topological manifolds.

  This class implements continuous maps of the type

  \[\Phi: M \longrightarrow N,\]

  where \(M\) and \(N\) are topological manifolds over the same topological field \(K\).

  Continuous maps are the morphisms of the category of topological manifolds. The set of all continuous maps from \(M\) to \(N\) is therefore the homset between \(M\) and \(N\), which is denoted by \(\mathrm{Hom}(M,N)\).

  The class `ContinuousMap` is a Sage element class, whose parent class is `TopologicalManifoldHomset`.

  INPUT:

  - `parent` – homset \(\mathrm{Hom}(M,N)\) to which the continuous map belongs

  - `coord_functions` – 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\))

  - `name` – (default: `None`) name given to `self`

  - `latex_name` – (default: `None`) LaTeX symbol to denote the continuous map; if `None`, the LaTeX symbol is set to `name`

  - `is_isomorphism` – boolean (default: `False`); determines whether the constructed object is a isomorphism (i.e. a homeomorphism). If set to `True`, then the manifolds \(M\) and \(N\) must have the same dimension.

  - `is_identity` – boolean (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 continuous map, further coordinate expressions, in other charts, can be subsequently added by means of the method `add_expr()`.

  EXAMPLES:

  The standard embedding of the sphere \(S^2\) into \(\RR^3\):

  Sage

      sage: M = Manifold(2, 'S^2', structure='topological') # 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', latex_name=r'\RR^3', structure='topological')  # R^3
      sage: c_cart.<X,Y,Z> = N.chart()  # Cartesian coordinates on R^3
      sage: Phi = M.continuous_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
      Continuous map Phi from the 2-dimensional topological manifold S^2
       to the 3-dimensional topological manifold R^3
      sage: Phi.parent()
      Set of Morphisms from 2-dimensional topological manifold S^2
       to 3-dimensional topological manifold R^3
       in Category of manifolds over Real Field with 53 bits of precision
      sage: Phi.parent() is Hom(M, N)
      True
      sage: type(Phi)
      <class 'sage.manifolds.manifold_homset.TopologicalManifoldHomset_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))

  Python

      >>> from sage.all import *
      >>> M = Manifold(Integer(2), 'S^2', structure='topological') # the 2-dimensional sphere S^2
      >>> U = M.open_subset('U') # complement of the North pole
      >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)# stereographic coordinates from the North pole
      >>> V = M.open_subset('V') # complement of the South pole
      >>> c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2)# stereographic coordinates from the South pole
      >>> M.declare_union(U,V)   # S^2 is the union of U and V
      >>> xy_to_uv = c_xy.transition_map(c_uv, (x/(x**Integer(2)+y**Integer(2)), y/(x**Integer(2)+y**Integer(2))),
      ...                                intersection_name='W',
      ...                                restrictions1=x**Integer(2)+y**Integer(2)!=Integer(0),
      ...                                restrictions2=u**Integer(2)+v**Integer(2)!=Integer(0))
      >>> uv_to_xy = xy_to_uv.inverse()
      >>> N = Manifold(Integer(3), 'R^3', latex_name=r'\RR^3', structure='topological')  # R^3
      >>> c_cart = N.chart(names=('X', 'Y', 'Z',)); (X, Y, Z,) = c_cart._first_ngens(3)# Cartesian coordinates on R^3
      >>> Phi = M.continuous_map(N,
      ...   {(c_xy, c_cart): [Integer(2)*x/(Integer(1)+x**Integer(2)+y**Integer(2)), Integer(2)*y/(Integer(1)+x**Integer(2)+y**Integer(2)), (x**Integer(2)+y**Integer(2)-Integer(1))/(Integer(1)+x**Integer(2)+y**Integer(2))],
      ...    (c_uv, c_cart): [Integer(2)*u/(Integer(1)+u**Integer(2)+v**Integer(2)), Integer(2)*v/(Integer(1)+u**Integer(2)+v**Integer(2)), (Integer(1)-u**Integer(2)-v**Integer(2))/(Integer(1)+u**Integer(2)+v**Integer(2))]},
      ...   name='Phi', latex_name=r'\Phi')
      >>> Phi
      Continuous map Phi from the 2-dimensional topological manifold S^2
       to the 3-dimensional topological manifold R^3
      >>> Phi.parent()
      Set of Morphisms from 2-dimensional topological manifold S^2
       to 3-dimensional topological manifold R^3
       in Category of manifolds over Real Field with 53 bits of precision
      >>> Phi.parent() is Hom(M, N)
      True
      >>> type(Phi)
      <class 'sage.manifolds.manifold_homset.TopologicalManifoldHomset_with_category.element_class'>
      >>> 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 using `continuous_map()` with 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 codomain:

  Sage

      sage: Phi1 = M.continuous_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')

  [Python]

      >>> from sage.all import *
      >>> Phi1 = M.continuous_map(N, [Integer(2)*x/(Integer(1)+x**Integer(2)+y**Integer(2)), Integer(2)*y/(Integer(1)+x**Integer(2)+y**Integer(2)), (x**Integer(2)+y**Integer(2)-Integer(1))/(Integer(1)+x**Integer(2)+y**Integer(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

      sage: Phi1 = M.continuous_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')

  Python

      >>> from sage.all import *
      >>> Phi1 = M.continuous_map(N, [Integer(2)*x/(Integer(1)+x**Integer(2)+y**Integer(2)), Integer(2)*y/(Integer(1)+x**Integer(2)+y**Integer(2)), (x**Integer(2)+y**Integer(2)-Integer(1))/(Integer(1)+x**Integer(2)+y**Integer(2))],
      ...                         name='Phi', latex_name=r'\Phi')

  With such a declaration, the continuous map `Phi1` is only partially defined on the manifold \(S^2\) as it is known in only one chart:

  Sage

      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))

  [Python]

      >>> from sage.all import *
      >>> 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 using `add_expr()`:

  Sage

      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))

  Python

      >>> from sage.all import *
      >>> Phi1.add_expr(c_uv, c_cart, [Integer(2)*u/(Integer(1)+u**Integer(2)+v**Integer(2)), Integer(2)*v/(Integer(1)+u**Integer(2)+v**Integer(2)), (Integer(1)-u**Integer(2)-v**Integer(2))/(Integer(1)+u**Integer(2)+v**Integer(2))])
      >>> 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

      sage: Phi1 == Phi
      True

  [Python]

      >>> from sage.all import *
      >>> Phi1 == Phi
      True

  The map acts on points:

  Sage

      sage: np = M.point((0,0), chart=c_uv)  # the North pole
      sage: Phi(np)
      Point on the 3-dimensional topological manifold R^3
      sage: Phi(np).coord()  # Cartesian coordinates
      (0, 0, 1)
      sage: sp = M.point((0,0), chart=c_xy)  # the South pole
      sage: Phi(sp).coord()  # Cartesian coordinates
      (0, 0, -1)

  Python

      >>> from sage.all import *
      >>> np = M.point((Integer(0),Integer(0)), chart=c_uv)  # the North pole
      >>> Phi(np)
      Point on the 3-dimensional topological manifold R^3
      >>> Phi(np).coord()  # Cartesian coordinates
      (0, 0, 1)
      >>> sp = M.point((Integer(0),Integer(0)), chart=c_xy)  # the South pole
      >>> Phi(sp).coord()  # Cartesian coordinates
      (0, 0, -1)

  The test suite is passed:

  Sage

      sage: TestSuite(Phi).run()
      sage: TestSuite(Phi1).run()

  [Python]

      >>> from sage.all import *
      >>> TestSuite(Phi).run()
      >>> TestSuite(Phi1).run()

  Continuous maps can be composed by means of the operator `*`. Let us introduce the map \(\RR^3 \to \RR^2\) corresponding to the projection from the point \((X, Y, Z) = (0, 0, 1)\) onto the equatorial plane \(Z = 0\):

  Sage

      sage: P = Manifold(2, 'R^2', latex_name=r'\RR^2', structure='topological') # R^2 (equatorial plane)
      sage: cP.<xP, yP> = P.chart()
      sage: Psi = N.continuous_map(P, (X/(1-Z), Y/(1-Z)), name='Psi',
      ....:                      latex_name=r'\Psi')
      sage: Psi
      Continuous map Psi from the 3-dimensional topological manifold R^3
       to the 2-dimensional topological manifold R^2
      sage: Psi.display()
      Psi: R^3 → R^2
         (X, Y, Z) ↦ (xP, yP) = (-X/(Z - 1), -Y/(Z - 1))

  Python

      >>> from sage.all import *
      >>> P = Manifold(Integer(2), 'R^2', latex_name=r'\RR^2', structure='topological') # R^2 (equatorial plane)
      >>> cP = P.chart(names=('xP', 'yP',)); (xP, yP,) = cP._first_ngens(2)
      >>> Psi = N.continuous_map(P, (X/(Integer(1)-Z), Y/(Integer(1)-Z)), name='Psi',
      ...                      latex_name=r'\Psi')
      >>> Psi
      Continuous map Psi from the 3-dimensional topological manifold R^3
       to the 2-dimensional topological manifold R^2
      >>> 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 \to \RR^2\):

  Sage

      sage: ster = Psi * Phi ; ster
      Continuous map from the 2-dimensional topological manifold S^2
       to the 2-dimensional topological manifold R^2

  [Python]

      >>> from sage.all import *
      >>> ster = Psi * Phi ; ster
      Continuous map from the 2-dimensional topological manifold S^2
       to the 2-dimensional topological manifold R^2

  Let us test on the South pole (`sp`) that `ster` is indeed the composite of `Psi` and `Phi`:

  Sage

      sage: ster(sp) == Psi(Phi(sp))
      True

  Python

      >>> from sage.all import *
      >>> ster(sp) == Psi(Phi(sp))
      True

  Actually `ster` is the stereographic projection from the North pole, as its coordinate expression reveals:

  Sage

      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))

  [Python]

      >>> from sage.all import *
      >>> 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 the codomain of a continuous map is 1-dimensional, the map can be defined by a single symbolic expression for each pair of charts and not by a list/tuple with a single element:

  Sage

      sage: N = Manifold(1, 'N', structure='topological')
      sage: c_N = N.chart('X')
      sage: Phi = M.continuous_map(N, {(c_xy, c_N): x^2+y^2,
      ....:                            (c_uv, c_N): 1/(u^2+v^2)})

      sage: Psi = M.continuous_map(N, {(c_xy, c_N): [x^2+y^2],
      ....:                            (c_uv, c_N): [1/(u^2+v^2)]})
      sage: Phi == Psi
      True

  Python

      >>> from sage.all import *
      >>> N = Manifold(Integer(1), 'N', structure='topological')
      >>> c_N = N.chart('X')
      >>> Phi = M.continuous_map(N, {(c_xy, c_N): x**Integer(2)+y**Integer(2),
      ...                            (c_uv, c_N): Integer(1)/(u**Integer(2)+v**Integer(2))})

      >>> Psi = M.continuous_map(N, {(c_xy, c_N): [x**Integer(2)+y**Integer(2)],
      ...                            (c_uv, c_N): [Integer(1)/(u**Integer(2)+v**Integer(2))]})
      >>> Phi == Psi
      True

  Next we construct an example of continuous map \(\RR \to \RR^2\):

  Sage

      sage: R = Manifold(1, 'R', structure='topological')  # field R
      sage: T.<t> = R.chart()  # canonical chart on R
      sage: R2 = Manifold(2, 'R^2', structure='topological')  # R^2
      sage: c_xy.<x,y> = R2.chart() # Cartesian coordinates on R^2
      sage: Phi = R.continuous_map(R2, [cos(t), sin(t)], name='Phi'); Phi
      Continuous map Phi from the 1-dimensional topological manifold R
       to the 2-dimensional topological manifold R^2
      sage: Phi.parent()
      Set of Morphisms from 1-dimensional topological manifold R
       to 2-dimensional topological manifold R^2
       in Category of 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))

  [Python]

      >>> from sage.all import *
      >>> R = Manifold(Integer(1), 'R', structure='topological')  # field R
      >>> T = R.chart(names=('t',)); (t,) = T._first_ngens(1)# canonical chart on R
      >>> R2 = Manifold(Integer(2), 'R^2', structure='topological')  # R^2
      >>> c_xy = R2.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)# Cartesian coordinates on R^2
      >>> Phi = R.continuous_map(R2, [cos(t), sin(t)], name='Phi'); Phi
      Continuous map Phi from the 1-dimensional topological manifold R
       to the 2-dimensional topological manifold R^2
      >>> Phi.parent()
      Set of Morphisms from 1-dimensional topological manifold R
       to 2-dimensional topological manifold R^2
       in Category of manifolds over Real Field with 53 bits of precision
      >>> Phi.parent() is Hom(R, R2)
      True
      >>> Phi.display()
      Phi: R → R^2
         t ↦ (x, y) = (cos(t), sin(t))

  An example of homeomorphism between the unit open disk and the Euclidean plane \(\RR^2\):

  Sage

      sage: D = R2.open_subset('D', coord_def={c_xy: x^2+y^2<1}) # the open unit disk
      sage: Phi = D.homeomorphism(R2, [x/sqrt(1-x^2-y^2), y/sqrt(1-x^2-y^2)],
      ....:                       name='Phi', latex_name=r'\Phi')
      sage: Phi
      Homeomorphism Phi from the Open subset D of the 2-dimensional
       topological manifold R^2 to the 2-dimensional topological manifold R^2
      sage: Phi.parent()
      Set of Morphisms from Open subset D of the 2-dimensional topological
       manifold R^2 to 2-dimensional topological manifold R^2 in Category of
       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))

  Python

      >>> from sage.all import *
      >>> D = R2.open_subset('D', coord_def={c_xy: x**Integer(2)+y**Integer(2)<Integer(1)}) # the open unit disk
      >>> Phi = D.homeomorphism(R2, [x/sqrt(Integer(1)-x**Integer(2)-y**Integer(2)), y/sqrt(Integer(1)-x**Integer(2)-y**Integer(2))],
      ...                       name='Phi', latex_name=r'\Phi')
      >>> Phi
      Homeomorphism Phi from the Open subset D of the 2-dimensional
       topological manifold R^2 to the 2-dimensional topological manifold R^2
      >>> Phi.parent()
      Set of Morphisms from Open subset D of the 2-dimensional topological
       manifold R^2 to 2-dimensional topological manifold R^2 in Category of
       manifolds over Real Field with 53 bits of precision
      >>> Phi.parent() is Hom(D, R2)
      True
      >>> 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

      sage: p = D.point((1/2,0))
      sage: q = Phi(p) ; q
      Point on the 2-dimensional topological manifold R^2
      sage: q.coord()
      (1/3*sqrt(3), 0)

  [Python]

      >>> from sage.all import *
      >>> p = D.point((Integer(1)/Integer(2),Integer(0)))
      >>> q = Phi(p) ; q
      Point on the 2-dimensional topological manifold R^2
      >>> q.coord()
      (1/3*sqrt(3), 0)

  The inverse homeomorphism is computed by `inverse()`:

  Sage

      sage: Phi.inverse()
      Homeomorphism Phi^(-1) from the 2-dimensional topological manifold R^2
       to the Open subset D of the 2-dimensional topological 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))

  Python

      >>> from sage.all import *
      >>> Phi.inverse()
      Homeomorphism Phi^(-1) from the 2-dimensional topological manifold R^2
       to the Open subset D of the 2-dimensional topological manifold R^2
      >>> 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

      sage: Phi^(-1) is Phi.inverse()
      True
      sage: ~Phi is Phi.inverse()
      True

  [Python]

      >>> from sage.all import *
      >>> Phi**(-Integer(1)) is Phi.inverse()
      True
      >>> ~Phi is Phi.inverse()
      True

  Check that `~Phi` is indeed the inverse of `Phi`:

  Sage

      sage: (~Phi)(q) == p
      True
      sage: Phi * ~Phi == R2.identity_map()
      True
      sage: ~Phi * Phi == D.identity_map()
      True

  Python

      >>> from sage.all import *
      >>> (~Phi)(q) == p
      True
      >>> Phi * ~Phi == R2.identity_map()
      True
      >>> ~Phi * Phi == D.identity_map()
      True

  The coordinate expression of the inverse homeomorphism:

  Sage

      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))

  [Python]

      >>> from sage.all import *
      >>> (~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 homeomorphism: the identity map of the open unit disk:

  Sage

      sage: id = D.identity_map() ; id
      Identity map Id_D of the Open subset D of the 2-dimensional topological
       manifold R^2
      sage: latex(id)
      \mathrm{Id}_{D}
      sage: id.parent()
      Set of Morphisms from Open subset D of the 2-dimensional topological
       manifold R^2 to Open subset D of the 2-dimensional topological
       manifold R^2 in Join of Category of subobjects of sets and Category of
       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

  Python

      >>> from sage.all import *
      >>> id = D.identity_map() ; id
      Identity map Id_D of the Open subset D of the 2-dimensional topological
       manifold R^2
      >>> latex(id)
      \mathrm{Id}_{D}
      >>> id.parent()
      Set of Morphisms from Open subset D of the 2-dimensional topological
       manifold R^2 to Open subset D of the 2-dimensional topological
       manifold R^2 in Join of Category of subobjects of sets and Category of
       manifolds over Real Field with 53 bits of precision
      >>> id.parent() is Hom(D, D)
      True
      >>> id is Hom(D,D).one()  # the identity element of the monoid Hom(D,D)
      True

  The identity map acting on a point:

  Sage

      sage: id(p)
      Point on the 2-dimensional topological manifold R^2
      sage: id(p) == p
      True
      sage: id(p) is p
      True

  [Python]

      >>> from sage.all import *
      >>> id(p)
      Point on the 2-dimensional topological manifold R^2
      >>> id(p) == p
      True
      >>> id(p) is p
      True

  The coordinate expression of the identity map:

  Sage

      sage: id.display()
      Id_D: D → D
         (x, y) ↦ (x, y)

  Python

      >>> from sage.all import *
      >>> id.display()
      Id_D: D → D
         (x, y) ↦ (x, y)

  The identity map is its own inverse:

  Sage

      sage: id^(-1) is id
      True
      sage: ~id is id
      True

  [Python]

      >>> from sage.all import *
      >>> id**(-Integer(1)) is id
      True
      >>> ~id is id
      True

  add_expr(chart1, chart2, coord_functions)

    Set a new coordinate representation of `self`.

    The previous expressions with respect to other charts are kept. To clear them, use `set_expr()` instead.

    INPUT:

    - `chart1` – chart for the coordinates on the map’s domain

    - `chart2` – chart for the coordinates on the map’s codomain

    - `coord_functions` – the coordinate symbolic expression of the map in the above charts: list (or tuple) of the coordinates of the image expressed in terms of the coordinates of the considered point; if the dimension of the arrival manifold is 1, a single coordinate expression can be passed instead of a tuple with a single element

    Warning

    If the map has already expressions in other charts, it is the user’s responsibility to make sure that the expression to be added is consistent with them.

    EXAMPLES:

    Polar representation of a planar rotation initially defined in Cartesian coordinates:

    Sage

        sage: M = Manifold(2, 'R^2', latex_name=r'\RR^2', structure='topological')  # the Euclidean plane R^2
        sage: c_xy.<x,y> = M.chart() # Cartesian coordinate on R^2
        sage: U = M.open_subset('U', coord_def={c_xy: (y!=0, x<0)}) # the complement of the segment y=0 and x>0
        sage: c_cart = c_xy.restrict(U) # Cartesian coordinates on U
        sage: c_spher.<r,ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi') # spherical coordinates on U

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'R^2', latex_name=r'\RR^2', structure='topological')  # the Euclidean plane R^2
        >>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)# Cartesian coordinate on R^2
        >>> U = M.open_subset('U', coord_def={c_xy: (y!=Integer(0), x<Integer(0))}) # the complement of the segment y=0 and x>0
        >>> c_cart = c_xy.restrict(U) # Cartesian coordinates on U
        >>> c_spher = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi', names=('r', 'ph',)); (r, ph,) = c_spher._first_ngens(2)# spherical coordinates on U

    We construct the links between spherical coordinates and Cartesian ones:

    Sage

        sage: ch_cart_spher = c_cart.transition_map(c_spher, [sqrt(x*x+y*y), atan2(y,x)])
        sage: ch_cart_spher.set_inverse(r*cos(ph), r*sin(ph))
        Check of the inverse coordinate transformation:
          x == x  *passed*
          y == y  *passed*
          r == r  *passed*
          ph == arctan2(r*sin(ph), r*cos(ph))  **failed**
        NB: a failed report can reflect a mere lack of simplification.
        sage: rot = U.continuous_map(U, ((x - sqrt(3)*y)/2, (sqrt(3)*x + y)/2),
        ....:                        name='R')
        sage: rot.display(c_cart, c_cart)
        R: U → U
           (x, y) ↦ (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)

    [Python]

        >>> from sage.all import *
        >>> ch_cart_spher = c_cart.transition_map(c_spher, [sqrt(x*x+y*y), atan2(y,x)])
        >>> ch_cart_spher.set_inverse(r*cos(ph), r*sin(ph))
        Check of the inverse coordinate transformation:
          x == x  *passed*
          y == y  *passed*
          r == r  *passed*
          ph == arctan2(r*sin(ph), r*cos(ph))  **failed**
        NB: a failed report can reflect a mere lack of simplification.
        >>> rot = U.continuous_map(U, ((x - sqrt(Integer(3))*y)/Integer(2), (sqrt(Integer(3))*x + y)/Integer(2)),
        ...                        name='R')
        >>> rot.display(c_cart, c_cart)
        R: U → U
           (x, y) ↦ (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)

    If we calculate the expression in terms of spherical coordinates, via the method `display()`, we notice some difficulties in `arctan2` simplifications:

    Sage

        sage: rot.display(c_spher, c_spher)
        R: U → U
           (r, ph) ↦ (r, arctan2(1/2*(sqrt(3)*cos(ph) + sin(ph))*r, -1/2*(sqrt(3)*sin(ph) - cos(ph))*r))

    Python

        >>> from sage.all import *
        >>> rot.display(c_spher, c_spher)
        R: U → U
           (r, ph) ↦ (r, arctan2(1/2*(sqrt(3)*cos(ph) + sin(ph))*r, -1/2*(sqrt(3)*sin(ph) - cos(ph))*r))

    Therefore, we use the method `add_expr()` to set the spherical-coordinate expression by hand:

    Sage

        sage: rot.add_expr(c_spher, c_spher, (r, ph+pi/3))
        sage: rot.display(c_spher, c_spher)
        R: U → U
           (r, ph) ↦ (r, 1/3*pi + ph)

    [Python]

        >>> from sage.all import *
        >>> rot.add_expr(c_spher, c_spher, (r, ph+pi/Integer(3)))
        >>> rot.display(c_spher, c_spher)
        R: U → U
           (r, ph) ↦ (r, 1/3*pi + ph)

    The call to `add_expr()` has not deleted the expression in terms of Cartesian coordinates, as we can check by printing the internal dictionary `_coord_expression`, which stores the various internal representations of the continuous map:

    Sage

        sage: rot._coord_expression # random (dictionary output)
        {(Chart (U, (x, y)), Chart (U, (x, y))):
         Coordinate functions (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)
          on the Chart (U, (x, y)),
         (Chart (U, (r, ph)), Chart (U, (r, ph))):
          Coordinate functions (r, 1/3*pi + ph) on the Chart (U, (r, ph))}

    Python

        >>> from sage.all import *
        >>> rot._coord_expression # random (dictionary output)
        {(Chart (U, (x, y)), Chart (U, (x, y))):
         Coordinate functions (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)
          on the Chart (U, (x, y)),
         (Chart (U, (r, ph)), Chart (U, (r, ph))):
          Coordinate functions (r, 1/3*pi + ph) on the Chart (U, (r, ph))}

    If, on the contrary, we use `set_expr()`, the expression in Cartesian coordinates is lost:

    Sage

        sage: rot.set_expr(c_spher, c_spher, (r, ph+pi/3))
        sage: rot._coord_expression
        {(Chart (U, (r, ph)), Chart (U, (r, ph))):
         Coordinate functions (r, 1/3*pi + ph) on the Chart (U, (r, ph))}

    [Python]

        >>> from sage.all import *
        >>> rot.set_expr(c_spher, c_spher, (r, ph+pi/Integer(3)))
        >>> rot._coord_expression
        {(Chart (U, (r, ph)), Chart (U, (r, ph))):
         Coordinate functions (r, 1/3*pi + ph) on the Chart (U, (r, ph))}

    It is recovered (thanks to the known change of coordinates) by a call to `display()`:

    Sage

        sage: rot.display(c_cart, c_cart)
        R: U → U
           (x, y) ↦ (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)

        sage: rot._coord_expression # random (dictionary output)
        {(Chart (U, (x, y)), Chart (U, (x, y))):
         Coordinate functions (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)
          on the Chart (U, (x, y)),
         (Chart (U, (r, ph)), Chart (U, (r, ph))):
         Coordinate functions (r, 1/3*pi + ph) on the Chart (U, (r, ph))}

    Python

        >>> from sage.all import *
        >>> rot.display(c_cart, c_cart)
        R: U → U
           (x, y) ↦ (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)

        >>> rot._coord_expression # random (dictionary output)
        {(Chart (U, (x, y)), Chart (U, (x, y))):
         Coordinate functions (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)
          on the Chart (U, (x, y)),
         (Chart (U, (r, ph)), Chart (U, (r, ph))):
         Coordinate functions (r, 1/3*pi + ph) on the Chart (U, (r, ph))}

    The rotation can be applied to a point by means of either coordinate system:

    Sage

        sage: p = M.point((1,2))  #  p defined by its Cartesian coord.
        sage: q = rot(p)  # q is computed by means of Cartesian coord.
        sage: p1 = M.point((sqrt(5), arctan(2)), chart=c_spher) # p1 is defined only in terms of c_spher
        sage: q1 = rot(p1) # computation by means of spherical coordinates
        sage: q1 == q
        True

    [Python]

        >>> from sage.all import *
        >>> p = M.point((Integer(1),Integer(2)))  #  p defined by its Cartesian coord.
        >>> q = rot(p)  # q is computed by means of Cartesian coord.
        >>> p1 = M.point((sqrt(Integer(5)), arctan(Integer(2))), chart=c_spher) # p1 is defined only in terms of c_spher
        >>> q1 = rot(p1) # computation by means of spherical coordinates
        >>> q1 == q
        True

  add_expression(chart1, chart2, coord_functions)

    alias of `add_expr()`.

  coord_functions(chart1=None, chart2=None)

    Return the functions of the coordinates representing `self` in a given pair of charts.

    If these functions are not already known, they are computed from known ones by means of change-of-chart formulas.

    INPUT:

    - `chart1` – (default: `None`) chart on the domain of `self`; if `None`, the domain’s default chart is assumed

    - `chart2` – (default: `None`) chart on the codomain of `self`; if `None`, the codomain’s default chart is assumed

    OUTPUT:

    - a `MultiCoordFunction` representing the continuous map in the above two charts

    EXAMPLES:

    Continuous map from a 2-dimensional manifold to a 3-dimensional one:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: N = Manifold(3, 'N', structure='topological')
        sage: c_uv.<u,v> = M.chart()
        sage: c_xyz.<x,y,z> = N.chart()
        sage: Phi = M.continuous_map(N, (u*v, u/v, u+v), name='Phi',
        ....:                        latex_name=r'\Phi')
        sage: Phi.display()
        Phi: M → N
           (u, v) ↦ (x, y, z) = (u*v, u/v, u + v)
        sage: Phi.coord_functions(c_uv, c_xyz)
        Coordinate functions (u*v, u/v, u + v) on the Chart (M, (u, v))
        sage: Phi.coord_functions() # equivalent to above since 'uv' and 'xyz' are default charts
        Coordinate functions (u*v, u/v, u + v) on the Chart (M, (u, v))
        sage: type(Phi.coord_functions())
        <class 'sage.manifolds.chart_func.MultiCoordFunction'>

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> N = Manifold(Integer(3), 'N', structure='topological')
        >>> c_uv = M.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2)
        >>> c_xyz = N.chart(names=('x', 'y', 'z',)); (x, y, z,) = c_xyz._first_ngens(3)
        >>> Phi = M.continuous_map(N, (u*v, u/v, u+v), name='Phi',
        ...                        latex_name=r'\Phi')
        >>> Phi.display()
        Phi: M → N
           (u, v) ↦ (x, y, z) = (u*v, u/v, u + v)
        >>> Phi.coord_functions(c_uv, c_xyz)
        Coordinate functions (u*v, u/v, u + v) on the Chart (M, (u, v))
        >>> Phi.coord_functions() # equivalent to above since 'uv' and 'xyz' are default charts
        Coordinate functions (u*v, u/v, u + v) on the Chart (M, (u, v))
        >>> type(Phi.coord_functions())
        <class 'sage.manifolds.chart_func.MultiCoordFunction'>

    Coordinate representation in other charts:

    Sage

        sage: c_UV.<U,V> = M.chart()  # new chart on M
        sage: ch_uv_UV = c_uv.transition_map(c_UV, [u-v, u+v])
        sage: ch_uv_UV.inverse()(U,V)
        (1/2*U + 1/2*V, -1/2*U + 1/2*V)
        sage: c_XYZ.<X,Y,Z> = N.chart() # new chart on N
        sage: ch_xyz_XYZ = c_xyz.transition_map(c_XYZ,
        ....:                                   [2*x-3*y+z, y+z-x, -x+2*y-z])
        sage: ch_xyz_XYZ.inverse()(X,Y,Z)
        (3*X + Y + 4*Z, 2*X + Y + 3*Z, X + Y + Z)
        sage: Phi.coord_functions(c_UV, c_xyz)
        Coordinate functions (-1/4*U^2 + 1/4*V^2, -(U + V)/(U - V), V) on
         the Chart (M, (U, V))
        sage: Phi.coord_functions(c_uv, c_XYZ)
        Coordinate functions (((2*u + 1)*v^2 + u*v - 3*u)/v,
         -((u - 1)*v^2 - u*v - u)/v, -((u + 1)*v^2 + u*v - 2*u)/v) on the
         Chart (M, (u, v))
        sage: Phi.coord_functions(c_UV, c_XYZ)
        Coordinate functions
         (-1/2*(U^3 - (U - 2)*V^2 + V^3 - (U^2 + 2*U + 6)*V - 6*U)/(U - V),
          1/4*(U^3 - (U + 4)*V^2 + V^3 - (U^2 - 4*U + 4)*V - 4*U)/(U - V),
          1/4*(U^3 - (U - 4)*V^2 + V^3 - (U^2 + 4*U + 8)*V - 8*U)/(U - V))
         on the Chart (M, (U, V))

    [Python]

        >>> from sage.all import *
        >>> c_UV = M.chart(names=('U', 'V',)); (U, V,) = c_UV._first_ngens(2)# new chart on M
        >>> ch_uv_UV = c_uv.transition_map(c_UV, [u-v, u+v])
        >>> ch_uv_UV.inverse()(U,V)
        (1/2*U + 1/2*V, -1/2*U + 1/2*V)
        >>> c_XYZ = N.chart(names=('X', 'Y', 'Z',)); (X, Y, Z,) = c_XYZ._first_ngens(3)# new chart on N
        >>> ch_xyz_XYZ = c_xyz.transition_map(c_XYZ,
        ...                                   [Integer(2)*x-Integer(3)*y+z, y+z-x, -x+Integer(2)*y-z])
        >>> ch_xyz_XYZ.inverse()(X,Y,Z)
        (3*X + Y + 4*Z, 2*X + Y + 3*Z, X + Y + Z)
        >>> Phi.coord_functions(c_UV, c_xyz)
        Coordinate functions (-1/4*U^2 + 1/4*V^2, -(U + V)/(U - V), V) on
         the Chart (M, (U, V))
        >>> Phi.coord_functions(c_uv, c_XYZ)
        Coordinate functions (((2*u + 1)*v^2 + u*v - 3*u)/v,
         -((u - 1)*v^2 - u*v - u)/v, -((u + 1)*v^2 + u*v - 2*u)/v) on the
         Chart (M, (u, v))
        >>> Phi.coord_functions(c_UV, c_XYZ)
        Coordinate functions
         (-1/2*(U^3 - (U - 2)*V^2 + V^3 - (U^2 + 2*U + 6)*V - 6*U)/(U - V),
          1/4*(U^3 - (U + 4)*V^2 + V^3 - (U^2 - 4*U + 4)*V - 4*U)/(U - V),
          1/4*(U^3 - (U - 4)*V^2 + V^3 - (U^2 + 4*U + 8)*V - 8*U)/(U - V))
         on the Chart (M, (U, V))

    Coordinate representation with respect to a subchart in the domain:

    Sage

        sage: A = M.open_subset('A', coord_def={c_uv: u>0})
        sage: Phi.coord_functions(c_uv.restrict(A), c_xyz)
        Coordinate functions (u*v, u/v, u + v) on the Chart (A, (u, v))

    Python

        >>> from sage.all import *
        >>> A = M.open_subset('A', coord_def={c_uv: u>Integer(0)})
        >>> Phi.coord_functions(c_uv.restrict(A), c_xyz)
        Coordinate functions (u*v, u/v, u + v) on the Chart (A, (u, v))

    Coordinate representation with respect to a superchart in the codomain:

    Sage

        sage: B = N.open_subset('B', coord_def={c_xyz: x<0})
        sage: c_xyz_B = c_xyz.restrict(B)
        sage: Phi1 = M.continuous_map(B, {(c_uv, c_xyz_B): (u*v, u/v, u+v)})
        sage: Phi1.coord_functions(c_uv, c_xyz_B) # definition charts
        Coordinate functions (u*v, u/v, u + v) on the Chart (M, (u, v))
        sage: Phi1.coord_functions(c_uv, c_xyz) # c_xyz = superchart of c_xyz_B
        Coordinate functions (u*v, u/v, u + v) on the Chart (M, (u, v))

    [Python]

        >>> from sage.all import *
        >>> B = N.open_subset('B', coord_def={c_xyz: x<Integer(0)})
        >>> c_xyz_B = c_xyz.restrict(B)
        >>> Phi1 = M.continuous_map(B, {(c_uv, c_xyz_B): (u*v, u/v, u+v)})
        >>> Phi1.coord_functions(c_uv, c_xyz_B) # definition charts
        Coordinate functions (u*v, u/v, u + v) on the Chart (M, (u, v))
        >>> Phi1.coord_functions(c_uv, c_xyz) # c_xyz = superchart of c_xyz_B
        Coordinate functions (u*v, u/v, u + v) on the Chart (M, (u, v))

    Coordinate representation with respect to a pair `(subchart, superchart)`:

    Sage

        sage: Phi1.coord_functions(c_uv.restrict(A), c_xyz)
        Coordinate functions (u*v, u/v, u + v) on the Chart (A, (u, v))

    Python

        >>> from sage.all import *
        >>> Phi1.coord_functions(c_uv.restrict(A), c_xyz)
        Coordinate functions (u*v, u/v, u + v) on the Chart (A, (u, v))

    Same example with SymPy as the symbolic calculus engine:

    Sage

        sage: M.set_calculus_method('sympy')
        sage: N.set_calculus_method('sympy')
        sage: Phi = M.continuous_map(N, (u*v, u/v, u+v), name='Phi',
        ....:                        latex_name=r'\Phi')
        sage: Phi.coord_functions(c_uv, c_xyz)
        Coordinate functions (u*v, u/v, u + v) on the Chart (M, (u, v))
        sage: Phi.coord_functions(c_UV, c_xyz)
        Coordinate functions (-U**2/4 + V**2/4, (-U - V)/(U - V), V) on the Chart (M, (U, V))
        sage: Phi.coord_functions(c_UV, c_XYZ)
        Coordinate functions ((-U**3 + U**2*V + U*V**2 + 2*U*V + 6*U - V**3
         - 2*V**2 + 6*V)/(2*(U - V)), (U**3/4 - U**2*V/4 - U*V**2/4 + U*V
         - U + V**3/4 - V**2 - V)/(U - V), (U**3 - U**2*V - U*V**2 - 4*U*V
         - 8*U + V**3 + 4*V**2 - 8*V)/(4*(U - V))) on the Chart (M, (U, V))

    [Python]

        >>> from sage.all import *
        >>> M.set_calculus_method('sympy')
        >>> N.set_calculus_method('sympy')
        >>> Phi = M.continuous_map(N, (u*v, u/v, u+v), name='Phi',
        ...                        latex_name=r'\Phi')
        >>> Phi.coord_functions(c_uv, c_xyz)
        Coordinate functions (u*v, u/v, u + v) on the Chart (M, (u, v))
        >>> Phi.coord_functions(c_UV, c_xyz)
        Coordinate functions (-U**2/4 + V**2/4, (-U - V)/(U - V), V) on the Chart (M, (U, V))
        >>> Phi.coord_functions(c_UV, c_XYZ)
        Coordinate functions ((-U**3 + U**2*V + U*V**2 + 2*U*V + 6*U - V**3
         - 2*V**2 + 6*V)/(2*(U - V)), (U**3/4 - U**2*V/4 - U*V**2/4 + U*V
         - U + V**3/4 - V**2 - V)/(U - V), (U**3 - U**2*V - U*V**2 - 4*U*V
         - 8*U + V**3 + 4*V**2 - 8*V)/(4*(U - V))) on the Chart (M, (U, V))

  disp(chart1=None, chart2=None)

    alias of `display()`.

  display(chart1=None, chart2=None)

    Display the expression of `self` in one or more pair of charts.

    If the expression is not known already, it is computed from some expression in other charts by means of change-of-coordinate formulas.

    INPUT:

    - `chart1` – (default: `None`) chart on the domain of `self`; if `None`, the display is performed on all the charts on the domain in which the map is known or computable via some change of coordinates

    - `chart2` – (default: `None`) chart on the codomain of `self`; if `None`, the display is performed on all the charts on the codomain in which the map is known or computable via some change of coordinates

    The output is either text-formatted (console mode) or LaTeX-formatted (notebook mode).

    EXAMPLES:

    A simple reparametrization:

    Sage

        sage: R.<t> = manifolds.RealLine()
        sage: I = R.open_interval(0, 2*pi)
        sage: J = R.open_interval(2*pi, 6*pi)
        sage: h = J.continuous_map(I, ((t-2*pi)/2,), name='h')
        sage: h.display()
        h: (2*pi, 6*pi) → (0, 2*pi)
           t ↦ t = -pi + 1/2*t
        sage: latex(h.display())
        \begin{array}{llcl} h:& \left(2 \, \pi, 6 \, \pi\right) &
         \longrightarrow & \left(0, 2 \, \pi\right) \\ & t & \longmapsto &
         t = -\pi + \frac{1}{2} \, t \end{array}

    Python

        >>> from sage.all import *
        >>> R = manifolds.RealLine(names=('t',)); (t,) = R._first_ngens(1)
        >>> I = R.open_interval(Integer(0), Integer(2)*pi)
        >>> J = R.open_interval(Integer(2)*pi, Integer(6)*pi)
        >>> h = J.continuous_map(I, ((t-Integer(2)*pi)/Integer(2),), name='h')
        >>> h.display()
        h: (2*pi, 6*pi) → (0, 2*pi)
           t ↦ t = -pi + 1/2*t
        >>> latex(h.display())
        \begin{array}{llcl} h:& \left(2 \, \pi, 6 \, \pi\right) &
         \longrightarrow & \left(0, 2 \, \pi\right) \\ & t & \longmapsto &
         t = -\pi + \frac{1}{2} \, t \end{array}

    Standard embedding of the sphere \(S^2\) in \(\RR^3\):

    Sage

        sage: M = Manifold(2, 'S^2', structure='topological') # 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: N = Manifold(3, 'R^3', latex_name=r'\RR^3', structure='topological')  # R^3
        sage: c_cart.<X,Y,Z> = N.chart()  # Cartesian coordinates on R^3
        sage: Phi = M.continuous_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.display(c_xy, c_cart)
        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))
        sage: Phi.display(c_uv, c_cart)
        Phi: S^2 → R^3
        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))

    [Python]

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'S^2', structure='topological') # the 2-dimensional sphere S^2
        >>> U = M.open_subset('U') # complement of the North pole
        >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)# stereographic coordinates from the North pole
        >>> V = M.open_subset('V') # complement of the South pole
        >>> c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2)# stereographic coordinates from the South pole
        >>> M.declare_union(U,V)   # S^2 is the union of U and V
        >>> N = Manifold(Integer(3), 'R^3', latex_name=r'\RR^3', structure='topological')  # R^3
        >>> c_cart = N.chart(names=('X', 'Y', 'Z',)); (X, Y, Z,) = c_cart._first_ngens(3)# Cartesian coordinates on R^3
        >>> Phi = M.continuous_map(N,
        ...   {(c_xy, c_cart): [Integer(2)*x/(Integer(1)+x**Integer(2)+y**Integer(2)), Integer(2)*y/(Integer(1)+x**Integer(2)+y**Integer(2)), (x**Integer(2)+y**Integer(2)-Integer(1))/(Integer(1)+x**Integer(2)+y**Integer(2))],
        ...    (c_uv, c_cart): [Integer(2)*u/(Integer(1)+u**Integer(2)+v**Integer(2)), Integer(2)*v/(Integer(1)+u**Integer(2)+v**Integer(2)), (Integer(1)-u**Integer(2)-v**Integer(2))/(Integer(1)+u**Integer(2)+v**Integer(2))]},
        ...   name='Phi', latex_name=r'\Phi')
        >>> Phi.display(c_xy, c_cart)
        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))
        >>> Phi.display(c_uv, c_cart)
        Phi: S^2 → R^3
        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))

    The LaTeX output of that embedding is:

    Sage

        sage: latex(Phi.display(c_xy, c_cart))
        \begin{array}{llcl} \Phi:& S^2 & \longrightarrow & \RR^3
         \\ \text{on}\ U : & \left(x, y\right) & \longmapsto
         & \left(X, Y, Z\right) = \left(\frac{2 \, x}{x^{2} + y^{2} + 1},
           \frac{2 \, y}{x^{2} + y^{2} + 1},
           \frac{x^{2} + y^{2} - 1}{x^{2} + y^{2} + 1}\right)
         \end{array}

    Python

        >>> from sage.all import *
        >>> latex(Phi.display(c_xy, c_cart))
        \begin{array}{llcl} \Phi:& S^2 & \longrightarrow & \RR^3
         \\ \text{on}\ U : & \left(x, y\right) & \longmapsto
         & \left(X, Y, Z\right) = \left(\frac{2 \, x}{x^{2} + y^{2} + 1},
           \frac{2 \, y}{x^{2} + y^{2} + 1},
           \frac{x^{2} + y^{2} - 1}{x^{2} + y^{2} + 1}\right)
         \end{array}

    If the argument `chart2` is not specified, the display is performed on all the charts on the codomain in which the map is known or computable via some change of coordinates (here only one chart: `c_cart`):

    Sage

        sage: Phi.display(c_xy)
        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))

    [Python]

        >>> from sage.all import *
        >>> Phi.display(c_xy)
        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))

    Similarly, if the argument `chart1` is omitted, the display is performed on all the charts on the domain of `Phi` in which the map is known or computable via some change of coordinates:

    Sage

        sage: Phi.display(chart2=c_cart)
        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))

    Python

        >>> from sage.all import *
        >>> Phi.display(chart2=c_cart)
        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))

    If neither `chart1` nor `chart2` is specified, the display is performed on all the pair of charts in which `Phi` is known or computable via some change of coordinates:

    Sage

        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))

    [Python]

        >>> from sage.all import *
        >>> 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))

    If a chart covers entirely the map’s domain, the mention “on …” is omitted:

    Sage

        sage: Phi.restrict(U).display()
        Phi: U → R^3
           (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))

    Python

        >>> from sage.all import *
        >>> Phi.restrict(U).display()
        Phi: U → R^3
           (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))

    A shortcut of `display()` is `disp()`:

    Sage

        sage: Phi.disp()
        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))

    [Python]

        >>> from sage.all import *
        >>> Phi.disp()
        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))

    Display when SymPy is the symbolic engine:

    Sage

        sage: M.set_calculus_method('sympy')
        sage: N.set_calculus_method('sympy')
        sage: Phi.display(c_xy, c_cart)
        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))
        sage: latex(Phi.display(c_xy, c_cart))
        \begin{array}{llcl} \Phi:& S^2 & \longrightarrow & \RR^3
         \\ \text{on}\ U : & \left(x, y\right) & \longmapsto
         & \left(X, Y, Z\right) = \left(\frac{2 x}{x^{2} + y^{2} + 1},
           \frac{2 y}{x^{2} + y^{2} + 1},
           \frac{x^{2} + y^{2} - 1}{x^{2} + y^{2} + 1}\right)
         \end{array}

    Python

        >>> from sage.all import *
        >>> M.set_calculus_method('sympy')
        >>> N.set_calculus_method('sympy')
        >>> Phi.display(c_xy, c_cart)
        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))
        >>> latex(Phi.display(c_xy, c_cart))
        \begin{array}{llcl} \Phi:& S^2 & \longrightarrow & \RR^3
         \\ \text{on}\ U : & \left(x, y\right) & \longmapsto
         & \left(X, Y, Z\right) = \left(\frac{2 x}{x^{2} + y^{2} + 1},
           \frac{2 y}{x^{2} + y^{2} + 1},
           \frac{x^{2} + y^{2} - 1}{x^{2} + y^{2} + 1}\right)
         \end{array}

  expr(chart1=None, chart2=None)

    Return the expression of `self` in terms of specified coordinates.

    If the expression is not already known, it is computed from some known expression by means of change-of-chart formulas.

    INPUT:

    - `chart1` – (default: `None`) chart on the map’s domain; if `None`, the domain’s default chart is assumed

    - `chart2` – (default: `None`) chart on the map’s codomain; if `None`, the codomain’s default chart is assumed

    OUTPUT:

    - symbolic expression representing the continuous map in the above two charts

    EXAMPLES:

    Continuous map from a 2-dimensional manifold to a 3-dimensional one:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: N = Manifold(3, 'N', structure='topological')
        sage: c_uv.<u,v> = M.chart()
        sage: c_xyz.<x,y,z> = N.chart()
        sage: Phi = M.continuous_map(N, (u*v, u/v, u+v), name='Phi',
        ....:                        latex_name=r'\Phi')
        sage: Phi.display()
        Phi: M → N
           (u, v) ↦ (x, y, z) = (u*v, u/v, u + v)
        sage: Phi.expr(c_uv, c_xyz)
        (u*v, u/v, u + v)
        sage: Phi.expr()  # equivalent to above since 'uv' and 'xyz' are default charts
        (u*v, u/v, u + v)
        sage: type(Phi.expr()[0])
        <class 'sage.symbolic.expression.Expression'>

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> N = Manifold(Integer(3), 'N', structure='topological')
        >>> c_uv = M.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2)
        >>> c_xyz = N.chart(names=('x', 'y', 'z',)); (x, y, z,) = c_xyz._first_ngens(3)
        >>> Phi = M.continuous_map(N, (u*v, u/v, u+v), name='Phi',
        ...                        latex_name=r'\Phi')
        >>> Phi.display()
        Phi: M → N
           (u, v) ↦ (x, y, z) = (u*v, u/v, u + v)
        >>> Phi.expr(c_uv, c_xyz)
        (u*v, u/v, u + v)
        >>> Phi.expr()  # equivalent to above since 'uv' and 'xyz' are default charts
        (u*v, u/v, u + v)
        >>> type(Phi.expr()[Integer(0)])
        <class 'sage.symbolic.expression.Expression'>

    Expressions in other charts:

    Sage

        sage: c_UV.<U,V> = M.chart()  # new chart on M
        sage: ch_uv_UV = c_uv.transition_map(c_UV, [u-v, u+v])
        sage: ch_uv_UV.inverse()(U,V)
        (1/2*U + 1/2*V, -1/2*U + 1/2*V)
        sage: c_XYZ.<X,Y,Z> = N.chart() # new chart on N
        sage: ch_xyz_XYZ = c_xyz.transition_map(c_XYZ,
        ....:                                   [2*x-3*y+z, y+z-x, -x+2*y-z])
        sage: ch_xyz_XYZ.inverse()(X,Y,Z)
        (3*X + Y + 4*Z, 2*X + Y + 3*Z, X + Y + Z)
        sage: Phi.expr(c_UV, c_xyz)
        (-1/4*U^2 + 1/4*V^2, -(U + V)/(U - V), V)
        sage: Phi.expr(c_uv, c_XYZ)
        (((2*u + 1)*v^2 + u*v - 3*u)/v,
         -((u - 1)*v^2 - u*v - u)/v,
         -((u + 1)*v^2 + u*v - 2*u)/v)
        sage: Phi.expr(c_UV, c_XYZ)
         (-1/2*(U^3 - (U - 2)*V^2 + V^3 - (U^2 + 2*U + 6)*V - 6*U)/(U - V),
          1/4*(U^3 - (U + 4)*V^2 + V^3 - (U^2 - 4*U + 4)*V - 4*U)/(U - V),
          1/4*(U^3 - (U - 4)*V^2 + V^3 - (U^2 + 4*U + 8)*V - 8*U)/(U - V))

    [Python]

        >>> from sage.all import *
        >>> c_UV = M.chart(names=('U', 'V',)); (U, V,) = c_UV._first_ngens(2)# new chart on M
        >>> ch_uv_UV = c_uv.transition_map(c_UV, [u-v, u+v])
        >>> ch_uv_UV.inverse()(U,V)
        (1/2*U + 1/2*V, -1/2*U + 1/2*V)
        >>> c_XYZ = N.chart(names=('X', 'Y', 'Z',)); (X, Y, Z,) = c_XYZ._first_ngens(3)# new chart on N
        >>> ch_xyz_XYZ = c_xyz.transition_map(c_XYZ,
        ...                                   [Integer(2)*x-Integer(3)*y+z, y+z-x, -x+Integer(2)*y-z])
        >>> ch_xyz_XYZ.inverse()(X,Y,Z)
        (3*X + Y + 4*Z, 2*X + Y + 3*Z, X + Y + Z)
        >>> Phi.expr(c_UV, c_xyz)
        (-1/4*U^2 + 1/4*V^2, -(U + V)/(U - V), V)
        >>> Phi.expr(c_uv, c_XYZ)
        (((2*u + 1)*v^2 + u*v - 3*u)/v,
         -((u - 1)*v^2 - u*v - u)/v,
         -((u + 1)*v^2 + u*v - 2*u)/v)
        >>> Phi.expr(c_UV, c_XYZ)
         (-1/2*(U^3 - (U - 2)*V^2 + V^3 - (U^2 + 2*U + 6)*V - 6*U)/(U - V),
          1/4*(U^3 - (U + 4)*V^2 + V^3 - (U^2 - 4*U + 4)*V - 4*U)/(U - V),
          1/4*(U^3 - (U - 4)*V^2 + V^3 - (U^2 + 4*U + 8)*V - 8*U)/(U - V))

    A rotation in some Euclidean plane:

    Sage

        sage: M = Manifold(2, 'M', structure='topological') # the plane (minus a segment to have global regular spherical coordinates)
        sage: c_spher.<r,ph> = M.chart(r'r:(0,+oo) ph:(0,2*pi):\phi') # spherical coordinates on the plane
        sage: rot = M.continuous_map(M, (r, ph+pi/3), name='R') # pi/3 rotation around r=0
        sage: rot.expr()
        (r, 1/3*pi + ph)

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological') # the plane (minus a segment to have global regular spherical coordinates)
        >>> c_spher = M.chart(r'r:(0,+oo) ph:(0,2*pi):\phi', names=('r', 'ph',)); (r, ph,) = c_spher._first_ngens(2)# spherical coordinates on the plane
        >>> rot = M.continuous_map(M, (r, ph+pi/Integer(3)), name='R') # pi/3 rotation around r=0
        >>> rot.expr()
        (r, 1/3*pi + ph)

    Expression of the rotation in terms of Cartesian coordinates:

    Sage

        sage: c_cart.<x,y> = M.chart() # Declaration of Cartesian coordinates
        sage: ch_spher_cart = c_spher.transition_map(c_cart,
        ....:                 [r*cos(ph), r*sin(ph)]) # relation to spherical coordinates
        sage: ch_spher_cart.set_inverse(sqrt(x^2+y^2), atan2(y,x))
        Check of the inverse coordinate transformation:
          r == r  *passed*
          ph == arctan2(r*sin(ph), r*cos(ph))  **failed**
          x == x  *passed*
          y == y  *passed*
        NB: a failed report can reflect a mere lack of simplification.
        sage: rot.expr(c_cart, c_cart)
        (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)

    [Python]

        >>> from sage.all import *
        >>> c_cart = M.chart(names=('x', 'y',)); (x, y,) = c_cart._first_ngens(2)# Declaration of Cartesian coordinates
        >>> ch_spher_cart = c_spher.transition_map(c_cart,
        ...                 [r*cos(ph), r*sin(ph)]) # relation to spherical coordinates
        >>> ch_spher_cart.set_inverse(sqrt(x**Integer(2)+y**Integer(2)), atan2(y,x))
        Check of the inverse coordinate transformation:
          r == r  *passed*
          ph == arctan2(r*sin(ph), r*cos(ph))  **failed**
          x == x  *passed*
          y == y  *passed*
        NB: a failed report can reflect a mere lack of simplification.
        >>> rot.expr(c_cart, c_cart)
        (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)

  expression(chart1=None, chart2=None)

    alias of `expr()`.

  image(subset=None, inverse=None)

    Return the image of `self` or the image of `subset` under `self`.

    INPUT:

    - `inverse` – (default: `None`) continuous map from `map.codomain()` to `map.domain()`, which once restricted to the image of \(\Phi\) is the inverse of \(\Phi\) onto its image if the latter exists (NB: no check of this is performed)

    - `subset` – (default: the domain of `map`) a subset of the domain of `self`

    EXAMPLES:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: N = Manifold(1, 'N', ambient=M, structure='topological')
        sage: CM.<x,y> = M.chart()
        sage: CN.<u> = N.chart(coord_restrictions=lambda u: [u > -1, u < 1])
        sage: Phi = N.continuous_map(M, {(CN,CM): [u, u^2]}, name='Phi')
        sage: Phi.image()
        Image of the Continuous map Phi
          from the 1-dimensional topological submanifold N
            immersed in the 2-dimensional topological manifold M
          to the 2-dimensional topological manifold M

        sage: S = N.subset('S')
        sage: Phi_S = Phi.image(S); Phi_S
        Image of the Subset S of the
         1-dimensional topological submanifold N
          immersed in the 2-dimensional topological manifold M
         under the Continuous map Phi
          from the 1-dimensional topological submanifold N
           immersed in the 2-dimensional topological manifold M
         to the 2-dimensional topological manifold M
        sage: Phi_S.is_subset(M)
        True

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> N = Manifold(Integer(1), 'N', ambient=M, structure='topological')
        >>> CM = M.chart(names=('x', 'y',)); (x, y,) = CM._first_ngens(2)
        >>> CN = N.chart(coord_restrictions=lambda u: [u > -Integer(1), u < Integer(1)], names=('u',)); (u,) = CN._first_ngens(1)
        >>> Phi = N.continuous_map(M, {(CN,CM): [u, u**Integer(2)]}, name='Phi')
        >>> Phi.image()
        Image of the Continuous map Phi
          from the 1-dimensional topological submanifold N
            immersed in the 2-dimensional topological manifold M
          to the 2-dimensional topological manifold M

        >>> S = N.subset('S')
        >>> Phi_S = Phi.image(S); Phi_S
        Image of the Subset S of the
         1-dimensional topological submanifold N
          immersed in the 2-dimensional topological manifold M
         under the Continuous map Phi
          from the 1-dimensional topological submanifold N
           immersed in the 2-dimensional topological manifold M
         to the 2-dimensional topological manifold M
        >>> Phi_S.is_subset(M)
        True

  inverse()

    Return the inverse of `self` if it is an isomorphism.

    OUTPUT: the inverse isomorphism

    EXAMPLES:

    The inverse of a rotation in the Euclidean plane:

    Sage

        sage: M = Manifold(2, 'R^2', latex_name=r'\RR^2', structure='topological')
        sage: c_cart.<x,y> = M.chart()

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'R^2', latex_name=r'\RR^2', structure='topological')
        >>> c_cart = M.chart(names=('x', 'y',)); (x, y,) = c_cart._first_ngens(2)

    A pi/3 rotation around the origin:

    Sage

        sage: rot = M.homeomorphism(M, ((x - sqrt(3)*y)/2, (sqrt(3)*x + y)/2),
        ....:                       name='R')
        sage: rot.inverse()
        Homeomorphism R^(-1) of the 2-dimensional topological manifold R^2
        sage: rot.inverse().display()
        R^(-1): R^2 → R^2
           (x, y) ↦ (1/2*sqrt(3)*y + 1/2*x, -1/2*sqrt(3)*x + 1/2*y)

    [Python]

        >>> from sage.all import *
        >>> rot = M.homeomorphism(M, ((x - sqrt(Integer(3))*y)/Integer(2), (sqrt(Integer(3))*x + y)/Integer(2)),
        ...                       name='R')
        >>> rot.inverse()
        Homeomorphism R^(-1) of the 2-dimensional topological manifold R^2
        >>> rot.inverse().display()
        R^(-1): R^2 → R^2
           (x, y) ↦ (1/2*sqrt(3)*y + 1/2*x, -1/2*sqrt(3)*x + 1/2*y)

    Checking that applying successively the homeomorphism and its inverse results in the identity:

    Sage

        sage: a, b = var('a b')
        sage: p = M.point((a,b)) # a generic point on M
        sage: q = rot(p)
        sage: p1 = rot.inverse()(q)
        sage: p1 == p
        True

    Python

        >>> from sage.all import *
        >>> a, b = var('a b')
        >>> p = M.point((a,b)) # a generic point on M
        >>> q = rot(p)
        >>> p1 = rot.inverse()(q)
        >>> p1 == p
        True

    The result is cached:

    Sage

        sage: rot.inverse() is rot.inverse()
        True

    [Python]

        >>> from sage.all import *
        >>> rot.inverse() is rot.inverse()
        True

    The notations `^(-1)` or `~` can also be used for the inverse:

    Sage

        sage: rot^(-1) is rot.inverse()
        True
        sage: ~rot is rot.inverse()
        True

    Python

        >>> from sage.all import *
        >>> rot**(-Integer(1)) is rot.inverse()
        True
        >>> ~rot is rot.inverse()
        True

    An example with multiple charts: the equatorial symmetry on the 2-sphere:

    Sage

        sage: M = Manifold(2, 'M', structure='topological') # 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: s = M.homeomorphism(M, {(c_xy, c_uv): [x, y], (c_uv, c_xy): [u, v]},
        ....:                     name='s')
        sage: s.display()
        s: M → M
        on U: (x, y) ↦ (u, v) = (x, y)
        on V: (u, v) ↦ (x, y) = (u, v)
        sage: si = s.inverse(); si
        Homeomorphism s^(-1) of the 2-dimensional topological manifold M
        sage: si.display()
        s^(-1): M → M
        on U: (x, y) ↦ (u, v) = (x, y)
        on V: (u, v) ↦ (x, y) = (u, v)

    [Python]

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological') # the 2-dimensional sphere S^2
        >>> U = M.open_subset('U') # complement of the North pole
        >>> c_xy = U.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)# stereographic coordinates from the North pole
        >>> V = M.open_subset('V') # complement of the South pole
        >>> c_uv = V.chart(names=('u', 'v',)); (u, v,) = c_uv._first_ngens(2)# stereographic coordinates from the South pole
        >>> M.declare_union(U,V)   # S^2 is the union of U and V
        >>> xy_to_uv = c_xy.transition_map(c_uv, (x/(x**Integer(2)+y**Integer(2)), y/(x**Integer(2)+y**Integer(2))),
        ...                                intersection_name='W',
        ...                                restrictions1=x**Integer(2)+y**Integer(2)!=Integer(0),
        ...                                restrictions2=u**Integer(2)+v**Integer(2)!=Integer(0))
        >>> uv_to_xy = xy_to_uv.inverse()
        >>> s = M.homeomorphism(M, {(c_xy, c_uv): [x, y], (c_uv, c_xy): [u, v]},
        ...                     name='s')
        >>> s.display()
        s: M → M
        on U: (x, y) ↦ (u, v) = (x, y)
        on V: (u, v) ↦ (x, y) = (u, v)
        >>> si = s.inverse(); si
        Homeomorphism s^(-1) of the 2-dimensional topological manifold M
        >>> si.display()
        s^(-1): M → M
        on U: (x, y) ↦ (u, v) = (x, y)
        on V: (u, v) ↦ (x, y) = (u, v)

    The equatorial symmetry is of course an involution:

    Sage

        sage: si == s
        True

    Python

        >>> from sage.all import *
        >>> si == s
        True

  is_identity()

    Check whether `self` is an identity map.

    EXAMPLES:

    Tests on continuous maps of a 2-dimensional manifold:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: M.identity_map().is_identity()  # obviously...
        True
        sage: Hom(M, M).one().is_identity()  # a variant of the obvious
        True
        sage: a = M.continuous_map(M, coord_functions={(X,X): (x, y)})
        sage: a.is_identity()
        True
        sage: a = M.continuous_map(M, coord_functions={(X,X): (x, y+1)})
        sage: a.is_identity()
        False

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> M.identity_map().is_identity()  # obviously...
        True
        >>> Hom(M, M).one().is_identity()  # a variant of the obvious
        True
        >>> a = M.continuous_map(M, coord_functions={(X,X): (x, y)})
        >>> a.is_identity()
        True
        >>> a = M.continuous_map(M, coord_functions={(X,X): (x, y+Integer(1))})
        >>> a.is_identity()
        False

    Of course, if the codomain of the map does not coincide with its domain, the outcome is `False`:

    Sage

        sage: N = Manifold(2, 'N', structure='topological')
        sage: Y.<u,v> = N.chart()
        sage: a = M.continuous_map(N, {(X,Y): (x, y)})
        sage: a.display()
        M → N
           (x, y) ↦ (u, v) = (x, y)
        sage: a.is_identity()
        False

    [Python]

        >>> from sage.all import *
        >>> N = Manifold(Integer(2), 'N', structure='topological')
        >>> Y = N.chart(names=('u', 'v',)); (u, v,) = Y._first_ngens(2)
        >>> a = M.continuous_map(N, {(X,Y): (x, y)})
        >>> a.display()
        M → N
           (x, y) ↦ (u, v) = (x, y)
        >>> a.is_identity()
        False

  preimage(codomain_subset, name=None, latex_name=None)

    Return the preimage of `codomain_subset` under `self`.

    An alias is `pullback()`.

    INPUT:

    - `codomain_subset` – an instance of `ManifoldSubset`

    - `name` – string; name (symbol) given to the subset

    - `latex_name` – string (default: `None`); LaTeX symbol to denote the subset; if none are provided, it is set to `name`

    OUTPUT:

    - either a `TopologicalManifold` or a `ManifoldSubsetPullback`

    EXAMPLES:

    Sage

        sage: R = Manifold(1, 'R', structure='topological')  # field R
        sage: T.<t> = R.chart()  # canonical chart on R
        sage: R2 = Manifold(2, 'R^2', structure='topological')  # R^2
        sage: c_xy.<x,y> = R2.chart() # Cartesian coordinates on R^2
        sage: Phi = R.continuous_map(R2, [cos(t), sin(t)], name='Phi'); Phi
        Continuous map Phi
         from the 1-dimensional topological manifold R
         to the 2-dimensional topological manifold R^2
        sage: Q1 = R2.open_subset('Q1', coord_def={c_xy: [x>0, y>0]}); Q1
        Open subset Q1 of the 2-dimensional topological manifold R^2
        sage: Phi_inv_Q1 = Phi.preimage(Q1); Phi_inv_Q1
        Subset Phi_inv_Q1 of the 1-dimensional topological manifold R
        sage: R.point([pi/4]) in Phi_inv_Q1
        True
        sage: R.point([0]) in Phi_inv_Q1
        False
        sage: R.point([3*pi/4]) in Phi_inv_Q1
        False

    Python

        >>> from sage.all import *
        >>> R = Manifold(Integer(1), 'R', structure='topological')  # field R
        >>> T = R.chart(names=('t',)); (t,) = T._first_ngens(1)# canonical chart on R
        >>> R2 = Manifold(Integer(2), 'R^2', structure='topological')  # R^2
        >>> c_xy = R2.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)# Cartesian coordinates on R^2
        >>> Phi = R.continuous_map(R2, [cos(t), sin(t)], name='Phi'); Phi
        Continuous map Phi
         from the 1-dimensional topological manifold R
         to the 2-dimensional topological manifold R^2
        >>> Q1 = R2.open_subset('Q1', coord_def={c_xy: [x>Integer(0), y>Integer(0)]}); Q1
        Open subset Q1 of the 2-dimensional topological manifold R^2
        >>> Phi_inv_Q1 = Phi.preimage(Q1); Phi_inv_Q1
        Subset Phi_inv_Q1 of the 1-dimensional topological manifold R
        >>> R.point([pi/Integer(4)]) in Phi_inv_Q1
        True
        >>> R.point([Integer(0)]) in Phi_inv_Q1
        False
        >>> R.point([Integer(3)*pi/Integer(4)]) in Phi_inv_Q1
        False

    The identity map is handled specially:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: M.identity_map().preimage(M)
        2-dimensional topological manifold M
        sage: M.identity_map().preimage(M) is M
        True

    [Python]

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> M.identity_map().preimage(M)
        2-dimensional topological manifold M
        >>> M.identity_map().preimage(M) is M
        True

    Another trivial case:

    Sage

        sage: M = Manifold(2, 'M', structure='topological')
        sage: X.<x,y> = M.chart()
        sage: D1 = M.open_subset('D1', coord_def={X: x^2+y^2<1}) # the open unit disk
        sage: D2 = M.open_subset('D2', coord_def={X: x^2+y^2<4})
        sage: f = Hom(D1,D2)({(X.restrict(D1), X.restrict(D2)): (2*x, 2*y)}, name='f')
        sage: f.preimage(D2)
        Open subset D1 of the 2-dimensional topological manifold M
        sage: f.preimage(M)
        Open subset D1 of the 2-dimensional topological manifold M

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'M', structure='topological')
        >>> X = M.chart(names=('x', 'y',)); (x, y,) = X._first_ngens(2)
        >>> D1 = M.open_subset('D1', coord_def={X: x**Integer(2)+y**Integer(2)<Integer(1)}) # the open unit disk
        >>> D2 = M.open_subset('D2', coord_def={X: x**Integer(2)+y**Integer(2)<Integer(4)})
        >>> f = Hom(D1,D2)({(X.restrict(D1), X.restrict(D2)): (Integer(2)*x, Integer(2)*y)}, name='f')
        >>> f.preimage(D2)
        Open subset D1 of the 2-dimensional topological manifold M
        >>> f.preimage(M)
        Open subset D1 of the 2-dimensional topological manifold M

  pullback(codomain_subset, name=None, latex_name=None)

    alias of `preimage()`.

  restrict(subdomain, subcodomain=None)

    Restriction of `self` to some open subset of its domain of definition.

    INPUT:

    - `subdomain` – `TopologicalManifold`; an open subset of the domain of `self`

    - `subcodomain` – (default: `None`) an open subset of the codomain of `self`; if `None`, the codomain of `self` is assumed

    OUTPUT:

    - a `ContinuousMap` that is the restriction of `self` to `subdomain`

    EXAMPLES:

    Restriction to an annulus of a homeomorphism between the open unit disk and \(\RR^2\):

    Sage

        sage: M = Manifold(2, 'R^2', structure='topological')  # R^2
        sage: c_xy.<x,y> = M.chart()  # Cartesian coord. on R^2
        sage: D = M.open_subset('D', coord_def={c_xy: x^2+y^2<1}) # the open unit disk
        sage: Phi = D.continuous_map(M, [x/sqrt(1-x^2-y^2), y/sqrt(1-x^2-y^2)],
        ....:                        name='Phi', latex_name=r'\Phi')
        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))
        sage: c_xy_D = c_xy.restrict(D)
        sage: U = D.open_subset('U', coord_def={c_xy_D: x^2+y^2>1/2}) # the annulus 1/2 < r < 1
        sage: Phi.restrict(U)
        Continuous map Phi
         from the Open subset U of the 2-dimensional topological manifold R^2
         to the 2-dimensional topological manifold R^2
        sage: Phi.restrict(U).parent()
        Set of Morphisms from Open subset U of the 2-dimensional topological
         manifold R^2 to 2-dimensional topological manifold R^2 in Category
         of manifolds over Real Field with 53 bits of precision
        sage: Phi.domain()
        Open subset D of the 2-dimensional topological manifold R^2
        sage: Phi.restrict(U).domain()
        Open subset U of the 2-dimensional topological manifold R^2
        sage: Phi.restrict(U).display()
        Phi: U → R^2
           (x, y) ↦ (x, y) = (x/sqrt(-x^2 - y^2 + 1), y/sqrt(-x^2 - y^2 + 1))

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'R^2', structure='topological')  # R^2
        >>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)# Cartesian coord. on R^2
        >>> D = M.open_subset('D', coord_def={c_xy: x**Integer(2)+y**Integer(2)<Integer(1)}) # the open unit disk
        >>> Phi = D.continuous_map(M, [x/sqrt(Integer(1)-x**Integer(2)-y**Integer(2)), y/sqrt(Integer(1)-x**Integer(2)-y**Integer(2))],
        ...                        name='Phi', latex_name=r'\Phi')
        >>> Phi.display()
        Phi: D → R^2
           (x, y) ↦ (x, y) = (x/sqrt(-x^2 - y^2 + 1), y/sqrt(-x^2 - y^2 + 1))
        >>> c_xy_D = c_xy.restrict(D)
        >>> U = D.open_subset('U', coord_def={c_xy_D: x**Integer(2)+y**Integer(2)>Integer(1)/Integer(2)}) # the annulus 1/2 < r < 1
        >>> Phi.restrict(U)
        Continuous map Phi
         from the Open subset U of the 2-dimensional topological manifold R^2
         to the 2-dimensional topological manifold R^2
        >>> Phi.restrict(U).parent()
        Set of Morphisms from Open subset U of the 2-dimensional topological
         manifold R^2 to 2-dimensional topological manifold R^2 in Category
         of manifolds over Real Field with 53 bits of precision
        >>> Phi.domain()
        Open subset D of the 2-dimensional topological manifold R^2
        >>> Phi.restrict(U).domain()
        Open subset U of the 2-dimensional topological manifold R^2
        >>> Phi.restrict(U).display()
        Phi: U → R^2
           (x, y) ↦ (x, y) = (x/sqrt(-x^2 - y^2 + 1), y/sqrt(-x^2 - y^2 + 1))

    The result is cached:

    Sage

        sage: Phi.restrict(U) is Phi.restrict(U)
        True

    [Python]

        >>> from sage.all import *
        >>> Phi.restrict(U) is Phi.restrict(U)
        True

    The restriction of the identity map:

    Sage

        sage: id = D.identity_map() ; id
        Identity map Id_D of the Open subset D of the 2-dimensional
         topological manifold R^2
        sage: id.restrict(U)
        Identity map Id_U of the Open subset U of the 2-dimensional
         topological manifold R^2
        sage: id.restrict(U) is U.identity_map()
        True

    Python

        >>> from sage.all import *
        >>> id = D.identity_map() ; id
        Identity map Id_D of the Open subset D of the 2-dimensional
         topological manifold R^2
        >>> id.restrict(U)
        Identity map Id_U of the Open subset U of the 2-dimensional
         topological manifold R^2
        >>> id.restrict(U) is U.identity_map()
        True

    The codomain can be restricted (i.e. made tighter):

    Sage

        sage: Phi = D.continuous_map(M, [x/sqrt(1+x^2+y^2), y/sqrt(1+x^2+y^2)])
        sage: Phi
        Continuous map from
         the Open subset D of the 2-dimensional topological manifold R^2
         to the 2-dimensional topological manifold R^2
        sage: Phi.restrict(D, subcodomain=D)
        Continuous map from the Open subset D of the 2-dimensional
         topological manifold R^2 to itself

    [Python]

        >>> from sage.all import *
        >>> Phi = D.continuous_map(M, [x/sqrt(Integer(1)+x**Integer(2)+y**Integer(2)), y/sqrt(Integer(1)+x**Integer(2)+y**Integer(2))])
        >>> Phi
        Continuous map from
         the Open subset D of the 2-dimensional topological manifold R^2
         to the 2-dimensional topological manifold R^2
        >>> Phi.restrict(D, subcodomain=D)
        Continuous map from the Open subset D of the 2-dimensional
         topological manifold R^2 to itself

  set_expr(chart1, chart2, coord_functions)

    Set a new coordinate representation of `self`.

    The expressions with respect to other charts are deleted, in order to avoid any inconsistency. To keep them, use `add_expr()` instead.

    INPUT:

    - `chart1` – chart for the coordinates on the domain of `self`

    - `chart2` – chart for the coordinates on the codomain of `self`

    - `coord_functions` – the coordinate symbolic expression of the map in the above charts: list (or tuple) of the coordinates of the image expressed in terms of the coordinates of the considered point; if the dimension of the arrival manifold is 1, a single coordinate expression can be passed instead of a tuple with a single element

    EXAMPLES:

    Polar representation of a planar rotation initially defined in Cartesian coordinates:

    Sage

        sage: M = Manifold(2, 'R^2', latex_name=r'\RR^2', structure='topological')  # the Euclidean plane R^2
        sage: c_xy.<x,y> = M.chart() # Cartesian coordinate on R^2
        sage: U = M.open_subset('U', coord_def={c_xy: (y!=0, x<0)}) # the complement of the segment y=0 and x>0
        sage: c_cart = c_xy.restrict(U) # Cartesian coordinates on U
        sage: c_spher.<r,ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi') # spherical coordinates on U

    Python

        >>> from sage.all import *
        >>> M = Manifold(Integer(2), 'R^2', latex_name=r'\RR^2', structure='topological')  # the Euclidean plane R^2
        >>> c_xy = M.chart(names=('x', 'y',)); (x, y,) = c_xy._first_ngens(2)# Cartesian coordinate on R^2
        >>> U = M.open_subset('U', coord_def={c_xy: (y!=Integer(0), x<Integer(0))}) # the complement of the segment y=0 and x>0
        >>> c_cart = c_xy.restrict(U) # Cartesian coordinates on U
        >>> c_spher = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi', names=('r', 'ph',)); (r, ph,) = c_spher._first_ngens(2)# spherical coordinates on U

    Links between spherical coordinates and Cartesian ones:

    Sage

        sage: ch_cart_spher = c_cart.transition_map(c_spher,
        ....:                                       [sqrt(x*x+y*y), atan2(y,x)])
        sage: ch_cart_spher.set_inverse(r*cos(ph), r*sin(ph))
        Check of the inverse coordinate transformation:
          x == x  *passed*
          y == y  *passed*
          r == r  *passed*
          ph == arctan2(r*sin(ph), r*cos(ph))  **failed**
        NB: a failed report can reflect a mere lack of simplification.
        sage: rot = U.continuous_map(U, ((x - sqrt(3)*y)/2, (sqrt(3)*x + y)/2),
        ....:                        name='R')
        sage: rot.display(c_cart, c_cart)
        R: U → U
           (x, y) ↦ (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)

    [Python]

        >>> from sage.all import *
        >>> ch_cart_spher = c_cart.transition_map(c_spher,
        ...                                       [sqrt(x*x+y*y), atan2(y,x)])
        >>> ch_cart_spher.set_inverse(r*cos(ph), r*sin(ph))
        Check of the inverse coordinate transformation:
          x == x  *passed*
          y == y  *passed*
          r == r  *passed*
          ph == arctan2(r*sin(ph), r*cos(ph))  **failed**
        NB: a failed report can reflect a mere lack of simplification.
        >>> rot = U.continuous_map(U, ((x - sqrt(Integer(3))*y)/Integer(2), (sqrt(Integer(3))*x + y)/Integer(2)),
        ...                        name='R')
        >>> rot.display(c_cart, c_cart)
        R: U → U
           (x, y) ↦ (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)

    Let us use the method `set_expr()` to set the spherical-coordinate expression by hand:

    Sage

        sage: rot.set_expr(c_spher, c_spher, (r, ph+pi/3))
        sage: rot.display(c_spher, c_spher)
        R: U → U
           (r, ph) ↦ (r, 1/3*pi + ph)

    Python

        >>> from sage.all import *
        >>> rot.set_expr(c_spher, c_spher, (r, ph+pi/Integer(3)))
        >>> rot.display(c_spher, c_spher)
        R: U → U
           (r, ph) ↦ (r, 1/3*pi + ph)

    The expression in Cartesian coordinates has been erased:

    Sage

        sage: rot._coord_expression
        {(Chart (U, (r, ph)),
          Chart (U, (r, ph))): Coordinate functions (r, 1/3*pi + ph)
          on the Chart (U, (r, ph))}

    [Python]

        >>> from sage.all import *
        >>> rot._coord_expression
        {(Chart (U, (r, ph)),
          Chart (U, (r, ph))): Coordinate functions (r, 1/3*pi + ph)
          on the Chart (U, (r, ph))}

    It is recovered (thanks to the known change of coordinates) by a call to `display()`:

    Sage

        sage: rot.display(c_cart, c_cart)
        R: U → U
           (x, y) ↦ (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)

        sage: rot._coord_expression  # random (dictionary output)
        {(Chart (U, (x, y)),
          Chart (U, (x, y))): Coordinate functions (-1/2*sqrt(3)*y + 1/2*x,
          1/2*sqrt(3)*x + 1/2*y) on the Chart (U, (x, y)),
         (Chart (U, (r, ph)),
          Chart (U, (r, ph))): Coordinate functions (r, 1/3*pi + ph)
          on the Chart (U, (r, ph))}

    Python

        >>> from sage.all import *
        >>> rot.display(c_cart, c_cart)
        R: U → U
           (x, y) ↦ (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)

        >>> rot._coord_expression  # random (dictionary output)
        {(Chart (U, (x, y)),
          Chart (U, (x, y))): Coordinate functions (-1/2*sqrt(3)*y + 1/2*x,
          1/2*sqrt(3)*x + 1/2*y) on the Chart (U, (x, y)),
         (Chart (U, (r, ph)),
          Chart (U, (r, ph))): Coordinate functions (r, 1/3*pi + ph)
          on the Chart (U, (r, ph))}

  set_expression(chart1, chart2, coord_functions)

    alias of `set_expr()`.